diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..50361afbf6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +docs/changelog.txt merge=union diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..e68a754c63 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1 @@ +If this PR makes an externally-visible change in behavior or API, please add an appropriate line to `docs/changelog.txt`. diff --git a/.github/release_template.md b/.github/release_template.md new file mode 100644 index 0000000000..2bfc7a3c04 --- /dev/null +++ b/.github/release_template.md @@ -0,0 +1,64 @@ +#### Q: How do I download DFHack? +**A:** Either add to your Steam library from our [Steam page](https://store.steampowered.com/app/2346660/DFHack) or scroll to the latest release on our [GitHub releases page](https://github.com/DFHack/dfhack/releases), expand the "Assets" list, and download the file for your platform (e.g. `dfhack-XX.XX-rX-Windows-64bit.zip`. If you are on Windows and are manually installing from the zip file, please remember to right click on the file after downloading, open the file properties, and select the "Unblock" checkbox. This will prevent issues with Windows antivirus programs. + +------------- + +This release is compatible with all distributions of Dwarf Fortress: [Steam](https://store.steampowered.com/app/975370/Dwarf_Fortress/), [Itch](https://kitfoxgames.itch.io/dwarf-fortress), and [Classic](https://www.bay12games.com/dwarves/). + +- [Install DFHack from Steam](https://store.steampowered.com/app/2346660/DFHack) +- [Manual install](https://docs.dfhack.org/en/stable/docs/Installing.html#installing) +- [Quickstart guide (for players)](https://docs.dfhack.org/en/stable/docs/Quickstart.html#quickstart) +- [Modding guide (for modders)](https://docs.dfhack.org/en/stable/docs/guides/modding-guide.html) + +Please report any issues (or feature requests) on the DFHack [GitHub issue tracker](https://github.com/DFHack/dfhack/issues). When reporting issues, please upload a zip file of your savegame and a zip file of your `mods` directory to the cloud and add links to the GitHub issue. Make sure your files are downloadable by "everyone with the link". We need your savegame to reproduce the problem and test the fix, and we need your active mods so we can load your savegame. Issues with savegames and mods attached get fixed first! + +Highlights +---------------------------------- + +
+Highlight 1, Highlight 2 + +### Highlight 1 + +Demo screenshot/vidcap + +Text + +### Highlight 2 + +Demo screenshot/vidcap + +Text + +
+ +Announcements +---------------------------------- + +
+Annc 1, PSAs + +### Annc 1 + +Text + +### PSAs + +As always, remember that, just like the vanilla DF game, DFHack tools can also have bugs. It is a good idea to **save often and keep backups** of the forts that you care about. + +Some DFHack tools that worked in previous (pre-Steam) versions of DF have not been updated yet and are marked with the "unavailable" tag in their docs. If you try to run them, they will show a warning and exit immediately. You can run the command again to override the warning (though of course the tools may not work). We make no guarantees of reliability for the tools that are marked as "unavailable". + +The in-game interface for running DFHack commands (`gui/launcher`) will not show "unavailable" tools by default. You can still run them if you know their names, or you can turn on dev mode by hitting Ctrl-D while in `gui/launcher` and they will be added to the autocomplete list. Some tools listed as "unavailable" in the docs do not compile yet and are not accessible at all, even when in dev mode. + +If you see a tool complaining about the lack of a cursor, know that it's referring to the **keyboard** cursor (which used to be the only real option in Dwarf Fortress). You can enable the keyboard cursor by entering mining mode or selecting the dump/forbid tool and hitting Alt-K (the DFHack keybinding for `toggle-kbd-cursor`). We're working on making DFHack tools more mouse-aware and accessible so this step isn't necessary in the future. + +
+ +Changelog +==================== + +
+New tools, fixes, and improvements + +%RELEASE_NOTES% +
diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml new file mode 100644 index 0000000000..c2d946e300 --- /dev/null +++ b/.github/workflows/build-linux.yml @@ -0,0 +1,205 @@ +name: Build linux64 + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + default: DFHack/dfhack + dfhack_ref: + type: string + scripts_repo: + type: string + default: DFHack/scripts + scripts_ref: + type: string + structures_repo: + type: string + default: DFHack/df-structures + structures_ref: + type: string + stonesense_repo: + type: string + default: DFHack/stonesense + stonesense_ref: + type: string + artifact-name: + type: string + append-date-and-hash: + type: boolean + default: false + cache-id: + type: string + default: '' + cache-readonly: + type: boolean + default: false + platform-files: + type: boolean + default: true + plugins: + type: boolean + default: true + common-files: + type: boolean + default: true + docs: + type: boolean + default: false + html: + type: boolean + default: true + stonesense: + type: boolean + default: false + launchdf: + type: boolean + default: false + extras: + type: boolean + default: false + tests: + type: boolean + default: false + xml-dump-type-sizes: + type: boolean + default: false + gcc-ver: + type: string + default: "11" + +jobs: + build-linux64: + name: Build linux64 + runs-on: ubuntu-22.04 + steps: + - name: Install basic build dependencies + run: | + sudo apt-get update + sudo apt-get install ninja-build + - name: Install binary build dependencies + if: inputs.platform-files || inputs.xml-dump-type-sizes + run: | + sudo apt-get install \ + ccache \ + gcc-${{ inputs.gcc-ver }} \ + g++-${{ inputs.gcc-ver }} \ + libxml-libxslt-perl + - name: Install stonesense dependencies + if: inputs.stonesense + run: sudo apt-get install libgl-dev + - name: Install doc dependencies + if: inputs.docs + run: pip install 'sphinx' + - name: Clone DFHack + uses: actions/checkout@v4 + with: + repository: ${{ inputs.dfhack_repo }} + ref: ${{ inputs.dfhack_ref }} + submodules: true + fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} + - name: Clone scripts + if: inputs.scripts_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.scripts_repo }} + ref: ${{ inputs.scripts_ref }} + path: scripts + - name: Clone structures + if: inputs.structures_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.structures_repo }} + ref: ${{ inputs.structures_ref }} + path: library/xml + - name: Clone stonesense + if: inputs.stonesense_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.stonesense_repo }} + ref: ${{ inputs.stonesense_ref }} + path: plugins/stonesense + - name: Get 3rd party SDKs + if: inputs.launchdf + uses: actions/checkout@v4 + with: + repository: DFHack/3rdparty + ref: main + ssh-key: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} + path: depends/steam + - name: Fetch ccache + if: inputs.platform-files + uses: actions/cache/restore@v4 + with: + path: ~/.cache/ccache + key: linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }}-${{ github.sha }} + restore-keys: | + linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }} + linux-gcc-${{ inputs.gcc-ver }} + - name: Configure DFHack + env: + CC: gcc-${{ inputs.gcc-ver }} + CXX: g++-${{ inputs.gcc-ver }} + run: | + cmake \ + -S . \ + -B build \ + -G Ninja \ + -DCMAKE_INSTALL_PREFIX=build/image \ + -DCMAKE_BUILD_TYPE=Release \ + -DDFHACK_RUN_URL='https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' \ + ${{ inputs.platform-files && '-DCMAKE_C_COMPILER_LAUNCHER=ccache' || '' }} \ + ${{ inputs.platform-files && '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache' || '' }} \ + -DBUILD_LIBRARY:BOOL=${{ inputs.platform-files }} \ + -DBUILD_PLUGINS:BOOL=${{ inputs.platform-files && inputs.plugins }} \ + -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} \ + -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} \ + -DBUILD_DEV_PLUGINS:BOOL=${{ inputs.extras }} \ + -DBUILD_SIZECHECK:BOOL=${{ inputs.extras }} \ + -DBUILD_SKELETON:BOOL=${{ inputs.extras }} \ + -DBUILD_DOCS:BOOL=${{ inputs.docs }} \ + -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} \ + -DBUILD_TESTS:BOOL=${{ inputs.tests }} \ + -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }} \ + ${{ inputs.xml-dump-type-sizes && '-DINSTALL_XMLDUMP:BOOL=1' || ''}} \ + -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} \ + -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} + - name: Build DFHack + run: ninja -C build install + - name: Run cpp tests + if: inputs.platform-files + run: ninja -C build test + - name: Finalize ccache + if: inputs.platform-files + run: | + ccache --show-stats --verbose + ccache --max-size 40M + ccache --cleanup + ccache --max-size 500M + ccache --zero-stats + - name: Save ccache + if: inputs.platform-files && !inputs.cache-readonly + uses: actions/cache/save@v4 + with: + path: ~/.cache/ccache + key: linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }}-${{ github.sha }} + - name: Format artifact name + if: inputs.artifact-name + id: artifactname + run: | + if test "false" = "${{ inputs.append-date-and-hash }}"; then + echo name=${{ inputs.artifact-name }} >> $GITHUB_OUTPUT + else + echo name=${{ inputs.artifact-name }}-$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT + fi + - name: Prep artifact + if: inputs.artifact-name + run: | + cd build/image + tar cjf ../../${{ steps.artifactname.outputs.name }}.tar.bz2 . + - name: Upload artifact + if: inputs.artifact-name + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.artifactname.outputs.name }} + path: ${{ steps.artifactname.outputs.name }}.tar.bz2 diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml new file mode 100644 index 0000000000..1dec211117 --- /dev/null +++ b/.github/workflows/build-windows.yml @@ -0,0 +1,206 @@ +name: Build win64 + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + default: DFHack/dfhack + dfhack_ref: + type: string + scripts_repo: + type: string + default: DFHack/scripts + scripts_ref: + type: string + structures_repo: + type: string + default: DFHack/df-structures + structures_ref: + type: string + stonesense_repo: + type: string + default: DFHack/stonesense + stonesense_ref: + type: string + artifact-name: + type: string + append-date-and-hash: + type: boolean + default: false + cache-id: + type: string + default: '' + cache-readonly: + type: boolean + default: false + platform-files: + type: boolean + default: true + plugins: + type: boolean + default: true + common-files: + type: boolean + default: true + docs: + type: boolean + default: false + html: + type: boolean + default: true + stonesense: + type: boolean + default: false + tests: + type: boolean + default: false + xml-dump-type-sizes: + type: boolean + default: false + launchdf: + type: boolean + default: false + + +jobs: + build-win64: + name: Build win64 + runs-on: windows-2022 + steps: + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.x' + - name: Install build dependencies + run: | + choco install sccache + pip install Jinja2 + - name: Install doc dependencies + if: inputs.docs + run: | + pip install sphinx + - name: Clone DFHack + uses: actions/checkout@v4 + with: + repository: ${{ inputs.dfhack_repo }} + ref: ${{ inputs.dfhack_ref }} + submodules: true + fetch-depth: 0 + - name: Clone scripts + if: inputs.scripts_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.scripts_repo }} + ref: ${{ inputs.scripts_ref }} + path: scripts + - name: Clone structures + if: inputs.structures_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.structures_repo }} + ref: ${{ inputs.structures_ref }} + path: library/xml + - name: Clone stonesense + if: inputs.stonesense_ref + uses: actions/checkout@v4 + with: + repository: ${{ inputs.stonesense_repo }} + ref: ${{ inputs.stonesense_ref }} + path: plugins/stonesense + - name: Get 3rd party SDKs + if: inputs.launchdf + uses: actions/checkout@v4 + with: + repository: DFHack/3rdparty + ref: main + ssh-key: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} + path: depends/steam + - name: Prepare output directories + run: | + mkdir output + mkdir pdb + - name: Get sccache path + run: echo ("SCCACHE_DIR=" + $env:LOCALAPPDATA + "\Mozilla\sccache\cache") >> $env:GITHUB_ENV + - name: Fetch ccache + if: inputs.platform-files + uses: actions/cache/restore@v4 + with: + path: ${{ env.SCCACHE_DIR }} + key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }} + restore-keys: | + win-msvc-${{ inputs.cache-id }} + win-msvc + - uses: ilammy/msvc-dev-cmd@v1 + - name: Configure DFHack + run: | + cmake ` + -S . ` + -B build ` + -GNinja ` + -DDFHACK_BUILD_ARCH=64 ` + -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_INSTALL_PREFIX=output ` + -DCMAKE_C_COMPILER_LAUNCHER=sccache ` + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache ` + -DBUILD_PDBS:BOOL=${{ inputs.cache-id == 'release' }} ` + -DDFHACK_RUN_URL='https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' ` + -DBUILD_LIBRARY=${{ inputs.platform-files }} ` + -DBUILD_PLUGINS:BOOL=${{ inputs.platform-files && inputs.plugins }} ` + -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} ` + -DBUILD_DOCS:BOOL=${{ inputs.docs }} ` + -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} ` + -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} ` + -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} ` + -DBUILD_TESTS:BOOL=${{ inputs.tests }} ` + -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }} ` + ${{ inputs.xml-dump-type-sizes && '-DINSTALL_XMLDUMP:BOOL=1' || '' }} + - name: Build DFHack + env: + SCCACHE_CACHE_SIZE: 500M + run: | + ninja install -C build + - name: Finalize cache + run: | + cd build + sccache --show-stats + sccache --zero-stats + - name: Save ccache + if: inputs.platform-files && !inputs.cache-readonly + uses: actions/cache/save@v4 + with: + path: ${{ env.SCCACHE_DIR }} + key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }} + - name: Format artifact name + if: inputs.artifact-name + id: artifactname + run: | + if ("${{ inputs.append-date-and-hash }}" -eq "false") { + "name=${{ inputs.artifact-name }}" | Out-File -Append $env:GITHUB_OUTPUT + } else { + $date = Get-Date -Format "yyyMMdd" + $hash = git rev-parse --short HEAD + "name=${{ inputs.artifact-name}}-$date-$hash" | Out-File -Append $env:GITHUB_OUTPUT + } + - name: Prep pdbs + if: inputs.artifact-name && inputs.cache-id == 'release' + run: | + Get-ChildItem -Recurse -File -Path "build" -Filter *.pdb | + Copy-Item -Destination "pdb" + - name: Prep artifact + run: | + cd output + 7z a -ttar -so -an . | + 7z a -si -tbzip2 ../${{ steps.artifactname.outputs.name }}.tar.bz2 + - name: Upload artifact + if: inputs.artifact-name + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.artifactname.outputs.name }} + path: ${{ steps.artifactname.outputs.name }}.tar.bz2 + - name: Upload PDBs + if: inputs.artifact-name && inputs.cache-id == 'release' + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.artifactname.outputs.name }}_pdb + path: pdb diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 139bff74f9..3767b42ba5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,170 +3,36 @@ name: Build on: [push, pull_request] jobs: - build: - runs-on: ${{ matrix.os }} - name: build (Linux, GCC ${{ matrix.gcc }}, ${{ matrix.plugins }} plugins) - strategy: - fail-fast: false - matrix: - os: - - ubuntu-18.04 - gcc: - - 4.8 - - 7 - plugins: - - default - include: - - os: ubuntu-20.04 - gcc: 10 - plugins: all - steps: - - name: Set up Python 3 - uses: actions/setup-python@v2 - with: - python-version: 3 - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install \ - libgtk2.0-0 \ - libncursesw5 \ - libsdl-image1.2-dev \ - libsdl-ttf2.0-dev \ - libsdl1.2-dev \ - libxml-libxml-perl \ - libxml-libxslt-perl \ - lua5.3 \ - ninja-build \ - zlib1g-dev - pip install sphinx - - name: Install GCC - run: | - sudo apt-get install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} - - name: Clone DFHack - uses: actions/checkout@v1 - with: - fetch-depth: 0 # unlimited - we need past tags - submodules: true - - name: Set up environment - id: env_setup - run: | - DF_VERSION="$(sh ci/get-df-version.sh)" - echo "::set-output name=df_version::${DF_VERSION}" - echo "DF_VERSION=${DF_VERSION}" >> $GITHUB_ENV - echo "DF_FOLDER=${HOME}/DF/${DF_VERSION}/df_linux" >> $GITHUB_ENV - - name: Fetch DF cache - uses: actions/cache@v2 - with: - path: ~/DF - key: ${{ steps.env_setup.outputs.df_version }} - - name: Download DF - run: | - sh ci/download-df.sh - - name: Build DFHack - env: - CC: gcc-${{ matrix.gcc }} - CXX: g++-${{ matrix.gcc }} - run: | - cmake \ - -S . \ - -B build-ci \ - -G Ninja \ - -DDFHACK_BUILD_ARCH=64 \ - -DBUILD_TESTS:BOOL=ON \ - -DBUILD_DEV_PLUGINS:BOOL=${{ matrix.plugins == 'all' }} \ - -DBUILD_SIZECHECK:BOOL=${{ matrix.plugins == 'all' }} \ - -DBUILD_STONESENSE:BOOL=${{ matrix.plugins == 'all' }} \ - -DBUILD_SUPPORTED:BOOL=1 \ - -DCMAKE_INSTALL_PREFIX="$DF_FOLDER" - ninja -C build-ci install - - name: Run tests - id: run_tests - run: | - export TERM=dumb - status=0 - mv "$DF_FOLDER"/dfhack.init-example "$DF_FOLDER"/dfhack.init - script -qe -c "python ci/run-tests.py --headless --keep-status \"$DF_FOLDER\"" || status=$((status + 1)) - python ci/check-rpc.py "$DF_FOLDER/dfhack-rpc.txt" || status=$((status + 2)) - mkdir -p artifacts - cp "$DF_FOLDER"/test*.json "$DF_FOLDER"/*.log artifacts || status=$((status + 4)) - exit $status - - name: Upload test artifacts - uses: actions/upload-artifact@v1 - if: (success() || failure()) && steps.run_tests.outcome != 'skipped' - continue-on-error: true - with: - name: test-artifacts-${{ matrix.gcc }} - path: artifacts - - name: Clean up DF folder - # prevent DFHack-generated files from ending up in the cache - # (download-df.sh also removes them, this is just to save cache space) - if: success() || failure() - run: | - rm -rf "$DF_FOLDER" + test: + uses: ./.github/workflows/test.yml + with: + dfhack_repo: ${{ github.repository }} + dfhack_ref: ${{ github.ref }} + secrets: inherit + + package: + uses: ./.github/workflows/package.yml + with: + dfhack_repo: ${{ github.repository }} + dfhack_ref: ${{ github.ref }} + secrets: inherit docs: - runs-on: ubuntu-18.04 - steps: - - name: Set up Python 3 - uses: actions/setup-python@v2 - with: - python-version: 3 - - name: Install dependencies - run: | - pip install sphinx - - name: Clone DFHack - uses: actions/checkout@v1 - with: - submodules: true - - name: Build docs - run: | - sphinx-build -W --keep-going -j3 . docs/html - - name: Upload docs - uses: actions/upload-artifact@v1 - with: - name: docs - path: docs/html + uses: ./.github/workflows/build-linux.yml + with: + dfhack_repo: ${{ github.repository }} + dfhack_ref: ${{ github.ref }} + platform-files: false + common-files: false + docs: true + secrets: inherit lint: - runs-on: ubuntu-18.04 - steps: - - name: Set up Python 3 - uses: actions/setup-python@v2 - with: - python-version: 3 - - name: Set up Ruby 2.7 - uses: actions/setup-ruby@v1 - with: - ruby-version: 2.7 - - name: Install Lua - run: | - sudo apt-get update - sudo apt-get install lua5.3 - - name: Clone DFHack - uses: actions/checkout@v1 - with: - submodules: true - # don't need tags here - - name: Check whitespace - run: | - python ci/lint.py --git-only --github-actions - - name: Check Authors.rst - if: success() || failure() - run: | - python ci/authors-rst.py - - name: Check for missing documentation - if: success() || failure() - run: | - python ci/script-docs.py - - name: Check Lua syntax - if: success() || failure() - run: | - python ci/script-syntax.py --ext=lua --cmd="luac5.3 -p" --github-actions - - name: Check Ruby syntax - if: success() || failure() - run: | - python ci/script-syntax.py --ext=rb --cmd="ruby -c" --github-actions + uses: ./.github/workflows/lint.yml + with: + dfhack_repo: ${{ github.repository }} + dfhack_ref: ${{ github.ref }} + secrets: inherit check-pr: runs-on: ubuntu-latest diff --git a/.github/workflows/clean-cache.yml b/.github/workflows/clean-cache.yml new file mode 100644 index 0000000000..91d5675ad8 --- /dev/null +++ b/.github/workflows/clean-cache.yml @@ -0,0 +1,32 @@ +name: Clean up PR caches + +on: + workflow_call: + pull_request_target: + types: + - closed + +jobs: + cleanup: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v4 + - name: Cleanup + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh extension install actions/gh-actions-cache + + REPO=${{ github.repository }} + BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge" + + echo "Fetching list of cache keys" + cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1) + + set +e + echo "Deleting caches..." + for cacheKey in $cacheKeysForPR; do + gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm + done + echo "Done" diff --git a/.github/workflows/generate-symbols.yml b/.github/workflows/generate-symbols.yml new file mode 100644 index 0000000000..f78da19e74 --- /dev/null +++ b/.github/workflows/generate-symbols.yml @@ -0,0 +1,421 @@ +name: Generate symbols + +on: + workflow_dispatch: + inputs: + structures_ref: + description: Structures branch to build from and update + required: true + default: master + version: + description: DF version (can be "auto" if channel is steam) + required: true + platform: + description: Target OS platform + type: choice + required: true + default: all + options: + - all + - windows + - linux + channel: + description: DF distribution channel + type: choice + required: true + default: all + options: + - all + - steam + - itch + - classic + df_steam_branch: + description: DF Steam branch to read from (if processing Steam distribution channel) + required: true + type: choice + default: default + options: + - default + - experimental + - testing + - adventure_test + - beta + steam_branch: + description: DFHack Steam branch to deploy to (leave blank to skip deploy) + type: string + +jobs: + package-linux: + uses: ./.github/workflows/build-linux.yml + if: inputs.platform == 'all' || inputs.platform == 'linux' + with: + dfhack_ref: ${{ github.ref }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: dfhack-symbols-linux64-build + append-date-and-hash: false + cache-id: test + cache-readonly: true + plugins: false + secrets: inherit + + package-win64: + uses: ./.github/workflows/build-windows.yml + if: (inputs.platform == 'all' || inputs.platform == 'windows') && inputs.version == 'auto' + with: + dfhack_ref: ${{ github.ref }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: dfhack-symbols-windows64-build + append-date-and-hash: false + cache-id: test + cache-readonly: true + plugins: false + secrets: inherit + + generate-linux: + name: Generate linux64 symbols + runs-on: ubuntu-latest + if: inputs.platform == 'all' || inputs.platform == 'linux' + needs: + - package-linux + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install \ + ansifilter \ + libsdl2-2.0-0 \ + libsdl2-image-2.0-0 + - name: Clone structures + uses: actions/checkout@v4 + with: + repository: DFHack/df-structures + ref: ${{ inputs.structures_ref }} + token: ${{ secrets.DFHACK_GITHUB_TOKEN }} + path: xml + - name: Download DFHack + uses: actions/download-artifact@v4 + with: + name: dfhack-symbols-linux64-build + - name: Start X server + run: Xvfb :0 -screen 0 1600x1200x24 & + + # Steam + - name: Setup steamcmd + if: inputs.channel == 'all' || inputs.channel == 'steam' + id: steamcmd + uses: CyberAndrii/setup-steamcmd@v1 + - name: Generate Steam symbols + if: inputs.channel == 'all' || inputs.channel == 'steam' + env: + DISPLAY: :0 + STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }} + STEAM_CONFIG_VDF: ${{ secrets.STEAM_CONFIG_VDF }} + STEAM_DF_TESTING: ${{ secrets.STEAM_DF_TESTING }} + STEAM_DF_ADVENTURE_TEST: ${{ secrets.STEAM_DF_ADVENTURE_TEST }} + run: | + mkdir DF_steam + mkdir -p $HOME/Steam/config + echo "$STEAM_CONFIG_VDF" | base64 -d >$HOME/Steam/config/config.vdf + echo "DF steam branch: ${{ inputs.df_steam_branch }}" + if [ "${{ inputs.df_steam_branch }}" = "default" ]; then + BETA_PARAMS="" + elif [ "${{ inputs.df_steam_branch }}" = "testing" ]; then + BETA_PARAMS="-beta testing -betapassword $STEAM_DF_TESTING" + elif [ "${{ inputs.df_steam_branch }}" = "adventure_test" ]; then + BETA_PARAMS="-beta adventure_test -betapassword $STEAM_DF_ADVENTURE_TEST" + else + BETA_PARAMS="-beta ${{ inputs.df_steam_branch }}" + fi + ${{ steps.steamcmd.outputs.executable }} \ + +@ShutdownOnFailedCommand 1 \ + +force_install_dir $PWD/DF_steam \ + +login $STEAM_USERNAME \ + "+app_update 975370 $BETA_PARAMS validate" \ + +quit + tar xjf dfhack-symbols-linux64-build.tar.bz2 -C DF_steam + xml/symbols_gen_linux.sh ${{ inputs.version == 'auto' && '50.0' || inputs.version }} STEAM DF_steam + if [ "${{ inputs.version }}" == "auto" ]; then + while pgrep dwarfort; do + echo "waiting for DF to exit" + sleep 0.5 + done + cp xml/symbols.xml DF_steam/hack + cd DF_steam + DFHACK_DISABLE_CONSOLE=1 ./dfhack & + while ! ./dfhack-run lua 'print(scr)' | fgrep 'viewscreen_titlest' 2>/dev/null; do + echo "waiting for DF to start" + sleep 0.5 + done + df_ver=`./dfhack-run lua 'print(dfhack.gui.getDFViewscreen(true).str_version)' | ansifilter` + echo "Found version string: '$df_ver'" + echo "DETECTED_DF_VER=$df_ver" >>$GITHUB_ENV + sed -i "s/v0.50.0 linux64 STEAM/v0.$df_ver linux64 STEAM/" ../xml/symbols.xml + ./dfhack-run die || true + fi + + # Itch + - name: Generate Itch symbols + if: (inputs.channel == 'all' || inputs.channel == 'itch') && inputs.version != 'auto' + env: + DISPLAY: :0 + ITCH_API_KEY: ${{ secrets.ITCH_API_KEY }} + run: | + mkdir DF_itch + pip install itch-dl + minor=$(echo "${{ inputs.version }}" | cut -d. -f1) + patch=$(echo "${{ inputs.version }}" | cut -d. -f2) + fname="dwarf_fortress_${minor}_${patch}_linux.tar.bz2" + itch-dl https://kitfoxgames.itch.io/dwarf-fortress --download-to . --api-key $ITCH_API_KEY --filter-files-glob "${fname}" + tar xjf "kitfoxgames/dwarf-fortress/files/${fname}" -C DF_itch + tar xjf dfhack-symbols-linux64-build.tar.bz2 -C DF_itch + xml/symbols_gen_linux.sh ${{ inputs.version }} ITCH DF_itch + + # Classic + - name: Generate Classic symbols + if: (inputs.channel == 'all' || inputs.channel == 'classic') && inputs.version != 'auto' + env: + DISPLAY: :0 + run: | + mkdir DF_classic + minor=$(echo "${{ inputs.version }}" | cut -d. -f1) + patch=$(echo "${{ inputs.version }}" | cut -d. -f2) + fname="df_${minor}_${patch}_linux.tar.bz2" + wget "https://www.bay12games.com/dwarves/${fname}" + tar xjf "${fname}" -C DF_classic + tar xjf dfhack-symbols-linux64-build.tar.bz2 -C DF_classic + xml/symbols_gen_linux.sh ${{ inputs.version }} CLASSIC DF_classic + + # Finalize + - name: Merge updates + run: | + cd xml + if ! git diff --exit-code; then + git stash + git pull + git stash pop + fi + - name: Commit symbol updates + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Auto-update symbols for Linux DF version ${{ env.DETECTED_DF_VER || inputs.version }} + repository: xml + commit_user_name: DFHack-Urist via GitHub Actions + commit_user_email: 63161697+DFHack-Urist@users.noreply.github.com + + generate-windows: + name: Generate win64 symbols + runs-on: ubuntu-latest + if: inputs.platform == 'all' || inputs.platform == 'windows' + steps: + - name: Install dependencies + run: pip install pefile + - name: Clone structures + uses: actions/checkout@v4 + with: + repository: DFHack/df-structures + ref: ${{ inputs.structures_ref }} + token: ${{ secrets.DFHACK_GITHUB_TOKEN }} + path: xml + - name: Clone df_misc + uses: actions/checkout@v4 + with: + repository: DFHack/df_misc + path: df_misc + - name: Clone metasm + uses: actions/checkout@v4 + with: + repository: jjyg/metasm + path: metasm + + # Steam + - name: Setup steamcmd + if: inputs.channel == 'all' || inputs.channel == 'steam' + id: steamcmd + uses: CyberAndrii/setup-steamcmd@v1 + - name: Generate Steam symbols + if: inputs.channel == 'all' || inputs.channel == 'steam' + env: + STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }} + STEAM_CONFIG_VDF: ${{ secrets.STEAM_CONFIG_VDF }} + STEAM_DF_TESTING: ${{ secrets.STEAM_DF_TESTING }} + STEAM_DF_ADVENTURE_TEST: ${{ secrets.STEAM_DF_ADVENTURE_TEST }} + run: | + mkdir DF_steam + mkdir -p $HOME/Steam/config + echo "$STEAM_CONFIG_VDF" | base64 -d >$HOME/Steam/config/config.vdf + echo "DF steam branch: ${{ inputs.df_steam_branch }}" + if [ "${{ inputs.df_steam_branch }}" = "default" ]; then + BETA_PARAMS="" + elif [ "${{ inputs.df_steam_branch }}" = "testing" ]; then + BETA_PARAMS="-beta testing -betapassword $STEAM_DF_TESTING" + elif [ "${{ inputs.df_steam_branch }}" = "adventure_test" ]; then + BETA_PARAMS="-beta adventure_test -betapassword $STEAM_DF_ADVENTURE_TEST" + else + BETA_PARAMS="-beta ${{ inputs.df_steam_branch }}" + fi + ${{ steps.steamcmd.outputs.executable }} \ + +@ShutdownOnFailedCommand 1 \ + +@sSteamCmdForcePlatformType windows \ + +force_install_dir $PWD/DF_steam \ + +login $STEAM_USERNAME \ + "+app_update 975370 $BETA_PARAMS validate" \ + +quit + xml/symbols_gen_windows.sh ${{ inputs.version == 'auto' && '50.0' || inputs.version }} STEAM DF_steam + + # Itch + - name: Generate Itch symbols + if: (inputs.channel == 'all' || inputs.channel == 'itch') && inputs.version != 'auto' + env: + ITCH_API_KEY: ${{ secrets.ITCH_API_KEY }} + run: | + mkdir DF_itch + pip install itch-dl + minor=$(echo "${{ inputs.version }}" | cut -d. -f1) + patch=$(echo "${{ inputs.version }}" | cut -d. -f2) + fname="dwarf_fortress_${minor}_${patch}_windows.zip" + itch-dl https://kitfoxgames.itch.io/dwarf-fortress --download-to . --api-key $ITCH_API_KEY --filter-files-glob "${fname}" + unzip -d DF_itch "kitfoxgames/dwarf-fortress/files/${fname}" + xml/symbols_gen_windows.sh ${{ inputs.version }} ITCH DF_itch + + # Classic + - name: Generate Classic symbols + if: (inputs.channel == 'all' || inputs.channel == 'classic') && inputs.version != 'auto' + run: | + mkdir DF_classic + minor=$(echo "${{ inputs.version }}" | cut -d. -f1) + patch=$(echo "${{ inputs.version }}" | cut -d. -f2) + fname="df_${minor}_${patch}_win.zip" + wget "https://www.bay12games.com/dwarves/${fname}" + unzip -d DF_classic "${fname}" + xml/symbols_gen_windows.sh ${{ inputs.version }} CLASSIC DF_classic + + # Finalize + - name: Merge updates + run: | + cd xml + if ! git diff --exit-code; then + git stash + git pull + git stash pop + fi + - name: Commit symbol updates + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Auto-update symbols for Windows DF version ${{ inputs.version }} + repository: xml + commit_user_name: DFHack-Urist via GitHub Actions + commit_user_email: 63161697+DFHack-Urist@users.noreply.github.com + + auto-ver-windows: + name: Autodetect DF version string (Windows) + if: (inputs.platform == 'all' || inputs.platform == 'windows') && (inputs.channel == 'all' || inputs.channel == 'steam') && inputs.version == 'auto' + needs: + - package-win64 + - generate-windows + runs-on: windows-latest + steps: + - name: Clone structures + uses: actions/checkout@v4 + with: + repository: DFHack/df-structures + ref: ${{ inputs.structures_ref }} + token: ${{ secrets.DFHACK_GITHUB_TOKEN }} + path: xml + - name: Download DFHack + uses: actions/download-artifact@v4 + with: + name: dfhack-symbols-windows64-build + - name: Setup steamcmd + id: steamcmd + uses: CyberAndrii/setup-steamcmd@v1 + - name: Update DF version string + env: + STEAM_USERNAME: ${{ secrets.STEAM_USERNAME }} + STEAM_CONFIG_VDF: ${{ secrets.STEAM_CONFIG_VDF }} + STEAM_DF_TESTING: ${{ secrets.STEAM_DF_TESTING }} + STEAM_DF_ADVENTURE_TEST: ${{ secrets.STEAM_DF_ADVENTURE_TEST }} + shell: bash + run: | + mkdir DF_steam + echo "$STEAM_CONFIG_VDF" | base64 -d >${{ steps.steamcmd.outputs.directory }}/config/config.vdf + echo "DF steam branch: ${{ inputs.df_steam_branch }}" + if [ "${{ inputs.df_steam_branch }}" = "default" ]; then + BETA_PARAMS="" + elif [ "${{ inputs.df_steam_branch }}" = "testing" ]; then + BETA_PARAMS="-beta testing -betapassword $STEAM_DF_TESTING" + elif [ "${{ inputs.df_steam_branch }}" = "adventure_test" ]; then + BETA_PARAMS="-beta adventure_test -betapassword $STEAM_DF_ADVENTURE_TEST" + else + BETA_PARAMS="-beta ${{ inputs.df_steam_branch }}" + fi + ${{ steps.steamcmd.outputs.executable }} \ + +@ShutdownOnFailedCommand 1 \ + +@sSteamCmdForcePlatformType windows \ + +force_install_dir $PWD/DF_steam \ + +login $STEAM_USERNAME \ + "+app_update 975370 $BETA_PARAMS validate" \ + +quit + tar xjf dfhack-symbols-windows64-build.tar.bz2 -C DF_steam + cp xml/symbols.xml DF_steam/hack + cd DF_steam + "./Dwarf Fortress.exe" & + while ! ./dfhack-run.exe lua 'print(scr)' | fgrep 'viewscreen_titlest' 2>/dev/null; do + echo "waiting for DF to start" + sleep 0.5 + done + df_ver=`./dfhack-run.exe lua 'print(dfhack.gui.getDFViewscreen(true).str_version)'` + echo "Found version string: '$df_ver'" + echo "DETECTED_DF_VER=$df_ver" >>$GITHUB_ENV + sed -i "s/v0.50.0 win64 STEAM/v0.$df_ver win64 STEAM/" ../xml/symbols.xml + ./dfhack-run.exe die || true + - name: Merge updates + shell: bash + run: | + cd xml + if ! git diff --exit-code; then + git stash + git pull + git stash pop + fi + - name: Commit symbol updates + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Auto-update Windows DF version to ${{ env.DETECTED_DF_VER }} in symbols + repository: xml + commit_user_name: DFHack-Urist via GitHub Actions + commit_user_email: 63161697+DFHack-Urist@users.noreply.github.com + + update-ref: + name: Update structures ref + runs-on: ubuntu-latest + needs: + - generate-linux + - auto-ver-windows + if: ${{ ! failure() }} + steps: + - name: Clone DFHack + uses: actions/checkout@v4 + with: + token: ${{ secrets.DFHACK_GITHUB_TOKEN }} + - name: Update ref + shell: bash + run: | + git submodule update --init --no-single-branch library/xml + cd library/xml + git checkout ${{ inputs.structures_ref }} + git pull + df_ver=`grep -E 'symbol-table.*STEAM' symbols.xml | head -n1 | sed -r "s/.*name='v0.([^ ]+) .*/\1/"` + echo "using DF version: $df_ver" + echo "DETECTED_DF_VER=$df_ver" >>$GITHUB_ENV + - name: Commit ref update + uses: stefanzweifel/git-auto-commit-action@v5 + with: + commit_message: Auto-update structures ref for ${{ env.DETECTED_DF_VER }} + commit_user_name: DFHack-Urist via GitHub Actions + commit_user_email: 63161697+DFHack-Urist@users.noreply.github.com + - name: Launch steam-deploy + if: inputs.steam_branch + shell: bash + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh workflow run steam-deploy.yml -R DFHack/dfhack -r ${{ github.ref }} -f version=${{ env.DETECTED_DF_VER }} -f steam_branch=${{ inputs.steam_branch }} diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml new file mode 100644 index 0000000000..16a4602141 --- /dev/null +++ b/.github/workflows/github-release.yml @@ -0,0 +1,81 @@ +name: Deploy to GitHub + +on: + push: + tags: + - '*-r*' + + workflow_dispatch: + inputs: + ref: + description: Tag + required: true + +jobs: + package: + uses: ./.github/workflows/package.yml + with: + dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} + append-date-and-hash: false + cache-readonly: true + launchdf: true + secrets: inherit + + create-update-release: + name: Draft GitHub release + needs: package + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Install doc dependencies + run: pip install 'sphinx' + - name: Clone DFHack + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} + submodules: true + - name: Get tag + id: gettag + run: | + TAG=$(git describe --tags --abbrev=0 --exact-match) + echo name="$TAG" >> $GITHUB_OUTPUT + echo type=$(echo "$TAG" | egrep 'r[0-9]+$' && echo "release" || echo "prerelease") >> $GITHUB_OUTPUT + - name: Generate release text + run: | + python docs/gen_changelog.py -a + CHANGELOG_FILE=docs/changelogs/${{ steps.gettag.outputs.name }}-github.txt + if ! test -f $CHANGELOG_FILE; then CHANGELOG_FILE=docs/changelogs/future-github.txt; fi + TOKEN_LINE=$(grep -Fhne '%RELEASE_NOTES%' .github/release_template.md | sed 's/:.*//') + head -n $((TOKEN_LINE - 1)) .github/release_template.md > release_body.md + CHANGELOG_LINES=$(wc -l <$CHANGELOG_FILE) + tail -n $((CHANGELOG_LINES - 3)) $CHANGELOG_FILE >> release_body.md + tail -n 1 .github/release_template.md >> release_body.md + cat release_body.md + - name: Stage release + uses: actions/download-artifact@v4 + - name: Prep artifacts + run: | + mkdir artifacts + cd dfhack-windows64-build + tar xjf dfhack-windows64-build.tar.bz2 + rm dfhack-windows64-build.tar.bz2 + zip -qr ../artifacts/dfhack-${{ steps.gettag.outputs.name }}-Windows-64bit.zip . + cd ../dfhack-linux64-build + mv dfhack-linux64-build.tar.bz2 ../artifacts/dfhack-${{ steps.gettag.outputs.name }}-Linux-64bit.tar.bz2 + - name: Create or update GitHub release + uses: ncipollo/release-action@v1 + with: + artifacts: "artifacts/dfhack-*" + bodyFile: "release_body.md" + allowUpdates: true + artifactErrorsFailBuild: true + draft: true + name: "DFHack ${{ steps.gettag.outputs.name }}" + omitBodyDuringUpdate: true + omitDraftDuringUpdate: true + omitNameDuringUpdate: true + omitPrereleaseDuringUpdate: true + prerelease: ${{ steps.gettag.outputs.type == 'prerelease' }} + replacesArtifacts: true + tag: ${{ steps.gettag.outputs.name }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000..0b44747c01 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,50 @@ +name: Lint + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + default: DFHack/dfhack + dfhack_ref: + type: string + scripts_repo: + type: string + default: DFHack/scripts + scripts_ref: + type: string + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Install Lua + run: | + sudo apt-get update + sudo apt-get install lua5.3 + - name: Clone DFHack + uses: actions/checkout@v4 + with: + repository: ${{ inputs.dfhack_repo }} + ref: ${{ inputs.dfhack_ref }} + - name: Get scripts submodule ref + if: '!inputs.scripts_ref' + id: scriptssubmoduleref + run: echo ref=$(git submodule | fgrep scripts | cut -c2-41) >> $GITHUB_OUTPUT + - name: Clone scripts + uses: actions/checkout@v4 + with: + repository: ${{ inputs.scripts_repo }} + ref: ${{ inputs.scripts_ref || steps.scriptssubmoduleref.outputs.ref }} + path: scripts + - name: Check whitespace + run: python ci/lint.py --git-only --github-actions + - name: Check Authors.rst + if: always() + run: python ci/authors-rst.py + - name: Check for missing documentation + if: always() + run: python ci/script-docs.py + - name: Check Lua syntax + if: always() + run: python ci/script-syntax.py --ext=lua --cmd="luac5.3 -p" --github-actions diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml new file mode 100644 index 0000000000..41e72ea636 --- /dev/null +++ b/.github/workflows/package.yml @@ -0,0 +1,76 @@ +name: Package + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + dfhack_ref: + type: string + scripts_repo: + type: string + scripts_ref: + type: string + structures_repo: + type: string + structures_ref: + type: string + append-date-and-hash: + type: boolean + default: true + cache-readonly: + type: boolean + default: false + launchdf: + type: boolean + default: false + include_windows: + type: boolean + default: true + include_linux: + type: boolean + default: true + + +jobs: + package-win64: + name: Windows + uses: ./.github/workflows/build-windows.yml + if: inputs.include_windows + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_repo: ${{ inputs.scripts_repo }} + scripts_ref: ${{ inputs.scripts_ref }} + structures_repo: ${{ inputs.structures_repo }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: dfhack-windows64-build + append-date-and-hash: ${{ inputs.append-date-and-hash }} + cache-id: release + cache-readonly: ${{ inputs.cache-readonly }} + stonesense: true + docs: true + html: false + launchdf: ${{ inputs.launchdf }} + secrets: inherit + + package-linux: + name: Linux + uses: ./.github/workflows/build-linux.yml + if: inputs.include_linux + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_repo: ${{ inputs.scripts_repo }} + scripts_ref: ${{ inputs.scripts_ref }} + structures_repo: ${{ inputs.structures_repo }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: dfhack-linux64-build + append-date-and-hash: ${{ inputs.append-date-and-hash }} + cache-id: release + cache-readonly: ${{ inputs.cache-readonly }} + stonesense: true + docs: true + html: false + launchdf: ${{ inputs.launchdf }} + secrets: inherit diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml new file mode 100644 index 0000000000..2fbe6849e1 --- /dev/null +++ b/.github/workflows/steam-deploy.yml @@ -0,0 +1,96 @@ +name: Deploy to Steam + +on: + push: + tags: + - '*-r*' + workflow_dispatch: + inputs: + version: + description: Version or build description + type: string + required: true + steam_branch: + description: Steam release branch + type: string + required: true + default: staging + +jobs: + depot-common: + name: Common depot files + uses: ./.github/workflows/build-linux.yml + with: + artifact-name: common-depot + dfhack_ref: ${{ github.ref }} + platform-files: false + docs: true + html: false + stonesense: true + secrets: inherit + + depot-win64: + name: Windows depot files + uses: ./.github/workflows/build-windows.yml + with: + artifact-name: win64-depot + dfhack_ref: ${{ github.ref }} + cache-id: release + cache-readonly: true + common-files: false + stonesense: true + launchdf: true + secrets: inherit + + depot-linux64: + name: Linux depot files + uses: ./.github/workflows/build-linux.yml + with: + artifact-name: linux64-depot + dfhack_ref: ${{ github.ref }} + cache-id: release + cache-readonly: true + common-files: false + stonesense: true + launchdf: true + secrets: inherit + + deploy-to-steam: + name: Deploy to Steam + needs: + - depot-common + - depot-win64 + - depot-linux64 + runs-on: ubuntu-latest + concurrency: steamdeploy + steps: + - name: Download depot files + uses: actions/download-artifact@v4 + - name: Stage depot files + run: | + for name in common win64 linux64; do + cd ${name}-depot + tar xjf ${name}-depot.tar.bz2 + rm ${name}-depot.tar.bz2 + cd .. + done + - name: Get short SHA of commit + run: echo "SHORT_SHA=`echo ${{ github.sha }} | cut -c1-8`" >>$GITHUB_ENV + - name: steamcmd cache + uses: actions/cache@v4 + with: + path: /home/runner/work/_temp/_github_home + key: steamcmd-${{ github.sha }} + restore-keys: steamcmd + - name: Steam deploy + uses: game-ci/steam-deploy@v3 + with: + username: ${{ secrets.STEAM_USERNAME }} + configVdf: ${{ secrets.STEAM_CONFIG_VDF}} + appId: 2346660 + buildDescription: ${{ github.event.inputs && github.event.inputs.version || github.ref_name }} (${{ env.SHORT_SHA }}) + rootPath: . + depot1Path: common-depot + depot2Path: win64-depot + depot3Path: linux64-depot + releaseBranch: ${{ github.event.inputs && github.event.inputs.steam_branch || 'staging' }} diff --git a/.github/workflows/test-suite.yml b/.github/workflows/test-suite.yml new file mode 100644 index 0000000000..3fbf683b63 --- /dev/null +++ b/.github/workflows/test-suite.yml @@ -0,0 +1,93 @@ +name: Test suite + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + dfhack_ref: + type: string + os: + type: string + compiler: + type: string + plugins: + type: string + config: + type: string + +jobs: + run-tests: + name: Test (${{ inputs.os }}, ${{ inputs.compiler }}, ${{ inputs.plugins }} plugins, ${{ inputs.config }} config) + runs-on: ${{ inputs.os }}-latest + steps: + - name: Set env + shell: bash + run: echo "DF_FOLDER=DF" >>$GITHUB_ENV + - name: Install dependencies + if: inputs.os == 'ubuntu' + run: | + sudo apt-get update + sudo apt-get install \ + libsdl2-2.0-0 \ + libsdl2-image-2.0-0 + - name: Clone DFHack + uses: actions/checkout@v4 + with: + repository: ${{ inputs.dfhack_repo }} + ref: ${{ inputs.dfhack_ref }} + - name: Detect DF version + shell: bash + run: echo DF_VERSION="$(sh ci/get-df-version.sh)" >>$GITHUB_ENV + - name: Fetch DF cache + id: restore-df + uses: actions/cache/restore@v4 + with: + path: ${{ env.DF_FOLDER }} + key: df-${{ inputs.os }}-${{ env.DF_VERSION }}-${{ hashFiles('ci/download-df.sh') }} + - name: Download DF + if: steps.restore-df.outputs.cache-hit != 'true' + run: sh ci/download-df.sh ${{ env.DF_FOLDER }} ${{ inputs.os }} ${{ env.DF_VERSION }} + - name: Save DF cache + if: steps.restore-df.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ${{ env.DF_FOLDER }} + key: df-${{ inputs.os }}-${{ env.DF_VERSION }}-${{ hashFiles('ci/download-df.sh') }} + - name: Install blank DFHack init scripts + if: inputs.config == 'empty' + shell: bash + run: | + mkdir -p ${{ env.DF_FOLDER }}/dfhack-config/init + cd data/dfhack-config/init + for fname in *.init; do touch ../../../${{ env.DF_FOLDER }}/dfhack-config/init/$fname; done + - name: Download DFHack + uses: actions/download-artifact@v4 + with: + name: test-${{ inputs.compiler }} + - name: Install DFHack + shell: bash + run: tar xjf test-${{ inputs.compiler }}.tar.bz2 -C ${{ env.DF_FOLDER }} + - name: Start X server + if: inputs.os == 'ubuntu' + run: Xvfb :0 -screen 0 1600x1200x24 & + - name: Run lua tests + uses: nick-fields/retry@v3 + env: + DISPLAY: :0 + TERM: xterm-256color + with: + timeout_minutes: 1 + command: python ci/run-tests.py --keep-status "${{ env.DF_FOLDER }}" + - name: Check RPC interface + run: python ci/check-rpc.py "${{ env.DF_FOLDER }}/dfhack-rpc.txt" + - name: Upload test artifacts + uses: actions/upload-artifact@v4 + if: always() + continue-on-error: true + with: + name: test-output-${{ inputs.compiler }}-${{ inputs.plugins }}_plugins-${{ inputs.config }}_config + path: | + ${{ env.DF_FOLDER }}/dfhack-rpc.txt + ${{ env.DF_FOLDER }}/test*.json + ${{ env.DF_FOLDER }}/*.log diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000..175a1adf48 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,113 @@ +name: Test + +on: + workflow_call: + inputs: + dfhack_repo: + type: string + default: DFHack/dfhack + dfhack_ref: + type: string + scripts_repo: + type: string + default: DFHack/scripts + scripts_ref: + type: string + structures_repo: + type: string + default: DFHack/df-structures + structures_ref: + type: string + +jobs: + build-windows: + name: Windows MSVC + uses: ./.github/workflows/build-windows.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_repo: ${{ inputs.scripts_repo }} + scripts_ref: ${{ inputs.scripts_ref }} + structures_repo: ${{ inputs.structures_repo }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: test-msvc + cache-id: test + docs: true + html: false + tests: true + + build-linux: + name: Linux gcc-${{ matrix.gcc }} + uses: ./.github/workflows/build-linux.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_repo: ${{ inputs.scripts_repo }} + scripts_ref: ${{ inputs.scripts_ref }} + structures_repo: ${{ inputs.structures_repo }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: test-gcc-${{ matrix.gcc }} + cache-id: test + stonesense: ${{ matrix.plugins == 'all' }} + extras: ${{ matrix.plugins == 'all' }} + docs: true + html: false + tests: true + gcc-ver: ${{ matrix.gcc }} + secrets: inherit + strategy: + fail-fast: false + matrix: + include: + - gcc: 11 # baseline compatibility with ubuntu LTS 22.04 + plugins: "default" + - gcc: 12 # highest available in ubuntu 22.04 + plugins: "all" + + test-windows: + name: Run Windows test suite + needs: build-windows + uses: ./.github/workflows/test-suite.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + os: windows + compiler: msvc + plugins: default + config: default + + test-windows-empty: + name: Run Windows test suite (empty config) + needs: build-windows + uses: ./.github/workflows/test-suite.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + os: windows + compiler: msvc + plugins: default + config: empty + + test-linux: + name: Run Linux test suite + needs: build-linux + uses: ./.github/workflows/test-suite.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + os: ubuntu + compiler: gcc-11 + plugins: default + config: default + + test-linux-gcc-12-all-plugins: + name: Run Linux test suite (gcc-12, all plugins) + needs: build-linux + uses: ./.github/workflows/test-suite.yml + with: + dfhack_repo: ${{ inputs.dfhack_repo }} + dfhack_ref: ${{ inputs.dfhack_ref }} + os: ubuntu + compiler: gcc-12 + plugins: all + config: default diff --git a/.github/workflows/update-submodules.yml b/.github/workflows/update-submodules.yml index 45eaceb020..c634e94d0a 100644 --- a/.github/workflows/update-submodules.yml +++ b/.github/workflows/update-submodules.yml @@ -4,11 +4,6 @@ on: schedule: - cron: '0 7 * * *' workflow_dispatch: - inputs: - branch: - description: DFHack branch to update - required: false - default: develop jobs: run: @@ -16,10 +11,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Clone DFHack - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: fetch-depth: 0 - ref: ${{ github.event.inputs.branch }} + ref: ${{ github.ref }} submodules: true token: ${{ secrets.DFHACK_GITHUB_TOKEN }} - name: Update submodules diff --git a/.github/workflows/watch-df-release.yml b/.github/workflows/watch-df-release.yml new file mode 100644 index 0000000000..50950140d1 --- /dev/null +++ b/.github/workflows/watch-df-release.yml @@ -0,0 +1,159 @@ +name: Watch DF Releases + +on: + schedule: + - cron: '8/10 * * * *' + workflow_dispatch: + +jobs: + check-steam: + if: github.repository == 'DFHack/dfhack' + name: Check Steam (${{ matrix.df_steam_branch }}) for new DF releases + runs-on: ubuntu-latest + concurrency: watch-release-steam-${{ matrix.df_steam_branch }} + strategy: + fail-fast: false + matrix: + # df_steam_branch: which DF Steam branch to watch + # platform: for symbols generation; leave blank to default to all + # structures_ref: leave blank to default to master + # dfhack_ref: leave blank if no structures update is desired + # steam_branch: leave blank if no DFHack steam push is desired + include: + - df_steam_branch: public +# - df_steam_branch: beta +# - df_steam_branch: experimental +# structures_ref: experimental +# dfhack_ref: experimental +# steam_branch: experimental + steps: + - name: Fetch state + uses: actions/cache/restore@v4 + with: + path: state + key: watch-release-steam-${{ matrix.df_steam_branch }} + - name: Compare branch metadata + uses: nick-fields/retry@v3 + with: + timeout_minutes: 5 + retry_wait_seconds: 60 + command: | + blob=$(wget 'https://api.steamcmd.net/v1/info/975370?pretty=1' -O- | \ + awk '/^ *"branches"/,0' | \ + awk '/^ *"${{ matrix.df_steam_branch }}"/,0') + buildid=$(echo "$blob" | \ + fgrep buildid | \ + head -n1 | \ + cut -d'"' -f4) + timestamp=$(echo "$blob" | \ + fgrep timeupdated | \ + head -n1 | \ + cut -d'"' -f4) + test -z "$buildid" && echo "no buildid result" && exit 1 + test -z "$timestamp" && echo "no timestamp result" && exit 1 + test "$buildid" -gt 0 || exit 1 + test "$timestamp" -gt 0 || exit 1 + echo "buildid and timestamp of last branch update: $buildid, $timestamp" + mkdir -p state + touch state/buildid state/timestamp + last_buildid=$(cat state/buildid) + last_timestamp=$(cat state/timestamp) + if [ -z "$last_timestamp" ]; then + echo "no stored timestamp" + last_buildid=0 + last_timestamp=0 + else + echo "stored buildid and timestamp of last branch update: $last_buildid, $last_timestamp" + fi + if [ "$buildid" -ne "$last_buildid" -a "$timestamp" -gt "$last_timestamp" ]; then + echo "branch updated" + echo "$buildid" >state/buildid + echo "$timestamp" >state/timestamp + echo BUILDID=$buildid >> $GITHUB_ENV + fi + - name: Discord Webhook Action + uses: tsickert/discord-webhook@v5.3.0 + if: env.BUILDID + with: + webhook-url: ${{ secrets.DISCORD_TEAM_PRIVATE_WEBHOOK_URL }} + content: "<@&${{ secrets.DISCORD_TEAM_ROLE_ID }}> Steam ${{ matrix.df_steam_branch }} branch updated (build id: ${{ env.BUILDID }})" + - name: Launch symbol generation workflow + if: env.BUILDID && matrix.dfhack_ref + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh workflow run generate-symbols.yml \ + -R DFHack/dfhack \ + -r ${{ matrix.dfhack_ref }} \ + -f structures_ref=${{ matrix.structures_ref }} \ + -f version=auto \ + -f platform=${{ matrix.platform }} \ + -f channel=steam \ + -f df_steam_branch=${{ matrix.df_steam_branch }} \ + -f steam_branch=${{ matrix.steam_branch }} + - name: Save state + uses: actions/cache/save@v4 + if: env.BUILDID + with: + path: state + key: watch-release-steam-${{ matrix.df_steam_branch }}-${{ env.BUILDID }} + + check-non-steam: + if: github.repository == 'DFHack/dfhack' + name: Check ${{ matrix.channel }} for new DF releases + runs-on: ubuntu-latest + concurrency: watch-release-${{ matrix.channel }} + strategy: + fail-fast: false + matrix: + include: + - channel: itch + url: 'https://kitfoxgames.itch.io/dwarf-fortress' + prefix: 'dwarf_fortress' + - channel: classic + url: 'https://www.bay12games.com/dwarves/' + prefix: 'df' + steps: + - name: Fetch state + uses: actions/cache/restore@v4 + with: + path: state + key: watch-release-${{ matrix.channel }} + - name: Compare versions + uses: nick-fields/retry@v3 + with: + timeout_minutes: 5 + retry_wait_seconds: 60 + command: | + version=$(wget "${{ matrix.url }}" -qO- | tr '"' '\n' | fgrep 'tar.bz2' | head -n1 | sed -r 's/${{ matrix.prefix }}_([0-9]{2})_([0-9]{2})_linux.tar.bz2/\1.\2/') + echo "latest ${{ matrix.channel }} version: $version" + if ! grep -qE '^[0-9]+\.[0-9]+$' <<<"$version"; then + echo "invalid version" + exit 1 + fi + mkdir -p state + touch state/last_version + last_version=$(cat state/last_version) + if [ -z "$last_version" ]; then + echo "no stored version" + last_version=0 + else + echo "stored ${{ matrix.channel }} version: $last_version" + fi + if [ "$(tr -d '.' <<<"$version")" -gt "$(tr -d '.' <<<"$last_version")" ]; then + echo "${{ matrix.channel }} has been updated" + echo "$version" >state/last_version + echo NEW_VERSION=$version >> $GITHUB_ENV + fi + - name: Discord Webhook Action + uses: tsickert/discord-webhook@v5.3.0 + if: env.NEW_VERSION + with: + webhook-url: ${{ secrets.DISCORD_TEAM_PRIVATE_WEBHOOK_URL }} + content: "<@&${{ secrets.DISCORD_TEAM_ROLE_ID }}> ${{ matrix.channel }} updated to ${{ env.NEW_VERSION }}" + - name: Save state + uses: actions/cache/save@v4 + if: env.NEW_VERSION + with: + path: state + key: watch-release-${{ matrix.channel }}-${{ env.NEW_VERSION }} diff --git a/.gitignore b/.gitignore index 4b533ab20f..eda2b226d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # linux backup files *~ -#Kdevelop project files +# Kdevelop project files *.kdev4 .kdev4 @@ -9,27 +9,35 @@ build*/ nix buntu -build/VC2010 #except for the real one !build/ # Sphinx generated documentation -docs/_* +docs/changelogs/ docs/html/ docs/pdf/ +docs/pseudoxml/ +docs/tags/ +docs/text/ +docs/tools/ +docs/xml/ # in-place build build/Makefile build/CMakeCache.txt build/cmake_install.cmake build/CMakeFiles +build/CTestTestfile.cmake +build/DartConfiguration.tcl build/data -build/doc +build/docs build/lua build/bin +build/lib build/depends build/library +build/package build/plugins build/scripts build/install_manifest.txt @@ -40,6 +48,8 @@ build/*ninja* build/compile_commands.json build/dfhack_setarch.txt build/ImportExecutables.cmake +build/Testing +build/_deps # Python binding binaries *.pyc @@ -55,6 +65,7 @@ build/CPack*Config.cmake # VSCode files .vscode +*.code-workspace # ctags file tags @@ -62,7 +73,7 @@ tags # Mac OS X .DS_Store files .DS_Store -#VS is annoying about this one. +# VS is annoying about this one. /build/win64/DF_PATH.txt /build/win32/DF_PATH.txt /.vs @@ -70,5 +81,9 @@ tags # CLion .idea -# custom plugins +# external plugins /plugins/CMakeLists.custom.txt + +# 3rd party downloads +depends/steam +depends/SDL2 diff --git a/.gitmodules b/.gitmodules index 9c5ac2d511..596bafc98f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,6 @@ [submodule "plugins/stonesense"] path = plugins/stonesense url = ../../DFHack/stonesense.git -[submodule "plugins/isoworld"] - path = plugins/isoworld - url = ../../DFHack/isoworld.git [submodule "library/xml"] path = library/xml url = ../../DFHack/df-structures.git @@ -28,3 +25,9 @@ [submodule "depends/luacov"] path = depends/luacov url = ../../DFHack/luacov.git +[submodule "depends/googletest"] + path = depends/googletest + url = ../../google/googletest.git +[submodule "depends/dfhooks"] + path = depends/dfhooks + url = ../../DFHack/dfhooks diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000000..47251d8ed3 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,44 @@ +ci: + autofix_prs: false + autoupdate_schedule: monthly +repos: +# shared across repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: check-added-large-files + - id: check-case-conflict + - id: check-executables-have-shebangs + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-symlinks + - id: check-xml + - id: check-yaml + - id: destroyed-symlinks + - id: end-of-file-fixer + - id: mixed-line-ending + args: ['--fix=lf'] + - id: trailing-whitespace +- repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.37.4 + hooks: + - id: check-github-workflows +- repo: https://github.com/Lucas-C/pre-commit-hooks + rev: v1.5.6 + hooks: + - id: forbid-tabs + exclude_types: + - json + - id: remove-tabs + exclude_types: + - json +# specific to dfhack: +- repo: local + hooks: + - id: authors-rst + name: Check Authors.rst + language: python + entry: python3 ci/authors-rst.py + files: docs/about/Authors\.rst + pass_filenames: false +exclude: '^(depends/|data/.*\.json$|.*\.diff$|.*\.dfstock$)' diff --git a/plugins/tweak/tweaks/cursor-cross.h b/.readthedocs.requirements.txt similarity index 100% rename from plugins/tweak/tweaks/cursor-cross.h rename to .readthedocs.requirements.txt diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 0000000000..bf71c46b78 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,22 @@ +# .readthedocs.yaml +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3" + +submodules: + include: all + +sphinx: + configuration: conf.py + +formats: all + +python: + install: + - requirements: .readthedocs.requirements.txt diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py index e98f7a2a63..31a336b2b6 100644 --- a/.ycm_extra_conf.py +++ b/.ycm_extra_conf.py @@ -19,7 +19,6 @@ def DirectoryOfThisScript(): '-I','depends/md5', '-I','depends/jsoncpp/include', '-I','depends/tinyxml', - '-I','depends/tthread', '-I','depends/clsocket/src', '-x','c++', '-D','PROTOBUF_USE_DLLS', diff --git a/CMake/DownloadFile.cmake b/CMake/DownloadFile.cmake index aabcaeb3a6..d0165b11a3 100644 --- a/CMake/DownloadFile.cmake +++ b/CMake/DownloadFile.cmake @@ -11,7 +11,7 @@ endfunction() function(search_downloads FILE_MD5 VAR) set(${VAR} "" PARENT_SCOPE) - file(GLOB FILES ${CMAKE_SOURCE_DIR}/CMake/downloads/*) + file(GLOB FILES ${dfhack_SOURCE_DIR}/CMake/downloads/*) foreach(FILE ${FILES}) file(MD5 "${FILE}" CUR_MD5) if("${CUR_MD5}" STREQUAL "${FILE_MD5}") @@ -53,7 +53,7 @@ function(download_file_unzip URL ZIP_TYPE ZIP_DEST ZIP_MD5 UNZIP_DEST UNZIP_MD5) message("* Decompressing ${FILENAME}") if("${ZIP_TYPE}" STREQUAL "gz") execute_process(COMMAND - "${PERL_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/depends/gunzip.pl" + "${PERL_EXECUTABLE}" "${dfhack_SOURCE_DIR}/depends/gunzip.pl" "${ZIP_DEST}" --force) else() message(SEND_ERROR "Unknown ZIP_TYPE: ${ZIP_TYPE}") diff --git a/CMake/Modules/FindSphinx.cmake b/CMake/Modules/FindSphinx.cmake index 54fc5ea8dc..6b78a555ff 100644 --- a/CMake/Modules/FindSphinx.cmake +++ b/CMake/Modules/FindSphinx.cmake @@ -13,4 +13,3 @@ find_package_handle_standard_args(Sphinx DEFAULT_MSG ) mark_as_advanced(SPHINX_EXECUTABLE) - diff --git a/CMakeLists.txt b/CMakeLists.txt index f07cdf5af8..1495bea2b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,22 +1,31 @@ # main project file. use it from a build sub-folder, see COMPILE for details ## some generic CMake magic -cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR) +cmake_minimum_required(VERSION 3.18 FATAL_ERROR) cmake_policy(SET CMP0048 NEW) -project(dfhack) +cmake_policy(SET CMP0074 NEW) +set(CMAKE_INSTALL_MESSAGE "LAZY") -if("${CMAKE_GENERATOR}" STREQUAL Ninja) - if("${CMAKE_VERSION}" VERSION_LESS 3.9) - message(WARNING "You are using an old version of CMake (${CMAKE_VERSION}) with Ninja. This may result in ninja errors - see docs/Compile.rst for more details. Upgrading your CMake version is recommended.") - endif() -endif() +# set up versioning. +set(DF_VERSION "53.16") +set(DFHACK_RELEASE "r1.1") +set(DFHACK_PRERELEASE FALSE) -if(NOT("${CMAKE_VERSION}" VERSION_LESS 3.12)) - # make ZLIB_ROOT work in CMake >= 3.12 - # https://cmake.org/cmake/help/git-stage/policy/CMP0074.html - cmake_policy(SET CMP0074 NEW) +set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") +set(DFHACK_ABI_VERSION 2) +set(DFHACK_BUILD_ID "" CACHE STRING "Build ID (should be specified on command line)") + +# set up ccache +find_program(CCACHE_EXECUTABLE "ccache" HINTS /usr/local/bin /opt/local/bin) +if(CCACHE_EXECUTABLE) + message(STATUS "using ccache") + set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE) + set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_EXECUTABLE}" CACHE PATH "ccache" FORCE) endif() +# project must be declared *after* ccache setup +project(dfhack) + # Set up build types if(CMAKE_CONFIGURATION_TYPES) set(CMAKE_CONFIGURATION_TYPES "Release;RelWithDebInfo" CACHE STRING "List of supported configuration types" FORCE) @@ -32,18 +41,20 @@ else(CMAKE_CONFIGURATION_TYPES) endif(CMAKE_CONFIGURATION_TYPES) option(BUILD_DOCS "Choose whether to build the documentation (requires python and Sphinx)." OFF) +option(BUILD_DOCS_NO_HTML "Don't build the HTML docs, only the in-game docs." OFF) option(REMOVE_SYMBOLS_FROM_DF_STUBS "Remove debug symbols from DF stubs. (Reduces libdfhack size to about half but removes a few useful symbols)" ON) macro(CHECK_GCC compiler_path) execute_process(COMMAND ${compiler_path} -dumpversion OUTPUT_VARIABLE GCC_VERSION_OUT) string(STRIP "${GCC_VERSION_OUT}" GCC_VERSION_OUT) - if(${GCC_VERSION_OUT} VERSION_LESS "4.8") - message(SEND_ERROR "${compiler_path} version ${GCC_VERSION_OUT} cannot be used - use GCC 4.8 or later") - elseif(${GCC_VERSION_OUT} VERSION_GREATER "4.9.9") - # GCC 5 changes ABI name mangling to enable C++11 changes. - # This must be disabled to enable linking against DF. - # http://developerblog.redhat.com/2015/02/05/gcc5-and-the-c11-abi/ - add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) + if(${GCC_VERSION_OUT} VERSION_LESS "11") + message(SEND_ERROR "${compiler_path} version ${GCC_VERSION_OUT} cannot be used - use GCC 11 or later") + endif() + # GCC 16 currently has a defect that prevents it from compiling DFHack + # -Warray-bounds is broken in GCC 16 and we'd rather disable the compiler than remove this warning + # will reconsider when this defect is fixed in a future GCC release + if(${GCC_VERSION_OUT} VERSION_GREATER_EQUAL "16") + message(SEND_ERROR "${compiler_path} version ${GCC_VERSION_OUT} cannot be used - use GCC 15 or earlier") endif() endmacro() @@ -61,21 +72,29 @@ if(UNIX) endif() if(WIN32) - if((NOT MSVC) OR (MSVC_VERSION LESS 1900) OR (MSVC_VERSION GREATER 1919)) - message(SEND_ERROR "MSVC 2015 or 2017 is required") + set(MSVC_MIN_VER 1930) + set(MSVC_MAX_VER 1944) + if(NOT MSVC) + message(SEND_ERROR "No MSVC found! MSVC 2022 version ${MSVC_MIN_VER} to ${MSVC_MAX_VER} is required.") + elseif((MSVC_VERSION LESS MSVC_MIN_VER) OR (MSVC_VERSION GREATER MSVC_MAX_VER)) + message(SEND_ERROR "MSVC 2022 version ${MSVC_MIN_VER} to ${MSVC_MAX_VER} is required, Version Found: ${MSVC_VERSION}") endif() endif() -# Ask for C++11 standard from compilers -set(CMAKE_CXX_STANDARD 11) +# Ask for C++-20 standard from compilers +set(CMAKE_CXX_STANDARD 20) # Require the standard support from compilers. set(CMAKE_CXX_STANDARD_REQUIRED ON) # Use only standard c++ to keep code portable set(CMAKE_CXX_EXTENSIONS OFF) if(MSVC) + # increase warning level and treat warnings as errors + add_compile_options("/WX") + add_compile_options("/W3") + # disable C4819 code-page warning - add_definitions("/wd4819") + add_compile_options("/wd4819") # disable use of POSIX name warnings add_definitions("/D_CRT_NONSTDC_NO_WARNINGS /D_CRT_SECURE_NO_WARNINGS") @@ -84,24 +103,46 @@ if(MSVC) # weird and mysterious linking errors, you can disable this, but you'll have to # deal with a LOT of compiler noise over it # see https://msdn.microsoft.com/en-us/library/074af4b6.aspx - add_definitions("/wd4503") + add_compile_options("/wd4503") + + # suppress C4267 - VC++ considers a narrowing conversion from size_t to a smaller + # integer type a warning. this is technically correct but there are so many instances + # of this that we don't want to fix, so.... + add_compile_options("/wd4267") - # suppress C4267 - VC++ complains whenever we implicitly convert an integer to - # a smaller type, and most of the time this is just conversion from 64 to 32 bits - # for things like vector sizes, which are never that big anyway. - add_definitions("/wd4267") + # suppress C4251 - VC++ will warn when exporting an entire class which contains members + # referencing unexported compound types as this is potentially unsafe. because we don't + # guarantee a stable ABI for exports, we don't really care about this, and so we choose to + # be lazy and continue to export entire classes instead of exporting on a method-by-method basis + add_compile_options("/wd4251") + + # suppress C4068 - VC++ will warn for unknown pragmas by default. this is equivalent to gcc + # -Wno-unknown-pragmas (which is enabled for gcc below). + # we could work around this with sufficiently complex macros + add_compile_options("/wd4068") + + # suppress C4244 - VC++ warns by default (with /W3) about narrowing conversions that may lose data + # (such as double -> int or int32_t -> int16_t). dfhack has many of these, mostly related to Lua + # this is equivalent to gcc -Wno_conversions which is the default as gcc -Wall doesn't enable -Wconversions + add_compile_options("/wd4244") + + # Enable C5038 - This is equivalent to gcc's -Werror=reorder, which is enabled by default by gcc -Wall + add_compile_options("/w15038") + + # Enable C4062 - Warns about missing enum case in switch statement, equivalent to gcc -Wswitch + add_compile_options("/w14062") # MSVC panics if an object file contains more than 65,279 sections. this # happens quite frequently with code that uses templates, such as vectors. - add_definitions("/bigobj") + add_compile_options("/bigobj") endif() # Automatically detect architecture based on Visual Studio generator if(MSVC AND NOT DEFINED DFHACK_BUILD_ARCH) - if(${CMAKE_GENERATOR} MATCHES "Win64") - set(DFHACK_BUILD_ARCH "64") + if ((${CMAKE_GENERATOR} MATCHES "Win32") OR (${CMAKE_GENERATOR} MATCHES "x86")) + message(SEND_ERROR "DF v50 does not support 32-bit") else() - set(DFHACK_BUILD_ARCH "32") + set(DFHACK_BUILD_ARCH "64") endif() else() set(DFHACK_BUILD_ARCH "64" CACHE STRING "Architecture to build ('32' or '64')") @@ -117,7 +158,7 @@ elseif("${DFHACK_BUILD_ARCH}" STREQUAL "64") set(DFHACK_SETARCH "x86_64") add_definitions(-DDFHACK64) else() - message(SEND_ERROR "Invalid build architecture (should be 32/64): ${DFHACK_BUILD_ARCH}") + message(SEND_ERROR "Invalid build architecture (should be 32 or 64): ${DFHACK_BUILD_ARCH}") endif() if(CMAKE_CROSSCOMPILING) @@ -128,14 +169,8 @@ endif() find_package(Perl REQUIRED) # set up folder structures for IDE solutions -# MSVC Express won't load solutions that use this. It also doesn't include MFC supported -# Check for MFC! -find_package(MFC QUIET) -if(MFC_FOUND OR (NOT MSVC)) - option(CMAKE_USE_FOLDERS "Enable folder grouping of projects in IDEs." ON) -else() - option(CMAKE_USE_FOLDERS "Enable folder grouping of projects in IDEs." OFF) -endif() +# checking for msvc express is meaningless now, all available editions of msvc support folder groupings +option(CMAKE_USE_FOLDERS "Enable folder grouping of projects in IDEs." ON) if(CMAKE_USE_FOLDERS) set_property(GLOBAL PROPERTY USE_FOLDERS ON) @@ -174,78 +209,58 @@ if(HAVE_CUCHAR2) endif() # mixing the build system with the source code is ugly and stupid. enforce the opposite :) -if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") +if("${dfhack_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}") message(FATAL_ERROR "In-source builds are not allowed.") endif() # make sure all the necessary submodules have been set up if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhack_SOURCE_DIR}/scripts/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/dfhooks/CMakeLists.txt OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/clsocket/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/jsoncpp-sub/CMakeLists.txt OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/libexpat/expat/CMakeLists.txt OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/libzip/CMakeLists.txt OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/xlsxio/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/googletest/CMakeLists.txt OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/luacov/src ) - message(SEND_ERROR "One or more required submodules could not be found! Run 'git submodule update --init' from the root DFHack directory. (See the section 'Getting the Code' in docs/Compile.rst)") + message(SEND_ERROR "One or more required submodules could not be found! Run 'git submodule update --init' from the root DFHack directory. (See the section 'Getting the Code' in docs/dev/compile/Compile.rst)") endif() -# set up versioning. -set(DF_VERSION "0.47.05") -set(DFHACK_RELEASE "r3") -set(DFHACK_PRERELEASE FALSE) - -set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") - -set(DFHACK_ABI_VERSION 1) - -set(DFHACK_BUILD_ID "" CACHE STRING "Build ID (should be specified on command line)") +# dfhack data goes here: +set(DFHACK_DATA_DESTINATION hack) ## where to install things (after the build is done, classic 'make install' or package structure) # the dfhack libraries will be installed here: -if(UNIX) - # put the lib into DF/hack - set(DFHACK_LIBRARY_DESTINATION hack) - set(DFHACK_EGGY_DESTINATION libs) -else() - # windows is crap, therefore we can't do nice things with it. leave the libs on a nasty pile... - set(DFHACK_LIBRARY_DESTINATION .) - set(DFHACK_EGGY_DESTINATION .) -endif() + +# put the lib into DF/hack +# windows will find it because dfhooks will `AddDllDirectory` the hack folder at runtime +set(DFHACK_LIBRARY_DESTINATION ${DFHACK_DATA_DESTINATION}) # external tools will be installed here: set(DFHACK_BINARY_DESTINATION .) -# dfhack data goes here: -set(DFHACK_DATA_DESTINATION hack) # plugin libs go here: -set(DFHACK_PLUGIN_DESTINATION hack/plugins) -# dfhack header files go here: -set(DFHACK_INCLUDES_DESTINATION hack/include) +set(DFHACK_PLUGIN_DESTINATION ${DFHACK_DATA_DESTINATION}/plugins) # dfhack lua files go here: -set(DFHACK_LUA_DESTINATION hack/lua) -# the windows .lib file goes here: -set(DFHACK_DEVLIB_DESTINATION hack) +set(DFHACK_LUA_DESTINATION ${DFHACK_DATA_DESTINATION}/lua) # user documentation goes here: -set(DFHACK_USERDOC_DESTINATION hack) -# developer documentation goes here: -set(DFHACK_DEVDOC_DESTINATION hack) +set(DFHACK_USERDOC_DESTINATION ${DFHACK_DATA_DESTINATION}) # some options for the user/developer to play with -option(BUILD_LIBRARY "Build the library that goes into DF." ON) -option(BUILD_PLUGINS "Build the plugins." ON) +option(BUILD_LIBRARY "Build the DFHack library." ON) +option(BUILD_PLUGINS "Build the DFHack plugins." ON) +option(INSTALL_SCRIPTS "Install DFHack scripts." ON) +option(INSTALL_DATA_FILES "Install DFHack platform independent files." ON) set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) if(UNIX) ## flags for GCC # default to hidden symbols - # build 32bit # ensure compatibility with older CPUs - # enable C++11 features add_definitions(-DLINUX_BUILD) - add_definitions(-D_GLIBCXX_USE_C99) - set(GCC_COMMON_FLAGS "-fvisibility=hidden -mtune=generic -Wall -Werror") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g") + set(GCC_COMMON_FLAGS "-fvisibility=hidden -mtune=generic -Wall -Werror -Wl,--disable-new-dtags -Wno-unknown-pragmas") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COMMON_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_COMMON_FLAGS}") if(DFHACK_BUILD_64) @@ -256,12 +271,20 @@ if(UNIX) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -march=i686") endif() string(REPLACE "-DNDEBUG" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_INSTALL_RPATH "$ORIGIN") elseif(MSVC) # for msvc, tell it to always use 8-byte pointers to member functions to avoid confusion set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /vmg /vmm /MP") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od") string(REPLACE "/O2" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") string(REPLACE "/DNDEBUG" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + + option(BUILD_PDBS "Build PDB debug symbol files." OFF) + if(BUILD_PDBS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Z7") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} /DEBUG") + endif() endif() # use shared libraries for protobuf @@ -277,48 +300,72 @@ elseif(WIN32) add_definitions(-DWIN32) endif() -#### download depends #### +#### dependencies #### + +# fix for pyenv: default to `python3` before `python3.x` +set(Python_FIND_UNVERSIONED_NAMES FIRST) include(CMake/DownloadFile.cmake) if(WIN32) - # Download zlib on Windows - set(ZLIB_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/depends/zlib/lib/win${DFHACK_BUILD_ARCH}) - if(${DFHACK_BUILD_ARCH} STREQUAL "64") - download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-zlib.lib" - ${ZLIB_DOWNLOAD_DIR}/zlib.lib - "a3b2fc6b68efafa89b0882e354fc8418") - else() - download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win32-zlib.lib" - ${ZLIB_DOWNLOAD_DIR}/zlib.lib - "f4ebaa21d9de28566e88b1edfcdff901") + set(ZLIB_FILE zlib.lib) + set(ZLIB_PATH ${dfhack_SOURCE_DIR}/depends/zlib/) + set(ZLIB_MD5 a3b2fc6b68efafa89b0882e354fc8418) + download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-${ZLIB_FILE}" + ${ZLIB_PATH}lib/${ZLIB_FILE} + ${ZLIB_MD5}) + set(ZLIB_ROOT ${ZLIB_PATH}) +else() + # Rescan for pthread and zlib if the build arch changed + if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_BUILD_ARCH_PREV}") + unset(ZLIB_LIBRARY CACHE) + unset(CMAKE_HAVE_PTHREAD_H CACHE) + endif() + + if(NOT APPLE AND DFHACK_BUILD_32) + set(ZLIB_ROOT /usr/lib/i386-linux-gnu) endif() +endif() +find_package(ZLIB REQUIRED) - # Move zlib to the build folder so possible 32 and 64-bit builds - # in the same source tree don't conflict - file(COPY ${CMAKE_SOURCE_DIR}/depends/zlib - DESTINATION ${CMAKE_BINARY_DIR}/depends/) - file(COPY ${ZLIB_DOWNLOAD_DIR}/zlib.lib - DESTINATION ${CMAKE_BINARY_DIR}/depends/zlib/lib/) +set(USE_SYSTEM_SDL2 OFF CACHE BOOL "Set to ON to use the system SDL2 headers.") - # Do the same for SDLreal.dll - # (DFHack doesn't require this at build time, so no need to move it to the build folder) - set(SDLREAL_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/package/windows/win${DFHACK_BUILD_ARCH}) - if(${DFHACK_BUILD_ARCH} STREQUAL "64") - download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-SDL.dll" - ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll - "1ae242c4b94cb03756a1288122a66faf") +if(BUILD_LIBRARY) + if(USE_SYSTEM_SDL2) + find_package(SDL2 REQUIRED CONFIG REQUIRED COMPONENTS SDL2) else() - download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win32-SDL.dll" - ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll - "5a09604daca6b2b5ce049d79af935d6a") + # Download SDL release and extract into depends in the build dir + # all we need are the header files (including generated headers), so the same release package + # will work for all platforms + # (the above statement is untested for OSX) + set(SDL_VERSION 2.26.2) + set(SDL_ZIP_MD5 574daf26d48de753d0b1e19823c9d8bb) + set(SDL_ZIP_FILE SDL2-devel-${SDL_VERSION}-VC.zip) + set(SDL_ZIP_PATH ${dfhack_SOURCE_DIR}/depends/SDL2/) + download_file("https://github.com/libsdl-org/SDL/releases/download/release-${SDL_VERSION}/${SDL_ZIP_FILE}" + ${SDL_ZIP_PATH}${SDL_ZIP_FILE} + ${SDL_ZIP_MD5}) + file(ARCHIVE_EXTRACT INPUT ${SDL_ZIP_PATH}${SDL_ZIP_FILE} + DESTINATION ${SDL_ZIP_PATH}) + set(SDL2_INCLUDE_DIRS ${SDL_ZIP_PATH}/SDL2-${SDL_VERSION}/include) endif() endif() +# this can be made conditional once we get to better platform support for std::format +INCLUDE(FetchContent) +FetchContent_Declare( + fmt + GIT_REPOSITORY https://github.com/fmtlib/fmt.git + GIT_TAG 790b9389ae99c4ddebdd2736a8602eca1fec684e # 12.1.0 + bugfix for MSVC warning + build time improvements +) +FetchContent_MakeAvailable(fmt) +set(FMTLIB fmt) +add_definitions("-DUSE_FMTLIB") + if(APPLE) # libstdc++ (GCC 4.8.5 for OS X 10.6) # fixes crash-on-unwind bug in DF's libstdc++ - set(LIBSTDCXX_DOWNLOAD_DIR ${CMAKE_SOURCE_DIR}/package/darwin/osx${DFHACK_BUILD_ARCH}) + set(LIBSTDCXX_DOWNLOAD_DIR ${dfhack_SOURCE_DIR}/package/darwin/osx${DFHACK_BUILD_ARCH}) if(${GCC_VERSION_OUT} VERSION_LESS "4.9") set(LIBSTDCXX_GCC_VER "48") @@ -373,30 +420,6 @@ endif() #### expose depends #### -if(UNIX) - # Rescan for pthread and zlib if the build arch changed - if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_BUILD_ARCH_PREV}") - unset(ZLIB_LIBRARY CACHE) - unset(CMAKE_HAVE_PTHREAD_H CACHE) - endif() -endif() - -# find and make available libz -if(NOT UNIX) # Windows - # zlib is in here so 32-bit and 64-bit builds in the same source tree are possible - set(ZLIB_ROOT ${CMAKE_BINARY_DIR}/depends/zlib/) -else() - if(NOT APPLE AND DFHACK_BUILD_32) - # 32-bit Linux - set(ZLIB_ROOT /usr/lib/i386-linux-gnu) - endif() -endif() - -find_package(ZLIB REQUIRED) -include_directories(depends/protobuf) -include_directories(depends/lua/include) -include_directories(depends/md5) - # Support linking against external tinyxml # If we find an external tinyxml, set the DFHACK_TINYXML variable to "tinyxml" # Otherwise, set it to "dfhack-tinyxml" @@ -408,16 +431,23 @@ if(EXTERNAL_TINYXML) endif() set(DFHACK_TINYXML "tinyxml") else() - include_directories(depends/tinyxml) set(DFHACK_TINYXML "dfhack-tinyxml") endif() -include_directories(depends/lodepng) -include_directories(depends/tthread) -include_directories(${ZLIB_INCLUDE_DIRS}) -include_directories(depends/clsocket/src) -include_directories(depends/xlsxio/include) -add_subdirectory(depends) +if(BUILD_LIBRARY) + add_subdirectory(depends) +endif() + +# Testing with CTest +macro(dfhack_test name files) +if(BUILD_LIBRARY AND UNIX AND NOT APPLE) # remove this once our MSVC build env has been updated + add_executable(${name} ${files}) + target_include_directories(${name} PUBLIC depends/googletest/googletest/include) + target_link_libraries(${name} dfhack ${FMTLIB} gtest) + add_test(NAME ${name} COMMAND ${name}) +endif() +endmacro() +include(CTest) find_package(Git REQUIRED) if(NOT GIT_FOUND) @@ -425,62 +455,95 @@ if(NOT GIT_FOUND) endif() # build the lib itself +add_subdirectory(library) if(BUILD_LIBRARY) - add_subdirectory(library) - install(FILES LICENSE.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) - install(FILES docs/changelog-placeholder.txt DESTINATION ${DFHACK_USERDOC_DESTINATION} RENAME changelog.txt) + file(WRITE ${CMAKE_BINARY_DIR}/dfhack_setarch.txt ${DFHACK_SETARCH}) + install(FILES ${CMAKE_BINARY_DIR}/dfhack_setarch.txt DESTINATION ${DFHACK_DATA_DESTINATION}) endif() -file(WRITE "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" ${DFHACK_SETARCH}) -install(FILES "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" DESTINATION "${DFHACK_DATA_DESTINATION}") - -install(DIRECTORY dfhack-config/ DESTINATION dfhack-config/default) - # build the plugins -if(BUILD_PLUGINS) - add_subdirectory(plugins) +add_subdirectory(plugins) + +if(INSTALL_DATA_FILES) + add_subdirectory(data) + install(FILES LICENSE.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) + install(FILES docs/changelog-placeholder.txt DESTINATION ${DFHACK_USERDOC_DESTINATION} RENAME changelog.txt) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/depends/luacov/src/luacov/ DESTINATION ${DFHACK_DATA_DESTINATION}/lua/luacov) endif() -add_subdirectory(data) -add_subdirectory(scripts) +if(INSTALL_SCRIPTS) + add_subdirectory(scripts) +endif() -find_package(Sphinx QUIET) if(BUILD_DOCS) + find_package(Python3) + find_package(Sphinx) + if(NOT SPHINX_FOUND) message(SEND_ERROR "Sphinx not found but BUILD_DOCS enabled") endif() - file(GLOB SPHINX_DEPS - "${CMAKE_CURRENT_SOURCE_DIR}/docs/*.rst" - "${CMAKE_CURRENT_SOURCE_DIR}/docs/guides/*.rst" - "${CMAKE_CURRENT_SOURCE_DIR}/docs/changelog.txt" - "${CMAKE_CURRENT_SOURCE_DIR}/docs/gen_changelog.py" + file(GLOB SPHINX_GLOB_DEPS + LIST_DIRECTORIES false "${CMAKE_CURRENT_SOURCE_DIR}/docs/images/*.png" "${CMAKE_CURRENT_SOURCE_DIR}/docs/styles/*" - "${CMAKE_CURRENT_SOURCE_DIR}/conf.py" - "${CMAKE_CURRENT_SOURCE_DIR}/scripts/about.txt" - "${CMAKE_CURRENT_SOURCE_DIR}/scripts/*/about.txt" + "${CMAKE_CURRENT_SOURCE_DIR}/data/init/*init" + ) + file(GLOB_RECURSE SPHINX_GLOB_RECURSE_DEPS + "${CMAKE_CURRENT_SOURCE_DIR}/*.rst" + "${CMAKE_CURRENT_SOURCE_DIR}/changelog.txt" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/*py" ) - file(GLOB_RECURSE SPHINX_SCRIPT_DEPS - "${CMAKE_CURRENT_SOURCE_DIR}/scripts/*.lua" - "${CMAKE_CURRENT_SOURCE_DIR}/scripts/*.rb" + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/changelogs" ) - set(SPHINX_DEPS ${SPHINX_DEPS} ${SPHINX_SCRIPT_DEPS} - "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.rst" + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/html" + ) + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/tags" + ) + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/text" + ) + list(FILTER SPHINX_GLOB_RECURSE_DEPS + EXCLUDE REGEX "docs/tools" + ) + set(SPHINX_DEPS ${SPHINX_GLOB_DEPS} ${SPHINX_GLOB_RECURSE_DEPS} ${SPHINX_SCRIPT_DEPS} "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt" + "${CMAKE_CURRENT_SOURCE_DIR}/conf.py" + ) + + if(BUILD_DOCS_NO_HTML) + set(SPHINX_OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/docs/text/index.txt") + set(SPHINX_BUILD_TARGETS text) + else() + set(SPHINX_OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/docs/html/.buildinfo") + set(SPHINX_BUILD_TARGETS html text) + endif() + + set_property( + DIRECTORY PROPERTY ADDITIONAL_CLEAN_FILES TRUE + "${CMAKE_CURRENT_SOURCE_DIR}/docs/changelogs" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/html" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/pdf" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/pseudoxml" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/tags" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/text" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/tools" + "${CMAKE_CURRENT_SOURCE_DIR}/docs/xml" + "${CMAKE_BINARY_DIR}/docs/html" + "${CMAKE_BINARY_DIR}/docs/pdf" + "${CMAKE_BINARY_DIR}/docs/pseudoxml" + "${CMAKE_BINARY_DIR}/docs/text" + "${CMAKE_BINARY_DIR}/docs/xml" ) - set(SPHINX_OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/docs/html/.buildinfo") - set_source_files_properties(${SPHINX_OUTPUT} PROPERTIES GENERATED TRUE) add_custom_command(OUTPUT ${SPHINX_OUTPUT} - COMMAND ${SPHINX_EXECUTABLE} - -a -E -q -b html - "${CMAKE_CURRENT_SOURCE_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}/docs/html" - -w "${CMAKE_CURRENT_SOURCE_DIR}/docs/_sphinx-warnings.txt" - -j 2 + COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/docs/build.py" + ${SPHINX_BUILD_TARGETS} --sphinx="${SPHINX_EXECUTABLE}" --quiet -- -W DEPENDS ${SPHINX_DEPS} - COMMENT "Building HTML documentation with Sphinx" + COMMENT "Building documentation with Sphinx" ) add_custom_target(dfhack_docs ALL @@ -491,9 +554,15 @@ if(BUILD_DOCS) add_custom_command(TARGET dfhack_docs POST_BUILD COMMAND ${CMAKE_COMMAND} -E touch ${SPHINX_OUTPUT}) - install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/html/ + if(NOT BUILD_DOCS_NO_HTML) + install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/html/ + DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs + FILES_MATCHING PATTERN "*" + PATTERN html/_sources EXCLUDE) + endif() + install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/text/ DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs) - install(FILES docs/_auto/news.rst docs/_auto/news-dev.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) + install(FILES docs/changelogs/news.rst docs/changelogs/news-dev.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) install(FILES "README.html" DESTINATION "${DFHACK_DATA_DESTINATION}") endif() @@ -575,7 +644,9 @@ endif() set(DFHACK_BUILD_ARCH_PREV "${DFHACK_BUILD_ARCH}" CACHE STRING "Previous build architecture" FORCE) option(BUILD_SIZECHECK "Build the sizecheck library, for research" OFF) -if(BUILD_SIZECHECK) +if(BUILD_LIBRARY AND BUILD_SIZECHECK) add_subdirectory(depends/sizecheck) add_dependencies(dfhack sizecheck) endif() + +add_subdirectory(package) diff --git a/CMakeSettings.json b/CMakeSettings.json index fda8ecfd3d..d1511716f7 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -1,76 +1,10 @@ { - "environments": [ - { - "environment": "msvc_2015_x86", - "PATH": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\BIN\\amd64_x86;${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\BIN\\amd64;${env.ProgramFiles(x86)}\\Windows Kits\\10\\bin\\x86;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\bin\\x86;${env.PATH}", - "VS140COMNTOOLS": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", - "VCINSTALLDIR": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\", - "WindowsSdkDir": "${env.ProgramFiles(x86)}\\Windows Kits\\10\\", - "UCRTVersion": "10.0.10240.0", - "UniversalCRTSdkDir": "${env.ProgramFiles(x86)}\\Windows Kits\\10\\", - "LIB": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\LIB;${env.ProgramFiles(x86)}\\Windows Kits\\10\\lib\\10.0.10240.0\\ucrt\\x86;${env.ProgramFiles(x86)}\\Windows Kits\\10\\lib\\um\\x86;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Lib\\winv6.3\\um\\x86", - "INCLUDE": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\INCLUDE;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\shared;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\um;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\winrt;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Include\\um;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Include\\shared", - "LIBPATH": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\LIB" - }, - { - "environment": "msvc_2015_x64", - "PATH": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\BIN\\amd64;${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\BIN;${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\BIN\\1033;${env.ProgramFiles(x86)}\\Windows Kits\\bin\\x64;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\bin\\x64;${env.PATH}", - "VS140COMNTOOLS": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", - "VCINSTALLDIR": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\", - "WindowsSdkDir": "${env.ProgramFiles(x86)}\\Windows Kits\\10\\", - "UCRTVersion": "10.0.10240.0", - "UniversalCRTSdkDir": "${env.ProgramFiles(x86)}\\Windows Kits\\10\\", - "LIB": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64;${env.ProgramFiles(x86)}\\Windows Kits\\10\\lib\\10.0.10240.0\\ucrt\\x64;${env.ProgramFiles(x86)}\\Windows Kits\\10\\lib\\um\\x64;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Lib\\winv6.3\\um\\x64", - "INCLUDE": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\INCLUDE;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\shared;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\um;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\winrt;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Include\\um;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Include\\shared", - "LIBPATH": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64" - } - ], "configurations": [ - { - "name": "MSVC 32 Debug", - "generator": "Ninja", - "configurationType": "RelWithDebInfo", - "inheritEnvironments": [ "msvc_x86_x64", "msvc_2015_x86" ], - "variables": [ - { - "name": "DFHACK_BUILD_ARCH", - "value": "32" - }, - { - "name": "BUILD_STONESENSE", - "value": "1" - }, - { - "name": "REMOVE_SYMBOLS_FROM_DF_STUBS", - "value": "0" - }, - { - "name": "DFHACK_INCLUDE_CORE", - "value": "1" - } - ] - }, - { - "name": "MSVC 32 Release", - "generator": "Ninja", - "configurationType": "Release", - "inheritEnvironments": [ "msvc_x86_x64", "msvc_2015_x86" ], - "variables": [ - { - "name": "DFHACK_BUILD_ARCH", - "value": "32" - }, - { - "name": "BUILD_STONESENSE", - "value": "1" - } - ] - }, { "name": "MSVC 64 Debug", "generator": "Ninja", "configurationType": "RelWithDebInfo", - "inheritEnvironments": [ "msvc_x64_x64", "msvc_2015_x64" ], + "inheritEnvironments": [ "msvc_x64_x64" ], "variables": [ { "name": "DFHACK_BUILD_ARCH", @@ -94,7 +28,7 @@ "name": "MSVC 64 Release", "generator": "Ninja", "configurationType": "Release", - "inheritEnvironments": [ "msvc_x64_x64", "msvc_2015_x64" ], + "inheritEnvironments": [ "msvc_x64_x64" ], "variables": [ { "name": "DFHACK_BUILD_ARCH", diff --git a/LICENSE.rst b/LICENSE.rst index 68678dfb34..1ab6a682ee 100644 --- a/LICENSE.rst +++ b/LICENSE.rst @@ -4,16 +4,19 @@ Licenses ######## -DFHack is distributed under the Zlib license, with some MIT- -and BSD-licensed components. These licenses protect your right -to use DFHack for any purpose, distribute copies, and so on. +DFHack is distributed under the Zlib license, with some MIT- and BSD-licensed +components. These licenses protect your right to use DFHack for any purpose, +distribute copies, and so on. -The core, plugins, scripts, and other DFHack code all use the -ZLib license unless noted otherwise. By contributing to DFHack, -authors release the contributed work under this license. +The core, plugins, scripts, and other DFHack code all use the ZLib license +unless noted otherwise. By contributing to DFHack, authors release the +contributed work under this license. -DFHack also draws on several external packages. -Their licenses are summarised here and reproduced below. +Some graphic assets are derived from vanilla DF assets and used with permission +from Bay12. + +DFHack also draws on several external packages. Their licenses are summarised +here and reproduced below. =============== ============= ================================================= Component License Copyright @@ -31,11 +34,11 @@ luacov_ MIT \(c\) 2007 - 2018 Hisham Muhammad luafilesystem_ MIT \(c\) 2003-2014, Kepler Project lua-profiler_ MIT \(c\) 2002,2003,2004 Pepperfish protobuf_ BSD 3-clause \(c\) 2008, Google Inc. -tinythread_ Zlib \(c\) 2010, Marcus Geelnard tinyxml_ Zlib \(c\) 2000-2006, Lee Thomason UTF-8-decoder_ MIT \(c\) 2008-2010, Bjoern Hoehrmann xlsxio_ MIT \(c\) 2016-2020, Brecht Sanders alt-getopt_ MIT \(c\) 2009 Aleksey Cheusov +googletest_ BSD 3-Clause \(c\) 2008, Google Inc. =============== ============= ================================================= .. _DFHack: https://github.com/DFHack/dfhack @@ -51,11 +54,11 @@ alt-getopt_ MIT \(c\) 2009 Aleksey Cheusov .. _luafilesystem: https://github.com/keplerproject/luafilesystem .. _lua-profiler: http://lua-users.org/wiki/PepperfishProfiler .. _protobuf: https://github.com/google/protobuf -.. _tinythread: http://tinythreadpp.bitsnbites.eu/ .. _tinyxml: http://www.sourceforge.net/projects/tinyxml .. _UTF-8-decoder: http://bjoern.hoehrmann.de/utf-8/decoder/dfa .. _xlsxio: https://github.com/brechtsanders/xlsxio .. _alt-getopt: https://github.com/LuaDist/alt-getopt +.. _googletest: https://github.com/google/googletest .. _CC-BY-SA: http://creativecommons.org/licenses/by/3.0/deed.en_US diff --git a/README.html b/README.html index b8e15a0d11..4d1b0fd13c 100644 --- a/README.html +++ b/README.html @@ -13,4 +13,4 @@ Follow this link to the documentation. - \ No newline at end of file + diff --git a/README.md b/README.md index e4bfefb381..3a2db02fc5 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,13 @@ [![Build Status](https://github.com/DFHack/dfhack/workflows/Build/badge.svg?event=push)](https://github.com/DFHack/dfhack/actions?query=workflow%3ABuild) [![Documentation Status](https://readthedocs.org/projects/dfhack/badge)](https://dfhack.readthedocs.org) [![License](https://img.shields.io/badge/license-ZLib-blue.svg)](https://en.wikipedia.org/wiki/Zlib_License) +[![Discord](https://img.shields.io/discord/793331351645323264)](https://dfhack.org/discord) DFHack is a Dwarf Fortress memory access library, distributed with scripts and plugins implementing a wide variety of useful functions and tools. -The full documentation [is available online here](https://dfhack.readthedocs.org), -from the README.html page in the DFHack distribution, or as raw text in the `./docs` folder. -If you're an end-user, modder, or interested in contributing to DFHack - -go read those docs. +The full documentation [is available online here](https://dfhack.readthedocs.org). +If you have DFHack installed, it is also accessible as raw text in the `hack/docs` folder. +If you're an end-user, modder, or interested in contributing to DFHack -- go read those docs. -If that's unclear or you need more help, try -[the Bay12 forums thread](http://www.bay12forums.com/smf/index.php?topic=164123) -or the #dfhack IRC channel on freenode. +If the docs are unclear or you need more help, please check out our [support page](https://docs.dfhack.org/en/latest/docs/Support.html) for ways to contact the DFHack developers. diff --git a/build/.gitignore b/build/.gitignore index 47745bc1e5..0675a165cf 100644 --- a/build/.gitignore +++ b/build/.gitignore @@ -1,7 +1,11 @@ VC2010 VC2015 VC2015_32 +VC2022 DF_PATH.txt _CPack_Packages *.tar.* .cmake +win64-cross +dest +DF diff --git a/build/build-osx.sh b/build/build-osx.sh old mode 100644 new mode 100755 index 8e34101597..e6be0f3085 --- a/build/build-osx.sh +++ b/build/build-osx.sh @@ -7,88 +7,88 @@ LUA_PATCH=1 ME=$PWD/`basename $0` usage() { - echo "Usage: $0 [options] {DF_OSX_PATH}" - echo -e "\told\t- use on pre-Snow Leopard OSX installations" - echo -e "\tbrew\t- if GCC 4.5 was installed with homebrew" - echo -e "\tport\t- if GCC 4.5 was insalled with macports" - echo -e "\tclean\t- delete ../build-osx before compiling" - echo "Example:" - echo -e "\t$0 old brew ../../../personal/df_osx" - echo -e "\t$0 port clean /Users/dfplayer/df_osx" - exit $1 + echo "Usage: $0 [options] {DF_OSX_PATH}" + echo -e "\told\t- use on pre-Snow Leopard OSX installations" + echo -e "\tbrew\t- if GCC 4.5 was installed with homebrew" + echo -e "\tport\t- if GCC 4.5 was insalled with macports" + echo -e "\tclean\t- delete ../build-osx before compiling" + echo "Example:" + echo -e "\t$0 old brew ../../../personal/df_osx" + echo -e "\t$0 port clean /Users/dfplayer/df_osx" + exit $1 } options() { - case $1 in - brew) - echo "Using homebrew gcc." - export CC=/usr/local/bin/gcc-4.5 - export CXX=/usr/local/bin/g++-4.5 - targetted=1 - ;; - port) - echo "Using macports gcc." - export CC=/opt/local/bin/gcc-mp-4.5 - export CXX=/opt/local/bin/g++-mp-4.5 - targetted=1 - ;; - old) - LUA_PATCH=0 - ;; - clean) - echo "Deleting ../build-osx" - rm -rf ../build-osx - ;; - *) - ;; - esac + case $1 in + brew) + echo "Using homebrew gcc." + export CC=/usr/local/bin/gcc-4.5 + export CXX=/usr/local/bin/g++-4.5 + targetted=1 + ;; + port) + echo "Using macports gcc." + export CC=/opt/local/bin/gcc-mp-4.5 + export CXX=/opt/local/bin/g++-mp-4.5 + targetted=1 + ;; + old) + LUA_PATCH=0 + ;; + clean) + echo "Deleting ../build-osx" + rm -rf ../build-osx + ;; + *) + ;; + esac } # sanity checks if [[ $# -lt 1 ]] then - echo "Not enough arguments." - usage 0 + echo "Not enough arguments." + usage 0 fi if [[ $# -gt 4 ]] then - echo "Too many arguments." - usage 1 + echo "Too many arguments." + usage 1 fi # run through the arguments for last do - options $last + options $last done # last keeps the last argument if [[ $targetted -eq 0 ]] then - echo "You did not specify whether you intalled GCC 4.5 from brew or ports." - echo "If you continue, your default compiler will be used." - read -p "Are you sure you want to continue? [y/N] " -n 1 -r - echo # (optional) move to a new line - if [[ ! $REPLY =~ ^[Yy]$ ]] - then - exit 0 - fi + echo "You did not specify whether you intalled GCC 4.5 from brew or ports." + echo "If you continue, your default compiler will be used." + read -p "Are you sure you want to continue? [y/N] " -n 1 -r + echo # (optional) move to a new line + if [[ ! $REPLY =~ ^[Yy]$ ]] + then + exit 0 + fi fi # check for build folder and start working there if [[ ! -d ../build-osx ]] then - mkdir ../build-osx + mkdir ../build-osx fi cd ../build-osx # patch if necessary if [[ $LUA_PATCH -ne 0 ]] then - cd .. - echo "$PWD" - sed -e '1,/'"PATCH""CODE"'/d' "$ME" | patch -p0 - cd - + cd .. + echo "$PWD" + sed -e '1,/'"PATCH""CODE"'/d' "$ME" | patch -p0 + cd - fi echo "Generate" @@ -101,17 +101,17 @@ make install # unpatch if /libarary/luaTypes.cpp was patched if [[ $LUA_PATCH -ne 0 ]] then - cd .. - echo -n "un" - sed -e '1,/'"PATCH""CODE"'/d' "$ME" | patch -p0 -R - cd - + cd .. + echo -n "un" + sed -e '1,/'"PATCH""CODE"'/d' "$ME" | patch -p0 -R + cd - fi exit 0 # PATCHCODE - everything below this line is fed into patch ---- library/LuaTypes.cpp 2014-08-20 00:13:17.000000000 -0700 -+++ library/LuaTypes.cpp 2014-08-31 23:31:00.000000000 -0700 +--- library/LuaTypes.cpp 2014-08-20 00:13:17.000000000 -0700 ++++ library/LuaTypes.cpp 2014-08-31 23:31:00.000000000 -0700 @@ -464,7 +464,7 @@ { case struct_field_info::STATIC_STRING: diff --git a/build/build-win64-from-linux.sh b/build/build-win64-from-linux.sh new file mode 100755 index 0000000000..529893412f --- /dev/null +++ b/build/build-win64-from-linux.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +set -e +# Number of jobs == core count +jobs=$(grep -c ^processor /proc/cpuinfo) + +# Calculate absolute paths for docker to do mounts +srcdir=$(realpath "$(dirname "$(readlink -f "$0")")"/..) + +cd "$srcdir"/build + +builder_uid=$(id -u) + +mkdir -p win64-cross +mkdir -p win64-cross/output +mkdir -p win64-cross/pdb +mkdir -p win64-cross/ccache + +# Check for sudo; we want to use the real user +if [[ $(id -u) -eq 0 ]]; then + if [[ -z "$SUDO_UID" || "$SUDO_UID" -eq 0 ]]; then + echo "Please don't run this script directly as root, use sudo instead:" + echo + echo " sudo $0" + # This is because we can't change the buildmaster UID in the container to 0 -- + # that's already taken by root. + exit 1 + fi + + # If this was run using sudo, let's make sure the directories are owned by the + # real user (and set the BUILDER_UID to it) + builder_uid=$SUDO_UID + chown -R $builder_uid win64-cross +fi + +# Pulls the MSVC build env container from the GitHub registry +# +# NOTE: win64-cross is mounted in /src/build due to the hardcoded `cmake ..` in +# the Dockerfile +if ! docker run --rm -i -v "$srcdir":/src -v "$srcdir/build/win64-cross/":/src/build \ + -e BUILDER_UID=$builder_uid \ + -e CCACHE_DIR=/src/build/ccache \ + -e steam_username \ + -e steam_password \ + --name dfhack-win \ + ghcr.io/dfhack/build-env:master \ + bash -c "cd /src/build && dfhack-configure windows 64 Release -DCMAKE_INSTALL_PREFIX=/src/build/output -DBUILD_DOCS=1 $CMAKE_EXTRA_ARGS && dfhack-make -j$jobs install && find . \! -path './pdb/*' -name '*.pdb' -type f -exec cp '{}' pdb/ \;" \ + ; then + echo + echo "Build failed" + exit 1 +else + echo + echo "Windows artifacts are at win64-cross/output. Copy or symlink them to" + echo "your steam DF directory to install dfhack (and optionally delete the" + echo "hack/ directory already present)" + echo + echo "Typically this can be done like this:" + echo " cp -r win64-cross/output/* ~/.local/share/Steam/steamapps/common/\"Dwarf Fortress\"" +fi diff --git a/build/sublime/dfhack.sublime-project b/build/sublime/dfhack.sublime-project index 1b1aa272b8..cc147764f3 100644 --- a/build/sublime/dfhack.sublime-project +++ b/build/sublime/dfhack.sublime-project @@ -1,34 +1,34 @@ { - "folders": - [ - { - "path": "." - } - ], - "build_systems": - [ - { - "name": "DFHack make", - "working_dir": "$project_path", - "cmd": ["python", "$project_path/build/sublime/make.py", "$file"], - "variants": [ - { - "name": "Build all", - "cmd": ["python", "$project_path/build/sublime/make.py", "-a"] - }, - { - "name": "Build+install all", - "cmd": ["python", "$project_path/build/sublime/make.py", "-ai"] - }, - { - "name": "Build plugin", - "cmd": ["python", "$project_path/build/sublime/make.py", "-ap", "$file"] - }, - { - "name": "Build+install plugin", - "cmd": ["python", "$project_path/build/sublime/make.py", "-aip", "$file"] - } - ] - } - ] + "folders": + [ + { + "path": "." + } + ], + "build_systems": + [ + { + "name": "DFHack make", + "working_dir": "$project_path", + "cmd": ["python", "$project_path/build/sublime/make.py", "$file"], + "variants": [ + { + "name": "Build all", + "cmd": ["python", "$project_path/build/sublime/make.py", "-a"] + }, + { + "name": "Build+install all", + "cmd": ["python", "$project_path/build/sublime/make.py", "-ai"] + }, + { + "name": "Build plugin", + "cmd": ["python", "$project_path/build/sublime/make.py", "-ap", "$file"] + }, + { + "name": "Build+install plugin", + "cmd": ["python", "$project_path/build/sublime/make.py", "-aip", "$file"] + } + ] + } + ] } diff --git a/build/win32/build-debug.bat b/build/win32/build-debug.bat deleted file mode 100644 index b75676ff44..0000000000 --- a/build/win32/build-debug.bat +++ /dev/null @@ -1,4 +0,0 @@ -call "%VS140COMNTOOLS%vsvars32.bat" -cd VC2015_32 -msbuild /m /p:Platform=Win32 /p:Configuration=RelWithDebInfo ALL_BUILD.vcxproj -cd .. \ No newline at end of file diff --git a/build/win32/build-release.bat b/build/win32/build-release.bat deleted file mode 100644 index 0b7a2a4071..0000000000 --- a/build/win32/build-release.bat +++ /dev/null @@ -1,5 +0,0 @@ -call "%VS140COMNTOOLS%vsvars32.bat" -cd VC2015_32 -msbuild /m /p:Platform=Win32 /p:Configuration=Release ALL_BUILD.vcxproj -cd .. -pause \ No newline at end of file diff --git a/build/win32/generate-MSVC-all.bat b/build/win32/generate-MSVC-all.bat deleted file mode 100755 index 5c113c7b66..0000000000 --- a/build/win32/generate-MSVC-all.bat +++ /dev/null @@ -1,6 +0,0 @@ -IF EXIST DF_PATH.txt SET /P _DF_PATH= 0 Then - Set spoFile = fso.CreateTextFile("DF_PATH.txt", True) - spoFile.WriteLine(objF.Self.Path) - End If -End If - -Function IsValue(obj) - ' Check whether the value has been returned. - Dim tmp - On Error Resume Next - tmp = " " & obj - If Err <> 0 Then - IsValue = False - Else - IsValue = True - End If - On Error GoTo 0 -End Function \ No newline at end of file diff --git a/build/win64/build-debug.bat b/build/win64/build-debug.bat index 08ef6d3a9a..2db9df402c 100644 --- a/build/win64/build-debug.bat +++ b/build/win64/build-debug.bat @@ -1,4 +1 @@ -call "%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 -cd VC2015 -msbuild /m /p:Platform=x64 /p:Configuration=RelWithDebInfo ALL_BUILD.vcxproj -cd .. +cmake --build VC2022 -t ALL_BUILD -- /m /p:Platform=x64 /p:Configuration=RelWithDebInfo diff --git a/build/win64/build-release.bat b/build/win64/build-release.bat index dfeb108b37..f719d64bcf 100644 --- a/build/win64/build-release.bat +++ b/build/win64/build-release.bat @@ -1,5 +1 @@ -call "%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64 -cd VC2015 -msbuild /m /p:Platform=x64 /p:Configuration=Release ALL_BUILD.vcxproj -cd .. -pause +cmake --build VC2022 -t ALL_BUILD -- /m /p:Platform=x64 /p:Configuration=Release diff --git a/build/win64/generate-MSVC-all.bat b/build/win64/generate-MSVC-all.bat old mode 100755 new mode 100644 index d3261fa776..29240da7fd --- a/build/win64/generate-MSVC-all.bat +++ b/build/win64/generate-MSVC-all.bat @@ -1,6 +1,4 @@ IF EXIST DF_PATH.txt SET /P _DF_PATH= 0 Then + Set ObjF = fso.GetFolder(args.Item(0)) +else + Set objDlg = WScript.CreateObject("Shell.Application") + Set objF = objDlg.BrowseForFolder (&H0,"Select your DF folder", BIF_returnonlyfsdirs) + if IsValue(objF) Then + set ObjF = objF.self + end if +end if + If fso.FileExists("DF_PATH.txt") Then fso.DeleteFile "DF_PATH.txt", True End If -If IsValue(objF) Then +If IsValue(objF) Then If InStr(1, TypeName(objF), "Folder") > 0 Then Set spoFile = fso.CreateTextFile("DF_PATH.txt", True) - spoFile.WriteLine(objF.Self.Path) + spoFile.WriteLine(objF.Path) End If End If @@ -29,4 +39,4 @@ Function IsValue(obj) IsValue = True End If On Error GoTo 0 -End Function \ No newline at end of file +End Function diff --git a/ci/authors-rst.py b/ci/authors-rst.py index 076f7f2261..6f37172761 100755 --- a/ci/authors-rst.py +++ b/ci/authors-rst.py @@ -11,9 +11,9 @@ def error(line, msg, **kwargs): info += ' %s %s:' % (k, kwargs[k]) print('line %i:%s %s' % (line, info, msg)) if os.environ.get('GITHUB_ACTIONS'): - print('::error file=docs/Authors.rst,line=%i::%s %s' % (line, info.lstrip(), msg)) + print('::error file=docs/about/Authors.rst,line=%i::%s %s' % (line, info.lstrip(), msg)) success[0] = False - with open('docs/Authors.rst', 'rb') as f: + with open('docs/about/Authors.rst', 'rb') as f: lines = list(map(lambda line: line.decode('utf8').replace('\n', ''), f.readlines())) if lines[1].startswith('='): @@ -35,6 +35,8 @@ def error(line, msg, **kwargs): error(line_number, 'bad table divider') if line != lines[first_div_index]: error(line_number, 'malformed table divider') + if line == lines[first_div_index + i - 1]: + error(line_number, 'duplicate of previous line') if len(div_indices) < 3: error(len(lines), 'missing table divider(s)') for i in div_indices[3:]: diff --git a/ci/check-rpc.py b/ci/check-rpc.py index aba3e38115..5527e1b58c 100755 --- a/ci/check-rpc.py +++ b/ci/check-rpc.py @@ -1,8 +1,11 @@ #!/usr/bin/env python3 import glob +import itertools +import os import sys actual = {'': {}} +SEP = ('=' * 80) with open(sys.argv[1]) as f: plugin_name = '' @@ -26,7 +29,11 @@ parts = line.split(' ') expected[''][parts[2]] = (parts[4], parts[6]) -for p in glob.iglob('plugins/proto/*.proto'): +for p in itertools.chain(glob.iglob('plugins/proto/*.proto'), glob.iglob('plugins/*/proto/*.proto')): + if 'plugins/' + os.path.join('proto', 'example.proto') in p: + continue + print('Checking ' + p) + plugin_name = '' with open(p) as f: for line in f: @@ -53,6 +60,7 @@ methods = actual[plugin_name] if plugin_name not in expected: + print(SEP) print('Missing documentation for plugin proto files: ' + plugin_name) print('Add the following lines:') print('// Plugin: ' + plugin_name) @@ -73,12 +81,14 @@ missing.append('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1]) if len(missing) > 0: + print(SEP) print('Incomplete documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Add the following lines:') for m in missing: print(m) error_count += 1 if len(wrong) > 0: + print(SEP) print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Replace the following comments:') for m in wrong: print(m) @@ -88,6 +98,7 @@ methods = expected[plugin_name] if plugin_name not in actual: + print(SEP) print('Incorrect documentation for plugin proto files: ' + plugin_name) print('The following methods are documented, but the plugin does not provide any RPC methods:') for m in methods: @@ -102,6 +113,7 @@ missing.append('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1]) if len(missing) > 0: + print(SEP) print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Remove the following lines:') for m in missing: print(m) diff --git a/ci/download-df.sh b/ci/download-df.sh index 49dcedea75..a07f75f2a1 100755 --- a/ci/download-df.sh +++ b/ci/download-df.sh @@ -1,56 +1,56 @@ #!/bin/sh +DF_FOLDER=$1 +OS_TARGET=$2 +DF_VERSION=$3 + set -e -tardest="df.tar.bz2" - -selfmd5=$(openssl md5 < "$0") -echo $selfmd5 - -cd "$(dirname "$0")" -echo "DF_VERSION: $DF_VERSION" -echo "DF_FOLDER: $DF_FOLDER" -mkdir -p "$DF_FOLDER" -# back out of df_linux -cd "$DF_FOLDER/.." - -if [ -f receipt ]; then - if [ "$selfmd5" != "$(cat receipt)" ]; then - echo "download-df.sh changed; removing DF" - rm receipt - else - echo "Already downloaded $DF_VERSION" - fi +minor=$(echo "$DF_VERSION" | cut -d. -f1) +patch=$(echo "$DF_VERSION" | cut -d. -f2) +if [ "$DF_VERSION" = "51.03" -o "$DF_VERSION" = "51.04" ]; then + patch=02 +fi +df_url="https://www.bay12games.com/dwarves/df_${minor}_${patch}" +if test "$OS_TARGET" = "windows"; then + WGET="C:/msys64/usr/bin/wget.exe" + df_url="${df_url}_win.zip" + df_archive_name="df.zip" + df_extract_cmd="unzip -d ${DF_FOLDER}" +elif test "$OS_TARGET" = "ubuntu"; then + WGET=wget + df_url="${df_url}_linux.tar.bz2" + df_archive_name="df.tar.bz2" + df_extract_cmd="tar -x -j -C ${DF_FOLDER} -f" +else + echo "Unhandled OS target: ${OS_TARGET}" + exit 1 fi -if [ ! -f receipt ]; then - rm -f "$tardest" - minor=$(echo "$DF_VERSION" | cut -d. -f2) - patch=$(echo "$DF_VERSION" | cut -d. -f3) - url="http://www.bay12games.com/dwarves/df_${minor}_${patch}_linux.tar.bz2" - echo Downloading - while read url; do - echo "Attempting download: ${url}" - if wget -v "$url" -O "$tardest"; then - break - fi - done < receipt -ls +ls -l diff --git a/ci/lint-ignore.txt b/ci/lint-ignore.txt index d384b80f3e..6e9d32cf01 100644 --- a/ci/lint-ignore.txt +++ b/ci/lint-ignore.txt @@ -3,20 +3,22 @@ .git/* # Old files exempt from checks for now -plugins/isoworld/*.txt plugins/raw/*.txt plugins/stonesense/*.txt # Generated files *.pb.h build*/* -docs/_* +docs/changelogs/* docs/html/* docs/pdf/* +docs/pseudoxml/* +docs/tags/* +docs/text/* +docs/tools/* +docs/xml/* library/include/df/* # Dependencies that we don't control depends/* -plugins/isoworld/agui/* -plugins/isoworld/allegro/* plugins/stonesense/allegro/* diff --git a/ci/lint.py b/ci/lint.py index b2fb8e6472..f2c01cd9c5 100755 --- a/ci/lint.py +++ b/ci/lint.py @@ -97,7 +97,7 @@ class TrailingWhitespaceLinter(Linter): msg = 'Contains trailing whitespace' def check_line(self, line): line = line.replace('\r', '').replace('\n', '') - return not line.strip() or line == line.rstrip('\t ') + return line == line.rstrip('\t ') def fix_line(self, line): return line.rstrip('\t ') diff --git a/ci/run-tests.py b/ci/run-tests.py index 11534b3f9e..13eeb099c8 100755 --- a/ci/run-tests.py +++ b/ci/run-tests.py @@ -55,25 +55,33 @@ def change_setting(content, setting, value): os.remove(test_status_file) print('Backing up init.txt to init.txt.orig') -init_txt_path = 'data/init/init.txt' +default_init_txt_path = 'data/init/init_default.txt' +prefs_path = 'prefs' +init_txt_path = 'prefs/init.txt' +if not os.path.exists(init_txt_path): + os.makedirs(prefs_path, exist_ok=True) + shutil.copyfile(default_init_txt_path, init_txt_path) + shutil.copyfile(init_txt_path, init_txt_path + '.orig') with open(init_txt_path) as f: init_contents = f.read() -init_contents = change_setting(init_contents, 'INTRO', 'NO') init_contents = change_setting(init_contents, 'SOUND', 'NO') init_contents = change_setting(init_contents, 'WINDOWED', 'YES') -init_contents = change_setting(init_contents, 'WINDOWEDX', '80') -init_contents = change_setting(init_contents, 'WINDOWEDY', '25') -init_contents = change_setting(init_contents, 'FPS', 'YES') -if args.headless: - init_contents = change_setting(init_contents, 'PRINT_MODE', 'TEXT') - -test_init_file = 'dfhackzzz_test.init' # Core sorts these alphabetically +init_contents = change_setting(init_contents, 'WINDOWEDX', '1200') +init_contents = change_setting(init_contents, 'WINDOWEDY', '800') +#if args.headless: +# init_contents = change_setting(init_contents, 'PRINT_MODE', 'TEXT') + +init_path = 'dfhack-config/init' +if not os.path.isdir('hack/init'): + # we're on an old branch that still reads init files from the root dir + init_path = '.' +os.makedirs(init_path, exist_ok=True) +test_init_file = os.path.join(init_path, 'dfhackzzz_test.init') # Core sorts these alphabetically with open(test_init_file, 'w') as f: f.write(''' devel/dump-rpc dfhack-rpc.txt - :lua dfhack.internal.addScriptPath(dfhack.getHackPath()) - test --resume --modes=none,title "lua scr.breakdown_level=df.interface_breakdown_types.%s" + test --resume -- lua scr.breakdown_level=df.interface_breakdown_types.%s ''' % ('NONE' if args.no_quit else 'QUIT')) test_config_file = 'test_config.json' diff --git a/ci/script-docs.py b/ci/script-docs.py index 71d7f37b24..0106a8f706 100755 --- a/ci/script-docs.py +++ b/ci/script-docs.py @@ -1,12 +1,13 @@ #!/usr/bin/env python3 import os -from os.path import basename, dirname, join, splitext +from os.path import basename, dirname, exists, join, splitext import sys SCRIPT_PATH = sys.argv[1] if len(sys.argv) > 1 else 'scripts' +DOCS_PATH = join(SCRIPT_PATH, 'docs') IS_GITHUB_ACTIONS = bool(os.environ.get('GITHUB_ACTIONS')) -def expected_cmd(path): +def get_cmd(path): """Get the command from the name of a script.""" dname, fname = basename(dirname(path)), splitext(basename(path))[0] if dname in ('devel', 'fix', 'gui', 'modtools'): @@ -14,16 +15,6 @@ def expected_cmd(path): return fname -def check_ls(fname, line): - """Check length & existence of leading comment for "ls" builtin command.""" - line = line.strip() - comment = '--' if fname.endswith('.lua') else '#' - if '[====[' in line or not line.startswith(comment): - print_error('missing leading comment (requred for `ls`)', fname) - return 1 - return 0 - - def print_error(message, filename, line=None): if not isinstance(line, int): line = 1 @@ -32,48 +23,42 @@ def print_error(message, filename, line=None): print('::error file=%s,line=%i::%s' % (filename, line, message)) +def check_ls(docfile, lines): + """Check length & existence of first sentence for "ls" builtin command.""" + # TODO + return 0 + + def check_file(fname): - errors, doclines = 0, [] - tok1, tok2 = ('=begin', '=end') if fname.endswith('.rb') else \ - ('[====[', ']====]') - doc_start_line = None - with open(fname, errors='ignore') as f: + errors, doc_start_line = 0, None + docfile = join(DOCS_PATH, get_cmd(fname)+'.rst') + if not exists(docfile): + print_error('missing documentation file: {!r}'.format(docfile), fname) + return 1 + with open(docfile, errors='ignore') as f: lines = f.readlines() if not lines: - print_error('empty file', fname) + print_error('empty documentation file', docfile) return 1 - errors += check_ls(fname, lines[0]) for i, l in enumerate(lines): - if doclines or l.strip().endswith(tok1): - if not doclines: - doc_start_line = i + 1 - doclines.append(l.rstrip()) - if l.startswith(tok2): - break - else: - if doclines: - print_error('docs start but do not end', fname, doc_start_line) - else: - print_error('no documentation found', fname) - return 1 - - if not doclines: - print_error('missing or malformed documentation', fname) - return 1 + l = l.strip() + if l and not doc_start_line and doc_start_line != 0: + doc_start_line = i + doc_end_line = i + lines[i] = l - title, underline = [d for d in doclines - if d and '=begin' not in d and '[====[' not in d][:2] - title_line = doc_start_line + doclines.index(title) + errors += check_ls(docfile, lines) + title, underline = lines[doc_start_line:doc_start_line+2] expected_underline = '=' * len(title) if underline != expected_underline: print_error('title/underline mismatch: expected {!r}, got {!r}'.format( expected_underline, underline), - fname, title_line + 1) + docfile, doc_start_line+1) errors += 1 - if title != expected_cmd(fname): + if title != get_cmd(fname): print_error('expected script title {!r}, got {!r}'.format( - expected_cmd(fname), title), - fname, title_line) + get_cmd(fname), title), + docfile, doc_start_line) errors += 1 return errors @@ -81,11 +66,11 @@ def check_file(fname): def main(): """Check that all DFHack scripts include documentation""" err = 0 - exclude = set(['internal', 'test']) + exclude = {'.git', 'internal', 'test'} for root, dirs, files in os.walk(SCRIPT_PATH, topdown=True): dirs[:] = [d for d in dirs if d not in exclude] for f in files: - if f[-3:] in {'.rb', 'lua'}: + if f.split('.')[-1] in {'rb', 'lua'}: err += check_file(join(root, f)) return err diff --git a/ci/test.lua b/ci/test.lua index 9a4a33ef2b..a4846520ec 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -1,11 +1,14 @@ -- DFHack developer test harness --@ module = true -local expect = require 'test_util.expect' -local json = require 'json' -local mock = require 'test_util.mock' -local script = require 'gui.script' -local utils = require 'utils' +local expect = require('test_util.expect') +local gui = require('gui') +local helpdb = require('helpdb') +local json = require('json') +local mock = require('test_util.mock') +local overlay = require('plugins.overlay') +local script = require('gui.script') +local utils = require('utils') local help_text = [====[ @@ -13,49 +16,59 @@ local help_text = test ==== -Run DFHack tests. +Tags: dev -Usage: +Command: "test" + + Run DFHack regression tests. + +Discover DFHack functionality that has broken due to recent changes in DF or DFHack. + +Usage +----- test [] [] If a done_command is specified, it will be run after the tests complete. -Options: - - -h, --help display this help message and exit. - -d, --test_dir specifies which directory to look in for tests. defaults to - the "hack/scripts/test" folder in your DF installation. - -m, --modes only run tests in the given comma separated list of modes. - see the next section for a list of valid modes. if not - specified, the tests are not filtered by modes. - -r, --resume skip tests that have already been run. remove the - test_status.json file to reset the record. - -s, --save_dir the save folder to load for "fortress" mode tests. this - save is only loaded if a fort is not already loaded when - a "fortress" mode test is run. if not specified, defaults to - 'region1'. - -t, --tests only run tests that match one of the comma separated list of - patterns. if not specified, no tests are filtered. - -Modes: - - none the test can be run on any screen - title the test must be run on the DF title screen. note that if the game - has a map loaded, "title" mode tests cannot be run - fortress the test must be run while a map is loaded. if the game is - currently on the title screen, the save specified by the save_dir - parameter will be loaded. - -Examples: - - test runs all tests - test -r runs all tests that haven't been run before - test -m none runs tests that don't need the game to be in a - specific mode - test -t quickfort runs quickfort tests - test -d /path/to/dfhack-scripts/repo/test - runs tests in your dev scripts repo +Options +------- + +-d, --test_dir specifies which directory to look in for tests. defaults to + the "hack/scripts/test" folder in your DF installation. +-m, --modes only run tests in the given comma separated list of modes. + see the next section for a list of valid modes. if not + specified, the tests are not filtered by modes. +-r, --resume skip tests that have already been run. remove the + test_status.json file to reset the record. +-s, --save_dir the save folder to load for "fortress" mode tests. this + save is only loaded if a fort is not already loaded when + a "fortress" mode test is run. if not specified, defaults to + 'region1'. +-t, --tests only run tests that match one of the comma separated list of + patterns. if not specified, no tests are filtered and all tessts + are run. + +Modes +----- + +none the test can be run on any screen +title the test must be run on the DF title screen. note that if the game + has a map loaded, "title" mode tests cannot be run +fortress the test must be run while a map is loaded. if the game is + currently on the title screen, the save specified by the save_dir + parameter will be loaded. + +Examples +-------- + +test runs all tests +test -r runs all tests that haven't been run before +test -m none runs tests that don't need the game to be in a + specific mode +test -t quickfort runs quickfort tests +test -d /path/to/dfhack-scripts/repo/test + runs tests in your dev scripts repo Default values for the options may be set in a file named test_config.json in your DF folder. Options with comma-separated values should be written as json @@ -140,18 +153,37 @@ end test_envvars.require = clean_require test_envvars.reqscript = clean_reqscript -local function is_title_screen(scr) - scr = scr or dfhack.gui.getCurViewscreen() - return df.viewscreen_titlest:is_instance(scr) +local function is_title_screen() + return dfhack.gui.matchFocusString('title/Default') +end + +local function wait_for(ms, desc, predicate) + local start_ms = dfhack.getTickCount() + local prev_ms = start_ms + while not predicate() do + delay(10) + local now_ms = dfhack.getTickCount() + if now_ms - start_ms > ms then + qerror(('%s took too long (timed out at %s)'):format( + desc, dfhack.gui.getCurFocus(true)[1])) + end + if now_ms - prev_ms > 1000 then + print(('Waiting for %s...'):format(desc)) + prev_ms = now_ms + end + end end -- This only handles pre-fortress-load screens. It will time out if the player -- has already loaded a fortress or is in any screen that can't get to the title -- screen by sending ESC keys. local function ensure_title_screen() + if df.viewscreen_dwarfmodest:is_instance(dfhack.gui.getDFViewscreen(true)) then + qerror('Cannot reach title screen from loaded fort') + end for i = 1, 100 do local scr = dfhack.gui.getCurViewscreen() - if is_title_screen(scr) then + if is_title_screen() then print('Found title screen') return end @@ -160,57 +192,94 @@ local function ensure_title_screen() if i % 10 == 0 then print('Looking for title screen...') end end qerror(string.format('Could not find title screen (timed out at %s)', - dfhack.gui.getCurFocus(true))) + dfhack.gui.getCurFocus(true)[1])) end -local function is_fortress(focus_string) - focus_string = focus_string or dfhack.gui.getCurFocus(true) - return focus_string == 'dwarfmode/Default' +local function is_fortress() + return dfhack.gui.matchFocusString('dwarfmode/Default') +end + +-- error out if we're not running in a CI environment +-- the tests may corrupt saves, and we don't want to unexpectedly ruin a real player save +-- this heuristic is not perfect, but it should be able to detect most cases +local function ensure_ci_save(scr) + if #scr.savegame_header ~= 1 + or #scr.savegame_header_world ~= 1 + or not string.find(scr.savegame_header[0].fort_name, 'Dream') + then + qerror('Unexpected test save in slot 0; please manually load a fort for ' .. + 'running fortress mode tests. note that tests may alter or corrupt the ' .. + 'fort! Do not save after running tests.') + end +end + +local function click_top_title_button(scr) + local sw, sh = dfhack.screen.getWindowSize() + df.global.gps.mouse_x = sw // 2 + df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x + if sh < 60 then + df.global.gps.mouse_y = 25 + else + df.global.gps.mouse_y = (sh // 2) + 3 + end + df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y + gui.simulateInput(scr, '_MOUSE_L') +end + +local function load_first_save(scr) + if #scr.savegame_header == 0 then + qerror('no savegames available to load') + end + + click_top_title_button(scr) + wait_for(1000, 'world list', function() + return scr.mode == 2 + end) + click_top_title_button(scr) + wait_for(1000, 'savegame list', function() + return scr.mode == 3 + end) + click_top_title_button(scr) + wait_for(1000, 'loadgame progress bar', function() + return dfhack.gui.matchFocusString('loadgame') + end) end -- Requires that a fortress game is already loaded or is ready to be loaded via --- the "Continue Playing" option in the title screen. Otherwise the function +-- the "Continue active game" option in the title screen. Otherwise the function -- will time out and/or exit with error. local function ensure_fortress(config) - local focus_string = dfhack.gui.getCurFocus(true) for screen_timeout = 1,10 do - if is_fortress(focus_string) then - print('Loaded fortress map') + if is_fortress() then + print('Fortress map is loaded') -- pause the game (if it's not already paused) dfhack.gui.resetDwarfmodeView(true) return end - local scr = dfhack.gui.getCurViewscreen(true) - if focus_string == 'title' or - focus_string == 'dfhack/lua/load_screen' then + local scr = dfhack.gui.getCurViewscreen() + if dfhack.gui.matchFocusString('title/Default', scr) then + print('Attempting to load the test fortress') + -- TODO: reinstate loading of a specified save dir; for now + -- just load the first possible save, which will at least let us + -- run fortress tests in CI -- qerror()'s on falure - dfhack.run_script('load-save', config.save_dir) - elseif focus_string ~= 'loadgame' then + -- dfhack.run_script('load-save', config.save_dir) + ensure_ci_save(scr) + load_first_save(scr) + elseif not dfhack.gui.matchFocusString('loadgame', scr) then -- if we're not actively loading a game, hope we're in -- a screen where hitting ESC will get us to the game map -- or the title screen scr:feed_key(df.interface_key.LEAVESCREEN) end -- wait for current screen to change - local prev_focus_string = focus_string - for frame_timeout = 1,100 do - delay(10) - focus_string = dfhack.gui.getCurFocus(true) - if focus_string ~= prev_focus_string then - goto next_screen - end - if frame_timeout % 10 == 0 then - print(string.format( - 'Loading fortress (currently at screen: %s)', - focus_string)) - end - end - print('Timed out waiting for screen to change') - break - ::next_screen:: + local prev_focus_string = dfhack.gui.getCurFocus()[1] + wait_for(60000, 'screen change', function() + return dfhack.gui.getCurFocus()[1] ~= prev_focus_string + end) end qerror(string.format('Could not load fortress (timed out at %s)', - focus_string)) + table.concat(dfhack.gui.getCurFocus(), ' '))) end local MODES = { @@ -221,12 +290,13 @@ local MODES = { local function load_test_config(config_file) local config = {} + print ("loading test config from " .. config_file) if dfhack.filesystem.isfile(config_file) then config = json.decode_file(config_file) end if not config.test_dir then - config.test_dir = dfhack.getHackPath() .. 'scripts/test' + config.test_dir = dfhack.getHackPath() .. '/scripts/test' end if not config.save_dir then @@ -236,11 +306,30 @@ local function load_test_config(config_file) return config end +local function TestTable() + local inner = utils.OrderedTable() + local meta = copyall(getmetatable(inner)) + + function meta:__newindex(k, v) + if inner[k] then + error('Attempt to overwrite existing test: ' .. k) + elseif type(v) ~= 'function' then + error('Attempt to define test as non-function: ' .. k .. ' = ' .. tostring(v)) + else + inner[k] = v + end + end + + local self = {} + setmetatable(self, meta) + return self +end + -- we have to save and use the original dfhack.printerr here so our test harness -- output doesn't trigger its own dfhack.printerr usage detection (see -- detect_printerr below) local orig_printerr = dfhack.printerr -local function wrap_expect(func, private) +local function wrap_expect(func, private, path) return function(...) private.checks = private.checks + 1 local ret = {func(...)} @@ -269,7 +358,7 @@ local function wrap_expect(func, private) end -- Skip any frames corresponding to C calls, or Lua functions defined in another file -- these could include pcall(), with_finalize(), etc. - if info.what == 'Lua' and info.short_src == caller_src then + if info.what == 'Lua' and (info.short_src == caller_src or info.short_src == path) then orig_printerr((' at %s:%d'):format(info.short_src, info.currentline)) end frame = frame + 1 @@ -278,9 +367,9 @@ local function wrap_expect(func, private) end end -local function build_test_env() +local function build_test_env(path) local env = { - test = utils.OrderedTable(), + test = TestTable(), -- config values can be overridden in the test file to define -- requirements for the tests in that file config = { @@ -309,7 +398,7 @@ local function build_test_env() checks_ok = 0, } for name, func in pairs(expect) do - env.expect[name] = wrap_expect(func, private) + env.expect[name] = wrap_expect(func, private, path) end setmetatable(env, {__index = _G}) return env, private @@ -339,46 +428,58 @@ end local function finish_tests(done_command) dfhack.internal.IN_TEST = false + overlay.rescan() if done_command and #done_command > 0 then dfhack.run_command(done_command) end end local function load_tests(file, tests) - local short_filename = file:sub((file:find('test') or -4)+5, -1) + local short_filename = file:sub((file:find('test') or -4) + 5, -1) print('Loading file: ' .. short_filename) - local env, env_private = build_test_env() + local env, env_private = build_test_env(file) local code, err = loadfile(file, 't', env) if not code then dfhack.printerr('Failed to load file: ' .. tostring(err)) return false - else - dfhack.internal.IN_TEST = true - local ok, err = dfhack.pcall(code) - dfhack.internal.IN_TEST = false - if not ok then - dfhack.printerr('Error when running file: ' .. tostring(err)) - return false - else - if not MODES[env.config.mode] then - dfhack.printerr('Invalid config.mode: ' .. tostring(env.config.mode)) - return false - end - for name, test_func in pairs(env.test) do - if env.config.wrapper then - local fn = test_func - test_func = function() env.config.wrapper(fn) end - end - local test_data = { - full_name = short_filename .. ':' .. name, - func = test_func, - private = env_private, - config = env.config, - } - test_data.name = test_data.full_name:gsub('test/', ''):gsub('.lua', '') - table.insert(tests, test_data) - end + end + dfhack.internal.IN_TEST = true + local ok, err = dfhack.pcall(code) + dfhack.internal.IN_TEST = false + if not ok then + dfhack.printerr('Error when running file: ' .. tostring(err)) + return false + end + if not MODES[env.config.mode] then + dfhack.printerr('Invalid config.mode: ' .. tostring(env.config.mode)) + return false + end + if not env.config.target then + dfhack.printerr('Skipping tests for unspecified target in ' .. file) + return true -- TODO: change to false once existing tests have targets specified + end + local targets = type(env.config.target) == 'table' and env.config.target or {env.config.target} + for _,target in ipairs(targets) do + if target == 'core' then goto continue end + if type(target) ~= 'string' or helpdb.has_tag(target, 'unavailable') then + dfhack.printerr('Skipping tests for unavailable target: ' .. target) + return true + end + ::continue:: + end + for name, test_func in pairs(env.test) do + if env.config.wrapper then + local fn = test_func + test_func = function() env.config.wrapper(fn) end end + local test_data = { + full_name = short_filename .. ':' .. name, + func = test_func, + private = env_private, + config = env.config, + } + test_data.name = test_data.full_name:gsub('test/', ''):gsub('.lua', '') + table.insert(tests, test_data) end return true end @@ -520,6 +621,10 @@ local function filter_tests(tests, config) end local function run_tests(tests, status, counts, config) + wait_for(60000, 'game load', function() + local scr = dfhack.gui.getDFViewscreen() + return not df.viewscreen_initial_prepst:is_instance(scr) + end) print(('Running %d tests'):format(#tests)) local start_ms = dfhack.getTickCount() local num_skipped = 0 @@ -529,6 +634,7 @@ local function run_tests(tests, status, counts, config) goto skip end if not MODES[test.config.mode].detect() then + print(('Switching to %s mode for test: %s'):format(test.config.mode, test.name)) local ok, err = pcall(MODES[test.config.mode].navigate, config) if not ok then MODES[test.config.mode].failed = true @@ -537,12 +643,13 @@ local function run_tests(tests, status, counts, config) goto skip end end + -- pre-emptively mark the test as failed in case we induce a crash + status[test.full_name] = TestStatus.FAILED + save_test_status(status) if run_test(test, status, counts) then status[test.full_name] = TestStatus.PASSED - else - status[test.full_name] = TestStatus.FAILED + save_test_status(status) end - save_test_status(status) ::skip:: end local elapsed_ms = dfhack.getTickCount() - start_ms @@ -575,7 +682,7 @@ local function dump_df_state() enabler = { fps = df.global.enabler.fps, gfps = df.global.enabler.gfps, - fullscreen = df.global.enabler.fullscreen, + fullscreen_state = df.global.enabler.fullscreen_state.whole, }, gps = { dimx = df.global.gps.dimx, diff --git a/ci/update-submodules.manifest b/ci/update-submodules.manifest index 4bd3830185..7d2c1412cf 100644 --- a/ci/update-submodules.manifest +++ b/ci/update-submodules.manifest @@ -1,7 +1,10 @@ library/xml master scripts master plugins/stonesense master +depends/clsocket master depends/libzip dfhack depends/libexpat dfhack depends/xlsxio dfhack depends/luacov dfhack +depends/jsoncpp-sub dfhack +depends/dfhooks main diff --git a/conf.py b/conf.py index bf1dde2c41..f5dd4451a1 100644 --- a/conf.py +++ b/conf.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ DFHack documentation build configuration file @@ -16,178 +15,80 @@ # pylint:disable=redefined-builtin import datetime -from io import open import os import re import shlex # pylint:disable=unused-import +import sphinx import sys +sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'docs', 'sphinx_extensions')) +from dfhack.util import write_file_if_changed -# -- Support :dfhack-keybind:`command` ------------------------------------ -# this is a custom directive that pulls info from dfhack.init-example +if os.environ.get('DFHACK_DOCS_BUILD_OFFLINE'): + # block attempted image downloads, particularly for the PDF builder + def request_disabled(*args, **kwargs): + raise RuntimeError('Offline build - network request blocked') -from docutils import nodes -from docutils.parsers.rst import roles + import urllib3.util + urllib3.util.create_connection = request_disabled + import urllib3.connection + urllib3.connection.HTTPConnection.connect = request_disabled -def get_keybinds(): - """Get the implemented keybinds, and return a dict of - {tool: [(full_command, keybinding, context), ...]}. - """ - with open('dfhack.init-example') as f: - lines = [l.replace('keybinding add', '').strip() for l in f.readlines() - if l.startswith('keybinding add')] - keybindings = dict() - for k in lines: - first, command = k.split(' ', 1) - bind, context = (first.split('@') + [''])[:2] - if ' ' not in command: - command = command.replace('"', '') - tool = command.split(' ')[0].replace('"', '') - keybindings[tool] = keybindings.get(tool, []) + [ - (command, bind.split('-'), context)] - return keybindings - -KEYBINDS = get_keybinds() - - -# pylint:disable=unused-argument,dangerous-default-value,too-many-arguments -def dfhack_keybind_role_func(role, rawtext, text, lineno, inliner, - options={}, content=[]): - """Custom role parser for DFHack default keybinds.""" - roles.set_classes(options) - if text not in KEYBINDS: - msg = inliner.reporter.error( - 'no keybinding for {} in dfhack.init-example'.format(text), - line=lineno) - prb = inliner.problematic(rawtext, rawtext, msg) - return [prb], [msg] - newnode = nodes.paragraph() - for cmd, key, ctx in KEYBINDS[text]: - n = nodes.paragraph() - newnode += n - n += nodes.strong('Keybinding: ', 'Keybinding: ') - for k in key: - n += nodes.inline(k, k, classes=['kbd']) - if cmd != text: - n += nodes.inline(' -> ', ' -> ') - n += nodes.literal(cmd, cmd, classes=['guilabel']) - if ctx: - n += nodes.inline(' in ', ' in ') - n += nodes.literal(ctx, ctx) - return [newnode], [] - - -roles.register_canonical_role('dfhack-keybind', dfhack_keybind_role_func) - -# -- Autodoc for DFhack scripts ------------------------------------------- - -def doc_dir(dirname, files): - """Yield (command, includepath) for each script in the directory.""" + import requests + requests.request = request_disabled + requests.get = request_disabled + + +# -- Autodoc for DFhack plugins and scripts ------------------------------- + +def doc_dir(dirname, files, prefix): + """Yield (name, includepath) for each file in the directory.""" sdir = os.path.relpath(dirname, '.').replace('\\', '/').replace('../', '') + if prefix == '.': + prefix = '' + else: + prefix += '/' for f in files: - if f[-3:] not in ('lua', '.rb'): + if f[-4:] != '.rst': continue - with open(os.path.join(dirname, f), 'r', encoding='utf8') as fstream: - text = [l.rstrip() for l in fstream.readlines() if l.strip()] - # Some legacy lua files use the ruby tokens (in 3rdparty scripts) - tokens = ('=begin', '=end') - if f[-4:] == '.lua' and any('[====[' in line for line in text): - tokens = ('[====[', ']====]') - command = None - for line in text: - if command and line == len(line) * '=': - yield command, sdir + '/' + f, tokens[0], tokens[1] - break - command = line + yield prefix + f[:-4], sdir + '/' + f def doc_all_dirs(): """Collect the commands and paths to include in our docs.""" - scripts = [] - for root, _, files in os.walk('scripts'): - scripts.extend(doc_dir(root, files)) - return tuple(scripts) - -DOC_ALL_DIRS = doc_all_dirs() - + tools = [] + for root, _, files in os.walk('docs/builtins'): + tools.extend(doc_dir(root, files, os.path.relpath(root, 'docs/builtins'))) + for root, _, files in os.walk('docs/plugins'): + tools.extend(doc_dir(root, files, os.path.relpath(root, 'docs/plugins'))) + for root, _, files in os.walk('scripts/docs'): + tools.extend(doc_dir(root, files, os.path.relpath(root, 'scripts/docs'))) + return tuple(tools) -def document_scripts(): - """Autodoc for files with the magic script documentation marker strings. - Returns a dict of script-kinds to lists of .rst include directives. +def write_tool_docs(): """ - # Next we split by type and create include directives sorted by command - kinds = {'base': [], 'devel': [], 'fix': [], 'gui': [], 'modtools': []} - for s in DOC_ALL_DIRS: - k_fname = s[0].split('/', 1) - if len(k_fname) == 1: - kinds['base'].append(s) - else: - kinds[k_fname[0]].append(s) - - def template(arg): - tmp = '.. _{}:\n\n.. include:: /{}\n' +\ - ' :start-after: {}\n :end-before: {}\n' - if arg[0] in KEYBINDS: - tmp += '\n:dfhack-keybind:`{}`\n'.format(arg[0]) - return tmp.format(*arg) - - return {key: '\n\n'.join(map(template, sorted(value))) - for key, value in kinds.items()} - - -def write_script_docs(): + Creates a file for each tool with the ".. include::" directives to pull in + the original documentation. """ - Creates a file for eack kind of script (base/devel/fix/gui/modtools) - with all the ".. include::" directives to pull out docs between the - magic strings. - """ - kinds = document_scripts() - head = { - 'base': 'Basic Scripts', - 'devel': 'Development Scripts', - 'fix': 'Bugfixing Scripts', - 'gui': 'GUI Scripts', - 'modtools': 'Scripts for Modders'} - for k in head: - title = ('.. _scripts-{k}:\n\n{l}\n{t}\n{l}\n\n' - '.. include:: /scripts/{a}about.txt\n\n' - '.. contents:: Contents\n' - ' :local:\n\n').format( - k=k, t=head[k], - l=len(head[k])*'#', - a=('' if k == 'base' else k + '/') - ) - mode = 'w' if sys.version_info.major > 2 else 'wb' - with open('docs/_auto/{}.rst'.format(k), mode) as outfile: - outfile.write(title) - outfile.write(kinds[k]) - - -def all_keybinds_documented(): - """Check that all keybindings are documented with the :dfhack-keybind: - directive somewhere.""" - configured_binds = set(KEYBINDS) - script_commands = set(i[0] for i in DOC_ALL_DIRS) - with open('./docs/Plugins.rst') as f: - plugin_binds = set(re.findall(':dfhack-keybind:`(.*?)`', f.read())) - undocumented_binds = configured_binds - script_commands - plugin_binds - if undocumented_binds: - raise ValueError('The following DFHack commands have undocumented ' - 'keybindings: {}'.format(sorted(undocumented_binds))) - - -# Actually call the docs generator and run test -write_script_docs() -all_keybinds_documented() + for k in doc_all_dirs(): + label = ('.. _{name}:\n\n').format(name=k[0]) + include = ('.. include:: /{path}\n\n').format(path=k[1]) + os.makedirs(os.path.join('docs/tools', os.path.dirname(k[0])), + mode=0o755, exist_ok=True) + with write_file_if_changed('docs/tools/{}.rst'.format(k[0])) as outfile: + outfile.write(label) + outfile.write(include) -# -- General configuration ------------------------------------------------ -sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'docs', 'sphinx_extensions')) +write_tool_docs() + + +# -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. -needs_sphinx = '1.8' +needs_sphinx = '3.4.3' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom @@ -196,22 +97,33 @@ def all_keybinds_documented(): 'sphinx.ext.extlinks', 'dfhack.changelog', 'dfhack.lexer', + 'dfhack.tool_docs', ] +sphinx_major_version = sphinx.version_info[0] + +def get_caption_str(prefix=''): + return prefix + (sphinx_major_version >= 5 and '%s' or '') + # This config value must be a dictionary of external sites, mapping unique # short alias names to a base URL and a prefix. # See http://sphinx-doc.org/ext/extlinks.html extlinks = { - 'wiki': ('https://dwarffortresswiki.org/%s', ''), + 'wiki': ('https://dwarffortresswiki.org/%s', get_caption_str()), 'forums': ('http://www.bay12forums.com/smf/index.php?topic=%s', - 'Bay12 forums thread '), - 'dffd': ('https://dffd.bay12games.com/file.php?id=%s', 'DFFD file '), - 'bug': ('https://www.bay12games.com/dwarves/mantisbt/view.php?id=%s', - 'Bug '), - 'source': ('https://github.com/DFHack/dfhack/tree/develop/%s', ''), - 'source-scripts': ('https://github.com/DFHack/scripts/tree/master/%s', ''), - 'issue': ('https://github.com/DFHack/dfhack/issues/%s', 'Issue '), - 'commit': ('https://github.com/DFHack/dfhack/commit/%s', 'Commit '), + get_caption_str('Bay12 forums thread ')), + 'dffd': ('https://dffd.bay12games.com/file.php?id=%s', + get_caption_str('DFFD file ')), + 'bug': ('https://dwarffortressbugtracker.com/view.php?id=%s', + get_caption_str('Bug ')), + 'source': ('https://github.com/DFHack/dfhack/tree/develop/%s', + get_caption_str()), + 'source-scripts': ('https://github.com/DFHack/scripts/tree/master/%s', + get_caption_str()), + 'issue': ('https://github.com/DFHack/dfhack/issues/%s', + get_caption_str('Issue ')), + 'commit': ('https://github.com/DFHack/dfhack/commit/%s', + get_caption_str('Commit ')), } # Add any paths that contain templates here, relative to this directory. @@ -260,7 +172,7 @@ def get_version(): # for a list of supported languages. # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # strftime format for |today| and 'Last updated on:' timestamp at page bottom today_fmt = html_last_updated_fmt = '%Y-%m-%d' @@ -269,11 +181,19 @@ def get_version(): # directories to ignore when looking for source files. exclude_patterns = [ 'README.md', - 'docs/html*', - 'depends/*', + '.git/*', 'build*', - 'docs/_auto/news*', - 'docs/_changelogs/', + 'depends/*', + 'docs/html/*', + 'docs/tags/*', + 'docs/text/*', + 'docs/builtins/*', + 'docs/pdf/*', + 'docs/plugins/*', + 'docs/pseudoxml/*', + 'docs/xml/*', + 'scripts/docs/*', + 'plugins/*', ] # The reST default role (used for this markup: `text`) to use for all @@ -336,6 +256,10 @@ def get_version(): # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['docs/styles'] +# A list of paths that contain extra files not directly related to the +# documentation. +html_extra_path = ['robots.txt'] + # Custom sidebar templates, maps document names to template names. html_sidebars = { '**': [ @@ -346,16 +270,20 @@ def get_version(): ] } -# If false, no module index is generated. -html_domain_indices = False - -# If false, no index is generated. +# generate domain indices but not the (unused) genindex html_use_index = False +html_domain_indices = True + +# don't link to rst sources in the generated pages +html_show_sourcelink = False html_css_files = [ 'dfhack.css', ] +if sphinx_major_version >= 5: + html_css_files.append('sphinx5.css') + # -- Options for LaTeX output --------------------------------------------- # Grouping the document tree into LaTeX files. List of tuples @@ -367,3 +295,15 @@ def get_version(): ] latex_toplevel_sectioning = 'part' + +# -- Options for text output --------------------------------------------- + +from sphinx.writers import text + +# this value is arbitrary. it just needs to be bigger than the number of +# characters in the longest paragraph in the DFHack docs +text.MAXWIDTH = 1000000000 + +# this is the order that section headers will use the characters for underlines +# they are in the order of (subjective) text-mode readability +text_sectionchars = '=-~`+"*' diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 777e3c42b3..75146071b8 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -1,17 +1,34 @@ -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/quickfort/ - DESTINATION "${DFHACK_DATA_DESTINATION}/data/quickfort") +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/dfhack-config/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/dfhack-config-defaults") -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/examples/ - DESTINATION "${DFHACK_DATA_DESTINATION}/examples") +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/init/ + DESTINATION "${DFHACK_DATA_DESTINATION}/init") + +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/base_command_counts.json + DESTINATION "${DFHACK_DATA_DESTINATION}/data") + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/orders/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/orders") + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/stockpiles/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/stockpiles") + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/art/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/art") + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/professions/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/professions") install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/blueprints/ - DESTINATION blueprints + DESTINATION "${DFHACK_DATA_DESTINATION}/data/blueprints" FILES_MATCHING PATTERN "*" - PATTERN blueprints/library/test EXCLUDE) + PATTERN blueprints/test EXCLUDE) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/patches/ + DESTINATION ${DFHACK_DATA_DESTINATION}/patches +) if(BUILD_TESTS) - install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/blueprints/library/test/ - DESTINATION blueprints/library/test - ) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/blueprints/test/ + DESTINATION "${DFHACK_DATA_DESTINATION}/data/blueprints/test") endif() - diff --git a/data/art/border-bold.png b/data/art/border-bold.png new file mode 100644 index 0000000000..16423a3a74 Binary files /dev/null and b/data/art/border-bold.png differ diff --git a/data/art/border-medium.png b/data/art/border-medium.png new file mode 100644 index 0000000000..529a60ee43 Binary files /dev/null and b/data/art/border-medium.png differ diff --git a/data/art/border-panel.png b/data/art/border-panel.png new file mode 100644 index 0000000000..52b24b9199 Binary files /dev/null and b/data/art/border-panel.png differ diff --git a/data/art/border-thin.png b/data/art/border-thin.png new file mode 100644 index 0000000000..71fa59a3ea Binary files /dev/null and b/data/art/border-thin.png differ diff --git a/data/art/border-window.png b/data/art/border-window.png new file mode 100644 index 0000000000..34747d69b7 Binary files /dev/null and b/data/art/border-window.png differ diff --git a/data/art/control-panel.png b/data/art/control-panel.png new file mode 100644 index 0000000000..2f5e9468af Binary files /dev/null and b/data/art/control-panel.png differ diff --git a/data/art/curses-small-letters_top-left.png b/data/art/curses-small-letters_top-left.png new file mode 100644 index 0000000000..2bf2e5aff2 Binary files /dev/null and b/data/art/curses-small-letters_top-left.png differ diff --git a/data/art/damp_dig_map.png b/data/art/damp_dig_map.png new file mode 100644 index 0000000000..db82f1a1b0 Binary files /dev/null and b/data/art/damp_dig_map.png differ diff --git a/data/art/damp_dig_toolbar.png b/data/art/damp_dig_toolbar.png new file mode 100644 index 0000000000..4c2c1939e6 Binary files /dev/null and b/data/art/damp_dig_toolbar.png differ diff --git a/data/art/design.png b/data/art/design.png new file mode 100644 index 0000000000..38fed7e088 Binary files /dev/null and b/data/art/design.png differ diff --git a/data/art/design_toolbar.png b/data/art/design_toolbar.png new file mode 100644 index 0000000000..935a332f00 Binary files /dev/null and b/data/art/design_toolbar.png differ diff --git a/data/art/green-pin.png b/data/art/green-pin.png new file mode 100644 index 0000000000..25d0e696ff Binary files /dev/null and b/data/art/green-pin.png differ diff --git a/data/art/icons.png b/data/art/icons.png new file mode 100644 index 0000000000..141d9f79f4 Binary files /dev/null and b/data/art/icons.png differ diff --git a/data/art/logo.png b/data/art/logo.png new file mode 100644 index 0000000000..c34407b372 Binary files /dev/null and b/data/art/logo.png differ diff --git a/data/art/mass_remove_toolbar.png b/data/art/mass_remove_toolbar.png new file mode 100644 index 0000000000..d1b09ac93b Binary files /dev/null and b/data/art/mass_remove_toolbar.png differ diff --git a/data/art/note_green_pin_map.png b/data/art/note_green_pin_map.png new file mode 100644 index 0000000000..b692263f90 Binary files /dev/null and b/data/art/note_green_pin_map.png differ diff --git a/data/art/on-off.png b/data/art/on-off.png new file mode 100644 index 0000000000..2b731e1c6b Binary files /dev/null and b/data/art/on-off.png differ diff --git a/data/art/on-off_top-left.png b/data/art/on-off_top-left.png new file mode 100644 index 0000000000..7303ff10d4 Binary files /dev/null and b/data/art/on-off_top-left.png differ diff --git a/data/art/pathable.png b/data/art/pathable.png new file mode 100644 index 0000000000..00f7f831d1 Binary files /dev/null and b/data/art/pathable.png differ diff --git a/data/art/red-pin.png b/data/art/red-pin.png new file mode 100644 index 0000000000..763b83e97e Binary files /dev/null and b/data/art/red-pin.png differ diff --git a/data/art/sitemap_toolbar.png b/data/art/sitemap_toolbar.png new file mode 100644 index 0000000000..a29fa9b900 Binary files /dev/null and b/data/art/sitemap_toolbar.png differ diff --git a/data/art/tiletypes.png b/data/art/tiletypes.png new file mode 100644 index 0000000000..9411c7c91d Binary files /dev/null and b/data/art/tiletypes.png differ diff --git a/data/art/unsuspend.png b/data/art/unsuspend.png new file mode 100644 index 0000000000..f1d1d33da6 Binary files /dev/null and b/data/art/unsuspend.png differ diff --git a/data/base_command_counts.json b/data/base_command_counts.json new file mode 100644 index 0000000000..a05d50c1ed --- /dev/null +++ b/data/base_command_counts.json @@ -0,0 +1,145 @@ +{ + "manipulator": 75, + "autolabor": 59, + "reveal": 51, + "help": 50, + "ls": 50, + "die": 50, + "tags": 50, + "embark-assistant": 42, + "prospect": 37, + "autodump": 36, + "clean": 35, + "gui/workflow": 28, + "workflow": 28, + "exportlegends": 26, + "gui/autobutcher": 25, + "autobutcher": 25, + "digv": 24, + "fastdwarf": 22, + "autonestbox": 20, + "showmood": 19, + "gui/liquids": 18, + "liquids": 18, + "search": 18, + "gui/quickfort": 15, + "quickfort": 15, + "createitem": 14, + "stocks": 14, + "autofarm": 12, + "autochop": 12, + "tiletypes": 12, + "exterminate": 12, + "buildingplan": 12, + "quicksave": 11, + "gui/gm-editor": 11, + "cleanowned": 10, + "gui/autogems": 9, + "autogems": 9, + "stonesense": 9, + "gui/stockpiles": 8, + "stockpiles": 8, + "changevein": 8, + "gui/teleport": 7, + "teleport": 7, + "seedwatch": 6, + "automelt": 6, + "embark-tools": 6, + "cursecheck": 5, + "open-legends": 5, + "ban-cooking": 5, + "burial": 5, + "automaterial": 5, + "remove-stress": 5, + "gui/blueprint": 5, + "blueprint": 5, + "tailor": 4, + "startdwarf": 4, + "3dveins": 4, + "digcircle": 4, + "nestboxes": 3, + "deathcause": 3, + "list-agreements": 3, + "gui/room-list": 3, + "points": 3, + "region-pops": 3, + "gui/advfort": 3, + "unsuspend": 3, + "locate-ore": 3, + "changelayer": 3, + "source": 3, + "gui/gm-unit": 3, + "combine-drinks": 3, + "combine-plants": 3, + "deteriorate": 3, + "warn-starving": 3, + "gaydar": 2, + "gui/dfstatus": 2, + "gui/rename": 2, + "rename": 2, + "fix-ster": 2, + "job-material": 2, + "stockflow": 2, + "drain-aquifer": 2, + "full-heal": 2, + "spawnunit": 2, + "flashstep": 2, + "gui/family-affairs": 2, + "caravan": 2, + "mousequery": 2, + "tweak": 2, + "confirm": 2, + "autoclothing": 1, + "autounsuspend": 1, + "prioritize": 1, + "dwarfmonitor": 1, + "show-unit-syndromes": 1, + "troubleshoot-item": 1, + "gui/mechanisms": 1, + "gui/pathable": 1, + "hotkeys": 1, + "infinite-sky": 1, + "force": 1, + "hermit": 1, + "strangemood": 1, + "weather": 1, + "add-recipe": 1, + "autotrade": 1, + "zone": 1, + "autonick": 1, + "stripcaged": 1, + "unforbid": 1, + "workorder": 1, + "gui/mod-manager": 1, + "spotclean": 1, + "plant": 1, + "regrass": 1, + "dig-now": 1, + "build-now": 1, + "clear-webs": 1, + "gui/siege-engine": 1, + "assign-skills": 1, + "brainwash": 1, + "elevate-mental": 1, + "elevate-physical": 1, + "launch": 1, + "linger": 1, + "make-legendary": 1, + "rejuvenate": 1, + "resurrect-adv": 1, + "questport": 1, + "getplants": 1, + "gui/stamper": 1, + "tweak": 1, + "fixveins": 1, + "deramp": 1, + "fix/dead-units": 1, + "fix/fat-dwarves": 1, + "fix/loyaltycascade": 1, + "fix/retrieve-units": 1, + "tweak": 1, + "sort-items": 1, + "gui/color-schemes": 1, + "color-schemes": 1, + "season-palette": 1 +} diff --git a/data/blueprints/aquifer_tap.csv b/data/blueprints/aquifer_tap.csv new file mode 100644 index 0000000000..dc79e523d4 --- /dev/null +++ b/data/blueprints/aquifer_tap.csv @@ -0,0 +1,73 @@ +#notes label(help) +"This blueprint will help you get a safe, everlasting source of fresh water from a light aquifer. See https://youtu.be/hF3_fjLc_EU for a video tutorial." +"" +Here's the procedure: +"" +"1) Locate an area with a light aquifer. DFHack gives light aquifer tiles a two-drop icon that appears when you are in mining mode. If you dug through it on the way down, take note of the elevations where it's likely to be (but be aware that there is regional variation and there's no guarantee that it exists on the map where you want it to be). If you are having trouble finding the boundaries of your aquifer, you can run prospect all --show features to discover the general elevations or gui/reveal -o to see the actual tiles." +"" +2) Dig a one-tile-wide tunnel from where you want the water to end up (e.g. your well cistern) to an area on the same z-level directly below the target light aquifer. Dig a one-tile-wide diagonal segment in this tunnel near the cistern side so water that will eventually flow through the tunnel is depressurized. +"" +"3) Pause the game. From the end of that tunnel, go down one z-level then designate for digging a staircase straight up so that the top is in the lowest aquifer level (a tile with a two-drop icon). Your original tunnel should connect to the staircase one z-level above the bottom of the staircase." +"" +"4) Apply this blueprint (gui/quickfort aquifer_tap /dig) to the z-level at the top of the staircase. The tiles will be designated in ""damp dig"" mode so your miners can dig it out without the damp tiles canceling the digging designations. This blueprint also changes the staircase tile below the tap to a vanilla ""blueprint"" tile (shaded in blue) so your miners don't dig the tap before your drainage tunnel is ready." +"" +"5) You can now unpause the game. From the bottom of the staircase (the z-level below where the water will flow to your cisterns), dig a straight, one-tile wide tunnel to the closest edge of the map. This is your emergency drainage tunnel. Smooth the map edge tile and carve a fortification. The water can flow through the fortification and off the map, allowing the dwarves to dig out the aquifer tap without drowning." +"" +6) Place a lever-controlled floodgate in the drainage tunnel and open the floodgate. Place the lever somewhere else in your fort so that it will remain dry and accessible. +"" +"7) If you want, haul away any boulders in the tunnels and/or smooth the tiles (e.g. mark them for dumping -- hotkey i-p -- and wait for them to be dumped). Enable prioritize in gui/control-panel to focus dwarves on dumping tasks and make it go faster. You won't be able to access any of this area once it fills up with water!" +"" +"8) Convert the ""blueprint"" stairway tile to a regular up/down stair dig designation to allow your miners to dig out the tap. You can haul away any boulders if you like. There is no rush. The water will safely flow down the staircase, through the open floodgate, down the drainage tunnel, and off the map as long as the floodgate is open." +"8b) Sometimes, DF gets into a bad state with mining designations and miners will refuse to dig the stairway tile. If this happens to you, enter mining mode, enable the keyboard cursor if it's not already enabled (hotkey: Alt-k), highlight the undug stair designation, and run dig-now here in gui/launcher. You might also have to do this for the down stair designation in the center of the aquifer tap. Your miners should be able to handle the rest without assistance." + +"9) Once everything is dug out and all dwarves are out of the waterways, close the floodgate. Your cisterns will fill with water. Since the waterway to your cisterns is depressurized (due to the diagonal tunnel you dug), the cisterns will stay forever full, but will not flood." +"" +A diagram might be useful. Here is a vertical view through the z-levels. This blueprint goes at the top: +"" +"j <- down stairs, center of this blueprint" +"i <- up/down stairs, initially in ""blueprint mode"" to prevent digging before drainage is ready" +"... <- up/down stairs, make this as tall as you need" +i +i <- cistern outlet level with diagonal tunnel to depressurize +"u <- up stairs, drainage level" +"" +"Good luck! If done right, this method is the safest way to supply your fort with clean water." +#dig label(dig) start(10 10 center of tap) light aquifer water collector +,,,,,,,,,,,,,,,,,, +,,,,,,,,mdd3,mdd3,mdd3,,,,,,,, +,,,,,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,,,,, +,,,,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,,,, +,,,mdd3,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,mdd3,,, +,,mdd3,,,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,,,mdd3,, +,,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,, +,,,mdd3,mdd3,,,mdd3,mdd3,,mdd3,mdd3,,,mdd3,mdd3,,, +,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3, +,mdd3,mdd3,,,mdd3,mdd3,,,mdj3,,,mdd3,mdd3,,,mdd3,mdd3, +,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3, +,,,mdd3,mdd3,,,mdd3,mdd3,,mdd3,mdd3,,,mdd3,mdd3,,, +,,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,mdd3,, +,,mdd3,,,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,,,mdd3,, +,,,mdd3,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,mdd3,,, +,,,,mdd3,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,mdd3,,,, +,,,,,,mdd3,mdd3,mdd3,,mdd3,mdd3,mdd3,,,,,, +,,,,,,,,mdd3,mdd3,mdd3,,,,,,,, +,,,,,,,,,,,,,,,,,, +#>,,,,,,,,,,,,,,,,,, +,,,,,,,,,,,,,,,,,, +,,,,,,,,`,`,`,,,,,,,, +,,,,,,`,`,`,,`,`,`,,,,,, +,,,,`,,`,`,`,,`,`,`,,`,,,, +,,,`,`,`,`,,`,`,`,,`,`,`,`,,, +,,`,,,`,`,,`,`,`,,`,`,,,`,, +,,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,, +,,,`,`,,,`,`,,`,`,,,`,`,,, +,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`, +,`,`,,,`,`,,,mbmdi3,,,`,`,,,`,`, +,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`, +,,,`,`,,,`,`,,`,`,,,`,`,,, +,,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,, +,,`,,,`,`,,`,`,`,,`,`,,,`,, +,,,`,`,`,`,,`,`,`,,`,`,`,`,,, +,,,,`,,`,`,`,,`,`,`,,`,,,, +,,,,,,`,`,`,,`,`,`,,,,,, +,,,,,,,,`,`,`,,,,,,,, diff --git a/data/blueprints/bedrooms/28-3-Modified_Windmill_Villas.csv b/data/blueprints/bedrooms/28-3-Modified_Windmill_Villas.csv new file mode 100644 index 0000000000..af15f0cc4f --- /dev/null +++ b/data/blueprints/bedrooms/28-3-Modified_Windmill_Villas.csv @@ -0,0 +1,74 @@ +"#dig label(dig) start(12; 12) 28 bedrooms, 3 tiles each" + +,,,,,,,d,,,,,,d +,,,,,,,d,,,,,,d +,,,,,d,,d,,d,,d,,d,,d +,,,,,d,,d,,d,,d,,d,,d +,,,,,d,d,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,d,,,,,,d,d,,,d +,,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d +,,,,,,d,d,,,,d,,d,,,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,,d,d,d +,,,,,d,,,,d,~,~,~,d,,d +,,,d,d,d,,d,d,d,~,~,~,d,d,d,,d,d,d +,,,,,,,d,,d,~,~,~,d,,,,d +,,,d,d,d,,d,,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,d,,,,d,,d,,,,d,d +,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d +,,,,,d,,,d,d,,,,,,d +,,,d,d,d,,d,,d,d,d,,d,d,d,d,d +,,,,,,,d,,d,,d,,d,,d,,d +,,,,,,,d,,d,,d,,d,,d,,d +,,,,,,,,,d,,,,,,d +,,,,,,,,,d,,,,,,d + +#meta label(rooms) +zone/zone +build/build +#zone label(zone) start(12; 12) hidden() +,,,,,,b(3x5),,,,,,b(3x5) +,,,,,,,`,,,,,,` +,,,,b(3x5),,,`,b(3x5),,b(3x5),,,`,b(3x5) +,,,,,`,,`,,`,,`,,`,,` +,,,,,`,,`,,`,,`,,`,,`,b(5x3) +,,,,,`,`,`,`,`,,`,`,`,,`,,`,`,` +,,b(5x3),,,,,`,b(5x3),,,,,`,`,,,`,b(5x3) +,,,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,` +b(5x3),,,,,,`,`,,,,`,,`,b(3x5),,b(5x3),` +,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,` +,,b(5x3),,,`,b(3x5),,,`,`,`,`,`,,`,b(5x3) +,,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,` +,,b(5x3),,,,,`,,`,`,`,`,`,,,,`,b(5x3) +,,,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,` +b(5x3),,,,,`,,,,`,b(5x3),`,,,,`,b(5x3) +,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` +,,b(5x3),,,`,b(3x5),,`,`,b(3x5),,b(3x5),,,`,b(3x5) +,,,`,`,`,,`,,`,`,`,,`,`,`,`,` +,,,,,,,`,b(3x5),`,,`,,`,b(3x5),`,,` +,,,,,,,`,,`,,`,,`,,`,,` +,,,,,,,,,`,,,,,,` +,,,,,,,,,`,,,,,,` + +#build label(build) start(12; 12) hidden() + +,,,,,,,f,,,,,,f +,,,,,,,h,,,,,,h +,,,,,f,,b,,f,,f,,b,,f +,,,,,h,,d,,h,,h,,d,,h +,,,,,b,d,`,d,b,,b,d,`,,b,,b,h,f +,,,,,,,`,,,,,,`,d,,,d +,,,f,h,b,,`,,f,h,b,,`,`,`,`,`,d,b,h,f +,,,,,,d,`,,,,d,,`,,,,d +,f,h,b,d,`,`,`,`,`,`,`,`,`,,f,,b,h,f +,,,,,d,,,,`,`,`,`,`,,h +,,,f,h,b,,b,d,`,`,`,`,`,d,b,,b,h,f +,,,,,,,h,,`,`,`,`,`,,,,d +,,,f,h,b,,f,,`,`,`,`,`,`,`,`,`,d,b,h,f +,,,,,d,,,,`,,d,,,,`,d +,f,h,b,d,`,`,`,`,`,,b,h,f,,`,,b,h,f +,,,,,d,,,d,`,,,,,,` +,,,f,h,b,,b,,`,d,b,,b,d,`,d,b +,,,,,,,h,,d,,h,,h,,d,,h +,,,,,,,f,,b,,f,,f,,b,,f +,,,,,,,,,h,,,,,,h +,,,,,,,,,f,,,,,,f diff --git a/data/blueprints/bedrooms/48-4-Raynard_Whirlpool_Housing.csv b/data/blueprints/bedrooms/48-4-Raynard_Whirlpool_Housing.csv new file mode 100644 index 0000000000..ae7d83f6ec --- /dev/null +++ b/data/blueprints/bedrooms/48-4-Raynard_Whirlpool_Housing.csv @@ -0,0 +1,209 @@ +"#dig label(dig) start(17; 17) 48 rooms, 4 tiles each" + +,,,,,,,,,,,,,,d,,,,d +,,,,,d,,,,d,,,,d,d,d,d,d,d,d,,,,d,,,,d +,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d +,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d +,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d +,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d +,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d +,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d +,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d +,,,,,d,,d,,d,,,,d,d,d,d,d,d,d,,,,d,,d,,d +,,,d,,,,d,,,,d,,,d,,d,,d,,,d,,,,d,,,,d +,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d +,,,d,,,d,d,d,,,d,,,d,~,~,~,d,,,d,,,d,d,d,,,d +,,,d,d,d,d,d,d,d,d,d,d,d,d,~,~,~,d,d,d,d,d,d,d,d,d,d,d,d +,,,d,,,d,d,d,,,d,,,d,~,~,~,d,,,d,,,d,d,d,,,d +,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d +,,,d,,,,d,,,,d,,,d,,d,,d,,,d,,,,d,,,,d +,,,,,d,,d,,d,,,,d,d,d,d,d,d,d,,,,d,,d,,d +,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d +,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d +,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d +,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d +,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d +,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d +,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d +,,,,,d,,,,d,,,,d,d,d,d,d,d,d,,,,d,,,,d +,,,,,,,,,,,,,,d,,,,d + +#meta label(rooms) +zone1/zone1 +zone2/zone2 +zone3/zone3 +zone4/zone4 +build/build +#zone label(zone1) start(17; 17) hidden() + +,,,,,,,,,,,,,,`,,,,` +,,,,,`,,,,`,,,,`,,`,,`,,`,,,,`,,,,` +,b,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b +b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +,,,,,,,`,,,,,,,,,`,,,,,,,,,` +,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,` +,`,,`,,,,,,,,`,,`,,,,,,`,,`,,,,,,,,`,,` +,,`,,,`,,,,`,,,`,,,,,,,,`,,,`,,,,`,,,` +,,,,`,,`,,`,,`,,,,`,,,,`,,,,`,,`,,`,,` +,,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b +,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b +,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b +,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b +,,,,,,,`,,,,,,,,,,,,,,,,,,` +,,,`,,,,,,,,`,,,,,,,,,,`,,,,,,,,` +,,`,,`,,,,,,`,,`,,,,,,,,`,,`,,,,,,`,,` +,,,`,,,,,,,,`,,,`,,,,`,,,`,,,,,,,,` +,,,,,`,,,,`,,,,`,,`,,`,,`,,,,`,,,,` +,b,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b +b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +,,,,,,,`,,,,,,,,,`,,,,,,,,,` +,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,` +,`,,`,,,,,,,,`,,`,,,,,,`,,`,,,,,,,,`,,` +,,`,,,`,,,,`,,,`,,,,,,,,`,,,`,,,,`,,,` +,,,,`,,`,,`,,`,,,,`,,,,`,,,,`,,`,,`,,` +,,,,,`,,,,`,,,,`,,`,,`,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,` + +#zone label(zone2) start(17; 17) hidden() +,,,,,,,,,,,,,b,b,b +,,,,b,b,b,,,,,,b,b,b,b,,,`,,,,b,b,b +,,,b,b,b,b,,,`,,,b,b,b,b,,`,,`,,b,b,b,b,,,` +,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,~,~ +~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,~,~ +~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~ +,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,` +,`,,`,b,b,b,,,,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,` +,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,` +,,,b,b,b,b,,`,,`,,b,b,b,b,,,`,,,b,b,b,b,,`,,` +,,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,~ +,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~ +,,~,~,~,,,`,,,~,~,~,,,,,,,,~,~,~,,,`,,,~,~,~ +,,,`,,,,,,,,`,,,,,,,,,,`,,,,,,,,` +,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,`,,,,,,`,,` +,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,` +,,,b,b,b,b,,,`,,,b,b,b,b,,`,,`,,b,b,b,b,,,` +,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,~,~ +~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,~,~ +~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~ +,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,` +,`,,`,b,b,b,,,,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,` +,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,` +,,,b,b,b,b,,`,,`,,b,b,b,b,,,`,,,b,b,b,b,,`,,` +,,,b,b,b,b,,,`,,,b,b,b,b,,`,,`,,b,b,b,b,,,` +,,,,b,b,b,,,,,,b,b,b,b,,,`,,,,b,b,b +,,,,,,,,,,,,,b,b,b +#zone label(zone3) start(17; 17) hidden() +,,,,,,,,,,,,,~,~,~ +,,,,~,~,~,,,,,,~,~,~,~,~,,`,,,,~,~,~ +,,,~,~,~,~,~,,`,,,~,~,~,~,~,`,,`,,~,~,~,~,~,,` +,~,~,~,~,~,~,~,`,,`,~,~,~,~,~,~,,`,~,~,~,~,~,~,~,`,,`,~,~,~ +~,~,~,~,~,~,~,~,,`,~,~,~,~,~,~,,,~,~,~,~,~,~,~,~,,`,~,~,~,~,~ +~,~,~,~,~,~,~,,,,~,~,~,~,~,,,,~,~,~,~,~,~,~,,,,~,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,,,,,,,`,,,,,,,,,`,,,,,,,,,` +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +b,b,b,b,b,~,~,,,,b,b,b,b,b,,,,b,b,b,b,b,~,~,,,,b,b,b,b,b +b,b,b,b,b,~,~,~,,`,b,b,b,b,b,~,,,b,b,b,b,b,~,~,~,,`,b,b,b,b,b +,b,b,b,~,~,~,~,`,,`,b,b,b,~,~,~,,`,b,b,b,~,~,~,~,`,,`,b,b,b +,,~,~,~,~,~,~,,`,~,~,~,~,~,~,~,`,,`,~,~,~,~,~,~,,`,~,~,~ +,~,~,~,~,~,~,,,~,~,~,~,~,~,~,~,,`,~,~,~,~,~,~,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,~,~,,,,~,~,~,~,~,,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~ +,,,,,,,`,,,,,,,,,,,,,,,,,,` +,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b +,b,b,b,b,b,,,,b,b,b,b,b,~,~,,,,b,b,b,b,b,,,,b,b,b,b,b +,b,b,b,b,b,~,,,b,b,b,b,b,~,~,~,,`,b,b,b,b,b,~,,,b,b,b,b,b +,,b,b,b,~,~,~,,`,b,b,b,~,~,~,~,`,,`,b,b,b,~,~,~,,`,b,b,b +,~,~,~,~,~,~,~,`,,`,~,~,~,~,~,~,,`,~,~,~,~,~,~,~,`,,`,~,~,~ +~,~,~,~,~,~,~,~,,`,~,~,~,~,~,~,,,~,~,~,~,~,~,~,~,,`,~,~,~,~,~ +~,~,~,~,~,~,~,,,,~,~,~,~,~,,,,~,~,~,~,~,~,~,,,,~,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,,,,,,,`,,,,,,,,,`,,,,,,,,,` +b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b +b,b,b,b,b,~,~,,,,b,b,b,b,b,,,,b,b,b,b,b,~,~,,,,b,b,b,b,b +b,b,b,b,b,~,~,~,,`,b,b,b,b,b,~,,,b,b,b,b,b,~,~,~,,`,b,b,b,b,b +,b,b,b,~,~,~,~,`,,`,b,b,b,~,~,~,,`,b,b,b,~,~,~,~,`,,`,b,b,b +,,,~,~,~,~,~,,`,,,~,~,~,~,~,`,,`,,~,~,~,~,~,,` +,,,,~,~,~,,,,,,~,~,~,~,~,,`,,,,~,~,~ +,,,,,,,,,,,,,~,~,~ +#zone label(zone4) start(17; 17) hidden() +,,,,,,,,,,,,,~,~,~,,b,b,b +,,,,~,~,~,,b,b,b,,~,~,~,~,,b,b,b,b,,~,~,~,,b,b,b +,,,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b +,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~ +~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~ +~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~ +~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~ +,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~ +,,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~ +,~,~,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~ +,,~,~,~,,,`,,,~,~,~,,,,,,,,~,~,~,,,`,,,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~ +,~,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~ +,~,~,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~ +,,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~ +,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~ +~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~ +~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~ +~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~ +~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~ +~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~ +,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~ +,,,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b +,,,,~,~,~,,b,b,b,,~,~,~,~,,b,b,b,b,,~,~,~,,b,b,b +,,,,,,,,,,,,,~,~,~,,b,b,b +#build label(build) start(17; 17) hidden() + +,,,,,,,,,,,,,,f,,,,f +,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h +,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b +,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b +,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f +,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d +,,,,,,,s,,,,,,,,,s,,,,,,,,,s +,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d +,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f +,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b +,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b +,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h +,,,b,,,,,,,,b,,,f,,,,f,,,b,,,,,,,,b +,,h,,f,,,,,,f,,h,,,,,,,,h,,f,,,,,,f,,h +,,,d,,,,,,,,d,,,,,,,,,,d,,,,,,,,d +,,,,,,,s,,,,,,,,,,,,,,,,,,s +,,,d,,,,,,,,d,,,,,,,,,,d,,,,,,,,d +,,h,,f,,,,,,f,,h,,,,,,,,h,,f,,,,,,f,,h +,,,b,,,,,,,,b,,,f,,,,f,,,b,,,,,,,,b +,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h +,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b +,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b +,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f +,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d +,,,,,,,s,,,,,,,,,s,,,,,,,,,s +,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d +,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f +,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b +,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b +,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h +,,,,,,,,,,,,,,f,,,,f diff --git a/data/blueprints/bedrooms/95-9-Hactar1_3_Branch_Tree.csv b/data/blueprints/bedrooms/95-9-Hactar1_3_Branch_Tree.csv new file mode 100644 index 0000000000..78543b1e04 --- /dev/null +++ b/data/blueprints/bedrooms/95-9-Hactar1_3_Branch_Tree.csv @@ -0,0 +1,228 @@ +"#dig label(dig) start(36;73) 95 bedrooms (including 14 suites), 190 tombs" + +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,,d,,,d,,,d,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,,d,,,d,,,d,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,,,,,,,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,d,d,d,,,d,,,,,,,d,,,,,,,d,,,,,,,d,,,,,,,d,,,d,d,d +,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,d,d,d,,,d,,,,,,,d,,,,,,d,d,d,,,,,,d,,,,,,,d,,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,d,d,d,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,,,d,d,d,,,d,,,,,,,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,d,d,d,,d,d,d,,d,d,d,,,,,,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d +,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d +,,,,,,,,,,,,,d,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d,,,,,,,d +,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,,,,,,d,,,d,d,d,,,d,,,,,,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,d,d,d,,,d,,,,,,,d,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,d,,,,,,,d,,,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,,,d,,,,,,,d,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,d,,,,,,,d,,,d,d,d +,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,,,,,,d,,,d,d,d,,,d,,,,,,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,d,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d,,,,,,,d +,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d +,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d +,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,d,d,d,d,d,d,d,d,d,d,d,,,,,,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,d,,d,d,d,,d,d,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d +,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,~,~,~,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,~,~,~,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,~,~,~,d,d,d,d,d,d,d,d,d,d,d,d +#meta label(rooms) +zone/zone +build/build +#zone label(zone) start(36;73) hidden() +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),b(5x6),,`,,,`,b(5x6),,`,,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,b(5x5),,,,b(5x5),,,,,`,b(6x5),,,,,,`,b(6x5),,,,,,`,b(5x5),,,,b(5x5) +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,,`,`,` +,,,,,,,,,,,,,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5) +,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,,`,,,,,,,`,,,,,,,`,,,,,,,`,,,,,,,`,,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),b(5x5),,`,,b(5x5),,,,,`,b(5x5),,,,,`,`,`,b(5x5),,,,,`,b(5x5),,,,b(5x5),,`,,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,b(5x5),,`,,b(4x5),,,,`,`,`,b(4x5),,,b(5x5),,`,,b(5x5) +,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,b(5x4),,`,,,`,`,`,b(5x4),,`,,b(5x5),,,,,`,b(5x5) +,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,b(5x5),,`,,,`,`,`,b(5x5),,`,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,,`,b(5x5) +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` +,,,,,,,,,,,b(5x5),,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,,`,`,`,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,b(5x5) +,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` +,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),b(5x6),,`,,,`,b(5x5),,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),b(5x5),,`,,,`,b(5x6),,`,,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,b(5x5),,,,b(5x5),,,,,`,b(6x5),,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x4),,,,,`,`,`,b(5x4),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(6x5),,,,,,`,b(5x5),,,,b(5x5) +,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,` +b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,,,,,,,`,,,`,`,`,,,`,,,,,,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5) +,`,`,T{pets=true}(1x1),,,`,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,`,,,T{pets=true}(1x1),`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,T{pets=true}(1x1),b(5x5),,`,,b(5x5),,,,,`,b(6x5),,,,,b(5x6),,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,b(5x6),,,,b(6x5),,,,,,`,b(5x5),,,,b(5x5),,`,,,T{pets=true}(1x1),`,` +,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,b(5x5),,,,b(5x4),,`,,,`,`,`,b(5x4),,`,,b(5x5),,,,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,` +,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,b(5x5),,`,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,,`,`,`,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,b(5x5),,` +,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` +,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),b(5x5),,`,,,`,b(5x5),,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),b(5x5),,`,,,`,b(5x5),,`,,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x6),,,,,`,`,`,b(5x6),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` +,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,,`,`,`,`,`,`,`,`,`,`,`,b(5x5),,,,,`,b(5x5) +,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,,,`,,,`,`,`,,,`,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,` +,,,,,,,,,,,,,,,,,,,,,,b(5x5),,`,,b(5x5),,,,,`,`,,`,`,`,,`,`,b(5x5),,,,b(5x5),,` +,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,`,,`,`,`,,`,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1) +,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,`,,`,`,`,,`,`,,T{pets=true}(1x1),`,`,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` +#build label(build) start(36;73) hidden() + +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,f,`,n,,`,,n,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,d,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,n,,`,,n,`,h +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,`,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,,,,,f,`,n,,,d,,,`,,,d,,,n,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,n,,,d,,,`,,,d,,,n,`,h +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,r,b,t,,`,,r,b,t,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,a,`,c,,`,,a,`,c,,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,h,s,f,,`,,h,s,f,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,`,,,,,,,d +,,,,,,,,,,,,,,,,,,,,h,`,f,,f,`,n,,`,,n,r,a,h,,`,,h,a,r,n,,`,,n,`,f,,h,`,f +,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,s,,`,,s,`,b,`,d,`,d,`,b,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,n,`,n,,h,`,n,,`,,n,t,c,f,,`,,f,c,t,n,,`,,n,`,h,,n,`,n +,,,,,,,,,,,,,,,,f,`,n,,,d,,,,,,,`,,,,,,,`,,,,,,,`,,,,,,,d,,,n,`,f +,,,,,,,,,,,,,,,,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,` +,,,,,,,,,,,,,,,,h,`,n,,,d,,,,,,,`,,,,,,`,`,`,,,,,,`,,,,,,,d,,,n,`,h +,,,,,,,,,,,,,,,,,,,,n,`,n,,f,`,n,,`,,n,`,f,,`,`,`,,f,`,n,,`,,n,`,f,,n,`,n +,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,,`,`,`,,`,b,`,d,`,d,`,b,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,h,`,f,,h,`,n,,`,,n,`,h,,`,`,`,,h,`,n,,`,,n,`,h,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,`,`,`,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,n,`,n,,f,n,,`,`,`,,n,f,,n,`,n,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,,b,`,d,`,`,`,d,`,b,,`,b,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,h,`,f,,h,n,,`,`,`,,n,h,,h,`,f,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,,,`,`,`,,,d,,,,,,,d +,,,,,,,,,,,,,,,,,,,,f,`,n,,`,,n,`,f,,n,`,n,,`,`,`,,n,`,n,,f,`,n,,`,,n,`,f +,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,d,`,b,`,,h,b,f,,`,`,`,,h,b,f,,`,b,`,d,`,d,`,b,` +,,,,,,,,,,,,,,,,,,,,h,`,n,,`,,n,`,h,,,d,,,`,`,`,,,d,,,h,`,n,,`,,n,`,h +,,,,,,,,,,,,,,,,,,,,,,,,`,,,,,,n,`,n,,`,`,`,,n,`,n,,,,,,` +,,,,,,,,,,,,,,,,,,,,h,`,f,,`,,h,`,f,,`,b,`,,`,`,`,,`,b,`,,h,`,f,,`,,h,`,f +,,,,,,,,,,,,,,,,,,,,`,b,`,,`,,`,b,`,,h,`,f,,`,`,`,,h,`,f,,`,b,`,,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n +,,,,,,,,,,,,h,`,f,,f,`,n,,,d,,,`,,,d,,,n,`,f,,`,`,`,,f,`,n,,,d,,,`,,,d,,,n,`,f,,h,`,f +,,,,,,,,,,,,`,b,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,`,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,b,` +,,,,,,,,,,,,n,`,n,,h,`,n,,,d,,,`,,,d,,,n,`,h,,`,`,`,,h,`,n,,,d,,,`,,,d,,,n,`,h,,n,`,n +,,,,,,,,,,,,,d,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n,,,,,,,d +,,,,,h,`,f,,f,`,n,,`,,n,r,a,h,,r,b,t,,`,,`,b,`,,h,b,f,,`,`,`,,h,b,f,,`,b,`,,`,,r,b,t,,h,a,r,n,,`,,n,`,f,,h,`,f +,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,s,,a,`,c,,`,,h,`,f,,n,`,n,,`,`,`,,n,`,n,,h,`,f,,`,,a,`,c,,s,`,b,`,d,`,d,`,b,`,,`,b,` +,,,,,n,`,n,,h,`,n,,`,,n,t,c,f,,h,s,f,,`,,,,,,,d,,,`,`,`,,,d,,,,,,,`,,h,s,f,,f,c,t,n,,`,,n,`,h,,n,`,n +,f,`,n,,,d,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,d,,,n,`,f +,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,` +,h,`,n,,,d,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,d,,,n,`,h +,,,,,n,`,n,,f,`,n,,`,,n,r,a,h,,h,s,f,,`,,,,,,,d,,,`,`,`,,,d,,,,,,,`,,h,s,f,,h,a,r,n,,`,,n,`,f,,n,`,n +,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,s,,a,`,c,,`,,h,`,f,,n,`,n,,`,`,`,,n,`,n,,h,`,f,,`,,a,`,c,,s,`,b,`,d,`,d,`,b,`,,`,b,` +,,,,,h,`,f,,h,`,n,,`,,n,t,c,f,,r,b,t,,`,,`,b,`,,h,b,f,,`,`,`,,h,b,f,,`,b,`,,`,,r,b,t,,f,c,t,n,,`,,n,`,h,,h,`,f +,,,,,,,,,,,,,d,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n,,,,,,,d +,,,,,,,,,,,,n,`,n,,f,`,n,,,d,,,`,,,d,,,n,`,f,,`,`,`,,f,`,n,,,d,,,`,,,d,,,n,`,f,,n,`,n +,,,,,,,,,,,,`,b,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,`,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,b,` +,,,,,,,,,,,,h,`,f,,h,`,n,,,d,,,`,,,d,,,n,`,h,,`,`,`,,h,`,n,,,d,,,`,,,d,,,n,`,h,,h,`,f +,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n +,,,,,,,,,,,,,,,,,,,,`,b,`,,`,,`,b,`,,h,s,f,,`,`,`,,h,s,f,,`,b,`,,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,h,`,f,,`,,h,`,f,,a,`,c,,`,`,`,,a,`,c,,h,`,f,,`,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,`,,,,,,r,b,t,d,`,`,`,d,r,b,t,,,,,,` +,,,,,,,,,,,,,,,,,,,,f,`,n,,`,,n,`,f,,n,`,n,,`,`,`,,n,`,n,,f,`,n,,`,,n,`,f +,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,d,`,b,`,,,d,,,`,`,`,,,d,,,`,b,`,d,`,d,`,b,` +,,,,,,,,,,,,,,,,,,,,h,`,n,,`,,n,`,h,,`,`,`,,`,`,`,,`,`,`,,h,`,n,,`,,n,`,h +,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,`,`,,`,`,`,,`,`,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,f,`,n,,`,`,,`,`,`,,`,`,,n,`,f,,n,`,n +,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,d,`,`,,`,`,`,,`,`,d,`,b,`,,`,b,` +,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,h,`,n,,`,`,,`,`,`,,`,`,,n,`,h,,h,`,f +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` diff --git a/data/blueprints/dreamfort.csv b/data/blueprints/dreamfort.csv new file mode 100644 index 0000000000..c1266edb6e --- /dev/null +++ b/data/blueprints/dreamfort.csv @@ -0,0 +1,3238 @@ +#notes label(help) run me for the dreamfort walkthrough +"Welcome to Dreamfort! These blueprints will help you build a functional, secure, fully self-sustaining fortress that you can use as-is or extend to build the fortress of your dreams!" +"" +"It can be difficult to apply a set of blueprints that you did not write yourself. This walkthrough will guide you through the high-level steps of building Dreamfort. Run ""gui/quickfort dreamfort /checklist"" (or, if you're looking at the online version, switch to the ""checklist"" sheet) for a compact list of the blueprints you'll be applying. Each level also has its own mini-walkthrough with more details." +"" +"The final fort will have a walled-in area on the surface for livestock, trading, aboveground farming, and military training. One z-level down is the farming level, with related workshops and vents up to the surface for miasma prevention. The farming level also has a miniature dining hall and dormitory for use until you get the services and housing levels set up." +"" +"Beyond those two, the other layers can be built in any order, at any z-level, according to your preference and the layout peculiarities of your embark site:" +"- The industry level has a compact, but complete set of workshops and stockpiles (minus what is already provided on the farming level)." +"- The services level has dining, hospital, marksman barracks, and justice services. It has a well system and is 4 z-levels deep." +"- The guildhall level has large rooms for building libraries, temples, and guildhalls, with optional furniture layouts." +- The suites level has fancy rooms for your nobles with the furniture that they require. +- The apartments levels have small but well-furnished bedrooms for your other dwarves. +- The crypt level houses your dead. +"" +"Run each level's ""help"" blueprint (e.g. ""gui/quickfort dreamfort /surface_help"") for more details." +"" +"Dreamfort has a central stairs-based design. For all Dreamfort levels, place the cursor on the center (undug) tile of the 3x3 stairs area when you apply the blueprints for that level. The first surface blueprint will designate a column of stairs that you can use as a guide. If you need to extend the stairs down further to lower levels, run ""gui/quickfort dreamfort /central_stairs"" and set the repeat option to go down however many levels you need (each repetition is 2 levels). Apply it with the cursor on the z-level below the lowest current stairs." +"" +"Dreamfort blueprints take care of everything to get the fort up and running. You don't need to clear any extra trees or create any extra buildings or stockpiles (though of course you are free to do so). Blueprints that do require manual steps, like 'assign minecart to hauling route', will leave a message telling you so when you run them. Note that blueprints will designate buildings to build even if you don't have the materials needed to build them. You can use the ""o"" hotkey to automatically create the manager orders for all the needed items when you have a blueprint loaded in gui/quickfort. Make sure your manager is available to validate all the incoming work orders!" +"" +"There are some tasks common to all forts that Dreamfort doesn't specifically handle for you. For example, Dreamfort sets up a barracks, but managing squads is up to you. Here are some other common tasks that may need to be done manually (or with some other tool):" +- Exploratory mining for specific resources like iron (see gui/design for help with this) +"- Filling the well system with water (if you have a light aquifer, see library/aquifer_tap.csv for help with this)" +- Bringing magma up to the industry level to power magma forges/furnaces (see library/pump_stack.csv for help with this) +- Manufacturing trade goods +"- Custom stockpile setups to assist with, for example, encrusting only high-quality items" +"" +"Dreamfort works best at an embark site that is relatively flat and has at least one soil layer. New players should avoid embarks with aquifers if they are not prepared to deal with them. Bring picks for mining, an axe for woodcutting, and an anvil for a forge. Bring a few blocks to speed up initial workshop construction as well. That's all you really need, but see the example embark profile in the online spreadsheets for a more complete setup." +"" +"Other DFHack tools also work very well with Dreamfort, such as autofarm. See the /setup_help blueprint for a suggested list to turn on in the DFHack gui/control-panel." +"" +"Once you have your starting surface workshops up and running, you might want to configure buildingplan to only use blocks for constructions so it won't use your precious wood, boulders, and bars to build floors and walls. If you bring at least 7 blocks with you on embark, you can set this to be your default in the Automation -> Autostart tab of gui/control-panel." +"" +"Directly after embark, run ""gui/quickfort dreamfort /setup_help"" to get some advice on initial settings, and get started building your fort with ""gui/quickfort dreamfort /surface1"" on the surface (see /surface_help for how to select a good spot). Read the walkthroughs for each level to understand what's going on and follow the checklist to keep track of where you are in the building process. Good luck, and have fun building an awesome Dreamfort-based fort!" +"" +"The dreamfort.csv file distributed with DFHack is generated from online spreadsheet files. If you want to look at how these blueprints are put together, it is easier to look at the online spreadsheets than the giant .csv. You can view them at: https://drive.google.com/drive/folders/1dsmvnzbOKsyFS3DCj0F8ibSnMhVHEjdV" +You are welcome to copy the Dreamfort spreadsheets and make your own modifications! +"" +"If you like, you can download a fully built Dreamfort-based fort from https://dffd.bay12games.com/file.php?id=15434 and explore it +interactively." +"# The dreamfort.csv distributed with DFHack is generated from the online spreadsheets with the following command: + for fname in dreamfort*.xlsx; do xlsx2csv -a -p '' ""$fname""; done | sed 's/,*$//'" +#notes label(checklist) command checklist +"Here is the recommended order for Dreamfort commands. Each line is a blueprint that you run with gui/quickfort (default keybinding: Ctrl-Shift-Q), except where we use other tools as noted. If you set ""dreamfort"" as the filter when you open gui/quickfort, you'll conveniently only see Dreamfort blueprints to choose from. See the walkthroughs (the ""help"" blueprints) for context and details. You can also copy text from this spreadsheet when viewing it online and paste it into gui/launcher with Ctrl-V." +"If the checklist indicates that you should generate orders, that means to hit the ""o"" hotkey when the blueprint is loaded in gui/quickfort. You'll get a popup saying which orders were generated. Also remember to read the messages the blueprints display after you run them so you don't miss any important manual steps!" +"" +-- Preparation (before you embark!) -- +Optionally copy the premade Dreamfort embark profile from the online spreadsheets to the prefs/embark_profiles.txt file. +Run gui/control-panel and enable settings on the Autostart tabs. See the /setup_help notes for details. +"" +-- Set settings and preload initial orders -- +DFHack command,Blueprint,Generate orders,Notes +gui/quickfort,/setup_help,,For advice on how to do initial setup for success. +"quickfort orders library/dreamfort.csv -n ""/surface2, /farming2, /surface3, /industry2, /surface4, /industry3""",,,"Queue up orders required to get the fort minimally functional and secure. You can remove the order for the anvil (you brought one with you, right?)." +"" +-- Find a good starting spot on the surface -- +DFHack command,Blueprint,Generate orders,Notes +gui/quickfort,/perimeter,,Run at embark. Don't actually apply the blueprint -- it's way too early to dedicate resources to building walls. Just use the preview shadow to find a good spot on the surface. See the surface level help for how to find a good spot. +"" +-- Dig -- +DFHack command,Blueprint,Generate orders,Notes +gui/quickfort,/surface1,,Clear some trees and dig central staircase. Run when you find your center tile. Deconstruct your wagon if it is in the way. +gui/quickfort,/dig_all,,"Run when you find a suitable (non-aquifer) rock layer for the industry level. It designates digging for industry, services, guildhall, suites, apartments, and the crypt all in one go. This list does not include the farming level, which we'll designate in the uppermost soil layer once the surface miasma channels are dug. Note that it is more efficient for your miners if you designate the digging for a level before they dig the central stairs past that level. The stairs down on each level are designated at priority 5 instead of the regular priority 4. This lets the miners focus on one z-level at a time and not run up and down the stairs attempting to dig out two blueprints simultaneously. If you need to designate your levels individually due to caverns interrupting the sequence or just because it is your preference, run the level-specific dig blueprints (i.e. /industry1, /services1, /guildhall1, /suites1, 3 levels of /apartments1, and /crypt1) instead of running /dig_all." +"" +-- Core fort (should finish at about the third migration wave) -- +DFHack command,Blueprint,Generate orders,Notes +gui/quickfort,/surface2,,"Build starter workshops/stockpiles and dig miasma vents. Run after initial trees are cleared. If you are deconstructing the wagon, do it before running this blueprint so the jobs that depend on scattered wagon contents (e.g. blocks) don't get canceled later." +gui/quickfort,/farming1,,Dig out the farming level. Run when channels on the surface are dug and the additional designated trees are cleared. +gui/quickfort,/farming2,,Build farming level. Run as soon as the farming level has been completely dug out. +gui/quickfort,/surface3,,Cover the miasma vents and start protecting the central staircase from early invasions. Run when /farming2 is mostly complete. +gui/quickfort,/industry2,,"Build industry level. Run as soon as the industry level has been completely dug out. As industry workshops are built, you can remove the temporary workshops and stockpiles on the surface. Be sure that there are no items attached to jobs left in the surface workshops before deconstructing them, otherwise you'll get canceled jobs!" +gui/quickfort,/surface4,,Finish protecting the staircase and lay flooring for future buildings. Run after the walls and floors around the staircase are built and you have moved production from the surface to the industry level. +gui/quickfort,/industry3,,Build the rest of the industry level. Run once /surface4 is mostly complete. +orders import library/basic,,,"Run after the first migration wave, so you have dwarves to do all the basic tasks. Note that this is the ""orders"" plugin, not the ""quickfort orders"" command." +gui/quickfort,/services2,Yes,"Build simple hospital and dining room, including a well. Run once the 4 services levels have been dug out and you have built up some stone in your industry stone stockpiles. Feel free to remove the orders for the ropes if you brought some with you. If you are filling your wells from an aquifer or stream, now is also a good time to start digging the plumbing." +gui/quickfort,/surface5,Yes,"Build surface buildings, drawbridges, and furniture. Run when all marked trees on the surface are chopped down and previously-designated walls and floors have been constructed. Be sure to check that the little ""wing"" of roof section over the future barracks is constructed so we can place the barracks beds." +gui/quickfort,/surface6,Yes,Build security perimeter. Run once you have linked all levers to their respective bridges. +gui/quickfort,/surface7,Yes,Build roof. Run after the surface walls are completed and any marked trees are chopped down. Be sure to give your haulers some time to fill the stonecutter's stockpile with some stone first so your stonecutters won't be hauling it up from the depths by hand. +"" +-- Plumbing -- +"If you haven't done it already, this is a good time to fill your well cisterns, either with a bucket brigade or by routing water from a freshwater stream or an aquifer (see the aquifer_tap library blueprint for help with this)." +Also consider bringing magma up to your services level so you can replace the forge and furnaces on your industry level with more powerful magma versions. This is especially important if your embark has insufficient trees to convert into charcoal. Keep in mind that moving magma is a tricky process and can take a long time. Don't forget to continue making progress on the rest of the fort! +"" +-- Mature fort (fourth migration wave onward) -- +"The order of steps in this section is not important. Feel free to reorder as per the needs of your fort. Once you have about 50 dwarves, you can queue up as much as you want and your haulers will be able to keep your stonecutters supplied. You can even build another two Stonecutter's workshops to speed things along. You might need to dig a quarry on an unused level to get enough stone, though." +DFHack command,Blueprint,Generate orders,Notes +orders import library/furnace,,,Automated production of basic furnace-related items. Don't forget to create a sand collection zone (or remove the sand- and glass-related orders if you have no sand). +gui/quickfort,/guildhall2_default,Yes,"Build library and non-denominational temple, and prepare space for future temples and guildhalls. Run when the guildhall level has been dug out." +gui/quickfort,/services3,Yes,"Extend the dining room and hospital, and start the jail. Run when your population grows to about 20." +gui/quickfort,/apartments2,Yes,Build and zone bedrooms. Run when the first apartment level has been dug out and you have outgrown your starter dormintory. +gui/quickfort,/suites2_default,Yes,Build rooms that you can zone for your nobles. Run when the suites level has been dug out and you are approaching a population of 50. +gui/quickfort,/crypt2,Yes,Build a small group of tombs. Run when the crypt level has been dug out and you have outgrown your starter tomb on the farming level. +gui/quickfort,/surface8,Yes,"Build extended trap corridors. If you have a strong military, you might not need this." +gui/quickfort,/farming3,Yes,Add in all the doors we couldn't afford to build earlier. +orders import library/military,,,Automated production of military equipment. Turn on automelt in the meltables piles on the industry level to automatically upgrade all metal military equipment to masterwork quality. These orders are optional if you are not using a military. +orders import library/smelting,,,Automated production of all types of metal bars. +gui/quickfort,/services4,Yes,Build full dining room and jail. +orders import library/rockstock,,,Maintains a small stock of all types of rock furniture. Useful for filling out future guildhalls. +orders import library/glassstock,,,Maintains a small stock of all types of glass furniture and parts (only import if you have sand). +gui/quickfort,/apartments2,Yes,Repeat as needed as your fort grows. +gui/quickfort,/crypt3,Yes,Run when the crypt is starting to run out of free tombs. +"" +See this checklist online at https://docs.google.com/spreadsheets/d/13PVZ2h3Mm3x_G1OXQvwKd7oIR2lK4A1Ahf6Om1kFigw/edit#gid=1459509569 +#notes label(setup_help) pre- and post-embark tasks +These are Dreamfort's suggestions for adjustments to settings and initial setup. +"" +You can save some time by setting up your settings in gui/control-panel before you embark. +"Beyond the bugfix tools that are enabled by default, we recommend enabling the following DFHack tools in gui/control-panel (but they are not required if you prefer to do these things manually):" +"" +"On the gui/control-panel ""Autostart"" tabs, enable:" +"""Automation"":" +- autobutcher +- autobutcher target 10 10 14 2 BIRD_GOOSE +- autochop +- autocheese +- autofarm +- autofarm threshold 150 grass_tail_pig +- autofish +- automilk +- autonestbox +- autoshear +- autoslab +- ban-cooking all +- buildingplan set boulders false +- buildingplan set logs false +- cleanowned +- logistics enable autoretrain +- nestboxes +- orders-sort +- prioritize +- seedwatch +- suspendmanager +- tailor +"""Gameplay"" subtab:" +- combine +- dwarfvet +- immortal-cravings +- timestream +- work-now +"Note that if you've already started your fort and have missed the ""new fort"" trigger, you can enable these tools on the ""Enabled"" tabs instead. You can run the one-time commands (like ban-cooking all) manually from gui/launcher." +"" +"Now, after you've arrived at your embark site, open the nobles screen and:" +"- Assign dwarves to at least manager, chief medical dwarf, broker, and bookkeeper noble roles (they can all be the same dwarf)" +"" +On the work details screen (Labor -> Work details) + - Specialize your miners (click the hammer-lock button so it turns red) and make your miners also engravers (they'll need something to do once the mining is done) + - Deselect fishing from all dwarves -- you have enough food to get started and you'll need their time for hauling +"" +In standing orders (Labor -> Standing orders): +" - Change ""Automatically weave all thread"" to ""No automatic weaving"" so the hospital always has thread -- we'll be managing cloth production with automated orders" +"- On the ""Other"" tab, change ""Everybody harvests"" to ""Only farmers harvest"". This will prevent unilts that don't have the Planting labor enabled from harvesting plants, allowing planting skill gains to be concentrated into your designated planters and improving your overall crop yield." +"" +"Once you have your standing orders set the way you like, you can export them and instruct DFHack to autoload your saved settings on new embarks. The controls for getting this set up are available by default in a panel at the bottom of the Standing orders -> Automated workshops tab." +"#meta label(dig_all) start(central stairs on industry level) message(You can repeat the /central_stairs blueprint down more levels if you need more stairs.) dig industry, services, guildhall, suites, apartments, and crypt levels. does not include farming." +# Note that this blueprint will only work for the unified dreamfort.csv. It won't work if you have downloaded the individual .xlsx files since #meta blueprints can't cross file boundaries. +"" +/industry1 +#> +/services1 +#>4 +/guildhall1 +#> +/suites1 +#> +/apartments1 repeat(down 3) +#>3 +/crypt1 +#ignore +"Here are the most important skills for getting Dreamfort up and running, along with suggestions for how to distribute them." +"" +Hauler / Manager / Bookkeeper / Broker,Miner,Miner,Stoneworker,Craftsdwarf,Outdoorsdwarf,Farmer +Noble role skills,Miner,Miner,Stonecutter,Stonecrafting,Carpenter,Planter +,,,Stone Carver,Mechanic,Wood Cutter,Stonecutter +"" +"The most time-consuming tasks in early Dreamfort are: mining, chopping down trees, and making blocks. Starting with at least two miners, two woodcutters (assuming your embark has trees), and two stonecutters helps keep the fort from stalling." +"" +We suggest bringing at least: +2 picks,for the two miners +2 battleaxes,for one woodcutters and either a second woodcutter or an emergency weapon +1 anvil,for the forge +food and seeds,as per usual +3 ropes,"for the hospital well and traction benches. you could make the ropes out of raw materials, but dwarves are usually too busy to do textile work at the start of the game." +20 blocks,"for starting workshops, the temporary trade depot, and a few spares in case you need to shore up a light aquifer in a soil layer. necessary if you have buildingplan configured for blocks only." +many boulders,for quickly turning into more blocks while your miners are digging in dirt or dealing with aquifers. blocks are the limiting factor in the early stages. +dogs and cats,for protection and vermin control +geese,for bones and leather. bring at least 1 male and 2 females for the 2 early nestboxes. +"" +Also bring logs for beds if embarking in an area without many trees. +"" +See ldog's Dreamfort embark profile for a more advanced approach: +https://drive.google.com/file/d/1Et42JTzeYK23iI5wrPMsFJ7lUXwVBQob/view?usp=sharing +"#ignore Add these lines to the bottom of your ""prefs/embark_profiles.txt"" file to make the ""Dreamfort"" profile available in-game. Also see ldog's dreamfort embark profile for a more advanced, dwarfy approach." +[PROFILE] +[TITLE:Dreamfort] +[SKILL:1:JUDGING_INTENT:1] +[SKILL:1:APPRAISAL:2] +[SKILL:1:ORGANIZATION:1] +[SKILL:1:RECORD_KEEPING:1] +[SKILL:1:MILITARY_TACTICS:5] +[SKILL:2:MINING:5] +[SKILL:2:ENGRAVE_STONE:4] +[SKILL:2:SWIMMING:1] +[SKILL:3:MINING:5] +[SKILL:3:ENGRAVE_STONE:4] +[SKILL:3:SWIMMING:1] +[SKILL:4:CUT_STONE:5] +[SKILL:4:CARVE_STONE:5] +[SKILL:5:STONECRAFT:5] +[SKILL:5:MECHANICS:5] +[SKILL:6:WOODCUTTING:5] +[SKILL:6:CARPENTRY:5] +[SKILL:7:PLANT:5] +[SKILL:7:CUT_STONE:5] +[ITEM:10:CLOTH:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] +[ITEM:100:WOOD:NONE:PLANT_MAT:WILLOW:WOOD] +[ITEM:30:BLOCKS:NONE:INORGANIC:QUARTZITE] +[ITEM:21:SEEDS:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:GRASS_TAIL_PIG:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:GRASS_WHEAT_CAVE:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:POD_SWEET:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:BUSH_QUARRY:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:MUSHROOM_CUP_DIMPLE:SEED] +[ITEM:1:ANVIL:NONE:INORGANIC:IRON] +[ITEM:2:WEAPON:ITEM_WEAPON_AXE_BATTLE:INORGANIC:COPPER] +[ITEM:2:WEAPON:ITEM_WEAPON_PICK:INORGANIC:COPPER] +[ITEM:21:DRINK:NONE:PLANT_MAT:GRASS_TAIL_PIG:DRINK] +[ITEM:20:DRINK:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:DRINK] +[ITEM:20:DRINK:NONE:PLANT_MAT:POD_SWEET:DRINK] +[ITEM:20:DRINK:NONE:PLANT_MAT:GRASS_WHEAT_CAVE:DRINK] +[ITEM:30:PLANT:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:STRUCTURAL] +[ITEM:45:BOULDER:NONE:INORGANIC:QUARTZITE] +[ITEM:21:THREAD:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] +[ITEM:3:CHAIN:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] +[PET:2:DOG:FEMALE:STANDARD] +[PET:1:DOG:MALE:STANDARD] +[PET:2:CAT:FEMALE:STANDARD] +[PET:1:CAT:MALE:STANDARD] +[PET:2:BIRD_GOOSE:FEMALE:STANDARD] +[PET:2:BIRD_GOOSE:MALE:STANDARD] +#notes label(surface_help) surface level walkthrough +Sets up a protected entrance to your fort in a flat area on the surface. +Screenshot: https://drive.google.com/file/d/1dlu3nmwQszav-ZaTx-ac28wrcaYBQc_t +"" +Features: +- A starting set of workshops and stockpiles (which you can later remove once you establish your permanent workshops and storage) +"- Livestock grazing area, nestbox zones, and beehives" +"- Walls, roof, and lever-controlled gates for security" +- Barracks (with prisoner processing quantum dump) +- Trap-filled hallways for invaders +- Optional extended trap hallways (to handle larger sieges with a smaller/no military) +"- Protected trade depot, with separate trade goods stockpiles for organics and inorganics (for safe elven trading)" +- A grid of small farm plots for lucrative surface farming +"- A burrow named ""Inside+"" that grows with your fort as you dig it out. It is pre-registered as a civilian alert burrow so you can use it to get your civilians to safety during sieges." +"- A burrow named ""Clearcutting area"" that is automatically registered with autochop (if you have it enabled) to keep the area around your fort clear of trees. This prevents invaders from jumping over your walls. Moreover, it prevents trees from growing large near your exterior walls. If those trees are chopped down so they fall on the fort, they can collapse the roof." +"" +Manual steps you have to take: +"- Assign grazing livestock to the large pasture, dogs to the pasture over the central stairs, and male birds to the zone between the rows of nestboxes (DFHack's autonestbox will auto-assign the female egg-laying birds to the nestbox zones)" +- Connect levers to the drawbridges that match the names of the levers +- Assign minecarts to the trade goods and prisoner processing quantum stockpile hauling routes with assign-minecarts all +"" +Be sure to choose an embark site that has a flat area on the surface large enough to use these blueprints! +"" +Surface Walkthrough: +"1) Choose a tile for your central fortress stairs. The terrain around that tile should be perfectly flat. Trees are ok, but no slopes, rivers, or ponds. To be sure that the tile you've chosen is in a good spot, run ""gui/quickfort dreamfort /perimeter"". This will show you the eventual boundaries of the fort. Some wall segments might be missing due to existing trees, but that's ok. Make sure the area within the exterior wall is flat. Cancel out of the preview. You don't actually need to apply this blueprint. You may want to double-check your selected area with gui/biomes to make sure your surface farm plots (to the left of the central tile) will be in a biome that you want to grow in (e.g. you cannot grow surface plants in mountain biomes). Also, the biome to the north of the central tile will hold the underground farm plots, so be sure it has soil." +"" +"2) With the cursor on the chosen tile, run /surface1 to clear surrounding trees and set up your pastures. Deconstruct your wagon to get it out of the way of our upcoming walls and floors. Remember to assign your dogs to the pasture around the staircase, your grazing animals to the large pasture, and your male birds to the zone between the nestboxes. Your female egg-layers will automatically get assigned to nestbox zones once the nestboxes are built, so you don't need to worry about them. You can let your cats roam free to chase vermin." +"" +"3) Once the marked trees have been cleared, run /surface2 to setup starting workshops/stockpiles, channel out the miasma vents for the farming level, and start clearing trees from a larger area. If you haven't done it already, now is a good time to configure buildingplan to only build buildings with blocks, not logs or raw boulders. Generate manager orders for /surface2 if you haven't already preordered with the checklist command." +"" +"4) Once the channels are dug out and the trees are cleared, start digging the farming level one z-level down. Once you have run /farming2, come back to the surface and run /surface3 to cover the vents and build an enclosure around your central stairs. Although the vents will be covered with flooring (or solid walls), they will still work to prevent miasma on the farming level. Generate manager orders for /surface3 if you haven't already preordered with the checklist command." +"" +"5) Once all walls and floors have been constructed around the stairwell, run /surface4 to build floors and walls to support upcoming buildings and furniture. Generate manager orders for /surface4 if you haven't already preordered with the checklist command." +"" +"6) Once walls and floors have been constructed (including the small roof segment one z-level up over the barracks), run /surface5 to build furniture and the drawbridge gates. This blueprint also clearcuts the trees from around the exterior walls. The blueprint may appear to extend off the map or into a nearby hill, but that is ok. Generate manager orders for /surface5." +"" +"7) Once all marked trees are cleared, run /surface6 to build the security perimeter and remaining flooring. Generate manager orders for /surface6." +"" +"8) Once you have enough dwarves to do a lot of building without starving other important tasks, run /surface7 to build the roof. This blueprint also sets up the autochop-integrated clearcutting area, so it may extend off the map or into nearby hills. It is not a problem if that happens. Generate manager orders for /surface7." +"" +"9) For extra security, you can run /surface8 any time after /surface7 to extend the trap corridors. Generate manager orders for /surface8." +"" +"10) Once your industry and farming levels are set up and running, you can disassemble the surface workshops and remove the surface stockpiles. Disassembling a workshop scatters the items stored within it and cancels any pending jobs that happen to use those items. In order to avoid job cancellations, first set the surface workshops to not accept general work orders (click on the building, select the ""Work orders"" tab, and set the ""General work orders allowed"" to 0). Then check to see if any items in a workshop are marked as being part of an active job. Once no items in the workshop have that marker, you are free to disassemble that workshop." +"" +Sieges and Prisoner Processing: +Here are some tips and procedures for handling seiges -- including how to clean up afterwards! +"" +"- Your ""Inside+"" burrow will automatically grow with your fort and should include only safe areas. In particular, it does not include the ""atrium"" area (where the ""siege bait"" pasture is) or the trapped hallways." +"" +"- When a siege begins, set your civilian alert (attach the alert to your ""Inside+"" burrow if it isn't already) to ensure all your civilians stay out of danger. Immediately pull the lever to close the outer main gate. It is also wise to close the trade depot and inner main gate as well. That way, if enemies get past the traps, they'll have to go through the soldiers in your barracks (assuming you have a military)." +"" +"- During a siege, you can use the levers to control how attackers path through the trapped corridors. If there are more enemies than cage traps, time your lever pulling so that the inner gates snap closed before your last cage trap is sprung. Then the remaining attackers will have to backtrack and go through the other trap-filled hallway. You can also choose *not* to use the trap hallways and instead meet the siege head-on with your military. It's up to you!" +"" +"- If your cage traps fill up, ensure your hallways are free of uncaged attackers, then close the trap hallway outer gates and open the inner gates. Clear the civilian alert and allow your dwarves to reset all the traps -- make some extra cages in preparation for this! Then re-enable the civilian alert and open the trap hallway outer gates." +"" +"- Once the last attacker is caged, open all the gates and unset the civilian alert. Life is normal again!" +"" +"After a siege, you can use the caged prisoners to safely train your military. Here's how:" +"" +"- Once the prisoners are hauled to the ""prisoner quantum"" stockpile in the barracks, run ""stripcaged all"" in DFHack's gui/launcher." +"" +"- After all the prisoners' items have been confiscated, bring your military dwarves to the barracks (if they aren't already there)." +"" +- Assign a group of prisoners to the pasture that overlaps the prisoner quantum stockpile +"" +"- Hauler dwarves will come and release prisoners one by one. Your military dwarves will immediately pounce on the released prisoners and chop them to bits, saving the hauler dwarves from being attacked. Repeat until all prisoners have been ""processed"". Some prisoners are not directly hostile (like cavern-caught gorlaks) and you may need to be target them explicitly to get your soldiers to attack them." +#dig label(central_stairs_odd) start(2;2) hidden() carved spiral stairs odd levels +`,j6,` +u,`,u +`,j6,` +#meta label(central_stairs_even) hidden() carved spiral stairs even levels +/central_stairs_odd transform(cw) +#meta label(central_stairs) two levels of carved spiral stairs (repeat down as needed) +/central_stairs_odd +#> +/central_stairs_even +#build label(central_stairs_odd_constructed) start(2;2) hidden() constructed spiral stairs odd levels +`,Cd,` +Cu,`,Cu +`,Cd,` +#meta label(central_stairs_even_constructed) hidden() constructed spiral stairs even levels +/central_stairs_odd_constructed transform(cw) +#meta label(central_stairs_constructed) two levels of constructed spiral stairs (repeat down as needed) +/central_stairs_odd_constructed +#> +/central_stairs_even_constructed +"#meta label(perimeter) start(central stairs) message(If you accidentally applied this blueprint to the map, run quickfort undo on this blueprint to clean up.) show the eventual perimeter of the surface fort; useful for location scouting. DO NOT APPLY." +walls/surface_walls +corridor_gates/surface_corridor_gates +corridor/surface_corridor +corridor_traps/surface_corridor_traps +"" +"#meta label(surface1) start(central stairs) +message(Once the central stairs are mined out deeply enough, you should start digging the industry level in a non-aquifer rock layer. You'll need the boulders from the digging to make blocks. +If your wagon is within the fort perimeter, deconstruct it to get it out of the way. +Once the marked trees are all chopped down (if any), continue with /surface2.) clear trees and set up pastures" +clear_small/surface_clear_small +burrow_start/surface_burrow_start +zones/surface_zones +#> +central_stairs/central_stairs repeat(down 10) +"" +"#meta label(surface2) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now. +Once the channels are dug out and the marked trees are cleared, continue with /surface3.) set up starting workshops/stockpiles, channel miasma vents, and clear more trees" +place_start/surface_place_start +build_start/surface_build_start +channel/surface_channel +clear/surface_clear +"" +"#meta label(surface3) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now. +Once the walls and floors around the staircase have been constructed, continue with /surface4.) Cover vents and protect the central stairs." +cover_vents/surface_cover_vents +cover_stairs/surface_cover_stairs +"" +"#meta label(surface4) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now. +Once the bits of flooring have been constructed, continue with /surface5. Be sure to check one z-level above the surface to ensure the roof segment above the future barracks has been finished.) build walls and flooring to support upcoming buildings and furniture" +stairs_doors/surface_stairs_doors +pre_building/surface_pre_building +"" +"#meta label(surface5) start(central stairs) message(Remember to enqueue manager orders for this blueprint. +Once the marked trees are cleared, continue with /surface6.) build gates, furniture, and trade stockpile/depot" +traffic/surface_traffic +place/surface_place +build/surface_build +clear_large/surface_clear_large +"" +"#meta label(surface6) start(central stairs) message(Remember to enqueue manager orders for this blueprint. +Continue with /surface7 sometime after the walls are completed and any marked trees are chopped down, whenever you have enough dwarves to build the roof without starving other important construction tasks.) build traps and remaining walls/floors" +walls/surface_walls +floors/surface_floors +traps/surface_traps +clear_large/surface_clear_large +"" +"#meta label(surface7) start(central stairs (on ground level)) message(Remember to enqueue manager orders for this blueprint. +For extra security, you can run /surface8 at any time to extend the trap corridors.) expand Inside+ burrow to safe surface areas and build roof" +burrows/surface_burrows +#< +roof/surface_roof +roof2/surface_roof2 +roof3/surface_roof3 +roof4/surface_roof4 +"" +#meta label(surface8) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) build extended trap corridors +corridor_gates/surface_corridor_gates +corridor/surface_corridor +corridor_traps/surface_corridor_traps +#dig label(surface_clear_small) start(19; 19) hidden() clear trees for starting workshops and stockpiles + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,t1(25x11),,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,t1,`,`,`,`,`,`,,`,,`,`,`,`,`,t1,`,`,`,t1,`,`,,` +,,,`,,`,,`,t1,t1,,,,,,`,t1,t1,t1,t1,t1,`,,,,t1(5x5),,,,,,`,,` +,,,`,,`,,`,,,,,,,,,t1,t1,t1,t1,t1,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,t1,j,t1,j,t1,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,t1,t1,t1,t1,t1,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,t1,t1,t1,t1,t1,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,t1,,,,,,t1,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,t1,t1,,,,,,t1,t1,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,t1,t1,,t1,t1,t1,,t1,t1,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,t1,t1,t1,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,t1,,,t1,t1,t1,,,t1,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,t1,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#burrow label(surface_burrow_start) start(19; 19) hidden() create safety burrow that will grow with your fort + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,,`,`,,` +,,,`,,`,,`,,,,,,,,`,a{name=Inside+ create=true civalert=true}(5x5),,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,~,,~,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +"#zone label(surface_zones) start(19; 19) hidden() message(Remember to assign your dogs to the pasture surrounding the central stairs, your grazing animals to the large pasture, and your male birds to the zone between the rows of nestboxes. If your wagon is far away, you can let your animals wander closer to the fort before pasturing them to save hauling time.) pastures and training areas" + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,"n{name=""Main pasture""}(25x11)",,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,"t{name=""Pet training area""}(9x5)",,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,"n{name=""Nestbox 1""}(1x1)","n{name=""Nestbox 2""}(1x1)","n{name=""Nestbox 3""}(1x1)","n{name=""Nestbox 4""}(1x1)","n{name=""Nestbox 5""}(1x1)","n{name=""Nestbox 6""}(1x1)","n{name=""Nestbox 7""}(1x1)",`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,"n{name=""Male birds""}(7x3)",,,,,,,,"n/guarddogs{name=""Guard dogs""}(5x1)",~,~,~,~,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,n/guarddogs(5x1),~,~,~,~,,,,,,,,,,,`,,` +,,,`,,`,,`,"n{name=""Nestbox 8""}(1x1)","n{name=""Nestbox 9""}(1x1)","n{name=""Nestbox 10""}(1x1)","n{name=""Nestbox 11""}(1x1)","n{name=""Nestbox 12""}(1x1)","n{name=""Nestbox 13""}(1x1)","n{name=""Nestbox 14""}(1x1)",`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,m/welcome(7x1),,,,,,,`,,` +,,,`,,`,"B{name=""Surface barracks""}",B,B,B,B,B,B,B,`,,,,,,,,`,"m/welcome{name=""Welcome area/wagon parking lot""}(8x5)",,,,,,,,`,,` +,,,`,,`,B,B,B,B,B,B,B,B,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,B,B,B,B,B,B,B,B,,,,,"n{name=""Siege bait pasture""}",,,,,,,,,,,,,`,,` +,,,`,,`,B,B,B,B,B,B,B,B,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,B,B,B,B,B,B,"n{name=""Prisoner processing pen""}(1x2)",B,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#place label(surface_place_start) start(19; 19) hidden() starting stockpiles + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,"hlr{name=""Starting cloth/trash"" containers=0}(15x2)",,,,,,,,,,,,,,,,"gunzSpd{name=""Starting misc"" containers=0}(9x4)",,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,"w{name=""Starting wood""}(4x4)",,,,~,~,~,,"s2{name=""Starting stone""}:=otherstone(7x3)",,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,,,,,,,,,"f{name=""Starting food""}(9x2)",,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,,,,,~,~,~,,~,~,~,,~,~,~,,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,,~,~,~,,~,~,~,,~,~,~,,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,,~,~,~,,~,~,~,,~,~,~,,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,,,,,,,,,,,,,,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_build_start) start(19; 19) hidden() starting workshops + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,"wt{name=""Starter mechanic's"" do_now=true}",~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,~,~,~,,~,~,~,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,"wc{name=""Starter carpenter"" do_now=true}",~,,~,"wr{name=""Starter craftsdwarf's"" do_now=true}",~,,~,"wm{name=""Starter stoneworker's"" do_now=true max_general_orders=2}",~,,,,,,,,,,,`,,` +,,,`,,`,,,,,~,~,~,,~,~,~,,~,~,~,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,N{do_now=true},N{do_now=true},,,,,,`,,,,,,`,,,,~,~,~,~,~,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,~,~,~,~,~,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,~,~,D{do_now=true},~,~,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,~,~,~,~,~,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,~,~,~,~,~,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#dig label(surface_channel) start(19; 19) hidden() channel miasma vents + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,h1,`,`,`,`,`,`,,`,,`,`,`,`,`,h1,`,`,`,h1,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,h1,,,,,,h1,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,h1,h1,,,,,,h1,h1,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,h1,h1,,h1,h1,h1,,h1,h1,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,h1,h1,h1,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,h1,,,h1,h1,h1,,,h1,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,h1,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#dig label(surface_clear) start(19; 19) hidden() clear trees so the farming level can be dug without fear of generating surface holes + + +,,,t1(31x29) +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + +,,,,,,,,,,,,,,,t1,t1,t1,t1,t1,t1,t1 + +#build label(surface_cover_vents) start(19; 19) hidden() cover the miasma vents + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,Cw,`,`,`,`,`,`,,`,,`,`,`,`,`,Cw,`,`,`,Cw,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,Cf,,,,,,Cf,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,Cf,Cf,,,,,,Cf,Cf,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,Cf,Cf,,Cf,Cf,Cf,,Cf,Cf,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,Cf,Cf,Cf,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,Cw,,,Cf,Cf,Cf,,,Cw,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,Cf,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_cover_stairs) start(19; 19) hidden() protect the central stairs + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,Cw,Cw,Cf,Cw,Cf,Cw,Cw,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,Cw,,,,,,Cw,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,Cf,,`,`,`,,Cf,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,Cw,,H,~,H,,Cw,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,Cf,,`,`,`,,Cf,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,Cw,,,,,,Cw,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,Cw,Cw,Cf,Cw,Cf,Cw,Cw,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_stairs_doors) start(19; 19) hidden() + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,Cr{do_now=true},,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,d,`,d,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,d,,`,`,`,,d,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,d,,`,`,`,,d,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,d,`,d,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#< + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,Cf{do_now=true},`,Cf,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,Cf,Cf{do_now=true},Cf,Cf,Cf,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf,Cf,Cf,Cf,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,Cf{do_now=true},Cf,Cf,Cf,Cf,Cf,Cf,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,Cf,`,Cf,`,`,`,`,,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_pre_building) start(19; 19) hidden() flooring and anchoring walls for future buildings/doors +#< + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,~,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,~,~,~,~,~,~,~,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},~,~,~,~,~,~,~,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,Cf{do_now=true},,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,Cf{do_now=true},`,`,`,`,~,`,~,`,`,`,`,,,,,,,,`,,` +,,,`,,`,Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,Cf{do_now=true},,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,Cf{do_now=true},,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,Cf{do_now=true},,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},Cf{do_now=true},,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#> + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,~,~,N,N,N,N,N,`,Cf,,Cf,,Cf,`,Cf,Cf,,~,~,~,~,~,,`,,` +,,,`,,`,,Cw,,,,,,,,,,`,`,`,,,Cf,Cf,,~,~,~,~,~,,`,,` +,,,`,,`,,Cf,,,,,,,,`,,`,`,`,,`,Cf,Cf,,~,~,~,~,~,,`,,` +,,,`,,`,,Cw,,,,,,,,,,`,`,`,,,Cf,Cf,,~,~,~,~,~,,`,,` +,,,`,,`,,`,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,,~,~,~,~,~,,`,,` +,,,`,,`,`,`,`,`,`,Cw,Cf,Cw,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,,,,`,~,Cf,Cf,Cf,Cf,Cf,~,`,,,,,,,,,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,,,,~,~,Cf,Cf,Cf,Cf,Cf,~,~,,,,,,,,,`,,` +,,,`,,`,Cf,Cf,,,,,,,~,~,,~,~,~,,~,~,,,,,,,,,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,,Cf,,Cf,Cf,,~,~,~,,Cf,Cf,,,,,,,,,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,,Cf,,`,,,~,~,~,,,`,Cf,,Cf,,,Cf,,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,Cf,Cf,,,,,,,,Cf,Cf,,,,~,,,,Cf,Cf,,,,,,,,Cf,Cf,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,`,` + + + +#dig label(surface_traffic) start(19; 19) hidden() set traffic designations + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,or,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,`,or,or,ol,ol,ol,ol,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,ol,ol,or,ol,ol,ol,ol,ol,ol,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,ol,ol,or,,,,,ol,ol,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,ol,ol,or,,,,,ol,ol,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,`,or,or,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,ol,ol,ol,ol,ol,ol,ol,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,ol,ol,ol,ol,ol,ol,ol +,,,,,,,,,,,,,,,ol,ol,ol,ol,ol,ol,ol + +"#place label(surface_place) start(19; 19) hidden() message(Remember to assign minecarts to the trade goods and prisoner processing quantum stockpiles (run ""assign-minecarts all""). +Feel free to adjust the configuration of the ""trade goods"" feeder stockpile so it accepts the item types you want to trade away. If those items types are also accepted by other stockpiles, configure those stockpiles to give to the ""trade goods"" stockpile. +The inorganic trade goods stockpile is set to autotrade, but you can toggle that according to your preference.) remaining surface stockpiles" + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,"a10{name=""Pets/Prisoner feeder"" autotrain=true}(9x5)",,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,"c{name=""Organic trade goods quantum"" quantum=true}:+all",,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,"g{name=""Trade goods"" containers=0}:-cat_finished_goods/type/,core/artifact+crafts(2x3)",,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,"c{name=""Inorganic trade goods quantum"" autotrade=true quantum=true}:+all-organic",,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,"a{name=""Prisoner/cage quantum"" autotrain=true quantum=true}",,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +"#build label(surface_build) start(19; 19) hidden() message(Use autofarm to manage farm crop selection. +Remember to connect the levers to the gates once they are built.) gates, barracks, farm area, and trade area" + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,~,~,~,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,~,"ww{name=""Milking/shearing station"" labor=""Milking, Shearing""}",~,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,~,~,~,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,~,~,~,~,~,~,~,`,"Tl{name=""Barracks gate"" do_now=true}",,"Tl{name=""Inner main gate"" do_now=true}",,"Tl{name=""Trade depot gate"" do_now=true}",`,"trackstopE{name=""Organic trade goods dumper"" take_from=""Trade goods"" route=""Organic trade goods quantum""}",,,~,~,~,~,~,,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),,,`,`,`,,,,,,~,~,~,~,~,,`,,` +,,,`,,`,"~h{name=""reserved for splitting"" do_install=true}(1x1)",d,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),`,,`,`,`,,`,,,,~,~,~,~,~,,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),,,`,`,`,,,,,,~,~,~,~,~,,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,N,N,N,N,N,N,N,`,"Tl{name=""Left outer gate"" do_now=true}(1x1)","Tl{name=""Left inner gate"" do_now=true}(1x1)","Tl{name=""Outer main gate"" do_now=true}(1x1)","Tl{name=""Right inner gate"" do_now=true}(1x1)","Tl{name=""Right outer gate"" do_now=true}(1x1)",`,"trackstopE{name=""Inorganic trade goods dumper"" take_from=""Trade goods,Organic trade goods quantum"" route=""Inorganic trade goods quantum""}:-organic",,,~,~,~,~,~,,`,,` +,,,`,,`,`,`,`,`,`,`,d,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,b,b,b,b,b,,,,`,,"gw{name=""Inner main gate"" do_now=true}",gw,gw,gw,gw,,`,,,,,,,,,`,,` +,,,`,,`,h,h,h,h,h,,,,"ga{name=""Barracks gate"" do_now=true}",ga,gw,gw,gw,gw,gw,"gd{name=""Trade depot gate"" do_now=true}",gd,,,,,,,,,`,,` +,,,`,,`,a,r,,,,,,,ga,ga,,,,,,gd,gd,,,,,,,,,`,,` +,,,`,,`,h,h,h,h,h,,"trackstopS{name=""Prisoner/cage dumper"" take_from=""Pets/Prisoner feeder"" route=""Prisoner/cage quantum""}:-cat_animals/tameable",,ga,ga,,,,,,gd,gd,,,,,,,,,`,,` +,,,`,,`,b,b,b,b,b,,,,`,,,,,,,,`,s,,s,,,s,,s,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,"gd{name=""Left outer gate"" do_now=true}",gd,,,,,,,,"gd{name=""Left inner gate"" do_now=true}",gd,,,,,,,,"ga{name=""Right inner gate"" do_now=true}",ga,,,,,,,,"ga{name=""Right outer gate"" do_now=true}",ga,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,"gw{name=""Outer main gate"" do_now=true}",gw,gw,gw,gw,gw,gw,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,gw,gw,gw,gw,gw,gw,gw +,,,,,,,,,,,,,,,gw,gw,gw,gw,gw,gw,gw + +#dig label(surface_clear_large) start(19; 19) hidden() clear wider area of trees +t1(37x33) + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_walls) start(19; 19) hidden() build remaining walls + + + +,,,`,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,Cw,Cw,Cw,Cw,~,Cw,Cw,Cw,Cw,~,~,,~,,~,~,Cw,Cw,Cw,~,Cw,Cw,Cw,~,Cw,Cw,,` +,,,`,,Cw,,Cw,,,,,,,,~,,,,,,~,,,,,,,,,,Cw,,` +,,,`,,Cw,,~,,,,,,,,,,`,`,`,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,~,,`,`,`,,~,,,,,,,,,,Cw,,` +,,,`,,Cw,,~,,,,,,,,,,`,`,`,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,Cw,,,,,,,,~,,,,,,~,,,,,,,,,,Cw,,` +,,,`,,Cw,Cw,Cw,Cw,Cw,Cw,~,,~,Cw,~,~,,~,,~,~,Cw,Cw,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,Cw,,,,,,,,Cw,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` +,,,`,,Cw,,,,,,,,,~,,,,,,,,~,,,,,,,,,Cw,,` +,,,`,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,,,,,,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,,,,,,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,`,` + + + +#build label(surface_floors) start(19; 19) hidden() build remaining flooring + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,~,Cf,~,Cf,~,`,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,`,,,,,,,,~,Cf,Cf,Cf,Cf,Cf,~,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,~,,,,,,,,`,Cf,`,Cf,`,Cf,`,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,`,,,,,,,,~,Cf,Cf,Cf,Cf,Cf,~,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,Cf,Cf,Cf,`,~,~,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,Cf,Cf,Cf,~,~,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,Cf,Cf,Cf,Cf,Cf,Cf,~,~,Cf,~,~,~,Cf,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,Cf,~,Cf,~,~,Cf,~,~,~,Cf,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,Cf,~,Cf,`,Cf,Cf,~,~,~,Cf,Cf,`,~,Cf,~,Cf,Cf,~,Cf,~,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,,` +,,,`,~,,,,,,,,,,,Cf,Cf,Cf,~,Cf,Cf,Cf,,,,,,,,,,,~,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_traps) start(19; 19) hidden() + +,,,,,Tc,,,,,,,,,,,,,,,,,,,,,,,,,,Tc +,,,,,Tc,,,,,,,,,,,,,,,,,,,,,,,,,,Tc +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,Tc,Tc,Tc,Tc,Tc,Tc,Tc,,,,,,,,,,,,Tc,Tc,Tc,Tc,Tc,Tc,Tc,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,Tc,Tc,,,,,,,,Tc,Tc +,,,,,,,,,,,,,Tc,Tc,,,,,,,,Tc,Tc + +#burrow label(surface_burrows) start(19; 19) hidden() extend safety burrow to newly safe surface areas and set up surrounding clearcutting area + + +,,,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(-12x-10)","a{name=""Clearcutting area"" create=true autochop_clear=true}(28x-10)",,,,,,,,,,,,,,,,,,,,,,,,,,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(12x-10)" +,,,`,"a{name=""Clearcutting area"" create=true autochop_clear=true}(-12x27)",`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,"a{name=""Clearcutting area"" create=true autochop_clear=true}(12x27)",` +,,,`,,`,a{name=Inside+}(25x17),,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,~,,~,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,a{name=Inside+}(8x7),`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,a{name=Inside+}(8x7),,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(-12x10)","a{name=""Clearcutting area"" create=true autochop_clear=true}(28x10)",,,,,,,,,,,,,,,,,,,,,,,,,,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(12x10)" + + +#build label(surface_roof) start(19; 19) hidden() roof hatch and adjacent tiles + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,Cf,,Cf,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,Cf,"H{name=""Roof access""}",Cf,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,Cf,`,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,Cf,`,,,,,,,,~,~,~,~,~,~,~,,,,,,,,,,`,,` +,,,`,,`,Cf,Cf,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,Cf,`,,,,,~,~,~,~,~,~,~,~,~,~,,,,,,,,,,`,,` +,,,`,,`,Cf,`,,,,,~,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,,,,,,,,`,,` +,,,`,,`,~,~,~,~,~,~,~,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,~,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,~,~,~,~,~,~,~,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_roof2) start(19; 19) hidden() lower half of the roof + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,~,,~,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,~,~,~,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,`,Cf,Cf,Cf,Cf,~,~,~,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,`,Cf,Cf,Cf,Cf,~,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,~,~,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,~,~,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_roof3) start(19; 19) hidden() upper half center of the roof + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,Cf,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_roof4) start(19; 19) hidden() upper half remainder of the roof + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_corridor_gates) start(19; 19) hidden() message(Remember to connect the levers to the new external trap gates.) gates for the longer trap hallways + + +,,,,"gx{name=""Left trap gate"" do_now=true}",,,,,,,,,,,,,,,,,,,,,,,,,,,,"gx{name=""Right trap gate"" do_now=true}" +,,,`,gx,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,gx,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,"Tl{name=""Left trap gate"" do_now=true}",`,`,`,"Tl{name=""Right trap gate"" do_now=true}",`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_corridor) start(19; 19) hidden() longer trap hallway walls + + +,,,,~,,,,,,,,,,,,,,,,,,,,,,,,,,,,~ +,,,Cw,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,~,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,Cw +,,,Cw,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,Cw +,,,Cw,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,`,~,`,`,`,~,`,,,,,,,,,,`,,Cw +,,,Cw,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,Cw +,,,Cw,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw +,,,Cw,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,Cw +,,,Cw,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,Cw +,,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cw +,,,Cw,Cw,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,Cw,Cw + + + +#< + + + +,,,`,Cf,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,Cf,` +,,,`,Cf,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,Cf,` +,,,`,Cf,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,Cf,` +,,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` + + + +#build label(surface_corridor_traps) start(19; 19) hidden() traps for the longer trap hallways + + +,,Tc,Tc,~,,,,,,,,,,,,,,,,,,,,,,,,,,,,~,Tc,Tc +,,Tc,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,Tc +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,Tc,` +,,,`,Tc,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,`,~,`,`,`,~,`,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,Tc,` +,,,`,Tc,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` +,,,`,Tc,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,Tc,` +,,,`,Tc,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,Tc,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,Tc,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,Tc +,,Tc,Tc,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Tc,Tc + + +#notes label(farming_help) farming level walkthrough +"Sets up farming, food storage, and related industries. Also provides post-embark necessities that can later be disassembled." +Screenshot: https://drive.google.com/file/d/1vDaedLcgoexUdKREUz75ZXQi0ZSdwWwj +"" +Features: +- Pairs with the surface blueprints for vents that prevent miasma +- Farm plots (can be managed by DFHack autofarm) +- Plentiful food storage +- Refuse/corpse quantum stockpile +"- Starter dormitory, dining room, and tomb for use until more permanent versions are ready" +- Offices for your manager and bookkeeper +"" +Workshops: +- Kitchen +- Brewery +- Butcher +- Fishery +- Tannery +- Farmer's Workshop +- Quern +- Screw Press +"" +Manual steps you have to take: +"- Assign a minecart to your refuse quantum stockpile hauling route (you can run ""assign-minecarts all"" to do this)" +"" +Farming Walkthrough: +"1) Wait until you have channeled the miasma vents and cleared trees on the surface before digging out the farming level on the z-level below the surface, otherwise you will end up with extra ramps on the farming level and unprotected holes through the surface when you later chop down trees growing above empty space." +"" +2) Start digging with /farming1 and get started on manufacturing furniture by generating manager orders for /farming2 (if you haven't already preordered with the checklist command). +"" +"3) Once the level is dug out, run /farming2 to designate zones, build workshops and stockpiles, and place furniture. Remember to assign a minecart to the newly-designated quantum refuse dump with assign-minecarts all." +"" +"4) Once your fort has enough free time to build the remaining doors, run /farming3. Generate manager orders for /farming3." +"" +"5) You can disassemble the dining room and dormitory once the services and apartments levels are up and running, if you like. Also, you can turn on seasonal fertilization for the farm plots if you need to boost your crop yields." +"#dig label(farming1) start(16; 18; central stairs) message(Once the area is dug out, continue with /farming2.)" +# this level is dug at priority 3 since it is dug in soil. it's worth the miner's time to +# stop digging the industry level and quickly dig out this one. +,,,,,,,,,3,3,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,,,3,3,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,,,3,3,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,,,,,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,3,3,3,,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,3,3,3,3,3,,3,3,3,3,3,,3,3,3,3 +,,,,,,,3,3,3,,3,,3,3,3,3,3,,3 +,,,,,,,,,,,3,,3,3,3,3,3,,3,,3,3,3 +,,,,,,3,3,3,3,,3,,3,3,3,3,3,,3,3,3,3,3 +,,,,,,3,3,3,3,,3,,3,3,3,3,3,,3,,3,3,3 +,,,3,3,,3,3,3,3,,3,,3,3,3,3,3,,3 +,,3,3,3,,3,3,3,3,,3,,3,3,3,3,3,,3,,3,3,3,,3,3,3 +,,3,3,3,3,3,z3,2,2,2,2,,,3,,3,,,2,2,2,z3,2,2,2,z3,3 +,,,3,3,,3,3,3,3,,2,2,2,2,2,2,2,2,2,,3,3,3,,3,3,3 +,,,,3,,,3,,,,,,2,`,`,`,2,,,,,3,,,,3 +,,3,3,3,3,3,3,3,3,3,3,,2,`,~,`,2,,3,3,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,3,3,3,3,2,`,`,`,2,3,3,3,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,3,3,3,,2,2,2,2,2,,3,3,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,3,3,,,,2,,2,,,,3,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,3,,,z3,2,2,2,2,2,z3,,,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,3,,z3,z3,,,2,,,z3,z3,,3,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,,,z3,z3,,z3,z3,z3,,z3,z3,,,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,,3,2,3,,z3,z3,z3,,3,2,3,,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,,3,z3,3,,z3,z3,z3,,3,z3,3,,3,3,3,3,3,3,3 +,,3,3,3,3,3,3,3,,3,3,3,,,2,,,3,3,3,,3,3,3,3,3,3,3 +,,,,,,,,,,,,,,,z3 + + +"#meta label(farming2) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now. +Once furniture has been placed, continue with /farming3.) workshops, stockpiles, and important furniture" +zone/farming_zone +place/farming_place +build/farming_build +traffic/farming_traffic +burrow/farming_burrow +"" +#meta label(farming3) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) build remaining doors +doors/farming_doors +#zone label(farming_zone) start(16; 18) hidden() rooms + + +,,,,,,,,,T{pets=true}(1x1),`,`,,`,`,`,`,`,,"h{name=""Starter dining hall""}(4x6)",,,` +,,,,,,,,,T{pets=true}(1x1),`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,T{pets=true}(1x1),`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,"o{name=""Manager's office"" assigned_unit=manager}(3x1)",,`,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,"o{name=""Bookkeeper's office"" assigned_unit=bookkeeper}(3x1)",,`,,`,,`,`,`,`,`,,` +,,,,,,,,,,,`,,`,`,`,`,`,,`,,"D{name=""Starter dormitory""}(3x3)",,` +,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,`,` +,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,` +,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` +,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` +,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,` + + +"#place label(farming_place) start(16; 18) hidden() message(remember to assign a minecart to the refuse quantum stockpile (run ""assign-minecarts all"")" + + +,,,,,,,,,`,`,`,,`,`,`,"c{name=""Seeds"" barrels=10 links_only=true take_from=""Starting food""}:+seeds(1x9)","c{name=""Potash""}:+potash(1x12)",,"c{name=""Booze"" barrels=-1 take_from=""Starting food""}:+booze(4x2)",,,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,"c{name=""Prepared food"" take_from=""Starting food""}:+preparedmeals(3x2)",,` +,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,,`,,`,`,`,`,`,,` +,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,` +,,,,,,`,`,`,"u{name=""Pots"" take_from=""Starting misc""}:-cat_furniture/type+pots(1x4)",,`,,`,`,`,`,`,,`,`,`,`,` +,,,,,,`,`,`,~,,`,,"c{name=""Seeds feeder"" give_to=""Seeds"" take_from=""Starting food""}:+seeds(4x3)",,,,`,,`,,`,`,` +,,,"u{name=""Bags"" take_from=""Starting misc""}:-cat_furniture/type+bags(2x2)",~,,`,`,`,~,,`,,`,`,`,`,`,,` +,,`,~,~,,`,`,`,~,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,`,"c{name=""Jugs"" take_from=""Starting misc"" give_to=""Cookable food""}:+cat_finished_goods/core,total+woodtools(2x2)",~,`,`,`,`,"u{name=""Barrels"" take_from=""Starting misc,Starting food""}:-cat_furniture/type+barrels(1x2)",`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` +,,,~,~,,`,`,`,~,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` +,,"c{name=""Plants"" barrels=-1 take_from=""Starting food""}:+plants",c,c,c,c,c,c,c,c,c,,`,`,~,`,`,,"c{name=""Cookable food"" barrels=-1 take_from=""Starting food""}:+cat_food/meat/,fish/prepared/,egg/,cheese/,leaves/,powder/,glob/,liquid/plant/,paste/,pressed/,milk,royal_jelly-dye-cat_food/tallow,thread,liquid/misc/",c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,c,c,`,`,`,`,`,`,`,c,c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,c,c,,`,`,`,`,`,,c,c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,c,,,,`,,`,,,,c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,,,c,`,`,`,`,`,c,,,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,,"c{name=""Unprepared fish"" take_from=""Starting food""}:+unpreparedfish",c,,,`,,,"c{name=""Rawhides"" take_from=""Starting cloth/trash""}:+rawhides",c,,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,,c,c,,"c{name=""Refuse feeder"" give_to=""Rawhides"" take_from=""Starting cloth/trash""}:+cat_refuse/type(1x3)","y2{name=""Corpse feeder"" take_from=""Starting cloth/trash""}:+cat_refuse/corpses,bodyparts(2x3)",~,,c,c,,,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,`,`,`,,~,~,~,,`,`,`,,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,`,`,`,,~,~,~,,`,`,`,,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,`,`,`,,,`,,,`,`,`,,c,c,c,c,c,c,c +,,,,,,,,,,,,,,,"ry{name=""Refuse/corpse quantum"" give_to=""Rawhides"" quantum=true}" + + +#build label(farming_build) start(16; 18) hidden() workshops and important furniture + + +,,,,,,,,,n,`,`,,p(3x1),,,`,`,,`,`,`,` +,,,,,,,,,n,`,`,,p(3x1),,,`,`,,`,`,`,` +,,,,,,,,,n,`,`,,p(3x1),,,`,`,,c,t,t,c +,,,,,,,,,,,`,,p(3x1),,,`,`,,c,t,t,c +,,,,,,,t,c,`,,`,,p(3x1),,,`,`,,`,`,`,` +,,,,,,,`,`,`,`,`,,p(3x1),,,`,`,,`,`,`,` +,,,,,,,t,c,`,,`,,p(3x1),,,`,`,,` +,,,,,,,,,,,`,,p(3x1),,,`,`,,`,,b{do_now=true},b{do_now=true},b +,,,,,,`,`,`,`,,`,,p(3x1),,,`,`,,`,`,`,`,h +,,,,,,`,wl,`,`,,`,,`,`,`,`,`,,`,,b,b,b +,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` +,,wq,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,wp,`,`,`,`,"ww{labor_mask=""Milking, Shearing""}",`,`,`,`,,,`,,`,,,`,`,`,wu,`,`,`,wz,` +,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,,`,d,`,`,`,d,`,,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,`,`,,,d,,,`,`,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,wh,`,,`,`,`,,`,wn,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,,"trackstopS{name=""Refuse/corpse dumper"" take_from=""Refuse feeder,Corpse feeder"" route=""Refuse/corpse quantum""}",,,`,`,`,,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,` + + +#dig label(farming_traffic) start(16; 18) hidden() keep hungry dwarves away from the crops and food stores so they prefer the prepared meals + + +,,,,,,,,,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,,,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,,,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,,,,,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,ol,ol,ol,,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,ol,ol,ol,ol,ol,,or,or,or,or,or,,ol,ol,ol,ol +,,,,,,,ol,ol,ol,,ol,,or,or,or,or,or,,ol +,,,,,,,,,,,ol,,or,or,or,or,or,,ol,,ol,ol,ol +,,,,,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,ol,ol,ol,ol +,,,,,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,,ol,ol,ol +,,,ol,ol,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol +,,ol,ol,ol,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,,or,or,or,,or,or,or +,,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,or,,or,,,ol,or,or,or,or,ol,or,or,or +,,,ol,ol,,ol,ol,ol,ol,,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,,or,or,or +,,,,or,,,or,,,,,,ol,`,`,`,ol,,,,,or,,,,or +,,or,or,or,or,or,or,or,or,or,or,,ol,`,~,`,ol,,or,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,or,or,or,ol,`,`,`,ol,or,or,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,or,or,,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,or,,,,or,,or,,,,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,,,or,or,or,or,or,or,or,,,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,,or,or,,,or,,,or,or,,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,,or,or,,or,or,or,,or,or,,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,or,or,or,,,or,,,or,or,or,,or,or,or,or,or,or,or +,,,,,,,,,,,,,,,or + + +#burrow label(farming_burrow) start(16; 18) hidden() fix up safety burrow after channel incursions + +,,,,,,,,a{name=Inside+}(16x4) +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,a{name=Inside+}(18x3),,,,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,a{name=Inside+}(19x1),`,`,`,,`,,`,`,`,`,`,,` +,,,,,a{name=Inside+}(20x2),,,,,,`,,`,`,`,`,`,,`,,`,`,` +,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,`,` +,,a{name=Inside+}(23x1),,,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,` +,a{name=Inside+}(28x4),,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` +,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` +,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,a{name=Inside+}(29x12),,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,a{name=Inside+}(3x1) + +#build label(farming_doors) start(16; 18) hidden() remaining doors + + +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,`,`,`,,`,`,`,`,`,,~,~,~,~ +,,,,,,,,,,,d,,`,`,`,`,`,,~,~,~,~ +,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,d,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,,`,,`,`,`,`,`,,d +,,,,,,,,,,,`,,`,`,`,`,`,,`,,~,~,~ +,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,d,`,`,~ +,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,~,~,~ +,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` +,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,`,`,`,d,`,`,`,`,d,`,,,d{name=Farming},,d{name=Farming},,,`,d,`,`,`,d,`,`,` +,,,`,`,,`,`,`,`,,`,d{name=Farming},`,`,`,`,`,d{name=Farming},`,,`,`,`,,`,`,` +,,,,d,,,d,,,,,,`,`,`,`,`,,,,,d,,,,d +,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,d{name=Farming},`,`,`,`,`,d{name=Farming},`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,,,,d{name=Farming},,d{name=Farming},,,,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,,`,~,`,`,`,~,`,,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,`,`,,,~,,,`,`,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,` + + +#notes label(industry_help) industry level walkthrough +Sets up workshops for all non-farming industries +Screenshot: https://drive.google.com/file/d/1c8YTHxTgJY5tUII-BOWdLhmDFAHwIOEs +"" +Features: +- Compact layout that covers all workshops +- Manager orders that automate basic fortress maintenance +"- Space available underneath the forge and smelters for magma, allowing the starting forge and smelters to be eventually replaced by magma versions." +- Quantum stockpiles for compact storage (see the wiki for more info on QSPs) +with separate stockpiles for: +- A reserve of uncut gems for strange moods that the jeweler's workshop cannot take from +"- Wood, iron bars, steel bars, flux, and coal so you can see at a glance if you're low on stock" +"- Items that cannot be quantum stockpiled (e.g. lye, dye, and sand bags)" +- Meltable weapons and armor +"" +Workshops: +- 2x Stoneworker +- 4x Craftsdwarf (labor restrictions set to specialize for materials in adjacent stockpiles) +- 1x Jeweler +- 1x Mechanic +- 4x Smelter +- 1x Forge +- 1x Glassmaker +- 1x Kiln +- 4x Wood furnace +- 1x Ashery +- 1x Soap maker +- 1x Carpenter +- 1x Siege workshop +- 1x Bowyer +- 1x Dyer +- 1x Loom +- 1x Clothier +"" +Manual steps you have to take: +- Assign minecarts to your quantum stockpile hauling routes. The assign-minecarts all command will do it for you. +"" +Optional manual steps you can take: +"- If desired, set one or both stockpiles in the bottom left to auto-melt. This results in melting all weapons and armor that are inferior to masterwork. This is great for upgrading your military, but it takes a *lot* of fuel unless you have first replaced the forge and smelters with magma versions. If you enable automelt and you don't have magma forges and magma smelters, be sure to be in a forested area, set up autochop, and keep your coal stocks high!" +"" +Industry Walkthrough: +"1) Start digging out /industry1 as soon as you find a non-aquifer stone layer at least two layers beneath the surface so the boulders can be used by your starting workshops. The services level is intended to be dug beneath this one, and there is space on that level to route magma underneath your furnaces so you can replace the furnaces on this level with magma-powered equivalents." +"" +"2) Generate manager orders for /industry2 if you haven't already preordered with the checklist command. You brought an anvil with you (right??), so you can remove the unneeded anvil work order from the manager orders screen. Note that stockpiles that accept containers may claim the barrels you need to build the Dyer's Workshop and Ashery. If you see those two buildings not being constructed, build a few extra barrels or run combine all to free up some existing ones." +"" +"3) Once the area is dug out, run /industry2 to build replacements for your starter workshops up on the surface. Remember to assign minecarts to to your quantum stockpile hauling routes with assign-minecarts all." +"" +"4) After the initial workshops are constructed, run /industry3 to build the remaining workshops. Generate manager orders if you haven't already preordered with the checklist command." +"" +"5) Once you have enough dwarves to do maintenance tasks (that is, after the first or second migration wave), run ""orders import library/basic"" to use the provided manager orders to take care of your fort's basic needs, such as food, booze, and raw material processing." +"" +"6) If you want to automatically melt goblinite and other non-masterwork weapons and armor, mark the south-west stockpiles for auto-melt. If you don't have an abundance of fuel, though, be sure to route magma to the level beneath this one and replace the forge and furnaces with magma equivalents." +"" +"7) Once you have magma furnaces (or abundant fuel) and more dwarves, run ""orders import library/furnace"", ""orders import library/military"", and ""orders import library/smelting"" (in that order) to import the remaining fort automation orders. The military orders are optional if you are not planning to have a military, of course." +"" +"8) At any time, feel free to build extra workshops or designate custom stockpiles in the remaining open space. The space is there for you to use! Note the area in the bottom right can be used for additional magma-powered furnaces and workshops since there is space reserved for magma in those spots in the services level beneath." +"#dig label(industry1) start(18; 18; central stairs) message(Once the area is dug out, continue with /industry2.)" + + +,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,,,d,,d,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,,d,`,`,`,d,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,,,d,,d,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d + + +"#meta label(industry2) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now.) stockpiles and high-priority workshops" +traffic/industry_traffic +place/industry_place +build/industry_build +"#meta label(industry3) start(central stairs) message(If you preordered items on the checklist, good. If not, don't forget to generate orders for this blueprint now.) remaining workshops" +build2/industry_build2 +#dig label(industry_traffic) start(18; 18; central stairs) hidden() traffic patterns + + +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh +,,,,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,oh,oh,oh,oh,oh,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,oh,oh,`,oh,oh,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,oh,oh,`,oh,oh,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,ol,ol,ol,ol,ol,ol,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh,oh,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,,,`,,`,,,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,oh,oh,oh,oh,oh,oh,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,oh,oh,oh,oh,oh,oh,` +,,`,ol,ol,ol,oh,oh,oh,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,oh,oh,oh,ol,ol,ol,` +,,`,ol,ol,ol,oh,`,`,`,`,`,`,`,,`,,`,,`,,`,`,`,`,`,`,`,oh,ol,ol,ol,` +,,`,ol,ol,ol,oh,oh,oh,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,oh,oh,oh,ol,ol,ol,` +,,`,oh,oh,oh,oh,oh,oh,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,oh,oh,oh,oh,oh,oh,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,,,`,,`,,,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh,oh,` +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,oh,oh,`,oh,oh,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,`,oh,`,oh,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,ol,ol,ol,`,ol,ol,ol,oh,ol,ol,ol,ol,ol,ol,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,ol,ol,ol,`,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh +,,,,,,,,,,,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` + + +"#place label(industry_place) start(18; 18) hidden() message(remember to: +- assign minecarts to to your quantum stockpile hauling routes (use ""assign-minecarts all"") +- if you want to automatically melt goblinite and other low-quality weapons and armor, mark the south-east stockpiles for auto-melt +- once you have enough dwarves, run ""orders import library/basic"" to automate your fort's basic needs (see /industry_help for more info on this file)) industry stockpiles" + + +,,,,,,,,,,,"e{name=""Rough gems for moods"" containers=0 take_from=""Stoneworker quantum,Gem feeder""}:=roughgems",e,e,e,e,e,e,e,e,e,e,e,e +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"se{name=""Stoneworker quantum"" quantum=true}",`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,"s10{name=""Stone feeder""}:=otherstone(5x4)",,,~,~,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,` +,,"w{name=""Wood"" take_from=""Goods/wood quantum,Wood feeder""}",`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,"c{name=""Dye"" barrels=-1 }:+dye" +,,w,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,`,`,`,`,`,`,"e{name=""Gem feeder"" containers=0}(5x1)",,,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,"w{name=""Wood feeder""}(2x5)",,"g{name=""Goods feeder"" containers=0}:+cat_food/tallow+wax-crafts-goblets(3x3)",,`,,`,`,`,`,`,,"hlS{name=""Cloth/bones feeder"" containers=0}:+cat_refuse/skulls/,bones/,hair/,shells/,teeth/,horns/-adamantinethread(5x5)",,,~,~,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,~,~,~,~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c +,,`,`,`,`,`,"c{name=""Goods/wood quantum"" quantum=true give_to=""Pots,Barrels,Jugs,Bags,Seeds feeder""}:+all-cat_animals",`,~,~,~,~,~,,`,,`,,`,,~,~,~,~,~,`,"r{name=""Cloth/bones quantum"" quantum=true}:+all",`,`,`,`,c +,,"c{name=""Lye"" barrels=0}:+miscliquid",`,`,`,`,`,`,~,~,"u2{name=""Furniture feeder""}:-sand(3x2)",~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,~,~,~,~,~,,`,`,`,`,`,,~,~,~,~,~,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,`,"bnpdz{name=""Bar/military feeder"" containers=0}:-potash+adamantinethread(5x3)",,,,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,,,"pd{name=""Meltable steel/bronze"" take_from=""Metalworker quantum,Bar/military feeder"" containers=0}:-cat_weapons/mats/,other/-cat_armor/mats/,other/+bronzeweapons+bronzearmor+steelweapons+steelarmor-masterworks-artifacts(7x3)",,,~,~,~,~,`,`,`,`,"s5{name=""Ore/clay feeder""}:-otherstone(5x2)",,,~,~,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,"c{name=""Coal"" containers=0 take_from=""Metalworker quantum,Bar/military feeder""}:+coal",`,"c{name=""Metalworker quantum"" quantum=true}:+all",`,"c{name=""Iron"" containers=0 take_from=""Metalworker quantum,Bar/military feeder""}:+ironbars",`,`,`,`,`,`,`,`,`,`,` +,,,,"pd{name=""Other meltables"" take_from=""Metalworker quantum,Bar/military feeder"" containers=0}:-cat_weapons/other/-cat_armor/other/-bronzeweapons-bronzearmor-steelweapons-steelarmor-masterworks-artifacts(7x3)",,,~,~,~,~,`,`,`,`,c,"c{name=Flux take_from=""Metalworker quantum,Ore/clay feeder"" links_only=true}:+flux(3x1)",,,c,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,c,`,`,`,c,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,c,`,`,`,c,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,"u{name=""Sand bags""}:-cat_furniture/type+sand",u,u,u,u,u,`,"c{name=""Steel"" containers=0 take_from=""Metalworker quantum,Bar/military feeder""}:+steelbars",c,c,c,c,c + + +#build label(industry_build) start(18; 18) hidden() workshops to build first + + +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"wj{name=""Encruster"" do_now=true take_from=""Goods/wood quantum,Stoneworker quantum,Gem feeder""}",`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,"wr{name=""Stone craftsdwarf"" do_now=true labor=Stonecrafting}",`,`,`,`,`,`,`,wt{do_now=true},`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"trackstopN{name=""Stone/gem dumper"" do_now=true take_from=""Stone feeder,Gem feeder"" route=""Stone/gem quantum""}",`,`,`,`,`,`,`,`,~,`,`,`,` +,,,,`,`,~,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,wm{max_general_orders=2 do_now=true},`,`,`,`,`,`,`,wm{max_general_orders=10 do_now=true},`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,~,`,`,~,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,~,`,`,~,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,~,,~,,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,,,,`,~,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,wc{max_general_orders=9 do_now=true},`,`,`,"trackstopW{name=""Goods/wood dumper"" do_now=true take_from=""Wood feeder,Goods feeder,Furniture feeder"" route=""Goods/wood quantum""}",`,`,`,`,`,,`,,`,,`,,`,`,`,`,`,"trackstopE{name=""Cloth/bones dumper"" do_now=true take_from=""Cloth/bones feeder"" route=""Cloth/bones quantum""}",`,`,`,~,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,,,,`,~,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,~,,~,,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,~,`,`,~,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,~,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"trackstopS{name=""Metalworker dumper"" do_now=true take_from=""Bar/military feeder,Ore/clay feeder"" route=""Metalworker quantum""}",`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,~,`,`,`,~,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` + + +#build label(industry_build2) start(18; 18) hidden() remaining workshops + + +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,ws,`,`,`,` +,,,,`,`,wS,`,`,wb,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,wy,`,`,ew,`,`,ew,`,`,`,`,`,`,`,`,`,`,`,`,`,wk,`,`,wo,`,`,"wd{take_from=""Cloth/bones feeder,Cloth/bones quantum,Dye""}",`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,d{name=Industry},,d{name=Industry},,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,d{name=Industry},`,,,,`,d{name=Industry},`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,~,`,`,`,~,`,`,`,`,`,,`,,`,,`,,`,`,`,`,`,~,`,`,`,we,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,d{name=Industry},`,,,,`,d{name=Industry},`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,d{name=Industry},,d{name=Industry},,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,"wr{name=""Wood craftsdwarf"" labor=Woodcrafting}",`,`,ew,`,`,ew,`,`,`,`,`,`,`,`,`,`,`,`,`,"wr{name=""Misc craftsdwarf"" labor_mask=""Stonecrafting,Woodcrafting,Bone Carving""}",`,`,"wr{name=""Bone craftsdwarf"" labor=""Bone Carving""}",`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,eg,`,`,`,wf{max_general_orders=9},`,`,`,ek,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` + + +#notes label(services_help) services level walkthrough +"Sets up public services (dining, hospital, etc.)" +Screenshot: https://drive.google.com/file/d/1RQMy_zYQWM5GN7-zjn6LoLWmnrJjkxPM +"" +Features: +- Spacious dining room/tavern (tavern is restricted to citizens and residents only by default) +- Large prepared food and drink stockpiles +- Well cistern system (route or carry your own water) +- Hospital (also restricted to residents by default) with a well and soap for washing +- Well-appointed jail cells for happy prisoners +- Bolt-recycling archery range for your marksdwarves +- Interrogation room (office) for your Captain of the Guard +- Garbage dump +- Empty space for magma to power forges and smelters in the industry level above +"" +Manual steps you have to take: +"- If you want to tavern to attract visitors, change the restriction in the location configuration screen." +"- Fill the cisterns with water, either with a bucket brigade or by plumbing flowing water (e.g. with the aquifer_tap library blueprint). Fill so that there are two z-levels of 7-depth water to prevent muddiness. If you want to fill with buckets, you can use the pre-designated pond zones on the level below the main floor. If you feel adventurous and are experienced with water pressure, you can instead route (depressurized!) water to the second-to-bottom level (the one above the up staircases). See the aquifer_tap blueprint for help with getting water from a light aquifer." +"- If you are filling the wells with a bucket brigade and at least one well is already constructed, you'll run into issues with the dwarves stealing water from one well to fill another. Temporarily deconstruct the wells or temporarily build grates beneath the wells to block the buckets to avoid this issue. Remember to rebuild the wells or remove the grates afterwards, though!" +"" +Services Walkthrough: +1) Start this level when your fort grows to about 30 dwarves so everyone has a place to eat. +"" +2) Start digging with /services1. Note that this digs out the main level and three levels below for the well cisterns. +"" +"3) Once the area is dug out, start populating the rooms with /services2. Generate manager orders for /services2." +"" +"4) Fill the wells with either bucket brigades or by carefully routing flowing water (you can use the ""blueprinted"" plumbing template or erase it and plan your own). If you are using a bucket brigade, you have to activate the ""Cistern"" pond zones (which you can search for in the Places screen)." +"" +"5) When your fort has grown some more, or you start needing a jail, run /services3 to extend the rooms a bit more. Generate manager orders for /services3." +"" +"6) When your fort is more mature and you need to expand the rooms, run /services4 to finish everything up. If you didn't have a Sheriff/Captain of the Guard to automatically assign to the interrogation room when you ran /services2, you can manually assign the office now. Generate manager orders for /services4." +"#dig label(services1) start(18; 18; central stairs) message(Once the area is dug out, continue with /services2.)" + +,d,d,d,,d,d,d,,d,d,d,,d,h,d,,d,h,d,,d,h,d,,d,h,d,,d,h,d +,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d +,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d +,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,,,,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,,d,,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,h5,h5,h5,h5,h5,h5,h5,h5,h5,h5,d,,d,,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,h,h,h,h,h,h,h,h,h,h,d,,d,,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,,j,,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,,,,,d,,d,,,,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,d,d,,,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,,d,`,`,`,d,,d,,d,d,d,d,d,d,d,d,d,h +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,d,d,,,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,,,,,,d,,,,,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d +,,,,d,d,,d,d +,d,d,d,d,d,,d,d,d,d,d +,d,d,d,d,d,,d,d,d,d,d +,d,d,d,d,d,,d,d,d,d,d +,d,d,d,d,d,,d,d,d,d,d +,d,d,d,d,d,,d,d,d,d,d + +#> + +,,,,,,,,,,,,,j5,h5,j,,j5,h5,j,,j5,h5,j,,j5,h5,j,,j5,h5,j +,,,,,,,,,,,,,5,5,5,,5,5,5,,5,5,5,,5,5,5,,5,5,5 +,,,,,,,,,,,,,,d,,,,d,,,,d,,,,d,,,,d +,,,,,,,,,,,,,,d,,,,d,,,,d,,,,d,,,,d +,,,,,,,,,,,,,,d,,,,d,,,,d,,,,d,,,,d +,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,u,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,d,d,d,d,d,,,,,,,d +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,d,,,,,5,j5 +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,d,d,d,d,d,5,h5 +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,,5,j +,,,,,,,,,,,,,,,d,d,d,d,d + +#> + +,,,,,,,,,,,,,u5,h5,i,,u5,h5,i,,u5,h5,i,,u5,h5,i,,u5,h5,i +,,,,,,,,mbd,,,,,,mbd,,,,mbd,,,,mbd,,,,mbd,,,,mbd +,,,,,,,mbd,,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd,mbd +,,,,,,,,mbd,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,d,d,d,d,d,,,,,,,,,,,mbd +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,mbd,,u5 +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,mbd,mbd,h5 +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,,,i +,,,,,,,,,,,,,,,d,d,d,d,d + +#> + +,,,,,,,,,,,,,,d,u,,,d,u,,,d,u,,,d,u,,,d,u + + + + + + + + + + + + + +,,,,,,,,,,,,,,,d,d,d,d,d +,,,,,,,,,,,,,,,d,`,`,`,d +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,,,d +,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,,,,,,,u +,,,,,,,,,,,,,,,d,d,d,d,d + +"#meta label(services2) start(central stairs) message(Once furniture has been built, continue with /services3.) zones and minimally functional hospital and dining hall" +traffic/services_traffic +zones/services_zones +place/services_place +build/services_build +smooth/services_smooth +"" +"#meta label(services3) start(central stairs) message(Once furniture has been built, continue with /services4.) expand furnishings" +place2/services_place2 +build2/services_build2 +smooth2/services_smooth2 +"" +#meta label(services4) start(central stairs) complete furnishings +place3/services_place3 +build3/services_build3 +#dig label(services_traffic) start(18; 18) hidden() keep lollygaggers out of the cisterns and justice areas + +,`,`,`,,`,`,`,,`,`,`,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,`,`,`,,`,`,`,,`,`,`,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,`,`,`,,`,`,`,,`,`,`,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,,`,,,,`,,,,`,,,,or,,,,or,,,,or,,,,or,,,,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,,or,,or,,or,,or,,or +,`,`,`,`,`,`,`,`,`,`,`,,,,,or,,or,,,,,or,,or,,or,,or,,or +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,or,,or,,or,,or,,or +,`,ol,ol,ol,oh,oh,oh,ol,ol,ol,`,`,`,`,`,`,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,`,or,or,ol,oh,or,oh,ol,or,or,`,,`,,`,`,`,`,`,,`,,oh,oh,oh,oh,oh,oh,oh,oh,oh,or +,`,or,or,ol,oh,oh,oh,ol,or,or,`,`,`,`,`,`,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,`,or,or,or,ol,oh,ol,or,or,or,`,,,,`,`,`,`,`,,,,or,,or,,or,,or,,or +,`,or,or,or,or,oh,or,or,or,or,`,,,,,,or,,,,,,or,,or,,or,,or,,or +,`,or,or,or,or,oh,or,or,or,or,`,,,,,,,,,,,,or,,or,,or,,or,,or +,`,or,or,or,or,oh,or,or,or,or,` +,`,or,or,or,or,oh,or,or,or,or,` +,`,or,or,or,or,oh,or,or,or,or,` +,`,or,or,or,or,oh,or,or,or,or,` +,`,`,`,oh,oh,oh,oh,oh,`,`,` +,`,`,`,oh,oh,`,oh,oh,`,`,` +,,,,oh,oh,,oh,oh +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,,,,,,,,,,,,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,,,,,,,,,,,,,,or,,,,or,,,,or,,,,or,,,,or +,,,,,,,,,,,,,,or,,,,or,,,,or,,,,or,,,,or +,,,,,,,,,,,,,,or,,,,or,,,,or,,,,or,,,,or +,,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or +,,,,,,,,,,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or,or,,,,or +,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or,or,,,,or +,,,,,,,,,,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,,,,,,,,or,or,or +,,,,,,,,,,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,or,,,,,or,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,or,or,or,or,or,or,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,or,or +,,,,,,,,,,,,,,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or + + + + + + + + + + + + + +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,,or,or,,,or,or,,,or,or,,,or,or,,,or,or + + + + + + + + + + + + + +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,` + +"#zone label(services_zones) start(18; 18) hidden() message(Don't forget to assign a doctor to the hospital! +If you'd like to fill your wells via bucket brigade instead of routing water (e.g. with the aquifer_tap library blueprint), activate the inactive pond zones one level down from where the wells will be built.) garbage dump, hospital, taverrn, barracks, archery range, and pond zones" +,,,,,,,,,,,,j/jail1,"j/jail1{name=""Jail 1""}(4x5)",j/jail1,j/jail1,j/jail1,"j{name=""Jail 2""}(4x5)",,,,"j{name=""Jail 3""}(4x5)",,,,"j{name=""Jail 4""}(4x5)",,,,"j{name=""Jail 5""}(4x5)" +,"b{location=tavern/bigpub name=""Rented room 1""}(1x3)","b{location=tavern/bigpub name=""Rented room 2""}(1x3)","b{location=tavern/bigpub name=""Rented room 3""}(1x3)",,"b{location=tavern/bigpub name=""Rented room 4""}(1x3)","b{location=tavern/bigpub name=""Rented room 5""}(1x3)","b{location=tavern/bigpub name=""Rented room 6""}(1x3)",,"b{location=tavern/bigpub name=""Rented room 7""}(1x3)","b{location=tavern/bigpub name=""Rented room 8""}(1x3)","b{location=tavern/bigpub name=""Rented room 9""}(1x3)",j/jail1,j/jail1,j/jail1,j/jail1,j/jail1,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,j/jail1,j/jail1,j/jail1,j/jail1,j/jail1,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,j/jail1,j/jail1,j/jail1,j/jail1,j/jail1,`,`,`,,`,`,`,,`,`,`,,`,`,` +"h{location=tavern/bigpub allow=residents name=""Grand hall tavern""}(13x31)",,`,,,,`,,,,`,,,j/jail1,j/jail1,j/jail1,j/jail1,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,`,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,"B{name=""Marksdwarf barracks""}a{name=""Shooting gallery"" shoot_from=""south""}",Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,o/interrogation,"j{name=""Drunk tank""}",j,j,j,j,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,o/interrogation,j,"o/interrogation{name=""Interrogation room"" assigned_unit=sheriff}(3x3)",`,`,j,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,o/interrogation,j,`,`,`,j,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,`,`,o/interrogation,j,`,`,`,j,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,o/interrogation,j,j,j,j,j,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,,,,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation,o/interrogation +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,m{location=hospital name=Hospital allow=residents},,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,m,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,m,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,m,m,m,m,m,m,m,m,m,m +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,m,m,m,m,m,m,m,m,m,m +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,m,m,m,m,m,m,m,m,m,m +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,m,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,,,"d{name=""Garbage dump""}",,,,,,m,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,m,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,`,"p{name=""Jail 1 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 2 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 3 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 4 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 5 cistern"" pond=true active=false}",` +,,,,,,,,,,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,,,,` +,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,,,,,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,`,`,`,`,`,"p{name=""Hospital cistern"" pond=true active=false}" +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,`,` +,,,,,,,,,,,,,,,`,`,`,`,` + +#place label(services_place) start(18; 18) hidden() + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,"z{name=""Bolts quantum"" quantum=true}",`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,"b/soap{name=""Soap"" take_from=""Metalworker quantum""}:=soap" +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,b/soap +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,"c{name=""Garbage dump"" links_only=true}",,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,"c{name=""Prepared food"" barrels=-1}:+preparedmeals(5x5)",,,,`,,"c{name=""Booze"" barrels=-1}:+booze(5x5)",,,,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,"z{name=""Bolts feeder"" containers=0 take_from=""Metalworker quantum""}:-cat_ammo/type/,other/+bolts(10x1)",,,,,,,,,`,,,,` +,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,,,,,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,,,,,`,` +,,,,,,,,,,,,,,,`,`,`,`,` + +"#build label(services_build) start(18; 18) hidden() message(Remember to enqueue manager orders for this blueprint. +Assign a minecart to the training ammo quantum dump with ""assign-minecarts all"") build basic hospital, dining room, and barracks" + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,A,A,A,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,"trackstopS{name=""Bolts dumper"" take_from=""Bolts feeder"" route=""Bolts quantum""}",`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,h,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,b,`,`,`,`,`,`,`,`,,`,,`,,`,,b,,R +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,d,,d +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,h,`,`,`,`,t,`,`,`,l +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,`,,d +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,R +,`,`,`,`,`,`,t,c,c,t,` +,`,`,`,`,`,`,t,c,c,t,` +,`,`,`,`,`,`,t,c,c,t,` +,`,`,`,`,`,`,t,c,c,t,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,h,`,`,`,`,` +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#dig label(services_smooth) start(18; 18) hidden() smooth the floor where the pedestal will go + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,s1,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#place label(services_place2) start(18; 18) hidden() jail food and booze + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,"c{name=""Jail food"" barrels=-1 take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,~,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,~,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ + +#build label(services_build2) start(18; 18) hidden() message(Remember to enqueue manager orders for this blueprint.) expand each room + +,`,b,`,,`,b,`,,`,b,`,,`,`,`,,`,`,`,,t,l,b,,`,`,`,,`,`,` +,`,h,`,,`,h,`,,`,h,`,,`,`,`,,`,`,`,,c,v,`,,`,`,`,,`,`,` +,`,f,`,,`,f,`,,`,f,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,d,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,A,A,A,~,~,~,A,A,A,A,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,c,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,t,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,~,`,`,`,`,`,`,`,`,`,`,`,c,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,h,b,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,~,`,`,`,`,`,`,`,h +,`,`,`,`,`,`,`,`,`,`,`,,~,`,`,`,`,`,`,`,b,,b,,b,,b,,~,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,d,,d,,d,,~,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,` +,`,`,`,`,`,F,`,`,`,`,`,,`,,`,`,`,`,`,,`,,~,`,`,`,`,~,`,`,`,~ +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,`,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,~ +,`,t,c,c,t,`,~,~,~,~,` +,`,t,c,c,t,`,~,~,~,~,` +,`,t,c,c,t,`,~,~,~,~,` +,`,t,c,c,t,`,~,~,~,~,` +,`,`,`,`,`,`,`,`,`,`,` +,h,`,`,`,`,~,`,`,`,`,h +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#dig label(services_smooth2) start(18; 18) hidden() smooth the floor where the statues will go + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,s1,`,`,`,s1,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,s1,`,`,`,`,`,`,`,`,`,s1,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,s1,`,`,`,`,`,`,`,`,`,s1,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,s1,`,`,`,`,`,`,`,`,`,s1,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,s1,`,`,`,`,`,`,`,`,`,s1,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,s1,`,`,`,`,`,s1,`,` +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#place label(services_place3) start(18; 18) hidden() remaining jail food and booze + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,~,,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)" +,`,`,`,,`,`,`,,`,`,`,,"c{name=""Jail food"" barrels=-1 take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,"c{name=""Jail food"" barrels=-1 take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,~,`,`,,"c{name=""Jail food"" barrels=-1 take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,"c{name=""Jail food"" barrels=-1 take_from=""Prepared food""}:+preparedmeals(2x1)",,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,~,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,~,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ + +#build label(services_build3) start(18; 18) hidden() message(Remember to enqueue manager orders for this blueprint.) finalize furniture + +,b,~,b,,b,~,b,,b,~,b,,t,l,b,,t,l,b,,~,~,~,,t,l,b,,t,l,b +,h,~,h,,h,~,h,,h,~,h,,c,v,`,,c,v,`,,~,~,`,,c,v,`,,c,v,` +,f,~,f,,f,~,f,,f,~,f,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,d,,,,d,,,,d,,,,d,,,,d,,,,~,,,,d,,,,d +,`,`,`,s,`,`,`,s,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,,` +,s,`,`,`,`,`,`,`,`,`,s,,~,~,~,~,~,~,~,~,~,~,`,,`,,v,v,v,v,v +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,,`,,v,`,~,`,v +,s,`,`,`,`,`,`,`,`,`,s,,`,`,`,`,`,`,`,`,`,`,`,,`,,v,`,~,`,v +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,~,`,`,`,`,`,`,d,`,d,v,`,~,`,v +,s,`,`,`,`,`,`,`,`,`,s,,`,`,`,`,`,`,`,`,`,~,~,,`,,v,v,v,v,v +,`,`,`,`,`,`,`,`,`,`,`,,~,h,h,h,h,h,h,h,~ +,s,`,`,`,`,`,`,`,`,`,s,,~,b,b,b,b,b,b,b,~,,~,,~,,~,,~,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,,d{name=Services},,d{name=Services},,,,,~,,~,,~,,~,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,d,`,d{name=Services},`,`,`,`,`,d{name=Services},`,d,`,`,`,`,`,`,`,`,`,` +,`,t,c,`,`,~,`,`,c,t,`,,s,,`,`,`,`,`,,s,,~,`,`,t,`,~,`,`,`,~ +,`,t,c,`,`,`,`,`,c,t,`,d,`,d{name=Services},`,`,`,`,`,d{name=Services},`,d,`,`,`,`,`,`,`,`,`,` +,`,t,c,c,t,`,t,c,c,t,`,,,,`,`,`,`,`,,,,`,,`,,`,,`,,` +,`,t,c,c,t,`,t,c,c,t,`,,,,,,`,,,,,,d,,d,,d,,d,,` +,`,t,c,c,t,`,t,c,c,t,`,,,,,,,,,,,,b,,b,,b,,b,,` +,`,~,~,~,~,`,~,~,~,~,` +,`,~,~,~,~,`,~,~,~,~,` +,`,~,~,~,~,`,~,~,~,~,` +,`,~,~,~,~,`,~,~,~,~,` +,`,`,`,`,`,`,`,`,`,`,` +,~,`,s,`,`,~,`,`,s,`,~ +,,,,d,d,,d,d +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` + +#notes label(guildhall_help) guildhall level walkthrough +"Eight 7x7 rooms for guildhalls, temples, libraries, etc." +Screenshot: https://drive.google.com/file/d/1mt66QOkfBqFLtw6AJKU6GNYmhB72XSJG +"" +Features: +"- Big rooms, optionally pre-furnished. Double-thick walls to ensure engravings add maximum value. Pre-made meeting zones can be made into locations (e.g. guildhalls) as needed. Optional pre-configured library/temple combo." +"" +"Each 7x7 room will be worth about 3000 when fully engraved (with random quality of engravings). This will get you past the first ""tier"" threshold at standard difficulty settings. Add artifacts to the display cases or other fancy decorations if you need more value. You can also assign multiple 7x7 rooms to the same zone or location and gain more value that way." +"" +Guildhall Walkthrough: +1) Dig out the rooms with /guildhall1. +"" +"2) Once the area is dug out, choose a /guildhall2 variant based on your needs. For your first copy of this level, you probably want /guildhall2_default, which configures the temple and library zones as fully usable locations. For later copies you probably want to create all locations yourself, so you should choose /guildhall2_no_locations if you want the default furnishings or /guildhall2_custom for just the zones and doors, leaving the furnishings up to you. Generate manager orders for your chosen variant." +"" +"Note that the default temple and library are created ""Citizens and Long-Term Residents only"", but you can change this in the location configuration screen if you want them to attract visitors. If you need more rooms, you can dig another /guildhall1 in an unused z-level." +"#dig label(guildhall1) start(15; 15; central stairs) message(Once the area is dug out, continue with /guildhall2.)" + + +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,,,,,,,,d,,,,d,,d,,,,d +,,,,,,,,,,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,d,,,d,,d,,,d,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,d,,d,d,d,d,d,,d,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,d,,d,`,`,`,d,,d,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,d,,d,d,d,d,d,,d,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,d,,,d,,d,,,d,,d,d,d,d,d,d,d +,,,,,,,,,,d,d,d,d,d,d,d,d,d +,,,,,,,,,d,,,,d,,d,,,,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d + + +#meta label(guildhall2_default) furnished with default temple and library +locations/guildhall_locations +doors/guildhall_doors +furnish/guildhall_furnish +smooth/guildhall_smooth +"" +#meta label(guildhall2_no_locations) fully furnished and zoned but no locations +zones/guildhall_zones +doors/guildhall_doors +furnish/guildhall_furnish +smooth/guildhall_smooth +"" +#meta label(guildhall2_custom) only zones and doors +zones/guildhall_zones +doors/guildhall_doors +"" +"#zone label(guildhall_locations) start(15; 15; central stairs) hidden() message(The library and temple are restricted to residents only by default. If you'd like them to attract vistors, please go to the location screen and change the restrictions.) declare a library and temple" + +,m(9x9),,,,,,,,,"m{location=temple name=""All-inclusive temple"" allow=residents}(9x9)",,,,,,,,,m(9x9) +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,,,,,,,,~,,,,~,,~,,,,~ +,m(9x9),,,,,,,,,`,`,`,`,`,`,`,`,`,m(9x9) +,,`,`,`,`,`,`,`,,`,,,~,,~,,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,`,~,`,,,,`,~,`,~,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,,`,,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,`,~,`,,,,`,~,`,~,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,,~,,~,,,`,,`,`,`,`,`,`,` +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,m(9x9),,,,,,,,~,m{location=library name=Library allow=residents}(9x9),,,~,,~,,,,m(9x9) +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` + + +"#zone label(guildhall_zones) start(15; 15; central stairs) hidden() designate zones, ready for custom locations to be assigned" + +,m(9x9),,,,,,,,,m(9x9),,,,,,,,,m(9x9) +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,,,,,,,,~,,,,~,,~,,,,~ +,m(9x9),,,,,,,,,`,`,`,`,`,`,`,`,`,m(9x9) +,,`,`,`,`,`,`,`,,`,,,~,,~,,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,`,~,`,,,,`,~,`,~,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,,`,,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,`,~,`,,,,`,~,`,~,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,,~,,~,,,`,,`,`,`,`,`,`,` +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,m(9x9),,,,,,,,~,m(9x9),,,~,,~,,,,m(9x9) +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` + + +#build label(guildhall_doors) start(15; 15; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build doors + + +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,,,,,,,,d,,,,d,,d,,,,d +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,,d{name=Guidhall},,d{name=Guidhall},,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,d,`,d{name=Guidhall},`,,,,`,d{name=Guidhall},`,d,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,,`,,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,d,`,d{name=Guidhall},`,,,,`,d{name=Guidhall},`,d,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,,d{name=Guidhall},,d{name=Guidhall},,,`,,`,`,`,`,`,`,` +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,d,,,,d,,d,,,,d +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` + + +"#build label(guildhall_furnish) start(15; 15; central stairs) hidden() furnish 4 guildhalls, 3 temples, and a library" + + +,,F,`,`,`,s,`,`,,,F,`,`,c,`,`,f,,,`,`,s,`,`,`,F +,,`,`,c,`,`,`,`,,,`,`,`,~a,h,`,s,,,`,`,`,`,c,`,` +,,`,c,t,c,`,`,s,,,`,`,`,`,`,`,`,,,s,`,`,c,t,c,` +,,`,`,c,`,c,`,`,,,`,`,`,`,`,`,`,,,`,`,c,`,c,`,` +,,s,`,`,c,t,c,`,,,`,`,c,c,c,`,`,,,`,c,t,c,`,`,s +,,`,`,`,`,c,`,`,,,`,`,c,c,c,`,`,,,`,`,c,`,`,`,` +,,`,`,s,`,`,`,`,,,t,`,`,`,`,`,t,,,`,`,`,`,s,`,` +,,,,,,,,,~,,,,~,,~,,,,~ +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,f,s,`,`,`,`,t,,`,,,~,,~,,,`,,t,`,`,`,`,s,f +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,h,`,`,c,c,`,~,`,~,`,,,,`,~,`,~,`,c,c,`,`,h,` +,,c,~a,`,`,c,c,`,,`,,`,,`,,`,,`,,`,c,c,`,`,~a,c +,,`,`,`,`,c,c,`,~,`,~,`,,,,`,~,`,~,`,c,c,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,F,`,`,`,`,`,t,,`,,,~,,~,,,`,,t,`,`,`,`,`,F +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,~,,,,~,,~,,,,~ +,,`,`,s,`,`,`,`,,,t,`,`,`,`,`,t,,,`,`,`,`,s,`,` +,,`,`,`,`,c,`,`,,,`,`,`,`,`,`,`,,,`,`,c,`,`,`,` +,,s,`,`,c,t,c,`,,,t,c,`,`,`,c,t,,,`,c,t,c,`,`,s +,,`,`,c,`,c,`,`,,,t,c,`,`,`,c,t,,,`,`,c,`,c,`,` +,,`,c,t,c,`,`,s,,,t,c,`,`,`,c,t,,,s,`,`,c,t,c,` +,,`,`,c,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,c,`,` +,,F,`,`,`,s,`,`,,,h,~c,~c,s,~c,~c,h,,,`,`,s,`,`,`,F + + +#dig label(guildhall_smooth) start(15; 15; central stairs) hidden() smooth statue tiles + + +,,s,`,`,`,s,`,`,,,s,`,`,`,`,`,`,,,`,`,s,`,`,`,s +,,`,`,`,`,`,`,`,,,`,`,`,s,`,`,s,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,s,,,`,`,`,`,`,`,`,,,s,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,s,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,s +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,s,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,s,`,` +,,,,,,,,,`,,,,`,,`,,,,` +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,`,s,`,`,`,`,`,,`,,,`,,`,,,`,,`,`,`,`,`,s,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,` +,,`,s,`,`,`,`,`,,`,,`,,`,,`,,`,,`,`,`,`,`,s,` +,,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,,s,`,`,`,`,`,`,,`,,,`,,`,,,`,,`,`,`,`,`,`,s +,,,,,,,,,,`,`,`,`,`,`,`,`,` +,,,,,,,,,`,,,,`,,`,,,,` +,,`,`,s,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,s,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,s,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,s +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,s,,,`,`,`,`,`,`,`,,,s,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,s,`,`,`,s,`,`,,,`,s,s,s,s,s,`,,,`,`,s,`,`,`,s + + +#notes label(beds_help) walkthrough for the suites and apartments levels +Suites for nobles and apartments for the teeming masses +Suites screenshot: https://drive.google.com/file/d/16XRb1w5zFoyVq2LBMx_aCwOyjFq7GULc +Apt. screenshot: https://drive.google.com/file/d/16-NXlodLIQjeZUMSmsWRafeytwU2dXQo +"" +Features: +- Well-appointed suites to satisfy nobles or citizens with a need for opulence +"- Suite rooms are multi-functional. Any suite can be zoned as a bedroom, office, dining hall, or tomb. If a noble requires more wealth than what a default room provides, you can smooth, engrave, add furniture, or include multiple rooms in the zone. A default suites level can fully satisfy a monarch if each zone covers four (engraved) rooms." +- Apartments with beds and storage to keep dwarves happy and the fortress clean +"" +Suites Walkthrough: +1) Dig out the suites layer with /suites1. +"" +"2) Once the area is dug out, choose a /suites2 variant based on your needs. For your first copy of this level, you probably want /suites2_default, which defines zones and assigns them to the usual cohort of demanding nobles and administrators. For later copies where your needs are ad hoc, you can choose /suites2_no_zones. Generate manager orders for your chosen variant." +"" +Apartments Walkthrough: +"1) Dig out one layer of apartments with /apartments1, or 3 layers at once (180 bedrooms total) by configuring gui/quickfort to repeat down 3 levels." +"" +"2) Once a layer is dug out, build furniture with /apartments2. Generate manager orders for /apartments2." +"#dig label(suites1) start(18; 18; central stairs) message(Once the area is dug out, run /suites2) noble suites" + +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,,d,d,d,d,d,d,d,d,d,d,,d,`,~,`,d,,d,d,d,d,d,d,d,d,d,d,,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d + +"#meta label(suites2_default) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) build furniture, set traffic patterns, create zones, and assign them to nobles and administrators" +traffic_suites/suites_traffic +build_suites/suites_build +smooth_suites/suites_smooth +zone_suites/suites_zone +"" +"#meta label(suites2_no_zones) start(central stairs) message(Remember to enqueue manager orders for this blueprint. +rooms are left unzoned so you can configure them for specific nobles.) build furniture and set traffic patterns" +traffic_suites/suites_traffic +build_suites/suites_build +smooth_suites/suites_smooth +#dig label(suites_traffic) start(18; 18; central stairs) hidden() don't path through other dwarves' rooms + +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,,,,or,,,,,,,or,,,,`,`,`,,,,or,,,,,,,or,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,or,`,`,`,`,`,,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,,`,`,`,`,`,or,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,or,`,`,`,`,`,,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,,`,`,`,`,`,or,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,or,,,,,,,or,,,,oh,`,oh,,,,or,,,,,,,or,,,,` +,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,` +,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,,`,` +,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,` +,`,,,,or,,,,,,,or,,,,oh,`,oh,,,,or,,,,,,,or,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,or,`,`,`,`,`,,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,,`,`,`,`,`,or,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,or,`,`,`,`,`,,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,,`,`,`,`,`,or,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,or,,,,,,,or,,,,`,`,`,,,,or,,,,,,,or,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` + +#build label(suites_build) start(18; 18; central stairs) hidden() + +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d{name=Suites},,d{name=Suites},,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` +,`,`,d,`,`,`,`,`,`,`,`,`,`,d{name=Suites},`,`,`,`,`,d{name=Suites},`,`,`,`,`,`,`,`,`,`,d,`,` +,`,`,,`,`,`,s,`,`,s,`,`,`,,`,`,~,`,`,,`,`,`,s,`,`,s,`,`,`,,`,` +,`,`,d,`,`,`,`,`,`,`,`,`,`,d{name=Suites},`,`,`,`,`,d{name=Suites},`,`,`,`,`,`,`,`,`,`,d,`,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d{name=Suites},,d{name=Suites},,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` + +#dig label(suites_smooth) start(18; 18; central stairs) hidden() smooth statue tiles + +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,s,`,`,,,`,`,s,`,`,,`,s,`,,`,`,s,`,`,,,`,`,s,`,`,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,`,`,s,`,`,,,`,`,s,`,`,,`,s,`,,`,`,s,`,`,,,`,`,s,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,,`,`,`,s,`,`,s,`,`,`,,`,`,~,`,`,,`,`,`,s,`,`,s,`,`,`,,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,s,`,`,,,`,`,s,`,`,,`,s,`,,`,`,s,`,`,,,`,`,s,`,`,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,`,`,s,`,`,,,`,`,s,`,`,,`,s,`,,`,`,s,`,`,,,`,`,s,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` + +#zone label(suites_zone) start(18; 18; central stairs) hidden() + +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,h{assigned_unit=sheriff},h,h,b{assigned_unit=sheriff},b,b,b,o{assigned_unit=mayor}(7x7),,,`,,,,`,`,`,o{assigned_unit=baron}(7x7),,,`,,,,T{assigned_unit=baron}(7x7),,,`,,,,` +,`,h,h,h,b,b,b,b,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,h,h,h,b,b,b,b,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,h,h,h,b,b,b,b,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,h,h,h,h,b,b,b,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,h,h,h,h,b,b,b,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,h,h,h,h,b,b,b,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,h{assigned_unit=mayor}(7x7),,,,,,,b{assigned_unit=mayor}(7x7),,,,,,,`,`,`,b{assigned_unit=baron}(7x7),,,,,,,h{assigned_unit=baron}(7x7),,,,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,h{assigned_unit=outpost_liaison}(7x7),,,`,,,,b{assigned_unit=outpost_liaison}(7x7),,,`,,,,`,`,`,b{assigned_unit=monarch}(7x7),,,`,,,,h{assigned_unit=monarch}(7x7),,,`,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,T{assigned_unit=monarch}(7x7),,,,,,,o{assigned_unit=outpost_liaison}(7x7),,,,,,,`,`,`,o{assigned_unit=monarch}(14x7),,,,,,,,,,,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,`,,,,,,,`,,,,`,`,`,,,,`,,,,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` + +"#dig label(apartments1) start(18; 18; central stairs) message(Once the area is dug out, continue with /apartments2.) apartment complex" + +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,,d,,,d,,,d,,,d,,,d,,d,,,d,,,d,,,d,,,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,,d,,,d,,,d,,,d,,d,d,d,,d,,,d,,,d,,,d,,,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,,,,,,,,,,,,,,d,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,,,d,,,d,,,d,,,d,,,d,d,d,,,d,,,d,,,d,,,d,,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,`,~,`,d,,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,,,d,,,d,,,d,,,d,,,d,d,d,,,d,,,d,,,d,,,d,,,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,,,,,,,,,,,,,,d,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,d,,,d,,,d,,,d,,,d,,d,d,d,,d,,,d,,,d,,,d,,,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,,,d,,,d,,,d,,,d,,d,,,d,,,d,,,d,,,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d + +#meta label(apartments2) start(central stairs) zone rooms and build furniture +zone_apartments/apartments_rooms +build_apartments/apartments_build +#zone label(apartments_rooms) start(18; 18; central stairs) hidden() zone rooms +,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5) +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,,`,,,`,,,`,,,`,,,`,,`,,,`,,,`,,,`,,,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,,`,`,`,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,,`,`,`,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5) +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,,,`,,,`,,,`,,,`,,,`,`,`,,,`,,,`,,,`,,,`,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,,`,`,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,,`,`,`,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5) +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,`,,,`,,,`,,,`,,,`,,`,`,`,,`,,,`,,,`,,,`,,,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` + +#build label(apartments_build) start(18; 18; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build furniture + +,,,f,h,,f,h,,f,h,,f,h,,f,h,,h,f,,h,f,,h,f,,h,f,,h,f +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,b,`,,b,`,,b,`,,b,`,,b,`,,`,b,,`,b,,`,b,,`,b,,`,b +,,,,d,,,d,,,d,,,d,,,d,,d,,,d,,,d,,,d,,,d +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,d,,,d,,,d,,,d,,,d,,`,`,`,,d,,,d,,,d,,,d,,,d +,b,`,,b,`,,b,`,,b,`,,b,`,,`,`,`,,`,b,,`,b,,`,b,,`,b,,`,b +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,f,h,,f,h,,f,h,,f,h,,f,h,,`,`,`,,h,f,,h,f,,h,f,,h,f,,h,f +,,,,,,,,,,,,,,,,`,`,` +,h,f,,h,f,,h,f,,h,f,,h,f,,`,`,`,,f,h,,f,h,,f,h,,f,h,,f,h +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,b,,`,b,,`,b,,`,b,,`,b,,d{name=Apartments},,d{name=Apartments},,b,`,,b,`,,b,`,,b,`,,b,` +,d,,,d,,,d,,,d,,,d,,,`,`,`,,,d,,,d,,,d,,,d,,,d +,`,`,`,`,`,`,`,`,`,`,`,`,`,d{name=Apartments},`,`,`,`,`,d{name=Apartments},`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,d{name=Apartments},`,`,`,`,`,d{name=Apartments},`,`,`,`,`,`,`,`,`,`,`,`,` +,d,,,d,,,d,,,d,,,d,,,`,`,`,,,d,,,d,,,d,,,d,,,d +,`,b,,`,b,,`,b,,`,b,,`,b,,d{name=Apartments},,d{name=Apartments},,b,`,,b,`,,b,`,,b,`,,b,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,h,f,,h,f,,h,f,,h,f,,h,f,,`,`,`,,f,h,,f,h,,f,h,,f,h,,f,h +,,,,,,,,,,,,,,,,`,`,` +,f,h,,f,h,,f,h,,f,h,,f,h,,`,`,`,,h,f,,h,f,,h,f,,h,f,,h,f +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,b,`,,b,`,,b,`,,b,`,,b,`,,`,`,`,,`,b,,`,b,,`,b,,`,b,,`,b +,,d,,,d,,,d,,,d,,,d,,`,`,`,,d,,,d,,,d,,,d,,,d +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,d,,,d,,,d,,,d,,,d,,d,,,d,,,d,,,d,,,d +,,,b,`,,b,`,,b,`,,b,`,,b,`,,`,b,,`,b,,`,b,,`,b,,`,b +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,f,h,,f,h,,f,h,,f,h,,f,h,,h,f,,h,f,,h,f,,h,f,,h,f + +#notes label(crypt_help) crypt level walkthrough +Places to rest your dead +Screenshot: https://drive.google.com/file/d/16iT_ho7BIRPD_eofuxdlVQ4FunR1Li23 +"" +Features: +"- Staged crypt expansion that grows with your, um, need" +- 20 tombs in stage 1 +- 192 additional tombs in stage 2 (212 tombs total) +"- Extendable in any direction by reapplying the blueprints to the North, South, East, or West, overlapping by one tile" +"" +Crypt Walkthrough: +1) Dig out the layer with /crypt1. +"" +"2) Once the area is dug out, add initial tombs with /crypt2." +"" +"3) If/when you need additional tombs, apply /crypt3." +"#dig label(crypt1) start(18; 18; central stairs) message(Once the area is dug out, continue with /crypt2.) crypt complex" + +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,d,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,d,d,d,,,,d,d,d,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,,~,,d,d,d,d +,,d,,d,,d,,d,,d,,d,d,d,d,,,,d,d,d,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,d,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d + +#meta label(crypt2) start(central stairs) small crypt that can be extended later +zone/crypt_zone +build/crypt_build +"" +#meta label(crypt3) start(central stairs) crypt extension +zone_extended/crypt_extended_zone +build_extended/crypt_extended_build +#zone label(crypt_zone) start(18; 18; central stairs) hidden() zone tombs + + + + + + + + + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,` +,,,,,,,,,,,`,`,,,,,,,,,,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),,` +,,,,,,,,,,,`,`,,,,`,`,`,,,,`,` +,,,,,,,,,,,,`,`,`,`,,,,`,`,`,` +,,,,,,,,,,,,`,`,`,`,,~,,`,`,`,` +,,,,,,,,,,,,`,`,`,`,,,,`,`,`,` +,,,,,,,,,,,`,`,,,,`,`,`,,,,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,` +,,,,,,,,,,,`,`,,,,,,,,,,`,` +,,,,,,,,,,,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` + + + + + + + + + +#build label(crypt_build) start(18; 18; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build urns + + + + + + + + + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,n,,n,,n,,n,,` +,,,,,,,,,,,`,`,,,,,,,,,,`,` +,,,,,,,,,,,,`,,n,,n,,n,,n,,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,n,,`,s{name=Crypt},`,,n,,` +,,,,,,,,,,,`,`,,,,`,`,`,,,,`,` +,,,,,,,,,,,,`,`,`,`,,,,`,`,`,` +,,,,,,,,,,,,`,`,s{name=Crypt},`,,~,,`,s{name=Crypt},`,` +,,,,,,,,,,,,`,`,`,`,,,,`,`,`,` +,,,,,,,,,,,`,`,,,,`,`,`,,,,`,` +,,,,,,,,,,,,`,,n,,`,s{name=Crypt},`,,n,,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,`,,n,,n,,n,,n,,` +,,,,,,,,,,,`,`,,,,,,,,,,`,` +,,,,,,,,,,,,`,,n,,n,,n,,n,,` +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` + + + + + + + + + +#zone label(crypt_extended_zone) start(18; 18; central stairs) hidden() zone more tombs + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,~,,~,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,~,,~,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,`,`,`,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,`,`,`,,,,`,`,`,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,,~,,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,`,`,`,,,,`,`,`,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,`,`,`,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,~,,~,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,~,,~,,~,,~,,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` + +#build label(crypt_extended_build) start(18; 18; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build more urns + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,~,,~,,~,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,~,,~,,~,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,`,~,`,,~,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,`,`,`,,,,`,`,`,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,~,`,,~,,`,~,`,` +,,n,,n,,n,,n,,n,,`,`,`,`,,,,`,`,`,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,`,~,`,,~,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,~,,~,,~,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,~,,~,,~,,~,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` diff --git a/data/blueprints/library/embark.csv b/data/blueprints/embark.csv similarity index 100% rename from data/blueprints/library/embark.csv rename to data/blueprints/embark.csv diff --git a/data/blueprints/library/exploratory-mining/connected-mineshafts.csv b/data/blueprints/exploratory-mining/connected-mineshafts.csv similarity index 100% rename from data/blueprints/library/exploratory-mining/connected-mineshafts.csv rename to data/blueprints/exploratory-mining/connected-mineshafts.csv diff --git a/data/blueprints/library/exploratory-mining/tunnels.csv b/data/blueprints/exploratory-mining/tunnels.csv similarity index 100% rename from data/blueprints/library/exploratory-mining/tunnels.csv rename to data/blueprints/exploratory-mining/tunnels.csv diff --git a/data/blueprints/library/exploratory-mining/vertical-mineshafts.csv b/data/blueprints/exploratory-mining/vertical-mineshafts.csv similarity index 100% rename from data/blueprints/library/exploratory-mining/vertical-mineshafts.csv rename to data/blueprints/exploratory-mining/vertical-mineshafts.csv diff --git a/data/blueprints/library/layout-helpers/mark_down_left.csv b/data/blueprints/layout-helpers/mark_down_left.csv similarity index 100% rename from data/blueprints/library/layout-helpers/mark_down_left.csv rename to data/blueprints/layout-helpers/mark_down_left.csv diff --git a/data/blueprints/library/layout-helpers/mark_down_right.csv b/data/blueprints/layout-helpers/mark_down_right.csv similarity index 100% rename from data/blueprints/library/layout-helpers/mark_down_right.csv rename to data/blueprints/layout-helpers/mark_down_right.csv diff --git a/data/blueprints/library/layout-helpers/mark_up_left.csv b/data/blueprints/layout-helpers/mark_up_left.csv similarity index 100% rename from data/blueprints/library/layout-helpers/mark_up_left.csv rename to data/blueprints/layout-helpers/mark_up_left.csv diff --git a/data/blueprints/library/layout-helpers/mark_up_right.csv b/data/blueprints/layout-helpers/mark_up_right.csv similarity index 100% rename from data/blueprints/library/layout-helpers/mark_up_right.csv rename to data/blueprints/layout-helpers/mark_up_right.csv diff --git a/data/blueprints/library/bedrooms/28-3-Modified_Windmill_Villas.csv b/data/blueprints/library/bedrooms/28-3-Modified_Windmill_Villas.csv deleted file mode 100644 index 89363e35f5..0000000000 --- a/data/blueprints/library/bedrooms/28-3-Modified_Windmill_Villas.csv +++ /dev/null @@ -1,70 +0,0 @@ -"#dig start(11; 12) 28 bedrooms, 3 tiles each (efficient layout)" -# see an image of this blueprint at https://i.imgur.com/XD7D4ux.png - , , , , , ,d, , , , , ,d, , , , , , , , ,# - , , , , , ,d, , , , , ,d, , , , , , , , ,# - , , , ,d, ,d, ,d, ,d, ,d, ,d, , , , , , ,# - , , , ,d, ,d, ,d, ,d, ,d, ,d, , , , , , ,# - , , , ,d,d,d,d,d, ,d,d,d, ,d, ,d,d,d, , ,# - , , , , , ,d, , , , , ,d,d, , ,d, , , , ,# - , ,d,d,d, ,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,# - , , , , ,d,d, , , ,d, ,d, , , ,d, , , , ,# -d,d,d,d,d,d,d,d,d,d,d,d,d, ,d, ,d,d,d, , ,# - , , , ,d, , , ,d,i,i,i,d, ,d, , , , , , ,# - , ,d,d,d, ,d,d,d,i,i,i,d,d,d, ,d,d,d, , ,# - , , , , , ,d, ,d,i,i,i,d, , , ,d, , , , ,# - , ,d,d,d, ,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,# - , , , ,d, , , ,d, ,d, , , ,d,d, , , , , ,# -d,d,d,d,d,d,d,d,d, ,d,d,d, ,d, ,d,d,d, , ,# - , , , ,d, , ,d,d, , , , , ,d, , , , , , ,# - , ,d,d,d, ,d, ,d,d,d, ,d,d,d,d,d, , , , ,# - , , , , , ,d, ,d, ,d, ,d, ,d, ,d, , , , ,# - , , , , , ,d, ,d, ,d, ,d, ,d, ,d, , , , ,# - , , , , , , , ,d, , , , , ,d, , , , , , ,# - , , , , , , , ,d, , , , , ,d, , , , , , ,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -"#build label(furniture) start(11; 11) 28x doors, beds, coffers, and cabinets" - , , , , , ,f, , , , , ,f, , , , , , , , ,# - , , , , , ,h, , , , , ,h, , , , , , , , ,# - , , , ,f, ,b, ,f, ,f, ,b, ,f, , , , , , ,# - , , , ,h, ,d, ,h, ,h, ,d, ,h, , , , , , ,# - , , , ,b,d,`,d,b, ,b,d,`, ,b, ,b,h,f, , ,# - , , , , , ,`, , , , , ,`,d, , ,d, , , , ,# - , ,f,h,b, ,`, ,f,h,b, ,`,`,`,`,`,d,b,h,f,# - , , , , ,d,`, , , ,d, ,`, , , ,d, , , , ,# -f,h,b,d,`,`,`,`,`,`,`,`,`, ,f, ,b,h,f, , ,# - , , , ,d, , , ,`,`,`,`,`, ,h, , , , , , ,# - , ,f,h,b, ,b,d,`,`,`,`,`,d,b, ,b,h,f, , ,# - , , , , , ,h, ,`,`,`,`,`, , , ,d, , , , ,# - , ,f,h,b, ,f, ,`,`,`,`,`,`,`,`,`,d,b,h,f,# - , , , ,d, , , ,`, ,d, , , ,`,d, , , , , ,# -f,h,b,d,`,`,`,`,`, ,b,h,f, ,`, ,b,h,f, , ,# - , , , ,d, , ,d,`, , , , , ,`, , , , , , ,# - , ,f,h,b, ,b, ,`,d,b, ,b,d,`,d,b, , , , ,# - , , , , , ,h, ,d, ,h, ,h, ,d, ,h, , , , ,# - , , , , , ,f, ,b, ,f, ,f, ,b, ,f, , , , ,# - , , , , , , , ,h, , , , , ,h, , , , , , ,# - , , , , , , , ,f, , , , , ,f, , , , , , ,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#query label(rooms) start(11; 11) room designations - , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,# - , , , , , ,r+,, , , , ,r+,, , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,# - , , , ,r+,, , ,r+,,r+,, , ,r+,,r+,, , , ,# - , , , , , , , , , , , , , , , , , , , , ,# - , , , ,r+,, , , , ,r+,, , , , , , ,r+,, ,# - , , , , , , , , , , , , , , , , , , , , ,# - , ,r+,, , , , , , , , , , , , ,r+,, , , ,# - , , , , , , , , , , , , , , , , , , , , ,# - , , , ,r+,,r+,, , , , , , ,r+,,r+,, , , ,# - , , , , , , , , , , , , , , , , , , , , ,# - , , , ,r+,, , , , , , , , , , , , ,r+,, ,# - , , , , , , , , , , , , , , , , , , , , ,# - , ,r+,, , , , , , ,r+,, , , , ,r+,, , , ,# - , , , , , , , , , , , , , , , , , , , , ,# - , , , ,r+,,r+,, , ,r+,,r+,, , ,r+,, , , ,# - , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , ,r+,, , , , ,r+,, , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# diff --git a/data/blueprints/library/bedrooms/48-4-Raynard_Whirlpool_Housing.csv b/data/blueprints/library/bedrooms/48-4-Raynard_Whirlpool_Housing.csv deleted file mode 100644 index 881be3dd1d..0000000000 --- a/data/blueprints/library/bedrooms/48-4-Raynard_Whirlpool_Housing.csv +++ /dev/null @@ -1,100 +0,0 @@ -"#dig start(16; 17; central 3x3 stairwell) 48 rooms, 4 tiles each (more aesthetic)" -# see an image of this blueprint at: https://i.imgur.com/3pNc0HM.png - , , , , , , , , , , , , ,d, , , ,d, , , , , , , , , , , , , ,# - , , , ,d, , , ,d, , , ,d,d,d,d,d,d,d, , , ,d, , , ,d, , , , ,# - , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,# - ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, ,# -d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d,# - ,d, , ,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d, , ,d, ,# - ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,# - ,d, , ,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d, , ,d, ,# -d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d,# - ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, ,# - , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,# - , , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , , ,# - , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,# - ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, ,# - , ,d, , ,d,d,d, , ,d, , ,d,i,i,i,d, , ,d, , ,d,d,d, , ,d, , ,# - , ,d,d,d,d,d,d,d,d,d,d,d,d,i,i,i,d,d,d,d,d,d,d,d,d,d,d,d, , ,# - , ,d, , ,d,d,d, , ,d, , ,d,i,i,i,d, , ,d, , ,d,d,d, , ,d, , ,# - ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, ,# - , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,# - , , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , , ,# - , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,# - ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, ,# -d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d,# - ,d, , ,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d, , ,d, ,# - ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,# - ,d, , ,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d, , ,d, ,# -d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d,# - ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, ,# - , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,# - , , , ,d, , , ,d, , , ,d,d,d,d,d,d,d, , , ,d, , , ,d, , , , ,# - , , , , , , , , , , , , ,d, , , ,d, , , , , , , , , , , , , ,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -"#build label(furniture) start(16; 16; central 3x3 stairwell) 48x doors, beds, cabinets, and coffers; 8x statues" - , , , , , , , , , , , , ,f, , , ,f, , , , , , , , , , , , , ,# - , , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# - , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# - ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, ,# -f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f,# - ,d, , , , , , , , , ,d, , , , , , , ,d, , , , , , , , , ,d, ,# - , , , , , ,s, , , , , , , , ,s, , , , , , , , ,s, , , , , , ,# - ,d, , , , , , , , , ,d, , , , , , , ,d, , , , , , , , , ,d, ,# -f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f,# - ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, ,# - , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# - , , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# - , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,# - ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, ,# - , ,d, , , , , , , ,d, , , , , , , , , ,d, , , , , , , ,d, , ,# - , , , , , ,s, , , , , , , , , , , , , , , , , ,s, , , , , , ,# - , ,d, , , , , , , ,d, , , , , , , , , ,d, , , , , , , ,d, , ,# - ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, ,# - , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,# - , , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# - , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# - ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, ,# -f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f,# - ,d, , , , , , , , , ,d, , , , , , , ,d, , , , , , , , , ,d, ,# - , , , , , ,s, , , , , , , , ,s, , , , , , , , ,s, , , , , , ,# - ,d, , , , , , , , , ,d, , , , , , , ,d, , , , , , , , , ,d, ,# -f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f,# - ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, ,# - , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# - , , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# - , , , , , , , , , , , , ,f, , , ,f, , , , , , , , , , , , , ,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#query label(rooms) start(16; 16; central 3x3 stairwell) room designations - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# - , , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# - ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# - , , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# - , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# - , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, ,# - , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# - , , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# - ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# - , , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# - , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# diff --git a/data/blueprints/library/bedrooms/95-9-Hactar1_3_Branch_Tree.csv b/data/blueprints/library/bedrooms/95-9-Hactar1_3_Branch_Tree.csv deleted file mode 100644 index ec2a1ce1ec..0000000000 --- a/data/blueprints/library/bedrooms/95-9-Hactar1_3_Branch_Tree.csv +++ /dev/null @@ -1,232 +0,0 @@ -"#dig start(36;74) 97 rooms, 9 tiles each (fractal design)" -# see an image of this blueprint at: https://i.imgur.com/ENi5QLX.png - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,d, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , ,d,d,d, , ,d, , , , , , ,d, , , , , , ,d, , , , , , ,d, , , , , , ,d, , ,d,d,d, , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , ,d,d,d, , ,d, , , , , , ,d, , , , , ,d,d,d, , , , , ,d, , , , , , ,d, , ,d,d,d, , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , ,d,d,d, , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,d, , ,d,d,d, , ,d, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , ,d,d,d, ,d,d,d, ,d,d,d, , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , ,d,d,d, , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, , , , , , , , , , , , ,# - , , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , ,# - , , , , , , , , , , , ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, , , , , , , , , , , , ,# - , , , , , , , , , , , , ,d, , , , , , ,d,d,d, ,d, ,d,d,d, , , , , ,d,d,d, , , , , ,d,d,d, ,d, ,d,d,d, , , , , , ,d, , , , , , , , , , , , , ,# - , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , ,# - , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , ,# - , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d,d,d, ,d, , , , , , ,d, , ,d,d,d, , ,d, , , , , , ,d, ,d,d,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , ,# - ,d,d,d, , ,d, , , , , , ,d, , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , ,d, , , , , , ,d, , ,d,d,d, ,# - ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,# - ,d,d,d, , ,d, , , , , , ,d, , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , ,d, , , , , , ,d, , ,d,d,d, ,# - , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d,d,d, ,d, , , , , , ,d, , ,d,d,d, , ,d, , , , , , ,d, ,d,d,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , ,# - , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , ,# - , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , ,# - , , , , , , , , , , , , ,d, , , , , , ,d,d,d, ,d, ,d,d,d, , , , , ,d,d,d, , , , , ,d,d,d, ,d, ,d,d,d, , , , , , ,d, , , , , , , , , , , , , ,# - , , , , , , , , , , , ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, , , , , , , , , , , , ,# - , , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , ,# - , , , , , , , , , , , ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , ,d,d,d, , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,d,d, ,d,d,d, ,d,d, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d, ,d,d,d, ,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,i,i,i,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,i,i,i,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,i,i,i,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -"#build label(furniture) start(36;73) 97 doors; 95 beds, coffers, and cabinets; 190 urns; 14 tables, chairs, weapon racks, armor stands, and statues" - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,f,`,n, ,`, ,n,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`,d,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,n, ,`, ,n,`,h, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, ,`, ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,`, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,n, , ,d, , ,`, , ,d, , ,n,`,h, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,`, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, ,r,b,t, ,`, ,r,b,t, ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, ,a,`,c, ,`, ,a,`,c, ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,h,s,f, ,`, ,h,s,f, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,`, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,h,`,f, ,f,`,n, ,`, ,n,r,a,h, ,`, ,h,a,r,n, ,`, ,n,`,f, ,h,`,f, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`,b,`,d,`,d,`,b,`,s, ,`, ,s,`,b,`,d,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,n,`,n, ,h,`,n, ,`, ,n,t,c,f, ,`, ,f,c,t,n, ,`, ,n,`,h, ,n,`,n, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , ,f,`,n, , ,d, , , , , , ,`, , , , , , ,`, , , , , , ,`, , , , , , ,d, , ,n,`,f, , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , ,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,`, , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , ,h,`,n, , ,d, , , , , , ,`, , , , , ,`,`,`, , , , , ,`, , , , , , ,d, , ,n,`,h, , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,n,`,n, ,f,`,n, ,`, ,n,`,f, ,`,`,`, ,f,`,n, ,`, ,n,`,f, ,n,`,n, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`,b,`,d,`,d,`,b,`, ,`,`,`, ,`,b,`,d,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,h,`,f, ,h,`,n, ,`, ,n,`,h, ,`,`,`, ,h,`,n, ,`, ,n,`,h, ,h,`,f, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , ,`,`,`, , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, ,n,`,n, ,f,n, ,`,`,`, ,n,f, ,n,`,n, ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`,b,`, ,b,`,d,`,`,`,d,`,b, ,`,b,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,h,`,f, ,h,n, ,`,`,`, ,n,h, ,h,`,f, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,d, , ,`,`,`, , ,d, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,f,`,n, ,`, ,n,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,f,`,n, ,`, ,n,`,f, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,`,b,`,d,`,d,`,b,`, ,h,b,f, ,`,`,`, ,h,b,f, ,`,b,`,d,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,h,`,n, ,`, ,n,`,h, , ,d, , ,`,`,`, , ,d, , ,h,`,n, ,`, ,n,`,h, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , ,`, , , , , ,n,`,n, ,`,`,`, ,n,`,n, , , , , ,`, , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,h,`,f, ,`, ,h,`,f, ,`,b,`, ,`,`,`, ,`,b,`, ,h,`,f, ,`, ,h,`,f, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`, ,`,b,`, ,h,`,f, ,`,`,`, ,h,`,f, ,`,b,`, ,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,n,`,n, ,`, ,n,`,n, , , , , ,`,`,`, , , , , ,n,`,n, ,`, ,n,`,n, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , ,h,`,f, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,`,`,`, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,h,`,f, , , , , , , , , , , , ,# - , , , , , , , , , , , ,`,b,`, ,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`, ,`,`,`, ,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , ,# - , , , , , , , , , , , ,n,`,n, ,h,`,n, , ,d, , ,`, , ,d, , ,n,`,h, ,`,`,`, ,h,`,n, , ,d, , ,`, , ,d, , ,n,`,h, ,n,`,n, , , , , , , , , , , , ,# - , , , , , , , , , , , , ,d, , , , , , ,n,`,n, ,`, ,n,`,n, , , , , ,`,`,`, , , , , ,n,`,n, ,`, ,n,`,n, , , , , , ,d, , , , , , , , , , , , , ,# - , , , , ,h,`,f, ,f,`,n, ,`, ,n,r,a,h, ,r,b,t, ,`, ,`,b,`, ,h,b,f, ,`,`,`, ,h,b,f, ,`,b,`, ,`, ,r,b,t, ,h,a,r,n, ,`, ,n,`,f, ,h,`,f, , , , , ,# - , , , , ,`,b,`, ,`,b,`,d,`,d,`,b,`,s, ,a,`,c, ,`, ,h,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,h,`,f, ,`, ,a,`,c, ,s,`,b,`,d,`,d,`,b,`, ,`,b,`, , , , , ,# - , , , , ,n,`,n, ,h,`,n, ,`, ,n,t,c,f, ,h,s,f, ,`, , , , , , ,d, , ,`,`,`, , ,d, , , , , , ,`, ,h,s,f, ,f,c,t,n, ,`, ,n,`,h, ,n,`,n, , , , , ,# - ,f,`,n, , ,d, , , , , , ,`, , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , ,`, , , , , , ,d, , ,n,`,f, ,# - ,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,`, ,# - ,h,`,n, , ,d, , , , , , ,`, , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , ,`, , , , , , ,d, , ,n,`,h, ,# - , , , , ,n,`,n, ,f,`,n, ,`, ,n,r,a,h, ,h,s,f, ,`, , , , , , ,d, , ,`,`,`, , ,d, , , , , , ,`, ,h,s,f, ,h,a,r,n, ,`, ,n,`,f, ,n,`,n, , , , , ,# - , , , , ,`,b,`, ,`,b,`,d,`,d,`,b,`,s, ,a,`,c, ,`, ,h,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,h,`,f, ,`, ,a,`,c, ,s,`,b,`,d,`,d,`,b,`, ,`,b,`, , , , , ,# - , , , , ,h,`,f, ,h,`,n, ,`, ,n,t,c,f, ,r,b,t, ,`, ,`,b,`, ,h,b,f, ,`,`,`, ,h,b,f, ,`,b,`, ,`, ,r,b,t, ,f,c,t,n, ,`, ,n,`,h, ,h,`,f, , , , , ,# - , , , , , , , , , , , , ,d, , , , , , ,n,`,n, ,`, ,n,`,n, , , , , ,`,`,`, , , , , ,n,`,n, ,`, ,n,`,n, , , , , , ,d, , , , , , , , , , , , , ,# - , , , , , , , , , , , ,n,`,n, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,`,`,`, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,n,`,n, , , , , , , , , , , , ,# - , , , , , , , , , , , ,`,b,`, ,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`, ,`,`,`, ,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , ,# - , , , , , , , , , , , ,h,`,f, ,h,`,n, , ,d, , ,`, , ,d, , ,n,`,h, ,`,`,`, ,h,`,n, , ,d, , ,`, , ,d, , ,n,`,h, ,h,`,f, , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,n,`,n, ,`, ,n,`,n, , , , , ,`,`,`, , , , , ,n,`,n, ,`, ,n,`,n, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`, ,`,b,`, ,h,s,f, ,`,`,`, ,h,s,f, ,`,b,`, ,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,h,`,f, ,`, ,h,`,f, ,a,`,c, ,`,`,`, ,a,`,c, ,h,`,f, ,`, ,h,`,f, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , ,`, , , , , ,r,b,t,d,`,`,`,d,r,b,t, , , , , ,`, , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,f,`,n, ,`, ,n,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,f,`,n, ,`, ,n,`,f, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,`,b,`,d,`,d,`,b,`, , ,d, , ,`,`,`, , ,d, , ,`,b,`,d,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , ,h,`,n, ,`, ,n,`,h, ,`,`,`, ,`,`,`, ,`,`,`, ,h,`,n, ,`, ,n,`,h, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,`,`, ,`,`,`, ,`,`, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,f,`,n, ,`,`, ,`,`,`, ,`,`, ,n,`,f, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`,b,`,d,`,`, ,`,`,`, ,`,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, ,h,`,n, ,`,`, ,`,`,`, ,`,`, ,n,`,h, ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,`,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#query label(rooms) start(36;73) message(use burial script to mark urns as usable) room designations - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, ,r+,, , , , , , ,r+,, ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# - , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,~,~,~, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,~,~,~, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,~,~,~, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# - , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# diff --git a/data/blueprints/library/dreamfort.csv b/data/blueprints/library/dreamfort.csv deleted file mode 100644 index 7ccca26634..0000000000 --- a/data/blueprints/library/dreamfort.csv +++ /dev/null @@ -1,2924 +0,0 @@ -#notes label(help) run me for the dreamfort walkthrough -"Welcome to Dreamfort! These blueprints will help you build a functional, secure, fully self-sustaining fortress that you can use as-is or extend to build the fortress of your dreams!" -"" -"It can be difficult to apply a set of blueprints that you did not write yourself. This walkthrough will guide you through the high-level steps of building Dreamfort. Run ""quickfort run library/dreamfort.csv -n /checklist"" (or, if you're looking at the online version, switch to the ""checklist"" sheet) for a compact list of the commands you'll be running. Each level also has its own mini-walkthrough with more details." -"" -"The final fort will have a walled-in area on the surface for livestock, trading, aboveground farming, and military training. One z-level down is the farming level, with related workshops and vents up to the surface for miasma prevention. The farming level also has a miniature dining hall and dormitory for use until you get the services and housing levels set up." -"" -"Beyond those two, the other layers can be built in any order, at any z-level, according to your preference and the layout peculiarities of your embark site:" -"- The industry level has a compact, but complete set of workshops and stockpiles (minus what is already provided on the farming level)." -"- The services level has dining, hospital, marksman barracks, and justice services, plus a well system. It is 4 z-levels deep." -"- The guildhall level has large, empty rooms for building libraries, temples, and guildhalls." -- The suites level has fancy rooms for your nobles. -- The apartments levels have small but well-furnished bedrooms for your other dwarves. -"" -"Run each level's ""help"" blueprint (e.g. ""quickfort run library/dreamfort.csv -n /surface_help"") for more details." -"" -"Dreamfort has a central stairs-based design. For all Dreamfort levels, place the cursor on the center (undug) tile of the 3x3 stairs area when you apply the blueprints for that level. The first surface blueprint will designate a column of stairs that you can use as a guide. If you need to extend the stairs down further to lower levels, run ""quickfort run library/dreamfort.csv -n /central_stairs"" with the cursor on the z-level below the lowest current stairs." -"" -"Dreamfort blueprints take care of everything to get the fort up and running. You don't need to clear any extra trees or create any extra buildings or stockpiles (though of course you are free to do so). Blueprints that do require manual steps, like 'assign minecart to hauling route', will leave a message telling you so when you run them. Note that blueprints will designate buildings to build even if you don't have the materials needed to build them. You can use ""quickfort orders"" to automatically create the manager orders for all the needed items. Make sure your manager is available to validate all the incoming work orders!" -"" -"There are some tasks common to all forts that Dreamfort doesn't specifically handle for you. For example, Dreamfort sets up a barracks, but managing squads is up to you. Here are some other common tasks that may need to be done manually (or with some other tool):" -- Exploratory mining for specific resources like iron -- Filling the well system with water -- Bringing magma up to the industry level to power magma forges/furnaces -- Manufacturing trade goods -- Assigning skilled labors to migrants (although the example professions included with DFHack will help with this) -"- Custom stockpile setups to assist with, for example, encrusting only high-quality items" -"" -"Dreamfort works best at an embark site that is flat and has at least one soil layer. New players should avoid embarks with aquifers if they are not prepared to deal with them. Bring picks for mining, an axe for woodcutting, and an anvil for a forge. Bring a few blocks to speed up initial workshop construction as well. That's all you really need, but see the example embark profile in the online spreadsheets for a more complete setup." -"" -"Other DFHack scripts and plugins also work very well with Dreamfort, such as autofarm, automelt, autonestbox, burial, prioritize, seedwatch, tailor, and, of course, buildingplan. An init file that configures all these plugins Is distributed with DFHack as hack/examples/init/onMapLoad_dreamfort.init." -Put that file in your Dwarf Fortress directory -- the same directory that has dfhack.init. -"" -"Also copy the files in hack/examples/orders/ to dfhack-config/orders/ and the files in hack/examples/professions/ to professions/. We'll be using these files later. See https://docs.dfhack.org/en/stable/docs/guides/examples-guide.html for more information, including suggestions on how many dwarves of each profession you are likely to need at each stage of fort maturity." -"" -"Once you have your starting surface workshops up and running, you might want to configure buildingplan (in its global settings, accessible from any building placement screen, e.g.: b-a-G) to only use blocks for constructions so it won't use your precious wood, boulders, and bars to build floors and walls. If you bring at least 7 blocks with you on embark, you can even set this in your onMapLoad.init file like this:" -on-new-fortress buildingplan set boulders false; buildingplan set logs false -"" -"Directly after embark, run ""quickfort run library/dreamfort.csv -n /setup"" with your cursor on your wagon to set settings, and get started building your fort with ""quickfort run library/dreamfort.csv -n /surface1"" on the surface (see /surface_help for how to select a good spot). Read the walkthroughs for each level to understand what's going on and follow the checklist to keep track of where you are in the building process. Good luck, and have fun building an awesome Dreamfort-based fort!" -"" -"The dreamfort.csv file distributed with DFHack is generated from online spreadsheet files. If you want to look at how these blueprints are put together, it is easier to look at the online spreadsheets than the giant .csv. You can view them at: https://drive.google.com/drive/folders/1iS90EEVqUkxTeZiiukVj1pLloZqabKuP" -You are welcome to copy the Dreamfort spreadsheets and make your own modifications! -"" -"If you like, you can download a fully built Dreamfort-based fort from https://dffd.bay12games.com/file.php?id=15434 and explore it -interactively." -"# dreamfort.csv is generated with the following command: - for fname in dreamfort*.xlsx; do xlsx2csv -a -p '' ""$fname""; done | sed 's/,*$//'" -#notes label(checklist) command checklist -"Here is the recommended order for Dreamfort commands. You can copy/paste the command lines directly into the DFHack terminal, or, if you prefer, you can run the blueprints in the UI with gui/quickfort. See the level walkthroughs for context and details. Also remember to read the messages the blueprints print out after you run them so you don't miss any important manual steps." -"" --- Preparation (before you embark!) -- -Copy hack/examples/init/onMapLoad_dreamfort.init to your DF directory -Copy the fort automation orders from hack/examples/orders/*.json to the dfhack-config/orders/ directory -Optionally copy the premade profession definitions from hack/examples/professions/ to the professions/ directory -"" --- Set settings and preload initial orders -- -quickfort run library/dreamfort.csv -n /setup,# Place the cursor on the center of your starting wagon. Run before making any manual adjustments to settings! Run the /setup_help blueprint for details on what this blueprint does. -"quickfort orders library/dreamfort.csv -n ""/surface2, /farming2, /surface3, /farming3, /industry2, /surface4""","# Queue up orders required to get the fort minimally functional and secure. You can remove the order for the anvil (you brought one with you, right?)." -"" --- Find a good starting spot on the surface -- -quickfort run library/dreamfort.csv -n /perimeter,# Run at embark. -quickfort undo library/dreamfort.csv -n /perimeter,# Clean up after you find your center tile. -"" --- Dig -- -quickfort run library/dreamfort.csv -n /surface1,# Run when you find your center tile. -quickfort run library/dreamfort.csv -n /dig_all,"# Run when you find a suitable rock layer for the industry level. It designates digging for industry, services, guildhall, suites, and apartments all in one go. This list does not include the farming level, which we'll dig in the uppermost soil layer a bit later. Note that it is more efficient for your miners if you designate your digging before they dig the central stairs past that level since the stairs are dug at a low priority. This keeps your miners focused on one level at a time. If you need to designate your levels individually due to caverns interrupting the sequence or just because it is your preference, run the level-specific dig blueprints (i.e. /industry1, /services1, /guildhall1, /suites1, and /apartments1_stack) instead of running /dig_all." -"" --- Core fort (should finish at about the third migration wave) -- -quickfort run library/dreamfort.csv -n /surface2,# Run after initial trees are cleared. -quickfort run library/dreamfort.csv -n /farming1,# Run when channels are dug and the additional designated trees are cleared. -quickfort run library/dreamfort.csv -n /farming2,# Run when the farming level has been dug out. -quickfort run library/dreamfort.csv -n /surface3,# Run right after /farming2. -quickfort run library/dreamfort.csv -n /farming3,# Run when furniture has been placed. -quickfort run library/dreamfort.csv -n /industry2,# Run when the industry level has been dug out. -prioritize ConstructBuilding,# To get those workshops up and running ASAP. You may have to run this several times as the materials for the building construction jobs become ready. -quickfort run library/dreamfort.csv -n /surface4,"# Run after the walls and floors are built on the surface. Even if /surface3 is finished before you run /industry2, though, wait until after /industry2 to run this blueprint so that surface walls, floors, and roofing don't prevent your workshops from being built (due to lack of blocks)." -"quickfort run,orders library/dreamfort.csv -n /services2",# Run when the services level has been dug out. Feel free to remove the orders for the ropes if you already brought them with you. -orders import basic,"# Run after the first migration wave, so you have dorfs to do all the basic tasks. Note that this is the ""orders"" plugin, not the ""quickfort orders"" command." -"quickfort run,orders library/dreamfort.csv -n /surface5","# Run when all marked trees on the surface are chopped down and walls and floors have been constructed, including the roof section over the future barracks." -prioritize ConstructBuilding,# Run when you see the bridges ready to be built so the masons come and actually build them. -"quickfort run,orders library/dreamfort.csv -n /surface6",# Run when at least the beehives and weapon rack are constructed and you have linked all levers to their respective bridges. -"quickfort run,orders library/dreamfort.csv -n /surface7",# Run after the surface walls are completed and any marked trees are chopped down. -"" --- Plumbing -- -"This is a good time to fill your well cisterns, either with a bucket brigade or by routing water from an aquifer or freshwater stream." -"Also consider bringing magma up to your services level so you can replace the forge and furnaces on your industry level with more powerful magma versions. This is especially important if your embark has insufficient trees to convert into charcoal. Keep in mind that moving magma is a tricky process and can take a long time. Don't forget to continue making progress through the checklist! If you choose to use magma, I suggest getting it in place before importing the military and smelting automation orders since they make heavy use of furnaces and forges." -"" --- Mature fort (third migration wave onward) -- -orders import furnace,# Automated production of basic furnace-related items. Don't forget to create a sand collection zone (or remove the sand- and glass-related orders if you have no sand). -"quickfort run,orders library/dreamfort.csv -n /suites2",# Run when the suites level has been dug out. -"quickfort run,orders library/dreamfort.csv -n /surface8","# Run if/when you need longer trap corridors on the surface for larger sieges, anytime after you run /surface7." -"quickfort run,orders library/dreamfort.csv -n /apartments2",# Run when the first apartment level has been dug out. -"quickfort run,orders library/dreamfort.csv -n /apartments3",# Run when all beds have been constructed on the first apartments level. -"quickfort run,orders library/dreamfort.csv -n /services3","# Run after the dining table and chair, weapon rack, and archery targets have been constructed. Also wait until after you complete /surface7, though, because surface defenses are more important than a grand dining hall." -"quickfort run,orders library/dreamfort.csv -n /guildhall2",# Run when the guildhall level has been dug out. -"quickfort run,orders library/dreamfort.csv -n /farming4",# Run once you have a cache of potash. -orders import military,# Automated production of military equipment. Turn on automelt in the meltables piles on the industry level to automatically upgrade all metal military equipment to masterwork quality. These orders are optional if you are not using a military. -orders import smelting,# Automated production of all types of metal bars. -"quickfort run,orders library/dreamfort.csv -n /services4","# Run when you need a jail and/or fancy statues in the dining room, anytime after the restraints are placed from /services3." -orders import rockstock,# Maintains a small stock of all types of rock furniture. -orders import glassstock,# Maintains a small stock of all types of glass furniture and parts (only import if you have sand). -"" --- Repeat for each remaining apartments level as needed -- -"quickfort run,orders library/dreamfort.csv -n /apartments2",# Run when the apartment level has been dug out. -"quickfort run,orders library/dreamfort.csv -n /apartments3",# Run when all beds have been constructed. -burial -pets,# Run once the coffins are placed to set them to allow for burial. This is handled for you if you are using the provided onMapLoad_dreamfort.init file. - -See this checklist online at https://docs.google.com/spreadsheets/d/13PVZ2h3Mm3x_G1OXQvwKd7oIR2lK4A1Ahf6Om1kFigw/edit#gid=1459509569 -#notes label(setup_help) -Makes common initial adjustments to in-game settings. -"" -"The /setup blueprint is intended to be run once at the start of the game, before anything else is changed. Players are welcome to make any further customizations after this blueprint is run. Please be sure to run the /setup blueprint before making any other changes, though, so your settings are not overwritten!" -"" -The following settings are changed: -"- The manager, chief medical dwarf, broker, and bookkeeper noble roles are assigned to the first suggested dwarf. This is likely to be the expedition leader, but the game could suggest others if they have relevant skills. Bookkeeping is also set to the highest precision." -"" -- Standing orders are set to: - - only farmers harvest - - gather refuse from outside (incl. vermin) - - no autoloom (we'll be managing cloth production with automated orders) -"" -"- A burrow named ""Inside"" is created (it's up to the player to define the area). It is intended for use in getting your civilians to safety during sieges. An alert named ""Siege"" is also created and associated with the ""Inside"" burrow." -"" -- Military uniforms get the following modifications: - - all default uniforms set to replace clothing -" - in the ""Metal armor"" uniform, the ""metal armor"" item is removed and replaced by ""metal breastplate"" and ""metal mail shirt""" -" - in the ""Metal armor"" uniform, the ""metal legwear"" item is removed and replaced by ""metal greaves""" -"" -"All default uniforms should also have a leather cloak added, but the position of the cloak in the equipment list changes for every embark. We suggest manually adding a leather cloak to your uniforms after running the /setup blueprint." -"" -- Hotkeys are created for the 8 most interesting levels. Only the names are set -- it's up to the player to adjust them to actual locations in the (H) menu since the blueprint can't know where the levels will eventually be built. Feel free to replace any hotkeys with locations that *you* think are interesting : ) -"" -These are all set for your convenience. Nothing in Dreamfort depends on these settings staying as they are. Feel free to change any setting to your personal preference. -"" -#aliases -startnobles: ^n{Down 4}{togglesequence 8}{Up}s{Up}&^^q -startorders: ^ohrov^Wl^^q -startburrows: ^wa&nInside&^^q -metalarmorsetup: A{Right 2}{Down 2}&{Down}&{Left}&M{Right}{Down}&{Left}{Down}{Right}{Down}&{Left}{Down 2}L{Right}{Down 2}&{Left}{Down 3}&M{Right}{Down}&{Left 2} -startmilitary: ^mnr{Down}r{metalarmorsetup}{Down}racNSiege&{Right}&^q -sethotkey: {fkey}n{name}& -starthotkeys: ^H{sethotkey fkey={F2} name=Farming}{sethotkey fkey={F3} name=Industry}{sethotkey fkey={F4} name=Services}{sethotkey fkey={F5} name=Guildhall}{sethotkey fkey={F6} name=Quarry}{sethotkey fkey={F7} name=Cavern}{sethotkey fkey={F8} name=Magma}^q -"" -"#query label(setup) start(center tile of the wagon) message(Please set the zoom targets of the hotkeys (the 'H' menu) according to where you actually end up digging the levels. -As you build your fort, expand the Inside burrow to include new civilian-safe areas. -Optionally, add a leather cloak to your military uniforms to enhance the protection of the uniforms. -Nothing in Dreamfort depends on these settings staying as they are. Feel free to change any setting to your personal preference.) assign nobles, set standing orders, create burrows, make adjustments to military uniforms, and set hotkey names" -{startnobles}{startorders}{startburrows}{startmilitary}{starthotkeys}{F1} -"#meta label(dig_all) start(central stairs on industry level) dig industry, services, guildhall, suites, and apartments levels. does not include farming." -# Note that this blueprint will only work for the unified dreamfort.csv. It won't work for the individual .xlsx files (since #meta blueprints can't cross file boundaries). -"" -/industry1 -#> -/services1 -#> -#> -#> -#> -/guildhall1 -#> -/suites1 -#> -/apartments1_stack -#ignore -"Here are the minimal labors needed for essential tasks in getting Dreamfort up and running, along with suggestions for which dwarves to assign them to. You can enable additional labors as you wish. Skills with an asterisk (*) are especially worth putting points into on the embark preparation screen." -"" -Manager / Bookkeeper / Broker,Miner,Miner,Mason,Mason,Outdoorsdwarf,Farmer -Mechanic (*),Miner (*),Miner (*),Mason (*),Mason (*),Carpenter (*),Grower (*) -Stonecrafter,,,,,Wood Cutter (*) -Wood Cutter,,,,,Bee Keeper -Architect -Misc. labors needed for constructing workshops -"" -"The most time-consuming tasks in early Dreamfort are: mining, chopping down trees, and making blocks. Starting with at least two miners, two woodcutters (assuming your embark has trees), and two masons helps in keeping the fort from stalling." -"" -We suggest bringing at least: -2 picks,for the two miners -2 battleaxes,for the two woodcutters -1 anvil,for the forge -food and seeds,as per usual -4 ropes,"for the hospital well and traction benches. you could build the ropes out of raw materials, but dwarves are usually too busy to do textile work at the start of the game." -7 blocks,for starting workshops and the temporary trade depot. necessary if you have buildingplan configured for blocks only. -many boulders,for quickly turning into more blocks. blocks are the limiting factor in the early stages. -dogs and cats,for protection and vermin control -geese,"for bones and leather. bring at least 1 male and 2 females for the 2 early nestboxes. autobutcher settings in the included onMapLoad_dreamfort.init file are optimized for raising geese. if you prefer another bird, be sure to adjust the autobutcher settings." -"" -Also bring logs for beds if embarking in an area without many trees. -"" -See ldog's Dreamfort embark profile for a more advanced (and more thoroughly explained!) approach: -https://drive.google.com/file/d/1Et42JTzeYK23iI5wrPMsFJ7lUXwVBQob/view?usp=sharing -"#ignore Add these lines to the bottom of your ""data/init/embark_profiles.txt"" file to make the ""Dreamfort"" profile available in-game. Also see ldog's dreamfort embark profile for a more advanced, dwarfy approach." -[TITLE:Dreamfort] -[SKILL:1:STONECRAFT:1] -[SKILL:1:MECHANICS:5] -[SKILL:1:JUDGING_INTENT:1] -[SKILL:1:APPRAISAL:1] -[SKILL:1:ORGANIZATION:1] -[SKILL:1:RECORD_KEEPING:1] -[SKILL:2:MINING:5] -[SKILL:2:DETAILSTONE:2] -[SKILL:2:SWIMMING:1] -[SKILL:3:MINING:5] -[SKILL:3:DETAILSTONE:2] -[SKILL:3:SWIMMING:1] -[SKILL:4:MASONRY:5] -[SKILL:5:MASONRY:5] -[SKILL:6:WOODCUTTING:5] -[SKILL:6:CARPENTRY:5] -[SKILL:7:PLANT:3] -[ITEM:2:WEAPON:ITEM_WEAPON_PICK:INORGANIC:COPPER] -[ITEM:2:WEAPON:ITEM_WEAPON_AXE_BATTLE:INORGANIC:COPPER] -[ITEM:1:ANVIL:NONE:INORGANIC:IRON] -[ITEM:7:DRINK:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:DRINK] -[ITEM:26:DRINK:NONE:PLANT_MAT:GRASS_TAIL_PIG:DRINK] -[ITEM:26:DRINK:NONE:PLANT_MAT:GRASS_WHEAT_CAVE:DRINK] -[ITEM:26:DRINK:NONE:PLANT_MAT:POD_SWEET:DRINK] -[ITEM:10:SEEDS:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:SEED] -[ITEM:10:SEEDS:NONE:PLANT_MAT:GRASS_TAIL_PIG:SEED] -[ITEM:10:SEEDS:NONE:PLANT_MAT:GRASS_WHEAT_CAVE:SEED] -[ITEM:10:SEEDS:NONE:PLANT_MAT:POD_SWEET:SEED] -[ITEM:10:SEEDS:NONE:PLANT_MAT:BUSH_QUARRY:SEED] -[ITEM:10:SEEDS:NONE:PLANT_MAT:MUSHROOM_CUP_DIMPLE:SEED] -[ITEM:25:PLANT:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:STRUCTURAL] -[ITEM:4:CHAIN:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] -[ITEM:5:CLOTH:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] -[ITEM:5:THREAD:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] -[ITEM:50:WOOD:NONE:PLANT_MAT:WILLOW:WOOD] -[ITEM:40:BOULDER:NONE:INORGANIC:QUARTZITE] -[ITEM:10:BLOCKS:NONE:INORGANIC:QUARTZITE] -[PET:2:DOG:FEMALE:STANDARD] -[PET:1:DOG:MALE:STANDARD] -[PET:2:CAT:FEMALE:STANDARD] -[PET:1:CAT:MALE:STANDARD] -[PET:2:BIRD_GOOSE:FEMALE:STANDARD] -[PET:2:BIRD_GOOSE:MALE:STANDARD] -#meta label(all_orders) hidden() references all blueprints that generate orders; for testing only -/surface2 -/surface3 -/surface4 -/surface5 -/surface6 -/surface7 -/surface8 -/farming2 -/farming3 -/farming4 -/industry2 -/services2 -/services3 -/services4 -/guildhall2 -/suites2 -/apartments2 -/apartments2 -/apartments2 -/apartments2 -/apartments2 -/apartments2 -/apartments3 -/apartments3 -/apartments3 -/apartments3 -/apartments3 -/apartments3 -#notes label(surface_help) -Sets up a protected entrance to your fort in a flat area on the surface. -Screenshot: https://drive.google.com/file/d/1YL_vQJLB2YnUEFrAg9y3HEdFq3Wpw9WP -"" -Features: -- A starting set of workshops and stockpiles (which you can later remove once you establish your permanent workshops and storage) -- Livestock grazing area with nestbox zones and beehives -"- Walls, roof, and lever-controlled gates for security" -- Barracks -- Trap-filled hallways for invaders -- Optional extended trap hallways (to handle larger sieges) -- Protected trade depot -- A grid of 1x1 farm plots (intended to be managed by DFHack autofarm) -"" -Manual steps you have to take: -- Assign grazing livestock to the large pasture and dogs to the pasture over the central stairs (DFHack's autonestbox can manage the nestbox zones) -- Connect levers to the gates that match the names of the levers -- Assign a minecart to the trade goods quantum stockpile hauling route -"" -Be sure to choose an embark site that has a flat area large enough to use these blueprints! -"" -Surface Walkthrough: -"1) Choose a tile for your central fortress stairs. The terrain around that tile should be perfectly flat. Trees are ok, but no slopes, rivers, or lakes. To be sure that the tile you've chosen is in a good spot, set the cursor over that tile and run ""quickfort run library/dreamfort.csv -n /perimeter"". This will show you the eventual boundaries of the fort. Some wall segments might be missing due to existing trees, but that's ok. Make sure the area within the exterior wall is flat. Run ""quickfort undo library/dreamfort.csv -n /perimeter"" to clean up." -"" -"2) With the cursor on the chosen tile, run /surface1 to clear surrounding trees and set up your pastures. Deconstruct your wagon to get it out of the way of our upcoming walls and floors. Remember to assign your dogs to the pasture around the staircase and your grazing animals to the large pasture. Your egg-layers will automatically get assigned to nestbox zones once the nestboxes are built, so you don't need to worry about them. You can let your cats roam free to chase vermin." -"" -"3) Once the marked trees have been cleared, run /surface2 to setup starting workshops/stockpiles, channel out the miasma vents for the farming level, and start clearing trees from a larger area. If you haven't done it already, now is a good time to configure buildingplan to only build buildings with blocks, not logs or raw boulders. Do this by entering buildingplan's global configuration (""baG"") and ensuring the only generic building material allowed is ""blocks"". Run ""quickfort orders"" for /surface2." -"" -"4) Once the channels are dug out and the trees are cleared, start digging the farming level one z-level down. Once you have run /farming2, come back to the surface and run /surface3 to cover the vents and build an enclosure around your central stairs. Although the vents will be covered with flooring, they will still work to prevent miasma on the farming level. Run ""quickfort orders"" for /surface3." -"" -"5) Once all walls and floors have been constructed around the stairwell, run /surface4 to build floors and walls to support upcoming buildings and furniture. Run ""quickfort orders"" for /surface4." -"" -"6) Once walls and floors have been constructed (including the small roof segment one z-level up over the barracks), run /surface5 to build furniture, gates, and the permanent trade depot. Remember to deconstruct the temporary trade depot once nobody is using it. Run ""quickfort orders"" for /surface5." -"" -"7) Once at least the beehives and weapon rack are built, run /surface6 to configure the rooms and build the remaining walls and floors. Run ""quickfort orders"" for /surface6." -"" -"8) Once you have enough dwarves to do a lot of building without starving other important tasks, run /surface7 to build the roof. Run ""quickfort orders"" for /surface7." -"" -"9) For extra security, you can run /surface8 any time after /surface7 to extend the trap corridors. Run ""quickfort orders"" for /surface8." -"" -"10) Once your industry and farming levels are set up and running, you can disassemble the surface workshops and remove the surface stockpiles. Disassembling a workshop scatters the items stored within it and cancels any pending jobs that happen to use those items. In order to avoid job cancellations, first set the surface workshops to not accept general work orders. Do this by entering query mode (""q""), selecting a workshop, entering the workshop profile (""P""), moving to work orders (right arrow), and hitting Enter. Then enter view mode (""t"") and check to see if any items in a workshop are marked with ""TSK"". Once no items in the workshop have that marker, you are free to disassemble that workshop." -#meta label(perimeter) start(central stairs) message(Run quickfort undo on this blueprint to clean up.) show the eventual perimeter of the surface fort; useful for location scouting -walls/surface_walls -corridor/surface_corridor -"" -"#meta label(surface1) start(central stairs) -message(Once the central stairs are mined out deeply enough, you should start digging the industry level in a non-aquifer rock layer. You'll need the boulders from the digging to make blocks. -If your wagon is within the fort perimeter, deconstruct it to get it out of the way. -Once the marked trees are all chopped down (if any), continue with /surface2.) clear trees and set up pastures" -central_stairs/central_stairs -clear_small/surface_clear_small -zones/surface_zones -name_zones/surface_name_zones -"" -"#meta label(surface2) start(central stairs) message(Remember to enqueue manager orders for this blueprint. -Once the channels are dug out and the marked trees are cleared, continue with /surface3.) set up starting workshops/stockpiles, channel miasma vents, and clear more trees" -build_start/surface_build_start -place_start/surface_place_start -query_start/surface_query_start -channel/surface_channel -clear/surface_clear -"" -"#meta label(surface3) start(central stairs) message(Remember to enqueue manager orders for this blueprint. -Once the walls and floors have been constructed, continue with /surface4.) Cover vents and protect the central stairs." -cover_vents/surface_cover_vents -cover_stairs/surface_cover_stairs -"" -"#meta label(surface4) start(central stairs) message(Remember to enqueue manager orders for this blueprint. -Once the walls and floors have been constructed, continue with /surface5. Be sure to check one z-level above the surface to ensure the roof segment above the future barracks has been finished.) build walls and flooring to support upcoming buildings and furniture" -stairs_doors/surface_stairs_doors -pre_building/surface_pre_building -"" -"#meta label(surface5) start(central stairs) message(Remember to enqueue manager orders for this blueprint. -Disassemble the temporary trade depot in the pasture once the new one is constructed (and no merchants are using the old one). -Once the marked trees are cleared and at least the beehives and weapon rack have been constructed, continue with /surface6.) build gates, furniture, and trade stockpile/depot" -place/surface_place -build/surface_build -query/surface_query -clear_large/surface_clear_large -"" -"#meta label(surface6) start(central stairs) message(Remember to enqueue manager orders for this blueprint. -Continue with /surface7 sometime after the walls are completed and any marked trees are chopped down, whenever you have enough dwarves to build the roof without starving other important construction tasks.) configure hives and barracks, build traps and remaining walls/floors" -query2/surface_query2 -walls/surface_walls -floors/surface_floors -traps/surface_traps -clear_large/surface_clear_large -"" -"#meta label(surface7) start(central stairs (on ground level)) message(Remember to enqueue manager orders for this blueprint. -For extra security, you can run /surface8 at any time to extend the trap corridors.) build roof" -#< -roof/surface_roof -roof2/surface_roof2 -roof3/surface_roof3 -roof4/surface_roof4 -"" -#meta label(surface8) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) build extended trap corridors -corridor/surface_corridor -corridor_traps/surface_corridor_traps -query_corridor/surface_query_corridor -#dig label(central_stairs) start(2;2) hidden() spiral stairs that go down 20 levels -`,u,` -j6,`,j6 -`,u,` -#> -`,j6,` -u,`,u -`,j6,` -#> -`,u,` -j6,`,j6 -`,u,` -#> -`,j6,` -u,`,u -`,j6,` -#> -`,u,` -j6,`,j6 -`,u,` -#> -`,j6,` -u,`,u -`,j6,` -#> -`,u,` -j6,`,j6 -`,u,` -#> -`,j6,` -u,`,u -`,j6,` -#> -`,u,` -j6,`,j6 -`,u,` -#> -`,j6,` -u,`,u -`,j6,` -#> -`,u,` -j6,`,j6 -`,u,` -#> -`,j6,` -u,`,u -`,j6,` -#> -`,u,` -j6,`,j6 -`,u,` -#> -`,j6,` -u,`,u -`,j6,` -#> -`,u,` -j6,`,j6 -`,u,` -#> -`,j6,` -u,`,u -`,j6,` -#> -`,u,` -j6,`,j6 -`,u,` -#> -`,j6,` -u,`,u -`,j6,` -#> -`,u,` -j6,`,j6 -`,u,` -#> -`,j6,` -u,`,u -`,j6,` -#dig label(surface_clear_small) start(19; 19) hidden() clear trees for starting workshops and stockpiles - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,t1(25x9),,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,t1,`,`,`,`,`,`,,`,,`,`,`,`,`,t1,`,`,`,t1,`,`,,` -,,,`,,`,,`,t1,t1,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,t1,,,,,,t1,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,t1,t1,,,,,,t1,t1,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,t1,t1,,t1,t1,t1,,t1,t1,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,t1,t1,t1,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,t1,,,t1,t1,t1,,,t1,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,t1,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -"#zone label(surface_zones) start(19; 19) hidden() message(Remember to assign your dogs to the pasture surrounding the central stairs and your grazing animals to the large pasture. -Feel free to assign an unimportant animal to the pasture in the main entranceway to use as bait during sieges.) pastures and training areas" - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,nmt(25x11),,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),`,,,,,,`,nt(9x5),,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,nt,nt,nt,nt,nt,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,nt,`,~,`,nt,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,nt,nt,nt,nt,nt,,,,,,,,,,,`,,` -,,,`,,`,,`,n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,n,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#query label(surface_name_zones) start(19; 19) hidden() - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,"{namezone name=""main pasture""}",,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,"{namezone name=""nestbox1""}","{namezone name=""nestbox2""}","{namezone name=""nestbox3""}","{namezone name=""nestbox4""}","{namezone name=""nestbox5""}","{namezone name=""nestbox6""}","{namezone name=""nestbox7""}",`,,,,,,`,"{namezone name=""taming area""}",,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,"{namezone name=""guard dogs""}",,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,"{namezone name=""nestbox8""}","{namezone name=""nestbox9""}","{namezone name=""nestbox10""}","{namezone name=""nestbox11""}","{namezone name=""nestbox12""}","{namezone name=""nestbox13""}","{namezone name=""nestbox14""}",`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,"{namezone name=""siege bait""}",,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#build label(surface_build_start) start(19; 19) hidden() message(There is room to the left of the carpenter's workshop to build one more workshop of any type if you need it.) starting workshops - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,wc,,,,wr,,,,wm,,,,wt,,,,,D,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,N,N,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -"#place label(surface_place_start) start(19; 19) hidden() message(if you haven't already, now is a good time to deconstruct the wagon) starting stockpiles" - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,f(8x4),,,,,,,,w(4x4),,,,s2(5x4),,,,,gunzSpd(4x4),,,,hlr(4x4),,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#query label(surface_query_start) start(19; 19) hidden() config stockpiles - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,"{givename name=""starting food""}",,,,"{givename name=""starting wood""}",,,,,"{givename name=""starting stone""}",,,,"{givename name=""starting misc""}",,,,"{givename name=""starting cloth/trash""}",`,,` -,,,`,,`,,,,,,,,,,,,,otherstone,,,,,nocontainers,,,,nocontainers,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#dig label(surface_channel) start(19; 19) hidden() channel miasma vents - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,h1,`,`,`,`,`,`,,`,,`,`,`,`,`,h1,`,`,`,h1,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,h1,,,,,,h1,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,h1,h1,,,,,,h1,h1,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,h1,h1,,h1,h1,h1,,h1,h1,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,h1,h1,h1,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,h1,,,h1,h1,h1,,,h1,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,h1,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#dig label(surface_clear) start(19; 19) hidden() clear trees so the farming level can be dug without fear of generating surface holes - - -,,,,t1(29x29) -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,t1,t1 -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,t1,t1 -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,t1,t1 -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,t1,t1 -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,t1,t1 -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,t1,t1 -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,t1,t1 -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,t1,t1 -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,t1,t1 -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - -,,,,,,,,,,,,,,,t1,t1,t1,t1,t1,t1,t1 - -#build label(surface_cover_vents) start(19; 19) hidden() cover the miasma vents - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,Cw,`,`,`,`,`,`,,`,,`,`,`,`,`,Cw,`,`,`,Cw,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,Cf,,,,,,Cf,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,Cf,Cf,,,,,,Cf,Cf,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,Cf,Cf,,Cf,Cf,Cf,,Cf,Cf,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,Cf,Cf,Cf,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,Cw,,,Cf,Cf,Cf,,,Cw,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,Cf,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#build label(surface_cover_stairs) start(19; 19) hidden() protect the central stairs - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,Cr,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,Cw,Cw,Cf,Cw,Cf,Cw,Cw,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,Cw,,,,,,Cw,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,Cf,,`,`,`,,Cf,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,Cw,,H,~,H,,Cw,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,Cf,,`,`,`,,Cf,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,Cw,,,,,,Cw,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,Cw,Cw,Cf,Cw,Cf,Cw,Cw,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#< - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,Cf,`,Cf,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,Cf,`,Cf,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#build label(surface_stairs_doors) start(19; 19) hidden() - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,d,`,d,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,d,,`,`,`,,d,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,d,,`,`,`,,d,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,d,`,d,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#build label(surface_pre_building) start(19; 19) hidden() flooring and anchoring walls for future buildings/doors -#< - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,~,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,~,~,~,~,~,~,~,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,~,~,~,~,~,~,~,Cf,Cf,Cf,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,Cf,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,~,`,~,`,`,`,`,Cf,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,Cf,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,Cf,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,Cf,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,Cf,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#> - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,Cf,,Cf,,Cf,`,,,,,,,,,,`,,` -,,,`,,`,,Cw,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,Cf,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` -,,,`,,`,,Cw,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,Cw,Cf,Cw,`,`,`,,`,,`,`,`,Cw,Cf,Cw,`,`,`,`,`,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,,,,,,~,`,,,,,,,Cf,Cf,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,Cf,Cf,Cf,Cf,Cf,~,~,,,,,,,,Cf,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,,~,~,~,,~,~,,,,,Cf,Cf,,Cf,`,,` -,,,`,,`,,Cf,,Cf,Cf,Cf,Cf,Cf,,Cf,,~,~,~,,Cf,,,,,,,,,Cf,`,,` -,,,`,,`,,Cf,,Cf,Cf,Cf,Cf,Cf,`,,,~,~,~,,,`,,,,,,,Cf,Cf,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,Cf,,,,,,,,,Cf,,,,,~,,,,,Cf,,,,,,,,,Cf,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#place label(surface_place) start(19; 19) hidden() remaining surface stockpiles - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,a5(9x5),,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,g(3x3),,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,c,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -"#build label(surface_build) start(19; 19) hidden() message(Use autofarm to manage farm crop selection. -Remember to connect the levers to the gates once they are built.) gates, barracks, farm area, and trade area" - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,~h,`,~,~,N,N,N,N,N,`,Tl,,Tl,,Tl,`,,,,,,,,,,`,,` -,,,`,,`,~h,`,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,~h,d,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),`,,`,`,`,,`,,,,,,,,,,`,,` -,,,`,,`,~h,`,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,~h,`,N,N,N,N,N,N,N,`,Tl,Tl,Tl,Tl,Tl,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,d,`,`,`,`,,`,,`,`,`,`,d,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,gw,gw,gw,gw,gw,,`,,,,,,,h,b,`,,` -,,,`,,`,,,,,,,,,ga,ga,gw,gw,gw,gw,gw,gd,gd,,,,,,,,b,`,,` -,,,`,,`,,,,,,D,,,ga,ga,,,,,,gd,gd,,,,,a,r,,b,`,,` -,,,`,,`,,trackstopS,,,,,,,ga,ga,,,,,,gd,gd,,,,,,,,b,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,h,b,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,gd,gd,,,,,,,,gd,gd,,,,,,,,ga,ga,,,,,,,,ga,ga,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,gw,gw,gw,gw,gw,gw,gw,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,gw,gw,gw,gw,gw,gw,gw -,,,,,,,,,,,,,,,gw,gw,gw,gw,gw,gw,gw - -"#query label(surface_query) start(19; 19) hidden() message(Remember to assign a minecart to the trade goods quantum stockpile. -Feel free to adjust the configuration of the ""trade goods"" feeder stockpile so it accepts the item types you want to trade away. If those items types are also accepted by other stockpiles, configure those stockpiles to give to the ""trade goods"" stockpile. -You might also want to set the ""trade goods quantum"" stockpile to Auto Trade if you have the autotrade DFHack plugin enabled.)" - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,"{givename name=""trade depo gate""}",,"{givename name=""inner main gate""}",,"{givename name=""barracks gate""}",`,"{givename name=""prison/training area""}",,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,"{givename name=""left outer gate""}","{givename name=""left inner gate""}","{givename name=""outer main gate""}","{givename name=""right inner gate""}","{givename name=""right outer gate""}",`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,nocontainers,crafts,,,,,,,`,,,,"{givename name=""inner main gate""}",,,,`,,,,,,,,,`,,` -,,,`,,`,"{givename name=""trade goods""}",,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,{forbidmasterworkfinishedgoods}{forbidartifactfinishedgoods},,,,,,,,"{givename name=""trade depo gate""}",,,,,,,,"{givename name=""barracks gate""}",,,,,,,,,`,,` -,,,`,,`,,"{quantumstopfromnorth name=""Trade Goods Dumper""}",,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,"{quantum name=""trade goods quantum""}",,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,"{givename name=""left outer gate""}",,,,,,,,,"{givename name=""left inner gate""}",,,,,,,,"{givename name=""right inner gate""}",,,,,,,,,"{givename name=""right outer gate""}",,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,"{givename name=""outer main gate""}",,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#dig label(surface_clear_large) start(19; 19) hidden() clear wider area of trees -t1(37x33) - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#query label(surface_query2) start(19; 19) hidden() - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,cg,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,cg,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,c,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` -,,,`,,`,cg,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,cg,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,r&,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#build label(surface_walls) start(19; 19) hidden() build remaining walls - - - -,,,`,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,Cw,Cw,Cw,Cw,~,Cw,Cw,Cw,Cw,~,~,,~,,~,~,Cw,Cw,Cw,~,Cw,Cw,Cw,~,Cw,Cw,,` -,,,`,,Cw,,Cw,,,,,,,,~,,,,,,~,,,,,,,,,,Cw,,` -,,,`,,Cw,,~,,,,,,,,,,`,`,`,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,~,,`,`,`,,~,,,,,,,,,,Cw,,` -,,,`,,Cw,,~,,,,,,,,,,`,`,`,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,Cw,,,,,,,,~,,,,,,~,,,,,,,,,,Cw,,` -,,,`,,Cw,Cw,Cw,Cw,Cw,Cw,~,,~,Cw,~,~,,~,,~,~,Cw,~,,~,Cw,Cw,Cw,Cw,Cw,Cw,,` -,,,`,,Cw,,,,,,,,,Cw,,,,,,,,Cw,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` -,,,`,,Cw,,,,,,,,,~,,,,,,,,~,,,,,,,,,Cw,,` -,,,`,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,,,,,,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,,,,,,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,`,` - - - -#build label(surface_floors) start(19; 19) hidden() build remaining flooring - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,~,Cf,~,Cf,~,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,~,Cf,Cf,Cf,Cf,Cf,~,,,,,,,,,,`,,` -,,,`,,`,,~,,,,,,,,`,Cf,`,Cf,`,Cf,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,~,Cf,Cf,Cf,Cf,Cf,~,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,~,Cf,~,~,~,Cf,~,~,Cf,Cf,Cf,Cf,~,~,Cf,~,`,,` -,,,`,,`,Cf,~,Cf,~,~,~,~,~,~,~,Cf,~,~,~,Cf,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,Cf,~,Cf,~,~,~,~,~,`,Cf,Cf,~,~,~,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,~,~,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,,` -,,,`,~,,,,,,,,,,,Cf,Cf,Cf,~,Cf,Cf,Cf,,,,,,,,,,,~,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#build label(surface_traps) start(19; 19) hidden() - -,,,,,Tc,Tc,,,,,,,,,,,,,,,,,,,,,,,,Tc,Tc -,,,,,Tc,Tc,,,,,,,,,,,,,,,,,,,,,,,,Tc,Tc -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,Tc,Tc,Tc,Tc,Tc,Tc,Tc,,,,,,,,,,,,Tc,Tc,Tc,Tc,Tc,Tc,Tc,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,Tc,Tc,,,,,,,,Tc,Tc -,,,,,,,,,,,,,Tc,Tc,,,,,,,,Tc,Tc - -#build label(surface_roof) start(19; 19) hidden() roof hatch and adjacent tiles - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,Cf,,Cf,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,Cf,H,Cf,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,~,~,~,~,~,~,~,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,~,~,~,~,~,~,~,~,~,~,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,~,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,~,~,~,~,~,~,~,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,~,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,~,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,~,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,~,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#build label(surface_roof2) start(19; 19) hidden() lower half of the roof - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,~,,~,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,~,~,~,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` -,,,`,,`,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` -,,,`,,`,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,~,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,`,,` -,,,`,,`,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,~,Cf,Cf,Cf,Cf,Cf,Cf,`,,` -,,,`,,`,`,`,`,`,`,`,Cf,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,~,~,~,~,~,~,~,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,`,` - - - -#build label(surface_roof3) start(19; 19) hidden() upper half center of the roof - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` -,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` -,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` -,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` -,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` -,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` -,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` -,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` -,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,Cf,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` -,,,`,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` - - - -#build label(surface_roof4) start(19; 19) hidden() upper half remainder of the roof - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` -,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` -,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` -,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` -,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` -,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` -,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` -,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` -,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` -,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` -,,,`,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` - - - -#build label(surface_corridor) start(19; 19) hidden() trap hallway walls - - - -,,,Cw,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,Cw -,,,Cw,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,Cw -,,,Cw,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,Cw -,,,Cw,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,Cw -,,,Cw,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,Cw -,,,Cw,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw -,,,Cw,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,Cw -,,,Cw,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,Cw -,,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cw -,,,Cw,Cw,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,Cw,Cw - - - -#< - - - -,,,`,Cf,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,Cf,` -,,,`,Cf,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,Cf,` -,,,`,Cf,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,` - - - -"#build label(surface_corridor_traps) start(19; 19) hidden() barracks, longer trap hallways, and outer levers/gates" - - -,,,,gx,,,,,,,,,,,,,,,,,,,,,,,,,,,,gx -,,,`,gx,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,gx,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,Tc,` -,,,`,Tc,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,`,Tl,`,`,`,Tl,`,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,Tc,` -,,,`,Tc,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,Tc,` -,,,`,Tc,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` -,,,`,Tc,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,Tc,` -,,,`,Tc,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,Tc,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#query label(surface_query_corridor) start(19; 19) hidden() (Remember to connect the levers to the new external trap gates.) configure barracks and name outer levers/gates - - - -,,,`,"{givename name=""left trap gate""}",`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,"{givename name=""right trap gate""}",` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,"{givename name=""left trap gate""}",`,`,`,"{givename name=""right trap gate""}",`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#notes label(farming_help) -"Sets up farming, food storage, and related industries. Also provides post-embark necessities that can later be disassembled." -Screenshot: https://drive.google.com/file/d/1fBC3G5Y888l4tVe5REAyAd_zeojADVme -"" -Features: -- Pairs with the surface blueprints for vents that prevent miasma -- Farm plots (intended to be managed by DFHack autofarm) -- Plentiful food storage -- Refuse/corpse quantum stockpile -- Small dormitory and dining room for post-embark needs -- Small offices for your manager and bookkeeper -"" -Workshops: -- Kitchen -- Brewery -- Butcher -- Fishery -- Tannery -- Farmer's Workshop -- Quern -- Screw Press -"" -Manual steps you have to take: -- Check to make sure the lower office is assigned to your manager and assign the upper office to your bookkeeper (if different from your manager) -- Assign a minecart to your refuse quantum stockpile hauling route -"- If the industry level is already built, configure the jugs, pots, and bags stockpiles to take from the ""Goods"" quantum stockpile (the one on the left) on the industry level" -"" -Farming Walkthrough: -"1) Wait until you have channeled the miasma vents and cleared trees on the surface before digging out the farming level on the z-level below the surface, otherwise you will end up with extra ramps on the farming level and unprotected holes through the surface when you later chop down trees growing above empty space." -"" -"2) Start digging with /farming1 and get started on manufacturing furniture by running ""quickfort orders"" on /farming2 and /farming3." -"" -"3) Once the level is dug out, run /farming2 to build workshops, stockpiles, and the furniture we need to anchor the rooms. Remember to assign a minecart to the newly-designated quantum refuse dump. There are also jugs, pots, and bags stockpiles on this level that should be configured to ""take"" from the industry level stockpile once we get the industry level built." -"" -"4) When the furniture is in place, run /farming3 to designate your starter dining room and dormitory and build the farm plots and remaining furniture. The blueprint also attempts to assign the lower office to your manager, but double-check this assignment in case your dwarves are in an unexpected order." -"" -"5) Once your fort has enough free time to build the remaining doors, run /farming4. This will also enable seasonal fertilization for your farm plots. Run ""quickfort orders"" for /farming4." -"" -"6) You can disassemble the dining room and dormitory once the services and apartments levels are up and running, if you like." -"#dig label(farming1) start(16; 18; central stairs) message(Once the area is dug out, continue with /farming2.)" -# this level is dug at priority 2 since it is dug in soil. it's worth the miner's time to stop digging the industry level and -# quickly dig out this one. -,,,,,,,,,2,2,2,,2,2,2,2,2,,2,2,2,2 -,,,,,,,,,2,2,2,,2,2,2,2,2,,2,2,2,2 -,,,,,,,,,2,2,2,,2,2,2,2,2,,2,2,2,2 -,,,,,,,,,,,2,,2,2,2,2,2,,2,2,2,2 -,,,,,,,2,2,2,,2,,2,2,2,2,2,,2,2,2,2 -,,,,,,,2,2,2,2,2,,2,2,2,2,2,,2,2,2,2 -,,,,,,,2,2,2,,2,,2,2,2,2,2,,2 -,,,,,,,,,,,2,,2,2,2,2,2,,2,,2,2,2 -,,,,,,2,2,2,2,,2,,2,2,2,2,2,,2,2,2,2,2 -,,,,,,2,2,2,2,,2,,2,2,2,2,2,,2,,2,2,2 -,,,2,2,,2,2,2,2,,2,,2,2,2,2,2,,2 -,,2,2,2,,2,2,2,2,,2,,2,2,2,2,2,,2,,2,2,2,,2,2,2 -,,2,2,2,2,2,z2,2,2,2,2,,,2,,2,,,2,2,2,z2,2,2,2,z2,2 -,,,2,2,,2,2,2,2,,2,2,2,2,2,2,2,2,2,,2,2,2,,2,2,2 -,,,,2,,,2,,,,,,2,`,`,`,2,,,,,2,,,,2 -,,2,2,2,2,2,2,2,2,2,2,,2,`,~,`,2,,2,2,2,2,2,2,2,2,2,2 -,,2,2,2,2,2,2,2,2,2,2,2,2,`,`,`,2,2,2,2,2,2,2,2,2,2,2,2 -,,2,2,2,2,2,2,2,2,2,2,,2,2,2,2,2,,2,2,2,2,2,2,2,2,2,2 -,,2,2,2,2,2,2,2,2,2,,,,2,,2,,,,2,2,2,2,2,2,2,2,2 -,,2,2,2,2,2,2,2,2,,,z2,2,2,2,2,2,z2,,,2,2,2,2,2,2,2,2 -,,2,2,2,2,2,2,2,2,,z2,z2,,,2,,,z2,z2,,2,2,2,2,2,2,2,2 -,,2,2,2,2,2,2,2,,,z2,z2,,z2,z2,z2,,z2,z2,,,2,2,2,2,2,2,2 -,,2,2,2,2,2,2,2,,2,2,2,,z2,z2,z2,,2,2,2,,2,2,2,2,2,2,2 -,,2,2,2,2,2,2,2,,2,z2,2,,z2,z2,z2,,2,z2,2,,2,2,2,2,2,2,2 -,,2,2,2,2,2,2,2,,2,2,2,,,2,,,2,2,2,,2,2,2,2,2,2,2 -,,,,,,,,,,,,,,,z2 - - -"#meta label(farming2) start(central stairs) message(Remember to enqueue manager orders for this blueprint. -Once furniture has been placed, continue with /farming3.) workshops, stockpiles, and important furniture" -build/farming_build -place/farming_place -query_stockpiles/farming_query_stockpiles -link_stockpiles/farming_link -"" -#meta label(farming3) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) configure rooms and build farm plots and more furniture -query_rooms/farming_rooms -build2/farming_build2 -"" -#meta label(farming4) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) configure farm plots and build remaining furniture -query_plots/farming_query_plots -build3/farming_build3 -#build label(farming_build) start(16; 18) hidden() workshops and important furniture - - -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,c,t,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,t,c -,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,c,t,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,b -,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,`,` -,,,,,,`,wl,`,`,,`,,`,`,`,`,`,,`,,`,`,` -,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` -,,wq,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,wp,`,`,`,`,ww,`,`,`,`,,,`,,`,,,`,`,`,wu,`,`,`,wz,` -,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,wh,`,,`,`,`,,`,wn,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,trackstopS,,,`,`,`,,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,` - - -#place label(farming_place) start(16; 18) hidden() stockpiles - - -,,,,,,,,,`,`,`,,`,`,`,f10(1x9),b(1x12),,f(4x2),,,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,f(3x2),,` -,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,` -,,,,,,`,`,`,u,,`,,`,`,`,`,`,,`,`,`,`,` -,,,,,,`,`,`,u,,`,,f(4x3),,,`,`,,`,,`,`,` -,,,u,u,,`,`,`,u,,`,,`,`,`,`,`,,` -,,`,u,u,,`,`,`,u,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,g,g,`,`,`,`,u,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,g,g,,`,`,`,u,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,f,f,f,f,f,f,f,f,f,f,,`,`,~,`,`,,f,f,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,f,f,f,`,`,`,`,`,`,`,f,f,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,f,f,f,,`,`,`,`,`,,f,f,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,f,f,,,,`,,`,,,,f,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,f,,,f,`,`,`,`,`,r,,,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,f,,f,f,,,`,,,r,r,,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,,,f,f,,r(2x3),,ry2(1x3),,r,r,,,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,,`,`,`,,`,`,`,,`,`,`,,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,,`,`,`,,`,`,`,,`,`,`,,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,,`,`,`,,,`,,,`,`,`,,f,f,f,f,f,f,f -,,,,,,,,,,,,,,,ry - - -"#query label(farming_query_stockpiles) start(16; 18) hidden() message(remember to: -- assign a minecart to the refuse quantum stockpile -- if the industry level is already built, configure the jugs, pots, and bags stockpiles to take from the ""Goods"" quantum stockpile on the industry level) config stockpiles" - - -,,,,,,,,,`,`,`,,`,`,`,seeds,potash,,booze,,,` -,,,,,,,,,`,`,`,,`,`,`,linksonly,nocontainers,,"{givename name=""booze""}",`,`,` -,,,,,,,,,`,`,`,,`,`,`,"{givename name=""seeds""}","{givename name=""potash""}",,`,`,`,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,preparedfood -,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,"{givename name=""prepared food""}",`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,` -,,,,,,`,`,`,pots,,`,,`,`,`,`,`,,`,`,`,`,` -,,,,,,`,`,`,"{givename name=""pots""}",,`,,seeds,nocontainers,"{givename name=""seeds feeder""}",give2up,`,,`,,`,`,` -,,,bags,,,`,`,`,`,,`,,`,`,`,`,`,,` -,,`,nocontainers,"{givename name=""bags""}",,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,jugs,,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,nocontainers,"{givename name=""jugs""}",,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,plants,,,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,,,,,,,"{givename name=""cookable food""}" -,,`,,,,"{givename name=""plants""}",`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,forbidplants,,,,,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,forbidtallow,,,,,`,` -,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,forbiddye,,,,`,`,` -,,`,`,`,`,`,`,`,`,,,unpreparedfish,,,,,,rawhides,,,`,forbidunpreparedfish,,,,,,` -,,`,`,`,`,`,`,`,`,,`,nocontainers,,,`,,,"{givename name=""rawhides""}",`,,`,forbidmiscliquid,,,,,,` -,,`,`,`,`,`,`,`,,,`,"{givename name=""unprepared fish""}",,forbidcraftrefuse,"{givename name=""refuse feeder""}",corpses,,t{Left 3}{Down 4}&,`,,,forbidpreparedfood,,,,,,` -,,`,`,`,`,`,`,`,,`,`,`,,forbidcorpses,"{give move=""{Right 3}{Up}""}","{givename name=""corpse feeder""}",,`,`,`,,forbidbooze,,,,,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,forbidseeds,,,,,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,"{quantumstop name=""Refuse/Corpse quantum"" sp_links=""{sp_link move={Up} move_back={Down}}{sp_link move=""""{Right}{Up}"""" move_back=""""{Down}{Left}""""}""}{givename name=""refuse/corpse dumper""}",,,`,`,`,,forbidwax,,,,`,`,` -,,,,,,,,,,,,,,,"{quantum name=""refuse/corpse quantum""}" - - -#query label(farming_link) start(16; 18) hidden() set farming stockpiles to take from starting surface stockpiles - - -,,,,,,,,,`,`,`,,`,`,`,t{Down 6}{Left 10}<&,`,,t{Down 6}{Left 13}<&,`,`,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,t{Down 2}{Left 14}<&,`,` -,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,` -,,,,,,`,`,`,t{Up 2}{Right 11}<&,,`,,`,`,`,`,`,,`,`,`,`,` -,,,,,,`,`,`,`,,`,,t{Up 3}{Left 7}<&,`,`,`,`,,`,,`,`,` -,,,t{Up 4}{Right 17}<&,`,,`,`,`,`,,`,,`,`,`,`,`,,` -,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,t{Up 6}{Right 17}<&,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,t{Up 9}{Right 4}<&,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,t{Up 9}{Left 13}<&,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,,t{Up 13}{Left 6}<&,`,`,`,`,`,`,,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,,t{Up 15}{Right 10}<&,`,`,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,` - - -#query label(farming_rooms) start(16; 18) hidden() message(Check to ensure the lower office got assigned to your manager and assign the upper office to your bookkeeper (if different from your manager).) configure rooms - - -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,r&,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,r+&h -,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,r&a+&,,,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,r&d -,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,`,` -,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,` -,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` -,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,` - - -"#build label(farming_build2) start(16; 18) hidden() farm plots, remaining furniture, and important doors" - - -,,,,,,,,,`,`,`,,p(3x1),,,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,p(3x1),,,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,p(3x1),,,`,`,,c,t,~,~ -,,,,,,,,,,,`,,p(3x1),,,`,`,,c,t,t,c -,,,,,,,`,`,`,,`,,p(3x1),,,`,`,,`,`,`,` -,,,,,,,`,`,`,`,`,,p(3x1),,,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,p(3x1),,,`,`,,` -,,,,,,,,,,,`,,p(3x1),,,`,`,,`,,b,b,~ -,,,,,,`,`,`,`,,`,,p(3x1),,,`,`,,`,`,`,`,h -,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,b,b,b -,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` -,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,,`,d,`,`,`,d,`,,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,`,`,,,d,,,`,`,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,` - - -#query label(farming_query_plots) start(16; 18) hidden() configure farm plots for seasonal fertilization - - -,,,,,,,,,`,`,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,,,,,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,`,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,s,`,`,`,`,,` -,,,,,,,,,,,`,,s,`,`,`,`,,`,,`,`,` -,,,,,,`,`,`,`,,`,,s,`,`,`,`,,`,`,`,`,` -,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,` -,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` -,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,` - - -#build label(farming_build3) start(16; 18) hidden() remaining doors - - -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,~,~,~,~ -,,,,,,,,,,,d,,`,`,`,`,`,,~,~,~,~ -,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,d,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,d -,,,,,,,,,,,`,,`,`,`,`,`,,`,,~,~,~ -,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,d,`,`,~ -,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,~,~,~ -,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` -,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,`,`,d,`,`,`,`,d,`,,,d,,d,,,`,d,`,`,`,d,`,`,` -,,,`,`,,`,`,`,`,,`,d,`,`,`,`,`,d,`,,`,`,`,,`,`,` -,,,,d,,,d,,,,,,`,`,`,`,`,,,,,d,,,,d -,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,,,,d,,d,,,,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,,`,~,`,`,`,~,`,,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,`,`,,,~,,,`,`,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,` - - -#notes label(industry_help) -Sets up workshops for all non-farming industries -Screenshot: https://drive.google.com/file/d/1emMaHHCaUPcdRbkLQqvr-0ZCs2tdM5X7 -"" -Features: -- Space-efficient layout for all workshops -- Manager orders that automate basic fortress maintenance -"- Space available underneath the forge and smelters for magma, allowing the starting forge and smelters to be eventually replaced by magma versions." -- Quantum stockpiles for compact storage -with separate stockpiles for: -- A reserve of uncut gems for strange moods that the jeweler's workshop cannot take from -"- Wood, steel bars, and coal so you can see at a glance if you're low on stock" -- Items that cannot be quantum stockpiled (e.g. lye and sand bags) -- Meltable weapons and armor -"" -Workshops: -- 2x Mason -- 4x Craftsdwarf -- 1x Jeweler -- 1x Mechanic -- 4x Smelter -- 1x Forge -- 1x Glassmaker -- 1x Kiln -- 4x Wood furnace -- 1x Ashery -- 1x Soap maker -- 1x Carpenter -- 1x Siege workshop -- 1x Bowyer -- 1x Dyer -- 1x Loom -- 1x Clothier -"" -"" -Manual steps you have to take: -- Assign minecarts to your quantum stockpile hauling routes -"- Give from the ""Goods"" quantum stockpile to the jugs, pots, and bags stockpiles on the farming level" -- Copy the fort automation manager orders (the .json files) from hack/examples/orders/ and put them in your dfhack-config/orders/ directory. -"" -Optional manual steps you can take: -- Restrict the Mechanic's workshop to only allow skilled workers so unskilled trap-resetters won't be tasked to build mechanisms. -"- Restrict the Craftsdwarf's workshops to only allow labors that take from the adjacent stockpiles. That is, only allow Woodcrafting for the Craftsdwarf's workshop on the left near the wood stockpile, Stonecrafting for the Craftsdwarf's workshop near the Mason's workshops, and Bonecrafting for one of the Craftsdwarf's workshop near the Clothier's workshop. The last Craftdwarf's workshop can hold all the remaining labors, or it can be a secondary workshop for a labor that you want more dwarves working on." -"- To encourage your masons to concentrate on building blocks and other high-volume orders, it helps to set one of your Mason's workshops to service a maximum of 2 manager orders at a time." -"- Once you have enough haulers, you can increase the rate of stone and ore hauling jobs by building more wheelbarrows and adding them to the stone and ore feeder stockpiles." -"- If desired, set one or both stockpiles in the bottom left to auto-melt. This results in melting all weapons and armor that are inferior to masterwork. This is great for upgrading your military, but it takes a *lot* of fuel unless you have first replaced the forge and smelters with magma versions. If you enable automelt and you don't have magma forges and magma smelters, be sure to be in a heavily forested area, enable auto-chop, and keep your coal stocks high." -"" -Industry Walkthrough: -"1) Start digging out /industry1 as soon as you find a stone layer at least two layers beneath the surface so the boulders can be used by your starting workshops. The services level is intended to be dug beneath this one, and there is space on that level to route magma underneath your furnaces so you can replace the furnaces on this level with magma-powered equivalents." -"" -"2) Queue up manufacturing by running ""quickfort orders"" on /industry2. You brought an anvil with you (right??), so you can remove the unneeded anvil work order from the manager orders screen (j-m). Note that stockpiles that accept containers may claim the barrels you need to build the Dyer's Workshop and Ashery. If you see those two buildings not being constructed, build a few extra barrels or run combine-plants and combine-drinks to free up some existing ones." -"" -"3) Once the area is dug out, run /industry2. Remember to assign minecarts to to your quantum stockpile hauling routes, and if the farming level is already built, give from the ""Goods"" quantum stockpile (the one on the left) to the jugs, pots, and bags stockpiles on the farming level." -"" -"4) Once you have enough dwarves to do maintenance tasks (that is, after the first or second migration wave), run ""orders import basic"" to use the provided basic.json to take care of your fort's basic needs, such as food, booze, and raw material processing." -"" -"5) If you want to automatically melt goblinite and other low-quality weapons and armor, mark the south-east stockpiles for auto-melt. If you don't have a high density of trees to make into charcoal, though, be sure to route magma to the level beneath this one and replace the forge and furnaces with magma equivalents." -"" -"6) Once you have magma furnaces (or abundant fuel) and more dwarves, run ""orders import furnace"", ""orders import military"", and ""orders import smelting"" to import the remaining fort automation orders. The military orders are optional if you are not planning to have a military, of course." -"" -"7) At any time, feel free to build extra workshops or designate custom stockpiles in the unused space in the top and bottom right. The space is there for you to use!" -"#dig label(industry1) start(18; 18; central stairs) message(Once the area is dug out, continue with /industry2.)" - - -,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,,,d,,d,,,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,,d,`,`,`,d,,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,,,d,,d,,,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d - - -"#meta label(industry2) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) build workshops and stockpiles, configure stockpiles" -build/industry_build -place/industry_place -query/industry_query -#build label(industry_build) start(18; 18) hidden() - - -,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,wj,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,wr,`,`,`,`,`,`,`,wt,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,trackstopN,`,`,`,`,`,`,`,`,ws,`,`,`,` -,,,,`,`,wS,`,`,wb,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,wm,`,`,`,`,`,`,`,wm,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,wy,`,`,ew,`,`,ew,`,`,`,`,`,`,`,`,`,`,`,`,`,wk,`,`,wo,`,`,wd,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,,,d,,d,,,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,d,`,,,,`,d,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,wc,`,`,`,trackstopW,`,`,`,`,`,,`,,`,,`,,`,`,`,`,`,trackstopE,`,`,`,we,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,d,`,,,,`,d,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,,,d,,d,,,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,wr,`,`,ew,`,`,ew,`,`,`,`,`,`,`,`,`,`,`,`,`,wr,`,`,wr,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,trackstopS,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,eg,`,`,`,wf,`,`,`,ek,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` - - -#place label(industry_place) start(18; 18) hidden() - - -,,,,,,,,,,,e,e,e,e,e,e,e,e,e,e,e,e,e -,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,c,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,s4(5x4),,,~,~,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,`,`,`,`,`,`,e(5x1),,,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,w(2x5),,fg(3x3),,`,,`,`,`,`,`,,rhlS(5x5),,,~,~,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,~,~,~,~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,` -,,`,`,`,`,`,c,`,~,~,~,~,~,,`,,`,,`,,~,~,~,~,~,`,r,`,`,`,`,` -,,f2,`,`,`,`,`,`,~,~,u2(3x2),~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,` -,,f2,`,`,`,`,`,`,~,~,~,~,~,,`,`,`,`,`,,~,~,~,~,~,`,`,`,`,`,`,` -,,f2,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,` -,,f2,`,`,`,`,`,`,`,`,`,`,`,`,bnpdz(5x3),,,,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,f2,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,f2,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,pd(7x3),,,~,~,~,~,`,`,`,`,s2(5x2),,,~,~,`,`,`,`,`,`,`,`,`,`,` -,,,,~,~,~,~,~,~,~,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,` -,,,,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,b,`,c,`,b,`,`,`,`,`,`,`,`,`,`,` -,,,,pd(7x3),,,~,~,~,~,`,`,`,`,b,b,b,b,b,`,`,`,`,`,`,`,`,`,`,` -,,,,~,~,~,~,~,~,~,`,`,`,`,b,`,`,`,b,`,`,`,`,`,`,`,`,`,`,` -,,,,~,~,~,~,~,~,~,`,`,`,`,b,`,`,`,b,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,u(6x1),,,~,~,~,`,b(6x1),,,~,~,~ - - -"#query label(industry_query) start(18; 18) hidden() message(remember to: -- assign minecarts to to your quantum stockpile hauling routes -- if the farming level is already built, give from the ""Goods"" quantum stockpile to the jugs, pots, and bags stockpiles on the farming level -- if you want to automatically melt goblinite and other low-quality weapons and armor, mark the south-east stockpiles for auto-melt -- once you have enough dwarves, run ""orders import basic"" to automate your fort's basic needs (see /industry_help for more info on this file) -- optionally, restrict the labors for your Craftsdwarf's and Mechanic's workshops as per the guidance in /industry_help)" - - -,,,,,,,,,,,roughgems,,,,nocontainers,"{givename name=""rough gems for moods""}",t{Down 5}&,,,,,~,~ -,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,"{quantum name=""stoneworker quantum""}g{Up 3}&",`,`,`,~,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"{quantumstop name=""Stoneworker quantum"" sp_links=""{sp_link move={Down} move_back={Up}}{sp_link move=""""{Down 5}"""" move_back=""""{Up 5}""""}""}{givename name=""stoneworker dumper""}",`,`,`,`,`,`,`,`,~,`,`,`,` -,,,,`,`,~,`,`,~,`,`,`,`,`,otherstone,,,,~,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,~,`,"{givename name=""stone feeder""}",~,~,~,~,`,~,`,`,`,`,`,`,`,`,` -,,"{givename name=""wood""}",`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,~,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,~,`,~,`,`,~,`,`,~,`,`,`,`,nocontainers,"{givename name=""gem feeder""}",~,~,~,`,`,`,`,~,`,`,~,`,`,~,`,` -,,~,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,` -,,~,`,`,`,`,`,`,"{givename name=""wood feeder""}",~,"{givename name=""goods feeder""}",nocontainers,~,,`,`,`,`,`,,craftrefuse,,,,~,`,`,`,`,`,`,` -,,t{Right 5}{Down}&,`,`,`,`,`,`,~,~,{tallow}{permitdye}{permitwax},~,~,`,`,,,,`,`,"{givename name=""cloth/bones feeder""}",~,~,~,~,`,`,`,`,`,`,` -,,`,`,~,`,`,"{quantum name=""goods/wood quantum""}g{Up 13}{Right 10}&","{quantumstop name=""Goods/Wood quantum"" sp_links=""{sp_link move={Right} move_back={Left}}{sp_link move=""""{Right 5}"""" move_back=""""{Left 5}""""}{sp_link move=""""{Down}{Right 5}"""" move_back=""""{Left 5}{Up}""""}""}{givename name=""goods/wood dumper""}",~,~,{forbidcrafts}{forbidgoblets},~,~,,`,,`,,`,,nocontainers,~,~,~,~,"{quantumstopfromwest name=""Clothier/Bones quantum""}{givename name=""cloth/bones dumper""}","{quantum name=""cloth/bones quantum""}",`,`,~,`,` -,,miscliquid,`,`,`,`,`,`,~,~,"{givename name=""furniture feeder""}",~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,` -,,"{givename name=""miscliquid""}",`,`,`,`,`,`,~,~,forbidsand,~,~,,`,`,`,`,`,,~,~,~,~,~,`,`,`,`,`,`,` -,,~,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,` -,,~,`,~,`,`,~,`,`,~,`,`,`,`,forbidpotash,nocontainers,"{givename name=""bar/military feeder""}",~,~,`,`,`,`,~,`,`,~,`,`,`,`,` -,,~,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,~,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,nocontainers,t{Right 12}{Up 3}&,t{Right 11}{Down 3}&,"{givename name=""meltable steel/brnze""}",,,,`,`,~,`,forbidotherstone,,,,,`,~,`,`,`,`,`,`,`,`,` -,,,,{bronzeweapons}{permitsteelweapons}{forbidmasterworkweapons}{forbidartifactweapons},,,,,,,`,`,`,`,"{givename name=""ore/clay feeder""}",~,~,~,~,`,`,`,`,`,`,`,`,`,`,` -,,,,{bronzearmor}{permitsteelarmor}{forbidmasterworkarmor}{forbidartifactarmor},,,,,,,`,`,`,`,`,`,"{quantumstop name=""Metalworker quantum"" sp_links=""{sp_link move={Up} move_back={Down}}{sp_link move=""""{Up 5}"""" move_back=""""{Down 5}""""}""}{givename name=""metalworker dumper""}",`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,"{quantum name=""metalworker quantum""}",`,`,`,~,`,`,`,`,`,`,`,`,` -,,,,nocontainers,t{Right 12}{Up 7}&,t{Right 11}{Up 1}&,"{givename name=""other meltables""}",,,,`,`,`,`,coal,"{givename name=""coal""}",t{Up}&,nocontainers,`,`,`,`,`,`,`,`,`,`,`,` -,,,,{metalweapons}{forbidbronzeweapons}{forbidsteelweapons}{forbidmasterworkweapons}{forbidartifactweapons},,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,{metalarmor}{forbidbronzearmor}{forbidsteelarmor}{forbidmasterworkarmor}{forbidartifactarmor},,,,,,,`,`,~,`,`,`,~,`,`,`,~,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,sand,"{givename name=""sand bags""}",nocontainers,~,~,~,`,t{Up 5}{Left}&,,,nocontainers,steelbars,"{givename name=""steel""}" - - -#notes label(services_help) -"Sets up public services (dining, hospital, etc.)" -Screenshot: https://drive.google.com/file/d/13vDIkTVOZGkM84tYf4O5nmRs4VZdE1gh -"" -Features: -- Spacious dining room (also usable as a tavern) -- Prepared food and drink stockpiles -- Well cistern system (bring your own water) -- Hospital with a well for washing -- Garbage dump -- Empty space for magma to power forges and smelters in the industry level above -"" -Note the hospital also has animal training enabled so it can be used with the dwarfvet plugin if it's enabled. -"" -Manual steps you have to take: -"- If you want to declare the dining room as a tavern, the bedrooms at the top can be assigned to the tavern as rented rooms." -"- Fill the cisterns with water, either with a bucket brigade or by plumbing flowing water. Fill so that there are two z-levels of 7-depth water to prevent muddiness. If you want to fill with buckets, designate a pond zone on the level below the main floor. If you feel adventurous and are experienced with water pressure, you can instead route (depressurized!) water to the second-to-bottom level (the one above the up staircases)." -"- If you are filling the wells with a bucket brigade and at least one well is already constructed, you'll run into issues with the dwarves stealing water from the wells to fill the wells. Temporarily deconstruct the wells or temporarily build grates beneath the wells to block the buckets to avoid this issue. Remember to rebuild the wells or remove the grates afterwards, though!" -"" -Services Walkthrough: -1) Start this level when your fort grows to about 50 dwarves so everyone has a place to eat. -"" -2) Start digging with /services1. Note that this digs out the main level and three levels below for the wells. -"" -"3) Once the area is dug out, set up important furniture, stockpiles, hospital zone and garbage dump zone with /services2. Run ""quickfort orders"" for /services2." -"" -"4) When the table and chair have been placed in the dining room and the weapon rack and archery targets have been constructed in the barracks, run /services3 to build the rest of the furniture and configure your dining room and barracks. Run ""quickfort orders"" for /services3." -"" -5) Fill the wells with either bucket brigades or by carefully routing flowing water. -"" -"6) When your fort is mature enough to need jail cells, run /services4 to set those up -- anytime after the restraints are built in the jail cell block. You also get some decorative statues to increase the value of your dining hall. Run ""quickfort orders"" for /services4." -"#dig label(services1) start(23; 22; central stairs) message(Once the area is dug out, continue with /services2.)" - - -,,,,d,d,d,,,d,d,d,,,d,d,d -,,,,d,d,d,,,d,d,d,,,d,d,d -,,,,d,d,d,,,d,d,d,,,d,d,d -,,,,,d,,,,,d,,,,,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,h,d,,j,,d,h,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,h,d,,d,,d,h,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,d,,d,,,,,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,d,d,,,,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,d,`,`,`,d,,,,d,d,d,d,h,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,d,d,,,,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,d,,,,,,d,d,d,d,d,d,d,d,d -,,,,,,,,d,d,,d,d,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,,d,d,d,d,d,d,,,,,,,,,,,,d,d,d,d,d,d,d,d,d -,,,,d,d,d,d,d,d,,d,d,d,d,d,d -,,,,d,d,d,d,d,d,,d,d,d,d,d,d -,,,,d,d,d,d,d,d,,d,d,d,d,d,d -,,,,d,d,d,d,d,d,,d,d,d,d,d,d -#> - - - - - - -,,,,,,,,,,,,,,,,,,j5,h5,j,,u,,j,h5,j5 -,,,,,,,,,,,,,,,,,,5,5,5,5,d,5,5,5,5 -,,,,,,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,,j5,h5,j,,d,,j,h5,j5 -,,,,,,,,,,,,,,,,,,5,5,5,5,d,5,5,5,5 -,,,,,,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d -,,,,,,,,,,,,,,,,,,,,,,6,,,,,,,,,,d -,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,,,,d -,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,,,,,,,,d -,,,,,,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,5,5,5 -,,,,,,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,j,h5,j5 -,,,,,,,,,,,,,,,,,,,,d,`,`,`,d -,,,,,,,,,,,,,,,,,,,,d,d,d,d,d - - -#> - - - - - - -,,,,,,,,,,,,,,,,,,u5,h5,i,,,,i,h5,u5 - - - -,,,,,,,,,,,,,,,,,,u5,h5,i,,,,i,h5,u5 - - - - - - - - -,,,,,,,,,,,,,,,,,,,,d,d,d,d,d -,,,,,,,,,,,,,,,,,,,,d,`,`,`,d -,,,,,,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,i,h5,u5 -,,,,,,,,,,,,,,,,,,,,d,`,`,`,d -,,,,,,,,,,,,,,,,,,,,d,d,d,d,d -#> - - - - - - -,,,,,,,,,,,,,,,,,,,d,u,,,,u,d - - - -,,,,,,,,,,,,,,,,,,,d,u,,,,u,d - - - - - - - - -,,,,,,,,,,,,,,,,,,,,d,d,d,d,d -,,,,,,,,,,,,,,,,,,,,d,`,`,`,d -,,,,,,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,,u,d -,,,,,,,,,,,,,,,,,,,,d,`,`,`,d -,,,,,,,,,,,,,,,,,,,,d,d,d,d,d - - -"#meta label(services2) start(central stairs) message(Remember to enqueue manager orders for this blueprint. -Once furniture has been placed, continue with /services3.) dining hall anchors, stockpiles, hospital, garbage dump" -build/services_build -place/services_place -zones/services_zones -name_zones/services_name_zones -query_stockpiles/services_query_stockpiles -"" -"#meta label(services3) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) configure dining room, build dining hall and hospital furniture" -query_dining/services_query_dining -build2/services_build2 -"" -#meta label(services4) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) complete jail and build decorative furniture -build3/services_build3 -place_jail/services_place_jail -query_jail/services_query_jail -#build label(services_build) start(23; 22) hidden() build basic hospital and dining room anchor - - -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,,`,,,,,`,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,d -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,A,A,A,`,A,A,A,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,r,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,b,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,h,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,d,,d,,,,,`,`,`,`,`,`,t,`,` -,,,,`,`,`,`,t,c,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,R -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,l,`,`,`,R -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,R -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,h,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,`,`,,`,`,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,`,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` - - -#place label(services_place) start(23; 22) hidden() - - -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,,`,,,,,`,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,z(7x2),`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,`,`,,`,`,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,f(6x5),`,`,`,`,`,,f(6x5),`,`,`,`,`,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` - - -"#zone label(services_zones) start(23; 22) hidden() message(If you'd like to fill your wells via bucket brigade, activate the inactive pond zones one level down from where the wells will be built.) hospital, garbage dump, and pond zones" - - -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,,`,,,,,`,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,ht(9x11),`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,d,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,`,`,,`,`,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,`,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -#> - - - - - - -,,,,,,,,,,,,,,,,,,`,apPf,`,,`,,`,apPf,` -,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,`,apPf,`,,`,,`,apPf,` -,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,`,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,apPf,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,` - - -#query label(services_name_zones) start(23; 22) hidden() - - -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,,`,,,,,`,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,"{namezone name=""hospital""}" -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,"{namezone name=""garbage dump""}",,,,,,,,,,,,,,` -,,,,,,,,`,`,,`,`,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,`,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -#> - - - - - - -,,,,,,,,,,,,,,,,,,`,"{namezone name=""jail3 well""}",`,,`,,`,"{namezone name=""jail4 well""}",` -,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,`,"{namezone name=""jail1 well""}",`,,`,,`,"{namezone name=""jail2 well""}",` -,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,`,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,"{namezone name=""hospital well""}",` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,` - - -#query label(services_query_stockpiles) start(23; 22) hidden() message(Configure the training ammo stockpile to take from the metalworker quantum on the industry level.) configure stockpiles - - -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,,`,,,,,`,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,nocontainers,{bolts}{forbidmetalbolts}{forbidartifactammo},"{givename name=""training bolts""}",`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,`,`,,`,`,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,preparedfood,"{givename name=""prepared food""}",`,`,`,`,,booze,"{givename name=""booze""}",`,`,`,`,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` - - -#query label(services_query_dining) start(23; 22) message(the bedrooms above the tavern are left unconfigured so you can add them as rented rooms) set up dining room and barracks - - -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,,`,,,,,`,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,r&w,r&w,r&w,`,r&w,r&w,r&w,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,r+++&,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,"r{+ 11}&h{givename name=""grand hall""}",,,,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,`,`,,`,`,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,`,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` - - -"#build label(services_build2) start(23; 22) hidden() build rest of hospital and dining room, doors, prep for jail" - - -,,,,b,b,b,,,b,b,b,,,b,b,b -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,f,`,h,,,f,`,h,,,f,`,h -,,,,,d,,,,,d,,,,,d -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,v,`,d,`,d,`,v,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,v,`,d,`,d,`,v,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,~ -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,b,~,~,~,`,~,~,~,b -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,b,`,`,`,~,`,`,`,b -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,b,`,`,`,a,`,`,`,b,,f,`,`,`,`,b,~,b,b -,,,,`,`,c,t,t,c,`,c,t,t,c,`,`,,h,`,`,`,`,`,`,`,h,,~,`,`,`,`,`,`,`,b -,,,,`,`,c,t,t,c,`,c,t,t,c,`,`,,,,,~,,~,,,,,f,`,`,`,`,`,~,`,b -,,,,`,`,c,t,~,~,`,c,t,t,c,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,c,t,t,c,`,c,t,t,c,`,`,~,`,d,`,`,`,`,`,d,`,d,`,`,`,`,`,`,`,`,~ -,,,,`,`,c,t,t,c,`,c,t,t,c,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,~ -,,,,`,`,c,t,t,c,`,c,t,t,c,`,`,~,`,d,`,`,`,`,`,d,`,d,`,`,`,`,`,`,`,`,~ -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,h,`,`,~,`,`,`,`,`,h,`,`,h,,,,,,`,,,,,,f,`,`,`,`,`,t,`,b -,,,,,,,,`,`,,`,`,,,,,,,,,,,,,,,,h,`,`,`,`,`,`,`,b -,,,,`,`,`,`,`,`,,`,`,`,`,`,`,,,,,,,,,,,,f,`,`,`,`,b,b,b,b -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` - - -#> - - - - - - -,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,` -,,,,,,,,,,,,,,,,,,`,`,`,d,`,d,`,`,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,` -,,,,,,,,,,,,,,,,,,`,`,`,d,`,d,`,`,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,,,,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,,d -,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,`,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,`,`,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,` -,,,,,,,,,,,,,,,,,,,,`,`,`,`,` - - - - -"#build label(services_build3) start(23; 22) hidden() jail, statues" - - -,,,,~,~,~,,,~,~,~,,,~,~,~ -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,~,`,~,,,~,`,~,,,~,`,~ -,,,,,~,,,,,~,,,,,~ -,,,,s,`,`,s,s,`,`,`,s,s,`,`,s,,t,l,b,,`,,t,l,b -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,c,~,`,~,`,~,c,~,` -,,,,s,`,`,`,`,`,`,`,`,`,`,`,s,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,s,`,`,`,`,`,`,`,`,`,`,`,s,,t,l,b,,`,,t,l,b -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,c,~,`,~,`,~,c,~,` -,,,,s,`,`,`,`,`,`,`,`,`,`,`,s,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,~ -,,,,s,`,`,`,`,`,`,`,`,`,`,`,s,,~,`,`,`,`,`,`,`,~ -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,~,`,`,`,~,`,`,`,~ -,,,,s,`,`,`,`,`,`,`,`,`,`,`,s,,~,`,`,`,~,`,`,`,~,,~,`,s,s,`,~,~,~,~ -,,,,`,`,~,~,~,~,`,~,~,~,~,`,`,,~,`,`,`,`,`,`,`,~,,~,`,`,`,`,`,`,`,~ -,,,,s,`,~,~,~,~,`,~,~,~,~,`,s,,,,,~,,~,,,,,~,`,`,`,`,`,~,`,~ -,,,,`,`,~,~,~,~,`,~,~,~,~,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,s,`,~,~,~,~,`,~,~,~,~,`,`,~,`,~,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,~ -,,,,`,`,~,~,~,~,`,~,~,~,~,`,`,,,,`,`,`,`,`,,,,`,`,`,`,~,`,`,`,~ -,,,,s,`,~,~,~,~,`,~,~,~,~,`,`,~,`,~,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,~ -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,~,s,s,~,`,`,`,`,`,~,s,s,~,,,,,,`,,,,,,~,`,`,`,`,`,~,`,~ -,,,,,,,,`,`,,`,`,,,,,,,,,,,,,,,,~,`,`,`,`,`,`,`,~ -,,,,`,`,`,`,`,`,,`,`,`,`,`,`,,,,,,,,,,,,~,`,s,s,`,~,~,~,~ -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` - - -#place label(services_place_jail) start(23; 22) hidden() - - -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,,`,,,,,`,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,f(1x2),`,`,`,`,`,f(1x2) -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,f(2x1),`,`,,`,,f(2x1),`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,f(1x2),`,`,`,`,`,f(1x2) -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,f(2x1),`,`,,`,,f(2x1),`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,`,`,,`,`,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,`,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` - - -#query label(services_query_jail) start(23; 22) hidden() set up barracks and jail - - -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,`,`,`,,,`,`,`,,,`,`,` -,,,,,`,,,,,`,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,"r--&j{givename name=""jail3""}","{booze}{givename name=""booze""}",`,`,`,`,"r--&j{givename name=""jail4""}","{booze}{givename name=""booze""}" -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,"{preparedfood}{givename name=""prepared food""}",t{Down 4}&,t{Down 4}&,,`,,"{preparedfood}{givename name=""prepared food""}",t{Down 4}&,t{Down 4}& -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,"r--&j{givename name=""jail1""}","{booze}{givename name=""booze""}",`,`,`,`,"r--&j{givename name=""jail2""}","{booze}{givename name=""booze""}" -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,"{preparedfood}{givename name=""prepared food""}",t{Down 14}{Left 10}&,t{Down 14}{Left 4}&,,`,,"{preparedfood}{givename name=""prepared food""}",t{Left 6}&,t{Left 6}& -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,`,`,,`,`,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,`,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` -,,,,`,`,`,`,`,`,,`,`,`,`,`,` - - -#notes label(guildhall_help) -"Eight 7x7 rooms for guildhalls, temples, libraries, etc." -Screenshot: https://drive.google.com/file/d/17jHiCKeZm6FSS-CI4V0r0GJZh09nzcO_ -"" -Features: -"- Big empty rooms. Double-thick walls to ensure engravings add value to the ""correct"" side. Fill with furniture and assign as needed." -"" -Guildhall Walkthrough: -1) Dig out the rooms with /guildhall1. -"" -"2) Once the area is dug out, add in generic furniture with /guildhall2. Run ""quickfort orders"" for /guildhall2." -"" -"3) Furnish individual rooms manually and declare appropriate locations as you need guildhalls, libraries, and temples. If you need more rooms, you can dig another /guildhall1 in an unused z-level." -"#dig label(guildhall1) start(15; 15; central stairs) message(Once the area is dug out, continue with /guildhall2.)" - - -,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,3,3,3,3,3,3,3,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,d,d,3,d,d,d,d,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,d,d,3,d,d,d,d,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,d,d,3,d,d,d,d,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,3,d,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,d,d,3,d,d,d,d,,,d,d,d,d,d,d,d -,,,,,,,d,,,,,,3,,d,,,,,,d -,,,,,,,d,,,,,,3,d,d,,,,,,d -,,d,d,d,d,d,d,d,,,,,3,,d,,,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,,3,3,3,3,3,,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,3,`,`,`,3,3,3,3,3,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,d,,3,`,`,`,3,,d,,3,3,3,3,3,d,d -,,d,d,d,d,d,d,d,d,d,d,3,`,`,`,3,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,,3,3,3,3,3,,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,,,d,,d,,,,,d,d,d,d,d,d,d -,,,,,,,d,,,,,,d,d,d,,,,,,d -,,,,,,,d,,,,,,d,,d,,,,,,d -,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d -,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d - - -"#build label(guildhall2) start(15; 15; central stairs) message(Remember to enqueue manager orders for this blueprint. -Smooth/engrave tiles, furnish rooms, and declare locations as required.) build basic furniture" - - -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,,,,,,d,,,,,,d,,d,,,,,,d -,,,,,,,d,,,,,,`,s,`,,,,,,d -,,`,`,`,`,`,`,`,,,,,d,,d,,,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,d,`,d,`,,,,`,d,`,d,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,s,,`,,`,,`,,s,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,d,`,d,`,,,,`,d,`,d,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,,,d,,d,,,,,`,`,`,`,`,`,` -,,,,,,,d,,,,,,`,s,`,,,,,,d -,,,,,,,d,,,,,,d,,d,,,,,,d -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` - - -#notes label(beds_help) -Suites for nobles and apartments for the teeming masses -Suites screenshot: https://drive.google.com/file/d/1IBqCf6fF3lw7sHiBE_15Euubysl5AAiS -Apt. screenshot: https://drive.google.com/file/d/1mDQQXG8BnXqasRGFC9R5N6xNALiswEyr -"" -Features: -- Well-appointed suites to satisfy nobles -- Apartments with beds and storage to keep dwarves happy and the fortress clean -- Apartments also serve as burial chambers since dwarves like looking at coffins -- Meta blueprint included for designating 5 levels of apartments for a full 200+ dwarves -"" -Suites Walkthrough: -1) Dig out the suites layer with /suites1. -"" -"2) Once the area is dug out, furnish the suites with /suites2. The rooms are left unconfigured so you can assign them to specific nobles. Each room can serve as a bedroom, a dining hall, an office, and/or a tomb. Run ""quickfort orders"" for /suites2." -"" -Apartments Walkthrough: -"1) Dig out one layer of apartments with /apartments1, or 5 layers at once (enough for 200 dwarves) with /apartments1_stack." -"" -"2) Once a layer is dug out, build beds with /apartments2. Run ""quickfort orders"" for /apartments2." -"" -"3) Once the beds are built, configure the rooms and build the remaining furniture with /apartments3. Run ""quickfort orders"" for /apartments3." -"" -"4) Once the coffins are all in place, run ""burial -pets"" to set them all to accept burials. This is handled for you if you're using the onMapLoad_dreamfort.init file included with DFHack." -"#dig label(suites1) start(18; 18; central ramp) message(Once the area is dug out, run /suites2) noble suites" - -,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,d,d,,,,d,,,,,,d,,,,d,,d,,,,d,,,,,,d,,,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,,,d,,,,,,d,,,,d,d,d,,,,d,,,,,,d,,,,d,d -,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,d,d,,d,d,d,d,d,d,d,d,d,d,,d,`,~,`,d,,d,d,d,d,d,d,d,d,d,d,,d,d -,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,d,d,,,,d,,,,,,d,,,,d,d,d,,,,d,,,,,,d,,,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,,,d,,,,,,d,,,,d,,d,,,,d,,,,,,d,,,,d,d -,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d - -"#build label(suites2) start(18; 18; central ramp) message(Remember to enqueue manager orders for this blueprint. -bedrooms are left unconfigured so you can assign them to specific nobles)" - -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,,,,d,,,,,,d,,,,d,,d,,,,d,,,,,,d,,,,`,` -,`,`,,a,r,`,`,h,,h,`,`,r,a,,`,s,`,,a,r,`,`,h,,h,`,`,r,a,,`,` -,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,` -,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,` -,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,s,`,,c,`,`,`,f,,f,`,`,`,c,,`,` -,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,` -,`,`,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,`,` -,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,n,`,s,`,t,,`,` -,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,` -,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,` -,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,s,`,,`,`,`,`,h,,h,`,`,`,`,,`,` -,`,`,,a,r,`,`,h,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,h,`,`,r,a,,`,` -,`,`,,,,d,,,,,,d,,,,`,`,`,,,,d,,,,,,d,,,,`,` -,`,`,d,`,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,`,d,`,` -,`,`,,s,`,`,s,`,`,s,`,`,s,,`,`,~,`,`,,s,`,`,s,`,`,s,`,`,s,,`,` -,`,`,d,`,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,`,d,`,` -,`,`,,,,d,,,,,,d,,,,`,`,`,,,,d,,,,,,d,,,,`,` -,`,`,,a,r,`,`,h,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,h,`,`,r,a,,`,` -,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,s,`,,`,`,`,`,h,,h,`,`,`,`,,`,` -,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,` -,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,` -,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,n,`,s,`,t,,`,` -,`,`,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,`,` -,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,` -,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,s,`,,c,`,`,`,f,,f,`,`,`,c,,`,` -,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,` -,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,` -,`,`,,a,r,`,`,h,,h,`,`,r,a,,`,s,`,,a,r,`,`,h,,h,`,`,r,a,,`,` -,`,`,,,,d,,,,,,d,,,,d,,d,,,,d,,,,,,d,,,,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` - -#meta label(apartments1_stack) start(central ramp) digs 5 layers of apartments - enough for 200 dwarves -/apartments1 -#> -/apartments1 -#> -/apartments1 -#> -/apartments1 -#> -/apartments1 - -"#dig label(apartments1) start(18; 18; central ramp) message(Once the area is dug out, continue with /apartments2.) apartment complex" - -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d -,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,,d,,,,d,,,,d,,,d,d,d,,,d,,,,d,,,,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,,,,,,,,,,,,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,,d,,d,d,d,,d,d,d,,d,d,d -,,,,,d,,,,d,,,,d,,,d,d,d,,,d,,,,d,,,,d -,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,`,~,`,d,,d,d,d,d,d,d,d,d,d,d,d,d,d -,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,,d,d,d -,,,,,d,,,,d,,,,d,,,d,d,d,,,d,,,,d,,,,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,,,,,,,,,,,,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,,d,,,,d,,,,d,,,d,d,d,,,d,,,,d,,,,d -,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d - -"#build label(apartments2) start(18; 18; central ramp) message(Remember to enqueue manager orders for this blueprint. -Once beds have been placed, continue with /apartments3.) build beds" - -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,`,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,,,,,,,,,,,,`,`,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,`,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` -,`,b,`,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,`,b,` -,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,`,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,,,,,,,,,,,,`,`,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,`,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` - -#meta label(apartments3) start(central ramp) message(Remember to enqueue manager orders for this blueprint.) configure rooms and build remaining furniture -query_apartments/apartments_rooms -build2_apartments/apartments_build2 -#query label(apartments_rooms) start(18; 18) hidden() configure rooms - -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,`,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,,,,,,,,,,,,`,`,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,`,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` -,`,r-&,`,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,`,r-&,` -,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,`,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,,,,,,,,,,,,`,`,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,`,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` - -"#build label(apartments_build2) start(18; 18) hidden() message(Coffins should be configured with DFHack ""burial"" script) build remaining furniture" - -,,,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f -,,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,d,,,,d,,,,d,,,`,s,`,,,d,,,,d,,,,d -,,,,n,`,h,,n,`,h,,n,`,h,,`,`,`,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,`,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,`,s,`,,n,`,f,,n,`,f,,n,`,f -,,,,,,,,,,,,,,,,`,`,` -,,,,n,`,h,,n,`,h,,n,`,h,,`,`,`,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,s,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,d,,d,,n,`,f,,n,`,f,,n,`,f -,,,,,d,,,,d,,,,d,,,`,`,`,,,d,,,,d,,,,d -,n,`,h,,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,,n,`,h -,`,~,`,d,`,`,s,`,`,s,`,`,s,,`,`,~,`,`,,s,`,`,s,`,`,s,`,`,d,`,~,` -,n,`,f,,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,,n,`,f -,,,,,d,,,,d,,,,d,,,`,`,`,,,d,,,,d,,,,d -,,,,n,`,h,,n,`,h,,n,`,h,,d,,d,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,s,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,`,`,`,,n,`,f,,n,`,f,,n,`,f -,,,,,,,,,,,,,,,,`,`,` -,,,,n,`,h,,n,`,h,,n,`,h,,`,s,`,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,`,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,`,`,`,,n,`,f,,n,`,f,,n,`,f -,,,,,d,,,,d,,,,d,,,`,s,`,,,d,,,,d,,,,d -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d -,,,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f - diff --git a/data/blueprints/library/quickfortress.csv b/data/blueprints/library/quickfortress.csv deleted file mode 100644 index edd52788bd..0000000000 --- a/data/blueprints/library/quickfortress.csv +++ /dev/null @@ -1,768 +0,0 @@ -#notes label(help) -"This is Buketgeshud, or translated from Dwarvish, The Quick Fortress. It is a set of basic blueprints for quickfort, demonstrating its use in assembling an entire basic (if incomplete) fort." - -Buketgeshud is designed around a 30x20 footprint with a common 2x2 central staircase. Blueprints can be repeated in any direction to connect in a modular fashion with adjacent 30x20 areas. A fortresswide example recirculating waterfall/plumbing system is included as an overlay if you're feeling hardcore. - -Walkthrough: -1) Embark! - -2) Clear a 30 wide x 20 high region of trees on the surface. This should be uninterrupted flat ground with soil (so that we can place farms below). Deconstruct your wagon. - -"3) Run /surface1. You'll want to put the cursor in the middle of the 30x20 cleared area (14 right, 8 down from the top left corner). This digs out stairs on the surface, a farm/depot/workshop level below, as well as the beginnings of an entrance moat. The beginnings of a 3rd z-level are also dug out; don't build anything here if you'd like to put waterfall plumbing in later." - -"4) After /surface1 is dug out, run /surface2 (beginning from the same starting position as you used for /surface1). This puts down a basic set of workshops commonly needed soon after embark, a couple farm plots, and a depot. It also places and configures starting stockpiles." - -"5) If your embark site is near any enemies, run /surface3 to build walls and traps on the surface to protect against invaders." - -"6) Dig out the central shaft and tunnels for several z-levels below our surface/depot level. Place the cursor THREE Z-levels below the surface, where no digging has occurred yet, and run /basic1 for 6 z-levels down starting from that level." - -"7) Optionally run /basic2 to designate booze-only stockpiles around the central stairs on every z-level below the farming level. The stockpiles are configured to take booze from the level above, so be sure to apply /basic2 on the top level first and work your way down." - -"8) Run workshops, bedrooms, and storeroom blueprints on any desired Z-level along our central shaft." - -"9) If desired, add a fortresswide waterfall system, bathing your dwarves in tile after tile of lovely waterfall mist as they go about their day. Run /waterfall1 on the z-level immediately below your farm/depot level (you left that space empty, didn't you?) and run /plumbing1 on z-levels below that, down to the bottom of your fort. Each application of /plumbing1 will dig out two floors. On the bottommost level, the screw pumps that will be placed there require 2 floor tiles to sit on, so remove or refloor the 2 northern channel designations in the lower right corner on that z-level. You'll also need a reservior in the z-level below that (not included)." - -"10) After all levels are dug out, apply /plumbing2 on the *bottommost* level, just above the reservior. The blueprint will build screw pumps on that level and the level above. Repeat on every alternate level up to the level below where you applied /waterfall1." - -"11) Finally, apply /waterfall2 on the z-level where you applied /waterfall1. Route flowing water to the 2 tiles in lower right." -"#dig label(surface1) start(15;10; top left corner of central stairs) message(The 3rd z-level just digs stairs; if you want to install the waterfall plumbing system later, leave this 3rd level EMPTY for now and start the base proper below that; use /basic1 to dig out areas for future use below.) Surface and farm/depot levels" -`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,,,,,~,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,,h,h,,~,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,,,h,,~,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,h,,h,`,`,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,,,h,h,h,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,,h,h,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,,,,h,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,h,h,h,h,,`,# -`,,,,j,,,,,,,,,,j,j,,,,,,,`,h,,,,,,`,# -`,,,,j,,,,,,,,,,j,j,,,,,,,`,h,,h,h,h,h,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,h,h,h,h,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,h,,h,h,h,h,`,# -`,,,,,,,,,,,,`,~,~,~,~,`,,,,,`,h,,,,,,`,# -`,,,,,,,,,,,,`,~,~,~,~,`,,,,,`,`,h,h,h,h,,`,# -`,,,,,,,,,,,,`,,,,,`,,,,,~,~,,,,,,`,# -`,,,,,,,,,,,,`,,,,,`,,,,,`,`,h,h,h,h,h,`,# -`,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,# -#>,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -d,d,d,d,j,d,d,d,d,d,d,d,d,d,j,j,d,d,d,d,d,d,`,`,`,`,`,`,`,`,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,d,d,d,d,d,`,,,,,,,`,# -`,,,,d,,,,,,,,d,,d,d,,d,,,,,`,,,,,,,`,# -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,`,,,,,,,`,# -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,`,,,,,,,`,# -`,,,,d,,,,d,d,d,d,,d,d,d,d,,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,,d,d,d,d,,d,d,d,d,,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,,,,d,d,,,d,d,,,,,,,`,,,,,,,`,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,,d,d,d,d,,d,d,d,d,d,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,,d,d,d,d,,r,r,r,r,d,d,d,d,d,`,,,,,,,`,# -d,d,d,d,d,d,d,d,d,d,d,d,,~,~,~,~,d,d,d,d,d,`,,,,,,,`,# -`,`,`,`,j,`,`,`,`,`,`,`,`,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,# -#>,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -d,,,,i,,,,,,,,,,i,i,,,,,,,,,,j,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,d,d,,,,,,,,,,,,,,,# -,,,,i,,,,,,,,,d,i,i,d,,,,,,,,,j,,,,,# -,,,,i,,,,,,,,,d,i,i,d,,,,,,,,,j,,,,,# -,,,,,,,,,,,,,,d,d,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,i,,,,,,,,,,j,j,,,,,,,,,,j,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#meta label(surface2) Build basic workshops and stockpiles -/surface2_build -/surface2_place -/surface2_query -/surface2_doors -"#build label(surface2_build) hidden() start(15;10; top left corner of central stairs) Populates the surface and farm/depot levels with farm plots, workshops and a depot" -`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,~,# -`,,,,,,,,wu,,,wr,,,,,,,,,,,`,,,,,,,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,,,,,wn,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,`,~,~,~,~,`,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,`,~,~,~,~,`,,,,,`,,,,,,,`,# -`,,,,,,,,,,,,`,,,,,`,,,,,~,,,,,,,`,# -`,,,,,,,,,,,,`,,,,,`,,,,,`,,,,,,,`,# -`,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,# -#>,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -,,,,`,,,,p(6x7),,,,,,`,`,p(6x7),,,,,,`,`,`,`,`,`,`,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,wl,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,`,`,`,,`,`,`,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,`,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,`,`,`,,,`,`,,,`,`,`,`,`,`,`,,,,,,,`,# -,wc,,,,wm,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,`,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,`,,,,,`,,,,,,,D,,,`,,,,,,,`,# -,wt,,,,wr,,`,,,,,`,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,`,,,,,,,,,,`,,,,,,,`,# -,,,,`,,,`,,,,,`,`,`,`,`,,,,,,`,`,`,`,`,`,`,`,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#place label(surface2_place) hidden() start(15;10; top left corner of central stairs) Lay stockpiles on surface and depot/farm levels -`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# -`,r(6x6),,,,,~,,,,,,,r(3x6),,,r(5x6),,,,,z(1x6),`,`,,,,,~,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,`,`,,~,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,,`,,~,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,,`,`,`,`,# -`,~,,,,,~,,,,,,,~,,,~,,,,,~,`,`,,`,`,,,`,# -`,,,,,,,,,,,,,,,,,,w(4x8),,,,`,`,,,,`,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,`,`,`,`,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,`,`,`,`,`,# -`,u(11x3),,,,,,,,,,,`,~,~,~,~,`,,,,,`,`,,,,,,`,# -`,,,,,,,,,,,,`,~,~,~,~,`,,,,,`,`,`,`,`,`,,`,# -`,,,,,,,,,,,,`,,,,,`,y(4x2),,,,~,~,,,,,,`,# -`,,,,,,,,,,,,`,~,~,~,~,`,,,,,`,`,`,`,`,`,`,`,# -`,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,# -#>,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -f,f,f,f,,f,f,f,,,,,,,`,`,,,,,,,`,`,`,`,`,`,`,`,# -f,f,f,f,f,f,f,f,,,,,,,f(2x6),,,,,,,,`,,,,,,,`,# -f,f,f,f,f,f,f,f,,,,,,,,,,,,,,,`,,,,,,,`,# -f,f,,,,f,f,f,,,,,,,,,,,,,,,`,,,,,,,`,# -f,f,,,,f,f,f,,,,,,,,,,,,,,,`,,,,,,,`,# -f,f,,,,f,f,f,,,,,,,,,,,,,,,`,,,,,,,`,# -f,f,f,f,f,f,f,f,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,`,,,,,,`,`,`,`,,,,,,`,,,,,,,`,# -,,,,`,,,,,,,,`,,f(2x1),,,`,,,,,`,,,,,,,`,# -w(4x2),,,,,f(9x2),,,,,,,,,`,`,f(1x2),,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,`,`,,,,,,,`,,,,,,,`,# -,,,,`,,,,g(4x2),,,,,,f(2x1),,,,,,,,`,,,,,,,`,# -,,,s(1x8),,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,`,`,,,,,,,`,,,,,,,`,# -,,,,,,,,g(4x5),,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,`,,,,,,,,,`,`,`,`,,,,,,`,`,`,`,`,`,`,`,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#query label(surface2_query) hidden() start(15;10; top left corner of central stairs) message(remember to set the farm plots to grow plump helmets) Adjust surface/depot level stockpiles -`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# -`,forbidrawhides,,,,,~,,,,,,,rawhides,,,craftrefuse,,,,,,`,`,,,,,~,~,# -`,forbidcraftrefuse,,,,,,,,,,,,,,,,,,,,,`,`,,`,`,,~,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,,`,,~,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,,`,`,`,`,# -`,~,,,,,~,,,,,,,~,,,~,,,,,~,`,`,,`,`,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,,,`,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,`,`,`,`,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,,,,,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,,`,`,`,`,`,# -`,,,,,,,,,,,,`,~,~,~,~,`,,,,,`,`,,,,,,`,# -`,,,,,,,,,,,,`,~,~,~,~,`,,,,,`,`,`,`,`,`,,`,# -`,,,,,,,,,,,,`,,,,,`,,,,,~,~,,,,,,`,# -`,,,,,,,,,,,,`,,,,,`,,,,,`,`,`,`,`,`,`,`,# -`,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,# -#>,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -forbidseeds,,,,,,,,,,,,,,`,`,,,,,,,`,`,`,`,`,`,`,`,# -,,,,,,,,,,,,,,seeds,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,`,,,,,,`,`,`,`,,,,,,`,,,,,,,`,# -,,,,`,,,,,,,,`,,booze,t{Down}{Left 2}&,,`,,,,,`,,,,,,,`,# -,,,,,booze,,,,,,,,,`,`,booze,,,,,,`,,,,,,,`,# -,,,,,t{Up 5}&,,,,,,,,,`,`,t{Left 3}&,,,,,,`,,,,,,,`,# -,,,,`,,,,,,,,,,booze,t{Up}{Left 2}&,,,,,,,`,,,,,,,`,# -,,,otherstone,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,`,`,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,~,~,~,~,,,,,,`,,,,,,,`,# -,,,,`,,,,,,,,,`,`,`,`,,,,,,`,`,`,`,`,`,`,`,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#build label(surface2_doors) hidden() start(15;10; top left corner of central stairs) Just builds doors on the depot level (just below the surface) -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -#>,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -`,,,,d,,,,,,,,d,,,,,d,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,`,`,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,`,`,,,,,,,`,,,,,,,`,# -`,,,,d,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,d,d,,,d,d,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,d,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,d,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,,,,,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,`,`,`,`,,,,,,`,,,,,,,`,# -,,,,,,,,,,,,,~,~,~,~,,,,,,`,,,,,,,`,# -`,`,`,`,~,`,`,`,`,`,`,`,`,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#meta label(surface3) Build walls and traps to protect against invaders -/surface3_walls -/surface3_traps -#build label(surface3_walls) hidden() start(15;10; top left corner of central stairs) Builds walls and bridges on the surface level. Note that the entrance on the southern wall juts out from the 30x20 footprint by 3 tiles; the southern bridge extends beyond the edge of the blueprint itself.\n\nYou'll need to add and connect levers yourself. -Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,gd(2x3),,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,Cw,Cw,Cw,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,Cw,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,Cw,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,Cw,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,Cw,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,Cw,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,Cw,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,Cw,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,Cw,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,Cw,# -Cw,,,,,,,,,,,,,,,,,,,,,,Cw,,,,,,,Cw,# -Cw,,,,,,,,,,,,Cw,gw(4x2),,,,Cw,,,,,Cw,,,,,,,Cw,# -Cw,,,,,,,,,,,,Cw,,,,,Cw,,,,,Cw,Cw,,,,,,Cw,# -Cw,,,,,,,,,,,,Cw,,,,,Cw,,,,,ga(2x1),,,,,,,Cw,# -Cw,,,,,,,,,,,,Cw,,,,,Cw,,,,,Cw,Cw,,,,,,Cw,# -Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,,,,,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,Cw,# -,,,,,,,,,,,,Cw,,,,,Cw,,,,,,,,,,,,,# -,,,,,,,,,,,,Cw,gw(4x2),,,,Cw,,,,,,,,,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#build label(surface3_traps) hidden() start(15;10; top left corner of central stairs) Put some stone-fall traps down. -`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,Ts,Ts,Ts,,~,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,Ts,`,`,,~,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,Ts,Ts,`,,~,~,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,`,Ts,`,`,`,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,Ts,Ts,`,`,`,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,Ts,`,`,Ts,Ts,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,Ts,Ts,Ts,`,Ts,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,Ts,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,Ts,Ts,Ts,Ts,Ts,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,Ts,`,`,`,`,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,Ts,Ts,Ts,Ts,Ts,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,Ts,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,Ts,Ts,Ts,Ts,Ts,`,# -`,,,,,,,,,,,,,,,,,,,,,,`,`,Ts,`,`,`,`,`,# -`,,,,,,,,,,,,`,~,~,~,~,`,,,,,`,`,Ts,Ts,Ts,Ts,Ts,`,# -`,,,,,,,,,,,,`,~,~,~,~,`,,,,,`,`,`,`,`,`,Ts,`,# -`,,,,,,,,,,,,`,,,,,`,,,,,~,~,Ts,Ts,Ts,Ts,Ts,`,# -`,,,,,,,,,,,,`,,,,,`,,,,,`,`,`,`,`,`,`,`,# -`,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#dig label(basic1) start(15;10; top left corner of central stairs) Common stair/shaft digging for all floors below surface/depot levels -,,,,i,,,,,,,,,,i,i,,,,,,,,,,i,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,d,d,d,i,d,d,d,d,# -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,d,d,d,i,d,d,d,d,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -,,,,i,,,,,,,,,,i,i,,,,,,,,,,i,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#meta label(basic2) Place and configure food/booze stockpiles around the central staircase -/basic2_place -/basic2_query -#place label(basic2_place) hidden() start(15;10; top left corner of central stairs) Places food stockpiles around the central staircase -,,,,`,,,,,,,,,,`,`,,,,,,,,,,`,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,f(2x1),,,,,,,,,,,,,,,,# -,,,,`,,,,,,,,,f(1x2),`,`,f(1x2),,,,,,,,,`,,,,,# -,,,,`,,,,,,,,,,`,`,,,,,,,,,,`,,,,,# -,,,,,,,,,,,,,,f(2x1),,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,`,,,,,,,,,,`,`,,,,,,,,,,`,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -"#query label(basic2_query) hidden() start(15;10; top left corner of central stairs) configures booze stockpiles around stairway, taking from the stockpile on the level above" -,,,,`,,,,,,,,,,`,`,,,,,,,,,,`,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,booze,t<&,,,,,,,,,,,,,,,# -,,,,`,,,,,,,,,booze,`,`,booze,,,,,,,,,`,,,,,# -,,,,`,,,,,,,,,t<&,`,`,t<&,,,,,,,,,`,,,,,# -,,,,,,,,,,,,,,booze,t<&,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,`,,,,,,,,,,`,`,,,,,,,,,,`,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -"#dig label(workshops1) start(15;10; top left corner of central stairs) Just four big rooms, suitable for workshops" -d,d,d,d,i,d,d,d,d,d,d,d,d,,i,i,,d,d,d,d,d,d,d,d,i,d,d,d,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,# -,d,,,d,,,,,,,,d,,d,d,,d,,,,,,,,d,,,,,# -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,d,d,d,i,d,d,d,d,# -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,d,d,d,i,d,d,d,d,# -,d,,,d,,,,,,,,d,,d,d,,d,,,,,,,,d,,,,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,`,`,`,`,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,`,,,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,`,,,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,,,,# -,,,,i,,,,,,,,,,i,i,,,,,,,,,,i,`,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#meta label(workshops2) Build commonly needed workshops and associated stockpiles -/workshops2_build -/workshops2_place -/workshops2_doors -#build label(workshops2_build) hidden() start(15;10; top left corner of central stairs) Sufficient workshops for basic non-food needs -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,wj,,,,we,,,,we,,,`,`,,,es,,,,ew,,,,ek,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,wj,,,,we,,,,we,,,`,`,,,es,,,,eg,,,,wf,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -`,`,`,`,~,`,`,`,`,`,`,`,`,`,~,~,`,`,`,`,`,`,`,`,`,~,`,`,`,`,# -`,`,`,`,~,`,`,`,`,`,`,`,`,`,~,~,`,`,`,`,`,`,`,`,`,~,`,`,`,`,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,wr,,,,wr,,,,wm,,,`,`,,,wc,,,,wc,,,,wb,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -`,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -`,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -`,,,wt,,,,wt,,,,wm,,,`,`,,,wc,,,,wc,,,,,,,,# -`,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -`,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#place label(workshops2_place) hidden() start(15;10; top left corner of central stairs) Workshop source material piles placed around the workshops. -e,e,e,e,,l,l,l,l,l,l,l,l,,`,`,,b,b,b,b,b,b,b,b,,b,b,b,,# -e,e,e,e,e,l,l,l,l,l,l,l,l,,`,`,,b,b,b,b,b,b,b,b,b,b,b,b,,# -e,e,,,,l,,,,l,,,,,`,`,,,,,b,,,,b,,,,b,,# -e,e,,,,l,,,,l,,,,,`,`,,,,,b,,,,b,,,,b,,# -e,e,,,,l,,,,l,,,,,`,`,,,,,b,,,,b,,,,b,,# -,,,,,l,,,,l,,,,,`,`,,,,,b,,,,b,,,,b,,# -,,,,,l,,,,l,,,,,`,`,,,,,b,,,,b,,,,b,,# -,,,,,l,,,,l,,,,,`,`,,,,,b,,,,b,,,,b,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -`,`,`,`,~,`,`,`,`,`,`,`,`,`,~,~,`,`,`,`,`,`,`,`,`,~,`,`,`,`,# -`,`,`,`,~,`,`,`,`,`,`,`,`,`,~,~,`,`,`,`,`,`,`,`,`,~,`,`,`,`,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,w,,,,w,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,w,,,,w,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,w,,,,w,,,,,,# -,,,s(10x1),,,,,,,,,,,`,`,,w,w,w,w,w,w,w,w,w,,,,,# -,,,,,,,,,,,,,,`,`,,,,,w,,,,w,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,w,,,,w,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,w,,,,w,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#build label(workshops2_doors) hidden() start(15;10; top left corner of central stairs) Fill in doors to the workrooms. -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,d,,,d,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,d,,,d,,,,,,,,,,,,,,# -,d,,,d,,,,,,,,d,,,,,d,,,,,,,,d,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,d,,,d,,,,,,,,d,,,,,d,,,,,,,,d,,,,,# -,,,,,,,,,,,,,d,,,d,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,d,,,d,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -"#dig label(storeroom1) start(15;10; Top left corner of central stairs) Just four big rooms, suitable for storerooms" -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,d,d,d,i,d,d,d,d,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# -,,,,d,,,,,,,,d,,d,d,,d,,,,,,,,d,,,,,# -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,d,d,d,i,d,d,d,d,# -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,d,d,d,i,d,d,d,d,# -,,,,d,,,,,,,,d,,d,d,,d,,,,,,,,d,,,,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,,,,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,,,,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,,,,,# -d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,,d,d,d,d,d,d,d,d,d,,,,,# -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,d,d,d,i,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#meta label(storeroom2a) General stockpiles -/storeroom2a_place -/storeroom2_doors -"#meta label(storeroom2b) Extra storage for wood, food and furniture" -/storeroom2b_place -/storeroom2_doors -#place label(storeroom2a_place) hidden() start(15;10; top left corner of central stairs) General stockpiles -g,g,g,g,~,g,l(7x8),,,,,,,,,,,d(7x5),,,,,,,p,~,p,p,p,p,# -g,g,g,g,g,g,,,,,,,,`,,,`,,,,,,,,p,p,p,p,p,p,# -g,g,g,g,g,g,,,,,,,,`,,,`,,,,,,,,p,p,p,p,p,p,# -g,g,g,g,g,g,,,,,,,,`,,,`,,,,,,,,p,p,p,p,p,p,# -g,g,g,g,g,g,,,,,,,,`,,,`,,,,,,,,p,p,p,p,p,p,# -g,g,g,g,g,g,,,,,,,,`,,,`,b(7x3),,,,,,,z(6x3),,,,,,# -g,g,g,g,g,g,,,,,,,,`,,,`,,,,,,,,,,,,,,# -g,g,g,g,g,g,,,,,,,,,,,,,,,,,,,,,,,,,# -`,`,`,`,,`,`,`,`,`,`,`,,`,,,`,,`,`,`,`,`,`,`,,`,`,`,`,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -`,`,`,`,,`,`,`,`,`,`,`,,`,,,`,,`,`,`,`,`,`,`,,`,`,`,`,# -u,u,u,u,u,u,u,u,u,u,u,u,u,,,,,u(7x8),,,,,,,w,w,w,w,w,w,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,,,,,,,,w,w,w,w,w,w,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,,,,,,,,w,w,w,w,w,w,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,,,,,,,,w,w,`,`,`,`,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,,,,,,,,w,w,`,,,,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,,,,,,,,w,w,`,,,,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,,,,,,,,w,w,`,,,,# -u,u,u,u,~,u,u,u,u,u,u,u,u,,,,,,,,,,,,w,~,`,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -"#place label(storeroom2b_place) hidden() start(15;10; top left corner of central stairs) Extra storage for wood, food and furniture" -w,w,w,w,~,w,w,w,w,w,w,w,w,,,,,f,f,f,f,f,f,f,f,~,f,f,f,f,# -w,w,w,w,w,w,w,w,w,w,w,w,w,`,,,`,f,f,f,f,f,f,f,f,f,f,f,f,f,# -w,w,w,w,w,w,w,w,w,w,w,w,w,`,,,`,f,f,f,f,f,f,f,f,f,f,f,f,f,# -w,w,w,w,w,w,w,w,w,w,w,w,w,`,,,`,f,f,f,f,f,f,f,f,f,f,f,f,f,# -w,w,w,w,w,w,w,w,w,w,w,w,w,`,,,`,f,f,f,f,f,f,f,f,f,f,f,f,f,# -w,w,w,w,w,w,w,w,w,w,w,w,w,`,,,`,f,f,f,f,f,f,f,f,f,f,f,f,f,# -w,w,w,w,w,w,w,w,w,w,w,w,w,`,,,`,f,f,f,f,f,f,f,f,f,f,f,f,f,# -w,w,w,w,w,w,w,w,w,w,w,w,w,,,,,f,f,f,f,f,f,f,f,f,f,f,f,f,# -`,`,`,`,,`,`,`,`,`,`,`,,`,,,`,,`,`,`,`,`,`,`,,`,`,`,`,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -`,`,`,`,,`,`,`,`,`,`,`,,`,,,`,,`,`,`,`,`,`,`,,`,`,`,`,# -u,u,u,u,u,u,u,u,u,u,u,u,u,,,,,u,u,u,u,u,u,u,u,u,u,u,u,u,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,u,u,u,u,u,u,u,u,u,u,u,u,u,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,u,u,u,u,u,u,u,u,u,u,u,u,u,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,u,u,u,u,u,u,u,u,u,`,`,`,`,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,u,u,u,u,u,u,u,u,u,`,,,,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,u,u,u,u,u,u,u,u,u,`,,,,# -u,u,u,u,u,u,u,u,u,u,u,u,u,`,,,`,u,u,u,u,u,u,u,u,u,`,,,,# -u,u,u,u,~,u,u,u,u,u,u,u,u,,,,,u,u,u,u,u,u,u,u,~,`,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#build label(storeroom2_doors) hidden() start(15;10; top left corner of central stairs) Build storeroom doors -,,,,,,,,,,,,,d,,,d,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,d,,,d,,,,,,,,,,,,,,# -,,,,d,,,,,,,,d,,,,,d,,,,,,,,d,,,,d,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,d,,,,,,,,d,,,,,d,,,,,,,,d,,,,d,# -,,,,,,,,,,,,,d,,,d,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,d,,,d,,,,,,,,,,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#dig label(bedrooms1) start(15;10; top left corner of central stairs) Bedroom complex -d,d,d,,i,,d,d,d,,d,d,d,,i,i,,d,d,d,,d,d,d,,i,,,,,# -d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,,d,d,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,d,d,,# -d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -d,,d,,d,,d,,d,,d,d,d,d,d,d,d,d,d,d,,d,,d,,d,,d,d,,# -d,,d,,d,,d,,d,,,,,,d,d,,,,,,d,,d,,d,,d,d,,# -d,,d,,d,,d,,d,,,d,d,d,d,d,d,d,d,,,d,,d,,d,d,d,d,,# -d,,d,,d,,d,,d,,d,d,d,d,d,d,d,d,d,d,,d,,d,,d,,,,,# -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,d,d,d,i,d,d,d,d,# -d,d,d,d,i,d,d,d,d,d,d,d,d,d,i,i,d,d,d,d,d,d,d,d,d,i,d,d,d,d,# -d,,d,,d,,d,,d,,d,d,d,d,d,d,d,d,d,d,,d,,d,,d,,,,,# -d,,d,,d,,d,,d,,,d,d,d,d,d,d,d,d,,,d,,d,,d,d,d,d,,# -d,,d,,d,,d,,d,,,,,,d,d,,,,,,d,,d,,d,,d,d,,# -d,,d,,d,,d,,d,,d,d,d,d,d,d,d,d,d,d,,d,,d,,d,,d,d,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,,,,,# -,,,,d,,,,,,,,,,d,d,,,,,,,,,,d,,,,,# -d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,,,,,# -,,,,i,,,,,,,,,,i,i,,,,,,,,,,i,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#build label(bedrooms2) start(15;10; top left corner of central stairs) Bedroom furniture -f,h,h,,,,h,h,f,,f,h,h,,,,,h,h,f,,f,h,h,,,,,,,# -b,,,d,,d,,,b,,b,,,d,,,d,,,b,,b,,,d,,,f,h,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,,# -b,f,h,d,,d,h,f,b,,b,f,h,d,,,d,h,f,b,,b,f,h,d,,d,,b,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -b,,b,,,,b,,b,,b,f,h,d,,,d,h,f,b,,b,,b,,,,f,h,,# -f,,f,,,,f,,f,,,,,,,,,,,,,f,,f,,,,,h,,# -h,,h,,,,h,,h,,,t,t,,,,,,,,,h,,h,,,d,,b,,# -d,,d,,,,d,,d,,,c,c,,,,,,,,,d,,d,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -d,,d,,,,d,,d,,,,,,,,,c,c,,,d,,d,,,,,,,# -h,,h,,,,h,,h,,,,,,,,,t,t,,,h,,h,,,d,,h,,# -f,,f,,,,f,,f,,,,,,,,,,,,,f,,f,,,,,h,,# -b,,b,,,,b,,b,,b,f,h,d,,,d,h,f,b,,b,,b,,,,f,b,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -b,f,h,d,,d,h,f,b,,b,f,h,d,,,d,h,f,b,,b,f,h,d,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -b,f,h,d,,d,h,f,b,,b,f,h,d,,,d,h,f,b,,b,f,h,d,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#query label(bedrooms3) start(15;10; top left corner of central stairs) Makes bedrooms and small dining rooms from beds and tables -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -r+,,,,,,,,r+,,r+,,,,,,,,,r+,,r+,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -r+,,,,,,,,r+,,r+,,,,,,,,,r+,,r+,,,,,,,r+,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -r+,,r+,,,,r+,,r+,,r+,,,,,,,,,r+,,r+,,r+,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,r++&,,,,,,,,,,,,,,,,,r+,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,r++&,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -r+,,r+,,,,r+,,r+,,r+,,,,,,,,,r+,,r+,,r+,,,,,r+,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -r+,,,,,,,,r+,,r+,,,,,,,,,r+,,r+,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -r+,,,,,,,,r+,,r+,,,,,,,,,r+,,r+,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#dig label(plumbing1) start(15;10; top left corner of central stairs) Plumbing for the waterfall system -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,h,h,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,h,,,,,,,,,h,,,,,,,,,,,# -,,,,,,,,,,h,,,,,,,,,h,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,h,h,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,h,# -,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,# -,,,,,,,,,,,,,,,,,,,,,,,,,,d,,h,h,# -,,,,,,,,,,,,,,,,,,,,,,,,,i,d,,d,d,# -#>,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,h,h,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,h,,,,,,,,,h,,,,,,,,,,,# -,,,,,,,,,,h,,,,,,,,,h,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,h,h,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,h,# -,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,# -,,,,,,,,,,,,,,,,,,,,,,,,,i,d,,h,h,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -"#build label(plumbing2) start(15;10; top left corner of central stairs) Grates, doors, and screw pumps for the waterfall plumbing" -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,G,G,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,G,,,,,,,,,G,,,,,,,,,,,# -,,,,,,,,,,G,,,,,,,,,G,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,G,G,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,d,Msm,Msm,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,~,~,# -#<,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,G,G,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,G,,,,,,,,,G,,,,,,,,,,,# -,,,,,,,,,,G,,,,,,,,,G,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,G,G,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,~,~,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,Msu,Msu,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -#dig label(waterfall1) start(15;10; top left corner of central stairs) Top-level plumbing for the waterfall system -,,,,i,,,,,,,,,,i,i,,,,,,,,,,i,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,# -,,,,,,d,,,,,,,,,,,,,,,,,,,,,,,d,# -,,,,,,d,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,# -,,,,,,d,,,,,,,,h,h,,,,,,,,,,,,d,,d,# -,,,,,,d,,,,,,,,,,,,,,,,,,,,,d,,d,# -,,,,,,d,,,,,,,,,,,,,,,,,,,,,d,,d,# -,,,,,,d,,,,,,,,,,,,,,,,,,,,,d,,d,# -,,,,i,,d,d,d,d,h,,,,i,i,,,,h,d,d,d,d,,i,,d,,d,# -,,,,i,,d,d,d,d,h,,,,i,i,,,,h,d,d,d,d,,i,,d,d,d,# -,,,,,,,,,,,,,,,,,,,,,,,d,,,,,d,d,# -,,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,# -,,,,,,,,,,,,,,h,h,,,,d,d,d,d,d,d,d,d,d,d,d,# -,,,,,,,,,,,,,,d,d,,,,d,,,,,,,,,d,d,# -,,,,,,,,,,,,,,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,# -,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,,,d,d,# -,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,# -,,,,i,,,,,,,,,,i,i,,,,,,,,,,i,,,d,d,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# -"#build label(waterfall2) start(15;10; top left corner of central stairs) message(Remember to link the levers and lock the doors manually) Floodgates, screw pumps, bridges and levers to control flow" -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,x,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,x,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,`,`,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,x,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,gw(2x1),,# -,,,,,,,,,,,,,,,,x,,,,,,Tl,,,,,d,,,# -,,,,,,,,,,,,,,,,,,,,,Tl,Tl,Tl,d,,,,,,# -,,,,,,,,,,,,,,,,,,,,,,Tl,,,,,d,Msm,Msm,# -,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,# -#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# \ No newline at end of file diff --git a/data/blueprints/library/test/ecosystem/in/buildings-build.csv b/data/blueprints/library/test/ecosystem/in/buildings-build.csv deleted file mode 100644 index 89e066e806..0000000000 --- a/data/blueprints/library/test/ecosystem/in/buildings-build.csv +++ /dev/null @@ -1,33 +0,0 @@ -#build label(build) -a,Mg,,CS,trackN -b,Mh(1x1),S,CSa,trackS,,,,,,Mw,,,wm,,,wp -c,Mhs(1x1),m,CSaa,trackE,,,,,,,,,,,,,,,,,D -n,Mv,v,CSaaa,trackW,,Msu -,Mr(1x1),j,CSaaaa,trackNS,,,,,,Mws,,,wu,,,ew -d,Mrq(1x1),A,CSd,trackNE,,,Msk -,Mrqq(1x1),R,CSda,trackNW -l,Mrqqq(1x1),N,CSdaa,trackSE,,Msm,,,,we,,,wn,,,es,,,,,k -x,Mrqqqq(1x1),~h,CSdaaa,trackSW -H,Mrs(1x1),~a,CSdaaaa,trackEW,,,Msh -W,Mrsq(1x1),~c,CSdd,trackNSE,,,,,,wq,,,wr,,,el -G,Mrsqq(1x1),F,CSdda,trackNSW -B,Mrsqqq(1x1),o(1x1),CSddaa,trackNEW,,,,,,,,,,,,,,,,,ws -~b,Mrsqqqq(1x1),Cw,CSddaaa,trackSEW,,,,,,wM,,,wt,,,eg -f,Mrss(1x1),Cf,CSddaaaa,trackNSEW -h,Mrssq(1x1),Cr,CSddd,trackrampN -r,Mrssqq(1x1),Cu,CSddda,trackrampS,,,,,,wo,,,wl,,,ea,,,,gx(1x2),gx(1x2) -s,Mrssqqq(1x1),Cd,CSdddaa,trackrampE -~s,Mrssqqqq(1x1),Cx,CSdddaaa,trackrampW,,,,,,,,,,,,,,gd(2x1),,gs(2x1),,ga(2x1) -t,Mrsss(1x1),CF,CSdddaaaa,trackrampNS,,,,,,wk,,,ww,,,ek,,gd(2x1),,gs(2x1),,ga(2x1) -gs(1x1),Mrsssq(1x1),,CSdddd,trackrampNE,,,,,,,,,,,,,,,,gw(1x2),gw(1x2) -ga(1x1),Mrsssqq(1x1),,CSdddda,trackrampNW -gd(1x1),Mrsssqqq(1x1),,CSddddaa,trackrampSE,,,,,,wb,,,wz,,,en -gw(1x1),Mrsssqqqq(1x1),,CSddddaaa,trackrampSW,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1),,Mhs(1x2),Mhs(1x2) -gx(1x1),,,CSddddaaaa,trackrampEW,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1) -,,,Ts,trackrampNSE,,,,,,wc,,,wh,,,ib,,Mr(1x2),Mr(1x2),Mrs(2x1),,Mhs(1x2),Mhs(1x2) -y,,,Tw,trackrampNSW,,,,,,,,,,,,,,,,Mrs(2x1) -Y,,,Tl,trackrampNEW,,,,,,,,,,,,,,Mr(1x2),Mr(1x2),Mrsq(2x1),,Mrsq(2x1) -,,,Tp,trackrampSEW,,,,,,wf,,,wy,,,ic,,,,Mrsssqqqq(2x1),,Mrsssqqqq(2x1) -,,,Tc,trackrampNSEW -,,,TS -,,,,,,,,,,wv,,,wd,,,wj,,,wS diff --git a/data/blueprints/library/test/quickfort/list/all_modes_separate_sheets.xlsx b/data/blueprints/library/test/quickfort/list/all_modes_separate_sheets.xlsx deleted file mode 100644 index 4fcfbf8672..0000000000 Binary files a/data/blueprints/library/test/quickfort/list/all_modes_separate_sheets.xlsx and /dev/null differ diff --git a/data/blueprints/library/test/quickfort/list/all_modes_single_sheet.xlsx b/data/blueprints/library/test/quickfort/list/all_modes_single_sheet.xlsx deleted file mode 100644 index 052f4e3fb7..0000000000 Binary files a/data/blueprints/library/test/quickfort/list/all_modes_single_sheet.xlsx and /dev/null differ diff --git a/data/blueprints/pump_stack.csv b/data/blueprints/pump_stack.csv new file mode 100644 index 0000000000..14ac78a37c --- /dev/null +++ b/data/blueprints/pump_stack.csv @@ -0,0 +1,80 @@ +#notes label(help) +A pump stack is useful for moving water or magma up through the z-levels. +"" +"1) Select the ""/dig"" blueprint and position the blueprint preview on the bottom level of the future pump stack. It should be on the z-level just above the liquid you want to pump." +"" +"2) Enable repetitions with the ""r"" hotkey (ensure you're repeating Up z-levels, not Down) and lock the blueprint in place with the ""L"" hotkey. Move up the z-levels to check that the pump stack has a clear path and doesn't intersect with any open areas (e.g. caverns). Increase the number of repetitions with the ""+"" or ""*"" hotkeys if you need the pump stack to extend further up. Unlock the blueprint and shift it around if you need to, then lock it again to recheck the vertical path." +"" +"3) If you need to flip the pump stack around to make it fit through the rock layers, enable transformations with the ""t"" hotkey and rotate/flip the blueprint as necessary." +"" +"4) Once you have everything lined up, hit Enter to apply. If the height ends up being one too many at the top, manually undesignate the top level." +"" +"5) Since the bottom up/down staircase is a liability, erase the Up/Down staircase designation on the lowest level and replace it with an Up staircase designation. Otherwise you might get water (or magma) critters climbing up through your access stairway!" +"" +"6) After the stack is dug out, haul away (or dump) any stones that are in the way of building the pumps." +"" +"7) Load up the ""/channel"" blueprint and apply it with the same repetition and transformation settings that you used for the ""/dig"" blueprint. Unless you have restarted DF, gui/quickfort will have saved your settings." +"" +"8) Since you do not need to transmit power down below the lowest level, erase the channel designation on the middle tile of the bottom-most pump stack level." +"" +"9) After the channels are dug, prepare for building by setting the buildingplan plugin material filters for screw pumps. If you are planning to move magma, be sure to select magma-safe materials (like green glass) for all three components of the screw pump." +"" +"10) Finally, generate orders for (the ""o"" hotkey) and run the ""/build"" blueprint with the same repetition and transformation settings that you used for the other blueprints. As you manufacture the materials you need to construct the screw pumps, your dwarves will build the pump stack from the bottom up, ensuring each new screw pump is properly supported by the one below." +"" +"If your dwarves end up building the pumps out of order, a section of the stack may spontaneously deconstruct. This will reduce the efficiency of the stack a little, but it's nothing to worry about. Just re-run the ""/build"" blueprint over the entire stack to ""fix up"" any broken pieces. The blueprint will harmlessly skip over any correctly-built screw pumps." +"" +See the wiki for more info on pump stacks: https://dwarffortresswiki.org/index.php/Screw_pump#Pump_stack +#dig label(digSN) start(2;4;on access stairs) hidden() for a pump from south level + +,,,mwmdd +,,,mwmdd +,mwmdi,mwmdd,mwmdd +,,,mwmdd + +#dig label(digNS) start(2;4;on access stairs) hidden() for a pump from north level + +,,,mwmdd +,mwmdd,mwmdd,mwmdd +,mwmdi,,mwmdd +,,,mwmdd + +#meta label(dig) start(at the bottom level on the access stairs) 2 levels of pump stack - bottom level pumps from the south +/digSN +#< +/digNS +#dig label(channelSN) start(2;4;on access stairs) hidden() for a pump from south level + +,,,` +,,,h +,~,`,` +,,,h + +#dig label(channelNS) start(2;4;on access stairs) hidden() for a pump from north level + +,,,h +,`,`,` +,~,,h +,,,` + +#meta label(channel) start(at the bottom level on the access stairs) 2 levels of pump stack - bottom level pumps from the south +/channelSN +#< +/channelNS +#build label(buildSN) start(2;4;on access stairs) hidden() for a pump from south level + +,,,` +,,,~ +,`,`,Msm +,,,` + +#build label(buildNS) start(2;4;on access stairs) hidden() for a pump from north level + +,,,` +,`,`,~ +,`,,Msu +,,,` + +#meta label(build) start(at the bottom level on the access stairs) 2 levels of pump stack - bottom level pumps from the south +/buildSN +#< +/buildNS diff --git a/data/blueprints/test/ecosystem/golden/meta-1-dig.csv b/data/blueprints/test/ecosystem/golden/meta-1-dig.csv new file mode 100644 index 0000000000..456d2ba92e --- /dev/null +++ b/data/blueprints/test/ecosystem/golden/meta-1-dig.csv @@ -0,0 +1,72 @@ +#dig label(dig) start(3;3) +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d +#> +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d +#> +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d +#> +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d +#> +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d +#> +d,d,,,d +d,,j,,d +d,u,d,u,d +d,,j +d,,,d,d +#> +d,d,d,d,d +,,u,,d +,j,d,j +d,,u +d,,d,d,d diff --git a/data/blueprints/library/test/ecosystem/in/tracks-track.csv b/data/blueprints/test/ecosystem/golden/tracks-2-carve.csv similarity index 84% rename from data/blueprints/library/test/ecosystem/in/tracks-track.csv rename to data/blueprints/test/ecosystem/golden/tracks-2-carve.csv index fdf373019a..c5b4309612 100644 --- a/data/blueprints/library/test/ecosystem/in/tracks-track.csv +++ b/data/blueprints/test/ecosystem/golden/tracks-2-carve.csv @@ -1,4 +1,4 @@ -#dig label(track) +#dig label(carve) trackSE,trackEW,trackEW,trackEW,trackSW trackNE,,,,trackNW #> diff --git a/data/blueprints/test/ecosystem/golden/transform-1-dig.csv b/data/blueprints/test/ecosystem/golden/transform-1-dig.csv new file mode 100644 index 0000000000..b26339d8a4 --- /dev/null +++ b/data/blueprints/test/ecosystem/golden/transform-1-dig.csv @@ -0,0 +1,28 @@ +#dig label(dig) start(14;14) +,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d +d,,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,,d +d,d,,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,,d,d +,,,,,,,,d,d,d,d,d,,d,d,d,d,d +d,d,d,,,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,,,d,d,d +d,d,d,,d,,d,,d,d,d,d,d,,d,d,d,d,d,,d,,d,,d,d,d +d,d,d,,d,d,,,d,d,d,d,d,,d,d,d,d,d,,,d,d,,d,d,d +,,,,,,,,d,d,d,d,d,,d,d,d,d,d +d,d,d,d,d,d,d,d,,,,,,,,,,,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,,d,d,d,,d,d,d,,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,d,,d,d,,d,d,,d,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,d,d,,d,,d,,d,d,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,d,d,d,,,,d,d,d,,d,d,d,d,d,d,d,d + +d,d,d,d,d,d,d,d,,d,d,d,,,,d,d,d,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,d,d,,d,,d,,d,d,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,d,,d,d,,d,d,,d,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,,d,d,d,,d,d,d,,,d,d,d,d,d,d,d,d +d,d,d,d,d,d,d,d,,,,,,,,,,,,d,d,d,d,d,d,d,d +,,,,,,,,d,d,d,d,d,,d,d,d,d,d +d,d,d,,d,d,,,d,d,d,d,d,,d,d,d,d,d,,,d,d,,d,d,d +d,d,d,,d,,d,,d,d,d,d,d,,d,d,d,d,d,,d,,d,,d,d,d +d,d,d,,,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,,,d,d,d +,,,,,,,,d,d,d,d,d,,d,d,d,d,d +d,d,,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,,d,d +d,,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,,d +,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d diff --git a/data/blueprints/test/ecosystem/golden/transform-2-construct.csv b/data/blueprints/test/ecosystem/golden/transform-2-construct.csv new file mode 100644 index 0000000000..9620c96c12 --- /dev/null +++ b/data/blueprints/test/ecosystem/golden/transform-2-construct.csv @@ -0,0 +1,28 @@ +#build label(construct) start(14;14) +,trackNS,trackE,,trackW,trackS,trackN,,,,,,,,,,,,,,trackN,trackS,trackE,,trackW,trackNS +trackEW,,trackSE,,trackSW,trackNE,trackNW,,,,,,,,,,,,,,trackNE,trackNW,trackSE,,trackSW,,trackEW +trackS,trackSE,,,trackNSE,trackNSW,trackEW,,,,,,,,,,,,,,trackEW,trackNSE,trackNSW,,,trackSW,trackS + +trackN,trackNE,trackSEW,,,trackSEW,trackNEW,,,,,,,,,,,,,,trackNEW,trackSEW,,,trackSEW,trackNW,trackN +trackE,trackSW,trackNEW,,trackNSE,,trackNSEW,,,,,,,,,,,,,,trackNSEW,,trackNSW,,trackNEW,trackSE,trackW +trackW,trackNW,trackNS,,trackNSW,trackNSEW,,,,,,,,,,,,,,,,trackNSEW,trackNSE,,trackNS,trackNE,trackE + + +,,,,,,,,,,trackrampNW,trackrampNS,trackrampN,,trackrampN,trackrampNS,trackrampNE +,,,,,,,,,trackrampNW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampNE +,,,,,,,,,trackrampEW,trackrampSEW,,trackrampNSEW,,trackrampNSEW,,trackrampSEW,trackrampEW +,,,,,,,,,trackrampW,trackrampNEW,trackrampNSEW,,,,trackrampNSEW,trackrampNEW,trackrampE + +,,,,,,,,,trackrampW,trackrampSEW,trackrampNSEW,,,,trackrampNSEW,trackrampSEW,trackrampE +,,,,,,,,,trackrampEW,trackrampNEW,,trackrampNSEW,,trackrampNSEW,,trackrampNEW,trackrampEW +,,,,,,,,,trackrampSW,,trackrampNSE,trackrampNSW,,trackrampNSE,trackrampNSW,,trackrampSE +,,,,,,,,,,trackrampSW,trackrampNS,trackrampS,,trackrampS,trackrampNS,trackrampSE + + +trackW,trackSW,trackNS,,trackNSW,trackNSEW,,,,,,,,,,,,,,,,trackNSEW,trackNSE,,trackNS,trackSE,trackE +trackE,trackNW,trackSEW,,trackNSE,,trackNSEW,,,,,,,,,,,,,,trackNSEW,,trackNSW,,trackSEW,trackNE,trackW +trackS,trackSE,trackNEW,,,trackNEW,trackSEW,,,,,,,,,,,,,,trackSEW,trackNEW,,,trackNEW,trackSW,trackS + +trackN,trackNE,,,trackNSE,trackNSW,trackEW,,,,,,,,,,,,,,trackEW,trackNSE,trackNSW,,,trackNW,trackN +trackEW,,trackNE,,trackNW,trackSE,trackSW,,,,,,,,,,,,,,trackSE,trackSW,trackNE,,trackNW,,trackEW +,trackNS,trackE,,trackW,trackN,trackS,,,,,,,,,,,,,,trackS,trackN,trackE,,trackW,trackNS diff --git a/data/blueprints/test/ecosystem/golden/transform-3-build.csv b/data/blueprints/test/ecosystem/golden/transform-3-build.csv new file mode 100644 index 0000000000..74434544ab --- /dev/null +++ b/data/blueprints/test/ecosystem/golden/transform-3-build.csv @@ -0,0 +1,28 @@ +#build label(build) start(14;14) +,~,~,,~,~,~,,gs(1x2),ga(2x1),,gx(1x2),gw(1x2),,gw(1x2),gx(1x2),gd(2x1),,gs(1x2),,~,~,~,,~,~ +~,,~,,~,~,~,,,gd(2x1),,,,,,,ga(2x1),,,,~,~,~,,~,,~ +~,~,,,~,~,~,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,~,~,~,,,~,~ +,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa +~,~,~,,,~,~,,CSa,,Mrss(1x2),Mw,,,,Mw,Mrss(1x2),,CSa,,~,~,,,~,~,~ +~,~,~,,~,,~,,,Msm,,,Mhs(1x2),,Mhs(1x2),,,Msm,,,~,,~,,~,~,~ +~,~,~,,~,~,,,Msu,,Mws,,,,,,Mws,,Msu,,,~,~,,~,~,~ +,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws +gs(2x1),,Mrqq(1x2),CSddaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSddaaaa,Mrqq(1x2),gs(2x1) +gw(1x2),gx(1x2),,,,Msk,,Mw,,,~,~,~,,~,~,~,,,Mw,,,Msh,,,gx(1x2),gw(1x2) +,,,Msm,Mrs(2x1),,Mw,,,~,,~,~,,~,~,,~,,,Mw,Mrsss(2x1),,Msm +gd(2x1),,Msu,,Mws,,,Mhs(1x2),,~,~,,~,,~,,~,~,,Mhs(1x2),,,Mws,,Msu,ga(2x1) +ga(2x1),,,Mws,,Mh(2x1),,,,~,~,~,,,,~,~,~,,,Mh(2x1),,,Mws,,gd(2x1) + +ga(2x1),,,Mws,,Mh(2x1),,Mhs(1x2),,~,~,~,,,,~,~,~,,Mhs(1x2),Mh(2x1),,,Mws,,gd(2x1) +gd(2x1),,,,Mws,,,,,~,~,,~,,~,,~,~,,,,,Mws,,,ga(2x1) +gx(1x2),gw(1x2),Msm,,Mrs(2x1),,Mw,,,~,,~,~,,~,~,,~,,,Mw,Mrsss(2x1),,,Msm,gw(1x2),gx(1x2) +,,Mrssqq(1x2),Msu,,Msk,,Mw,,,~,~,~,,~,~,~,,,Mw,,,Msh,Msu,Mrssqq(1x2) +gs(2x1),,,CSdaaaa,CSa,,Msh,,,,,,,,,,,,,,,Msk,CSa,CSdaaaa,,gs(2x1) +,,,,,,,,,Mws,,Mh(2x1),,,Mh(2x1),,,Mws +~,~,~,,~,~,,,,,Mws,,Mhs(1x2),,Mhs(1x2),,Mws,,,,,~,~,,~,~,~ +~,~,~,,~,,~,,Msm,,Mr(1x2),,,,,,Mr(1x2),,Msm,,~,,~,,~,~,~ +~,~,~,,,~,~,,CSa,Msu,,Mw,,,,Mw,,Msu,CSa,,~,~,,,~,~,~ +,,,,,,,,CSdddaaaa,,Msk,,Mw,,Mw,,,Msh,CSddddaaaa +~,~,,,~,~,~,,Mrsssqq(2x1),,,Msh,,,,,Msk,Mrsqq(2x1),,,~,~,~,,,~,~ +~,,~,,~,~,~,,gs(1x2),gd(2x1),,gw(1x2),gx(1x2),,gx(1x2),gw(1x2),ga(2x1),,gs(1x2),,~,~,~,,~,,~ +,~,~,,~,~,~,,,ga(2x1),,,,,,,gd(2x1),,,,~,~,~,,~,~ diff --git a/data/blueprints/library/test/ecosystem/in/basic-dig.csv b/data/blueprints/test/ecosystem/in/basic-1-dig.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/basic-dig.csv rename to data/blueprints/test/ecosystem/in/basic-1-dig.csv diff --git a/data/blueprints/library/test/ecosystem/in/basic-track.csv b/data/blueprints/test/ecosystem/in/basic-2-carve.csv similarity index 81% rename from data/blueprints/library/test/ecosystem/in/basic-track.csv rename to data/blueprints/test/ecosystem/in/basic-2-carve.csv index 23e7897e72..250ea23812 100644 --- a/data/blueprints/library/test/ecosystem/in/basic-track.csv +++ b/data/blueprints/test/ecosystem/in/basic-2-carve.csv @@ -1,4 +1,4 @@ -#dig label(track) +#dig label(carve) ,,trackS ,,trackNS trackE,trackEW,trackNSEW,trackEW,trackW diff --git a/data/blueprints/library/test/ecosystem/in/basic-build.csv b/data/blueprints/test/ecosystem/in/basic-3-build.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/basic-build.csv rename to data/blueprints/test/ecosystem/in/basic-3-build.csv diff --git a/data/blueprints/library/test/ecosystem/in/basic-place.csv b/data/blueprints/test/ecosystem/in/basic-4-place.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/basic-place.csv rename to data/blueprints/test/ecosystem/in/basic-4-place.csv diff --git a/data/blueprints/library/test/ecosystem/in/basic-zone.csv b/data/blueprints/test/ecosystem/in/basic-5-zone.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/basic-zone.csv rename to data/blueprints/test/ecosystem/in/basic-5-zone.csv diff --git a/data/blueprints/library/test/ecosystem/in/basic-spec.csv b/data/blueprints/test/ecosystem/in/basic-spec.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/basic-spec.csv rename to data/blueprints/test/ecosystem/in/basic-spec.csv diff --git a/data/blueprints/library/test/ecosystem/in/buildings-dig.csv b/data/blueprints/test/ecosystem/in/buildings-1-dig.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/buildings-dig.csv rename to data/blueprints/test/ecosystem/in/buildings-1-dig.csv diff --git a/data/blueprints/test/ecosystem/in/buildings-2-construct.csv b/data/blueprints/test/ecosystem/in/buildings-2-construct.csv new file mode 100644 index 0000000000..e7e1d12bbc --- /dev/null +++ b/data/blueprints/test/ecosystem/in/buildings-2-construct.csv @@ -0,0 +1,21 @@ +#build label(construct) + + + + + + + + + + + + + +Cw +Cf +Cr +Cu +Cd +Cx +CF diff --git a/data/blueprints/test/ecosystem/in/buildings-3-build.csv b/data/blueprints/test/ecosystem/in/buildings-3-build.csv new file mode 100644 index 0000000000..f48457c0a5 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/buildings-3-build.csv @@ -0,0 +1,33 @@ +#build label(build) +a,Mg,,CS +b,Mh(1x1),S,CSa,,,,,,Mw,,,wm,,,wp +c,Mhs(1x1),m,CSaa,,,,,,,,,,,,,,,,,D +n,Mv,v,CSaaa,,Msu +,Mr(1x1),j,CSaaaa,,,,,,Mws,,,wu,,,ew +d,Mrq(1x1),A,CSd,,,Msk +,Mrqq(1x1),R,CSda +l,Mrqqq(1x1),N,CSdaa,,Msm,,,,we,,,wn,,,es,,,,,k +x,Mrqqqq(1x1),~h,CSdaaa +H,Mrs(1x1),~a,CSdaaaa,,,Msh +W,Mrsq(1x1),~c,CSdd,,,,,,wq,,,wr,,,el +G,Mrsqq(1x1),F,CSdda +B,Mrsqqq(1x1),o(1x1),CSddaa,,,,,,,,,,,,,,,,,ws +~,~b,Mrsqqqq(1x1),CSddaaa,,,,,,wM,,,wt,,,eg +~,f,Mrss(1x1),CSddaaaa +~,h,Mrssq(1x1),CSddd +~,r,Mrssqq(1x1),CSddda,,,,,,wo,,,wl,,,ea,,,,gx(1x2),gx(1x2) +~,s,Mrssqqq(1x1),CSdddaa +~,~s,Mrssqqqq(1x1),CSdddaaa,,,,,,,,,,,,,,gd(2x1),,gs(2x1),,ga(2x1) +~,t,Mrsss(1x1),CSdddaaaa,,,,,,wk,,,ww,,,ek,,gd(2x1),,gs(2x1),,ga(2x1) +gs(1x1),Mrsssq(1x1),,CSdddd,,,,,,,,,,,,,,,,gw(1x2),gw(1x2) +ga(1x1),Mrsssqq(1x1),,CSdddda +gd(1x1),Mrsssqqq(1x1),,CSddddaa,,,,,,wb,,,wz,,,en +gw(1x1),Mrsssqqqq(1x1),,CSddddaaa,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1),,Mhs(1x2),Mhs(1x2) +gx(1x1),,,CSddddaaaa,,,,,,,,,,,,,,Mh(2x1),,Mh(2x1) +,,,Ts,,,,,,wc,,,wh,,,ib,,Mr(1x2),Mr(1x2),Mrs(2x1),,Mhs(1x2),Mhs(1x2) +y,,,Tw,,,,,,,,,,,,,,,,Mrs(2x1) +Y,,,Tl,,,,,,,,,,,,,,Mr(1x2),Mr(1x2),Mrsq(2x1),,Mrsq(2x1) +,,,Tp,,,,,,wf,,,wy,,,ic,,,,Mrsssqqqq(2x1),,Mrsssqqqq(2x1) +,,,Tc +,,,TS +,,,,,,,,,,wv,,,wd,,,wj,,,wS diff --git a/data/blueprints/library/test/ecosystem/in/buildings-spec.csv b/data/blueprints/test/ecosystem/in/buildings-spec.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/buildings-spec.csv rename to data/blueprints/test/ecosystem/in/buildings-spec.csv diff --git a/data/blueprints/test/ecosystem/in/fortifications-1-dig.csv b/data/blueprints/test/ecosystem/in/fortifications-1-dig.csv new file mode 100644 index 0000000000..dc40f07b26 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/fortifications-1-dig.csv @@ -0,0 +1,3 @@ +#dig label(dig) + +,d diff --git a/data/blueprints/test/ecosystem/in/fortifications-2-smooth.csv b/data/blueprints/test/ecosystem/in/fortifications-2-smooth.csv new file mode 100644 index 0000000000..bf91a23287 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/fortifications-2-smooth.csv @@ -0,0 +1,4 @@ +#dig label(smooth) +,s +s,,s +,s diff --git a/data/blueprints/test/ecosystem/in/fortifications-3-carve.csv b/data/blueprints/test/ecosystem/in/fortifications-3-carve.csv new file mode 100644 index 0000000000..c174cc918a --- /dev/null +++ b/data/blueprints/test/ecosystem/in/fortifications-3-carve.csv @@ -0,0 +1,4 @@ +#dig label(carve) +,F +F,,F +,F diff --git a/data/blueprints/test/ecosystem/in/fortifications-spec.csv b/data/blueprints/test/ecosystem/in/fortifications-spec.csv new file mode 100644 index 0000000000..462a2e6dbe --- /dev/null +++ b/data/blueprints/test/ecosystem/in/fortifications-spec.csv @@ -0,0 +1,4 @@ +#notes +description=test carving fortifications +width=3 +height=3 diff --git a/data/blueprints/test/ecosystem/in/meta-1-dig.csv b/data/blueprints/test/ecosystem/in/meta-1-dig.csv new file mode 100644 index 0000000000..7467bca2d5 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/meta-1-dig.csv @@ -0,0 +1,41 @@ +#ignore +tests recursive meta composition, z-level manipulation, transformations, and +repeat up/down + +#dig label(border) start(3 3) hidden() +d(2x1),,,,d(1x3) + + + +d(1x-4),,,,d(-2x1) +#dig label(center_tile) start(3 3) hidden() + + +,,d +#dig label(even_up) start(3 3) hidden() + + +,u,,u +#dig label(even_down) start(3 3) hidden() + +,,j + +,,j +#meta label(even) hidden() +/border +/even_up +/even_down +#meta label(odd) hidden() +/even transform(rotcw) +#meta label(twoz) hidden() +/even +#> +/odd +#meta label(fourz) hidden() +/twoz +#>2 +/twoz +#> +/center_tile repeat(up 4) +#meta label(dig) +/fourz repeat(>3) diff --git a/data/blueprints/test/ecosystem/in/meta-spec.csv b/data/blueprints/test/ecosystem/in/meta-spec.csv new file mode 100644 index 0000000000..5b32a29384 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/meta-spec.csv @@ -0,0 +1,6 @@ +#notes +description=meta coverage test +width=5 +height=5 +depth=12 +"start=3,3" diff --git a/data/blueprints/library/test/ecosystem/in/stockpiles-place.csv b/data/blueprints/test/ecosystem/in/stockpiles-2-place.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/stockpiles-place.csv rename to data/blueprints/test/ecosystem/in/stockpiles-2-place.csv diff --git a/data/blueprints/library/test/ecosystem/in/stockpiles-spec.csv b/data/blueprints/test/ecosystem/in/stockpiles-spec.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/stockpiles-spec.csv rename to data/blueprints/test/ecosystem/in/stockpiles-spec.csv diff --git a/data/blueprints/library/test/ecosystem/in/tracks-dig.csv b/data/blueprints/test/ecosystem/in/tracks-1-dig.csv similarity index 78% rename from data/blueprints/library/test/ecosystem/in/tracks-dig.csv rename to data/blueprints/test/ecosystem/in/tracks-1-dig.csv index 7e550fe379..734ecd0b7c 100644 --- a/data/blueprints/library/test/ecosystem/in/tracks-dig.csv +++ b/data/blueprints/test/ecosystem/in/tracks-1-dig.csv @@ -1,6 +1,6 @@ #dig label(dig) d,d,d,d,d -d,h,d,h,d +d,h,,h,d #> ,r,d,r diff --git a/data/blueprints/test/ecosystem/in/tracks-2-carve.csv b/data/blueprints/test/ecosystem/in/tracks-2-carve.csv new file mode 100644 index 0000000000..0646e5934d --- /dev/null +++ b/data/blueprints/test/ecosystem/in/tracks-2-carve.csv @@ -0,0 +1,6 @@ +#dig label(carve) +T(5x2) +,,,,T(-5x-2) +#> + +T(5x1) diff --git a/data/blueprints/library/test/ecosystem/in/tracks-build.csv b/data/blueprints/test/ecosystem/in/tracks-3-build.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/tracks-build.csv rename to data/blueprints/test/ecosystem/in/tracks-3-build.csv diff --git a/data/blueprints/library/test/ecosystem/in/tracks-spec.csv b/data/blueprints/test/ecosystem/in/tracks-spec.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/tracks-spec.csv rename to data/blueprints/test/ecosystem/in/tracks-spec.csv diff --git a/data/blueprints/test/ecosystem/in/transform-1-dig.csv b/data/blueprints/test/ecosystem/in/transform-1-dig.csv new file mode 100644 index 0000000000..92d386e551 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/transform-1-dig.csv @@ -0,0 +1,26 @@ +#dig label(big) hidden() +d(5x8) +#dig label(outer) hidden() +d,d,d,,d,d +d,d,d,,d +d,d,d + +d,d +d +#dig label(inner) hidden() +d,d,d +d,d +d +#meta label(chunk) hidden() +/big shift(1 -13) +/outer shift(7 -13) +/inner shift(1 -4) +#meta label(dig) +/chunk +/chunk transform(cw) +/chunk transform(cw cw) +/chunk transform(ccw) +/chunk transform(fliph) +/chunk transform(flipv) +/chunk transform(cw flipv) +/chunk transform(ccw flipv) diff --git a/data/blueprints/test/ecosystem/in/transform-2-construct.csv b/data/blueprints/test/ecosystem/in/transform-2-construct.csv new file mode 100644 index 0000000000..95717afa85 --- /dev/null +++ b/data/blueprints/test/ecosystem/in/transform-2-construct.csv @@ -0,0 +1,23 @@ +#build label(outer) hidden() +trackN,trackS,trackE,,trackW,trackNS +trackNE,trackNW,trackSE,,trackSW +trackEW,trackNSE,trackNSW + +trackNEW,trackSEW +trackNSEW +#build label(inner) hidden() +trackrampN,trackrampNS,trackrampNE +trackrampNSE,trackrampNSW +trackrampNSEW +#meta label(chunk) hidden() +/outer shift(7 -13) +/inner shift(1 -4) +#meta label(construct) +/chunk +/chunk transform(cw) +/chunk transform(cw cw) +/chunk transform(ccw) +/chunk transform(fliph) +/chunk transform(flipv) +/chunk transform(cw flipv) +/chunk transform(ccw flipv) diff --git a/data/blueprints/test/ecosystem/in/transform-3-build.csv b/data/blueprints/test/ecosystem/in/transform-3-build.csv new file mode 100644 index 0000000000..7907220e7c --- /dev/null +++ b/data/blueprints/test/ecosystem/in/transform-3-build.csv @@ -0,0 +1,20 @@ +#build label(big) hidden() +gw(1x2),gx(1x2),gd(2x1),,gs(1x2) +,,ga(2x1) +,,Msk,Mrsqq(2x1) +Mw,,,Msh,CSddddaaaa +,Mw,Mrss(1x2),,CSa +Mhs(1x2),,,Msm +,,Mws,,Msu +Mh(2x1),,,Mws +#meta label(chunk) hidden() +/big shift(1 -13) +#meta label(build) +/chunk +/chunk transform(cw) +/chunk transform(cw cw) +/chunk transform(ccw) +/chunk transform(fliph) +/chunk transform(flipv) +/chunk transform(cw flipv) +/chunk transform(ccw flipv) diff --git a/data/blueprints/test/ecosystem/in/transform-spec.csv b/data/blueprints/test/ecosystem/in/transform-spec.csv new file mode 100644 index 0000000000..2a3bba25fe --- /dev/null +++ b/data/blueprints/test/ecosystem/in/transform-spec.csv @@ -0,0 +1,5 @@ +#notes +description=transformation coverage test +width=27 +height=27 +"start=14,14" diff --git a/data/blueprints/library/test/ecosystem/in/zones-zone.csv b/data/blueprints/test/ecosystem/in/zones-2-zone.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/zones-zone.csv rename to data/blueprints/test/ecosystem/in/zones-2-zone.csv diff --git a/data/blueprints/library/test/ecosystem/in/zones-spec.csv b/data/blueprints/test/ecosystem/in/zones-spec.csv similarity index 100% rename from data/blueprints/library/test/ecosystem/in/zones-spec.csv rename to data/blueprints/test/ecosystem/in/zones-spec.csv diff --git a/data/blueprints/library/test/quickfort/list/all_modes.csv b/data/blueprints/test/quickfort/list/all_modes.csv similarity index 88% rename from data/blueprints/library/test/quickfort/list/all_modes.csv rename to data/blueprints/test/quickfort/list/all_modes.csv index 96594220fe..c8a042846a 100644 --- a/data/blueprints/library/test/quickfort/list/all_modes.csv +++ b/data/blueprints/test/quickfort/list/all_modes.csv @@ -3,7 +3,8 @@ #place hidden() #zone hidden() #query hidden() -#meta hidden() -#notes hidden() +#config hidden() #ignore #aliases +#meta hidden() +#notes hidden() diff --git a/data/blueprints/test/quickfort/list/all_modes_separate_sheets.xlsx b/data/blueprints/test/quickfort/list/all_modes_separate_sheets.xlsx new file mode 100644 index 0000000000..47445283f0 Binary files /dev/null and b/data/blueprints/test/quickfort/list/all_modes_separate_sheets.xlsx differ diff --git a/data/blueprints/test/quickfort/list/all_modes_single_sheet.xlsx b/data/blueprints/test/quickfort/list/all_modes_single_sheet.xlsx new file mode 100644 index 0000000000..51331918c1 Binary files /dev/null and b/data/blueprints/test/quickfort/list/all_modes_single_sheet.xlsx differ diff --git a/data/blueprints/library/tombs/Mini_Saracen.csv b/data/blueprints/tombs/Mini_Saracen.csv similarity index 100% rename from data/blueprints/library/tombs/Mini_Saracen.csv rename to data/blueprints/tombs/Mini_Saracen.csv diff --git a/data/blueprints/library/tombs/The_Saracen_Crypts.csv b/data/blueprints/tombs/The_Saracen_Crypts.csv similarity index 100% rename from data/blueprints/library/tombs/The_Saracen_Crypts.csv rename to data/blueprints/tombs/The_Saracen_Crypts.csv diff --git a/data/dfhack-config/autonick.txt b/data/dfhack-config/autonick.txt new file mode 100644 index 0000000000..bdd40beed4 --- /dev/null +++ b/data/dfhack-config/autonick.txt @@ -0,0 +1,1283 @@ +# autonick config file +# every line in this file that is not empty and does +# not start with "#" will be used as a nickname by the +# autonick script. + +# nicknames can be multiple words +Toady One +Threetoe + +#Dwarven single names taken from Classic Fantasy works +Balin +Dwalin +Fili +Kili +Gloin +Oin +Bifur +Bofur +Bombur +Ori +Gimli +Thrain +Thror +Fundin +Frerin +Gror +Ibun +Khim +Fimbrethil +Floi +Nali +Thor +Vili +Regin +Fafnir +Brokkr +Sindri +Nordri +Sudri +Austri +Doriath +Thingol +Eol +Mim +Telchar +Narvi +Gundabad +Muhrak +Skorri +Draupnir +Alaric +Grimr +Eitri +Svidurr +Thorgar +Hrungnir +Galar +Skirni +Hreinn +Dori +Hreimr +Hreinir +Hroaldr +Groin +Vestri +Nori +Durin +Dvalin +Eikinskjaldi +Bafur +Snorri +Fimafeng +Vitr +Dvali +Dain +Nain +Nipingr +Hrodvitnir +Sveinn +Ivaldi +Svein +Sveinbjorn +Havardr +Haki +Hakon +Mouri +Motsognir +Eberk +Thromar +Kragar +Borgar +Throk +Orvald +Berric +Rogar +Urgen +Morgrim +Keldar +Ingvar +Frandar +Grimsi +Hrokur +Orik +Rundar +Bjornar +Throki +Dworin +Thranduil +Faldar +Galdor +Thorkel +Dorrin +Borkan +Gundrik +Throkir +Raldor +Helgrim +Throgar +Borin +Ragnir +Orvar +Skalf +Baldir +Fror +Thorgil +Ulfar +Grimbold +Faldur +Varrin +Dornir +Halgrim +Gundin +Ulfgar +Skalfar +Yngvarr +Kaldur +Thrandar +Keldin +Rundin +Skaldur +Borgin +Haldur +Bjornulf +Orkarn +Ragnor +Baldrick +Thorlin +Graldor +Ulfrik +Fornir +Egil +Grimnor +Roldor +Ulfgard +Borgrim +Faldrik +Rognir +Balfor +Volmar +Thormund +Brynhild + +#Dwarven composite names taken from Classic Fantasy works +Gorin Stonehammer +Brundar Ironfoot +Haldrek Battlebeard +Orin Stonefist +Frida Stormaxe +Torvald Rockjaw +Einar Blackforge +Thorgar Granitebeard +Ragnir Hammerhelm +Hilda Ironbrow +Grimnar Deepdelver +Ulfrik Ironmane +Freya Thunderstone +Ragnar Firebeard +Gunnar Ironpeak +Astrid Ironheart +Bjorn Steelbreaker +Hrolf Thunderhammer +Sigrun Stonebreaker +Eirik Rockbeard +Helga Frostbeard +Skaldur Stormguard +Agnar Stonehand +Ingrid Mountainmace +Hjalmar Blackstone +Solveig Steelhelm +Rurik Stonegrip +Freyja Silveraxe +Thordur Goldbeard +Gudrun Ironfoot +Vali Fireforge +Thora Frostbeard +Vargr Stoneborn +Astrid Ironbrow +Einar Blackstone +Hilda Hammerheart +Leif Ironshaper +Thrain Stormbrow +Sigrid Steelheart +Haldor Boulderbreaker +Ragnhild Strongarm +Brynjar Ironmantle +Sigrun Thunderbeard +Valgard Steelbeard +Gunnhild Stonefist +Ingrid Ironrock +Eirik Frostbane +Helga Deepforge +Skaldur Ironshield +Agnar Stonemace +Solveig Stormgrip +Hjalmar Mountainheart +Gudrun Firebeard +Thora Thunderstrike +Vargr Ironhand +Freyja Stoneguard +Thordur Blackstone +Rurik Hammerbeard +Solveig Ironbreaker +Astrid Goldhand +Einar Stormbrew +Hilda Steelbeard +Thrain Ironmane +Sigrid Fireheart +Haldor Thunderstone +Ragnhild Ironfoot +Brynjar Blackhelm +Sigrun Frostbeard +Valgard Stoneshield +Gunnhild Ironheart +Bjorn Deepdelver +Ingrid Ironpeak +Eirik Thunderhammer +Gormund Stoneforge +Eovar Broadshield +Thrunir Hammerstone +Brunhild Steelbraid +Garrik Frostbeard +Haldrek Ironhand +Astrid Rockrider +Dagmar Stonefury +Borgar Thunderhelm +Ingrid Ironstrike +Rurik Blackmane +Fjorn Stoneborn +Siv Ironbreaker +Gudrik Stormbeard +Ulfgar Emberforge +Eilif Silverstone +Hilda Stormwarden +Ormar Ironjaw +Vali Steelshaper +Eira Frostbeard +Torgar Graniteheart +Brunhild Firebrand +Haldrek Ironmantle +Solveig Rockbreaker +Thrain Thunderaxe +Brynjar Stoneclaw +Asa Ironhide +Grimnar Blackmane +Ragnvald Hammerfall +Gudbrand Ironhand +Astrid Flamebeard +Ormur Steelbender +Hjalmar Rockjaw +Inga Thunderheart +Valgard Ironbeard +Eirik Swiftstrike +Sylvi Stoneguard +Helge Hammerfist +Jorunn Fireforge +Solveig Ironroot +Thora Stormbeard +Baldur Stonemane +Freydis Ironshaper +Gunnvald Deepstone +Bjorn Blackstone +Ingrid Frostmane +Agnar Steelhammer +Thordur Ironbeard +Ylva Goldhand +Greta Firestone +Rurik Rockhelm +Gunnhild Ironsong +Vali Steelgrip +Brynhild Stormblade +Astrid Ironmantle +Einar Stoneshield +Hilda Frostbeard +Ormr Ironheart +Inga Steelbreaker +Ulfrik Thunderaxe +Freyja Stonebeard +Sigrun Frostfury +Sylvi Blackmane +Thorvald Ironhelm +Eirik Stormstone +Haldora Deepdelver +Sigrid Steelshaper +Gunnar Thunderheart +Bjorn Ironbrow +Ingrid Goldmantle +Agnar Stormforge +Solveig Ironclaw +Thora Rockguard +Grimur Emberstone +Ragnhild Hammerstrike +Vali Ironfist +Brynjar Blackbraid +Astrid Flameforge +Einar Stonestorm +Hilda Frostbane +Ormur Ironhelm +Inga Steelshaper +Gudbrand Thunderbeard +Freya Stonefist +Gunnvald Stormmane +Bjorn Ironhelm +Ingrid Frostforge +Agnar Steelgrip +Thordur Ironhand +Ylva Flameheart +Greta Stonemane +Rurik Ironroot +Gunnhild Steelbeard +Vali Thunderstrike +Thorin Oakenshield +Dain Ironfoot +Gamil Zirak + + +# animals +Mouse +Otter +Snake +Owl +Bat +Fox +Mole +Cat +Badger +Squirrel +Kit +Wren +Jay +Crow +Raven +Sparrow +Platypus +House Mouse +Pangolin +Funnel Web +Weasel +Meerkats +Rat +Ant +Gopher +Fennec +Groundhog +Aardvark +Rabbit +Olm +Chipmunk +Bilbie +Vole +Nile Croc +Wombat +Worm +Gerbil +Armodillo +Thrinaxodon +Binky +Bandicoot +Bettongs +Potoroos +Antechinus +Jerboas +Numbat + +# colours +Flash +Red +Gray +Blue +Shadow +Indigo +Jade +Silver +Bistre +Black +Black bean +Noir +Charcoal +Ebony +Eerie +Jet +Licorice +Midnight +Night +Onyx +Space +Raisin +Rich +Russ violet +Smoky +Aero +Alice +Argent Lue +Azure +Azul +Baby blue +Berkeley +Bice +Bleu +Bondi +Brandeis Byzant +Cambridge +Carolina +Celestial +Celtic +Cerulean +Chefchaouen +Chrysler +Cobalt +Columbia +Cornflower +Delft +Denim +Dodger +Duke +Federal +Electrindigo +Eclipse +Illini +Klein +Jordy +Lapis Lazuli +Majorelle +Marian +Maya +Slate +Munsell +Navy +Neon blue +Oxford +Palatinate +Penn +Periwinkle +Phthalo +Picton +Poly +Powder +Prussia +Royal +Ruddy +Honolulu +Savoy +Silver Lake +Space cadet +Steel +Tang +Tufts +Ultramarine +Uranian +Vista +Yale +Zaffre +Auburn +Almond +Beaver +Beige +Bole +Bone +Bronze +Sienna +Umber +Camel +Caput mortuum +Caramel +Chamoisee +Chestnut +Chocolate +Citron +Cocoa +Coffee +Copper +Coyote +Desert +Drab +Dun +Earth +Fallow +Fawn +Field +Fulvous +Goldenrod +Harvest +Khaki +Kobicha +Lion +Liver +Mahogany +Maroon +Ochre +Redwood +Rufous +Russet +Rust +Sand +Satin +Sheen +Seal +Sepia +Sinopia +Tan +Tawny +Van Dyke +Walnut +Wenge +Aqua +Aquamarine +Capri +Caribbean +Celeste +Cyprus +Fluorescent +Jungle +Keppel +Ice +Sea +Myrtle +Pacific +Robin +Skobeloff +Teal +Verdigris +Vivid +Zomp +Platinum +Timberwolf +Rose quartz +Cinereous +Cadet +Cool +Davys +Paynes +Glaucous +Gunmetal +Feldgrau +Asparagus +Avocado +Brunswick +Cal Poly +Castleton +Celadon +Chartreuse +Moss +Pastel +Dartmouth +Emerald +Fern +Forest +Harlequin +Honeydew +Hunter +Kelly green +Lawn +Malachite +Mantis +Neon +Olivine +Paris +Pear +Pigment +Pistachio +Reseda +Rifle +Sage +Screamin' +Shamrock +Bud +Amaranth +Baker-Miller +Cerise +Carmine +Magenta +Eggplant +Fandango +Finn +Fuchsia +Haze +Plum +Pizzazz +Quinacridone +Razzle dazzle +Rose +Shocking +Telemagenta +Aerospace +Alloy +Amber +Atomic +Tangerine +Burnt +Butterscotch +Carrot +Champagne +Coral +Flame +Gold +Hunyadi +Melon +Peel +Papaya +Peach +Persimmon +Princeton +Pumpkin +Safety orange +Saffron +Tangelo +Tigers Eye +Titian +Xanthous +Blush +Brilliant +Brink +Carnation +Cherry +Cyclamen +Dogwood +Hollywood +Hot +Lavender +Mimi +Misty +Mountbatten +Orchid +Phlox +Pompadour +Puce +Raspberry +Razzmatazz +Bonbon +Quartz +Taupe +Vale +Rosewood +Rosy +Salmon +Tea +Tickle +Thulian +Ultra +Burgundy +Byzantium +Eminence +Grape +Iris +Mardi Gras +Mauve +Mauveine +Mulberry +Murrey +Pale +Pomp +Power +Purpureus +Tekhelet +Thistle +Tropical +Tyrian +Wisteria +Barn +Bittersweet +Shimmer +Blood +Candy apple +Cantaloupe +Cardinal +Chili +Cosmos +Cinnabar +Claret +Coquelicot +Cordovan +Cornell +Crimson +Falu +Brick +Engine +Folly +Imperial +Jaspar +Poppy +Rojo +Rusty +Scarlet +Syracuse +Tomato +Turkey +Vermilion +Wine +Alabaster +Antique +Cornsilk +Latte +Cream +Eggshell +Flax +Floral +Ghost +Isabelline +Ivory +Lemon +chiffon +Linen +Navajo +Nyanza +Lace +Parchment +Pearl +Seasalt +Seashell +Vanilla +Smoke +Apricot +Arylide +Aureolin +Buff +Canary +Ecru +Gamboge +Icterine +Jonquil +Maize +Mikado +Mindaro +Mustard +Selective +Stil de grain +Straw +Sunglow +Sunset +Wheat + +# planets +Mars +Jupiter +Saturn +Pluto +Neptune +Europa + +# charites +Damia +Auxesia +Cleta +Phaenna +Hegemone +Peitho +Paregoros +Pasithea +Charis +Kale +Antheia +Eudaimonia +Euthymia +Eutychia +Paidia +Pandaisia +Pannychis +Aglaea +Euphrosyne +Thalia + +# nature +Blaze +River +Snow +Bones +Rain +Reed +Lake +Briar +Brook +Sky +Storm +Clay +Ember +Marsh +Star + +# trees +Ash +Oak +Rowan +Aspen +Alder +Apple +Beech +Birch +Box +Cedar +Cypress +Elder +Elm +Larch +Fir +Juniper +Lime +Pine +Poplar +Spruce +Yew + +# seasons +Spring +Summer +Autumn +Winter + +# cardinals +North +South +East +West + +# other +Ink +Echo +Mint +Mel +X +Sam +Tango +Gadget +Brum +Wall +Beam +Ud +Tal +Ren +Aki +Jun +Kei +Lynn +Lex +Cid +Miles +Rotor +Mesa +Verse + +# from the "300 list" +Aiden +Arden +Auden +August +Avery +Avis +Bay +Blake +Erin +Ezra +Kai +Lane +Leah +Noel +Pat +Ray +Remi +Roan +Robyn +Salem +Sean +Tate +Tobin +Tori +True +Val +Wilder +Wisdom +Wyatt +Zephyr + +# Gemstones +Actinolite +Nephrite +Adamite +Aegirine +Afghanite +Agrellite +Algodonite +Alunite +Amblygonite +Analcime +Anatase +Andalusite +Chiastolite +Anglesite +Anhydrite +Annabergite +Anorthite +Antigorite +Bowenite +Apatite +Apophyllite +Aragonite +Asbestos +Astrophyllite +Augelite +Austinite +Ferro +Magnes +Mangan +Tinzenite +Azurmalachite +Azurite +Baryte +Bast +Bayldonite +Benitoite +Beryl +Maxixe +Goshenite +Golden beryl +Heliodor +Morganite +Red beryl +Beryllonite +Beudantite +Bismutot +Biotit +Boracite +Bornite +Brazilianite +Brookite +Brucite +Bustam +Bytown +Calcite +Caledonite +Canasite +Cancrin +Vishnev +Carleton +Carnall +Cassiterite +Cataplei +Cavans +Celestite +Ceruleite +Cerussite +Chalcopyr +Chambers +Charlesite +Charoite +Childrenite +Chiolite +Chrysoberyl +Alexandrite +Cymophane +Chromite +Chrysocolla +Clinochlore +Clinohumite +Clintonite +Cobaltite +Coleman +Cordierite +Iolite +Cornwallite +Corundum +Ruby +Sapphire +Padparadscha +Covell +Creedite +Crocite +Cuprite +Danburite +Datolite +Descloiz +Diamond +Bort +Ballas +Diaspore +Dickinsonite +Diopside +Dioptase +Dolomite +Dumortier +Ekanite +Trapiche +Enstatite +Bronzite +Hypersthene +Eosphorite +Epidote +Piemont +Erythrite +Esperite +Ettring +Eudialyte +Faya +Feldspar +Andesine +Albite +Anorth +Anorthoc +Amazon +Celsian +Microcline +Moonstone +Adularia +Rainbow +Ortho +Kite +Plagioclase +Labradorite +Oligoclase +Sunstone +Oregon Sunstone +Rainbow Lattice +Fergusonite +Ferroaxin +Fluora +Fluorapophyl +Fluorite +Forster +Friedelite +Gadolin +Gahnite +Gahnospinel +Garnet +Pyralspite +Almandine +Spessartine +Ugrand +Demantoid +Melanite +Topazolita +Grossular +Hessonite +Hydrogrossular +Tsavorite +Pyrope +Rhodolite +Mali garnet +Malaia +Umbal +Gaspe +Gayluss +Gibbsite +Glaucophane +Goeth +Goosecreek +Grandidier +Gypsum +Gyro +Halite +Hambergite +Hanksite +Hardystonite +Helenite +Hematite +Herder +Hexagonite +Hibonite +Hidden +Hodgkinsonite +Holtite +Howlite +Huebnerite +Humite +Hurlbut +Ilmenite +Inderite +Jadeite +Jasper +Jeremejevite +Kainite +Kämmerer +Kaolin +Kornerup +Kurnakov +Kyanite +Langbein +Lawsonite +Lazulite +Lazurite +Legrandite +Lepidolite +Leucite +Leucophan +Linarite +Lizardite +Londonite +Ludlamite +Ludwigite +Maria-meionite +Werner +Marcasite +Meliphanite +Mellite +Mesolite +Milar +Millerite +Mime +Monazite +Mordenite +Mottram +Muscovite +Fuchsite +Nambul +Natrolite +Nepheline +Neptunite +Nickeline +Niccolite +Nosean +Nuumm +Opal +Fire opal +Moss opal +Painite +Papagoite +Pargas +Parisite +Pectol +Larimar +Pentland +Periclase +Perthite +Petal +Castor +Pezzottaite +Phena +Phosgen +Phospho +Piemontite +Realgar +Rhodizite +Rhodochros +Rhodon +Richter +Riebeck +Crocidolite +Rosasite +Rutile +Samarskite +Sanidine +Sapphirine +Sarcol +Scapol +Marialite +Meionite +Scheel +Schizol +Scorod +Selenite +Sella +Senarmon +Sepio +Meerschaum +Sérandite +Seraph +Serendibite +Serpentine +Bowen +Stich +Shattuck +Shiga +Shortite +Shung +Siderite +Silliman +Simpsonite +Sinhal +Smalt +Smithsonite +Sodalite +Hackman +Sogdian +Sperry +Spessar +Sphaler +Spinel +Ceylon +Spodumene +Triphane +Spurrite +Stauro +Strontian +Titanate +Sulfur +Bustamite +Sylvite +Taaffeita +Talc +Tantalite +Tektites +Tephroite +Thomsonite +Thaumasite +Topaz +Tourmaline +Achroite +Chrome +Dravite +Elbaite +Indicol +Olenite +Paraiba +Rossman +Rubellite +Tremol +Triphyl +Triplite +Tugtup +Turquoise +Ulex +Ussing +Vanadinite +Variscite +Vesuvianite +Californite +Villiaum +Vivianite +Vlasov +Wardite +Wavell +Welogan +Whewell +Wilkeite +Willemite +Wither +Wollastone +Wulfenite +Wurtzite +Xonot +Yugawara +Zektzer +Zeolites +Chabaz +Steller +Stilbite +Zinc +Zinnwald +Zircon +Jacinth +Zoisite +Tanzan +Thulite +Zultan +Zany +Lapis lazuli +Desert glass +Llanite +Maw sit-sit +Obsidian +Tears +Pallas +Peridot +Soapstone +Tact +Unakite +Bauxite +Concretions +Bloodstone +Heliotrope +Eilat stone +Epidos +Glimmer +Goldstone +Hawks eye +Iddings +Lampro diff --git a/data/blueprints/README.md b/data/dfhack-config/blueprints/README.md similarity index 91% rename from data/blueprints/README.md rename to data/dfhack-config/blueprints/README.md index 2facb3f4ec..5d0e41a245 100644 --- a/data/blueprints/README.md +++ b/data/dfhack-config/blueprints/README.md @@ -1,5 +1,5 @@ This folder contains blueprints that can be applied by the `quickfort` script. For more information, see: -* [Quickfort command reference](https://docs.dfhack.org/en/stable/docs/_auto/base.html#quickfort) +* [Quickfort command reference](https://docs.dfhack.org/en/stable/docs/tools/quickfort.html) * [Quickfort blueprint guide](https://docs.dfhack.org/en/stable/docs/guides/quickfort-user-guide.html) * [Quickfort library guide](https://docs.dfhack.org/en/stable/docs/guides/quickfort-library-guide.html) diff --git a/data/dfhack-config/buildingplan.json b/data/dfhack-config/buildingplan.json new file mode 100644 index 0000000000..9bb3052b71 --- /dev/null +++ b/data/dfhack-config/buildingplan.json @@ -0,0 +1,5 @@ +{ + "planner": { + "minimized": true + } +} \ No newline at end of file diff --git a/dfhack-config/dfstatus.lua b/data/dfhack-config/dfstatus.lua similarity index 100% rename from dfhack-config/dfstatus.lua rename to data/dfhack-config/dfstatus.lua diff --git a/data/dfhack-config/dwarfmonitor.json b/data/dfhack-config/dwarfmonitor.json new file mode 100644 index 0000000000..9bd3b1f769 --- /dev/null +++ b/data/dfhack-config/dwarfmonitor.json @@ -0,0 +1,3 @@ +{ + "date_format": "Y-M-D" +} diff --git a/data/dfhack-config/init/default.dfhack.init b/data/dfhack-config/init/default.dfhack.init new file mode 100644 index 0000000000..aad18dd1c4 --- /dev/null +++ b/data/dfhack-config/init/default.dfhack.init @@ -0,0 +1,7 @@ +# Load DFHack defaults. +# +# If you delete this file, it will reappear when you restart DFHack. +# Instead, please comment out the following line if you do not want DFHack to +# load its default configuration. + +script hack/init/dfhack.default.init diff --git a/data/dfhack-config/init/default.onLoad.init b/data/dfhack-config/init/default.onLoad.init new file mode 100644 index 0000000000..fe87d42097 --- /dev/null +++ b/data/dfhack-config/init/default.onLoad.init @@ -0,0 +1,7 @@ +# Load DFHack defaults. +# +# If you delete this file, it will reappear when you restart DFHack. +# Instead, please comment out the following line if you do not want DFHack to +# load its default configuration. + +script hack/init/onLoad.default.init diff --git a/data/dfhack-config/init/default.onMapLoad.init b/data/dfhack-config/init/default.onMapLoad.init new file mode 100644 index 0000000000..9e781b924a --- /dev/null +++ b/data/dfhack-config/init/default.onMapLoad.init @@ -0,0 +1,7 @@ +# Load DFHack defaults. +# +# If you delete this file, it will reappear when you restart DFHack. +# Instead, please comment out the following line if you do not want DFHack to +# load its default configuration. + +script hack/init/onMapLoad.default.init diff --git a/data/dfhack-config/init/default.onMapUnload.init b/data/dfhack-config/init/default.onMapUnload.init new file mode 100644 index 0000000000..716680fd01 --- /dev/null +++ b/data/dfhack-config/init/default.onMapUnload.init @@ -0,0 +1,7 @@ +# Load DFHack defaults. +# +# If you delete this file, it will reappear when you restart DFHack. +# Instead, please comment out the following line if you do not want DFHack to +# load its default configuration. + +script hack/init/onMapUnload.default.init diff --git a/data/dfhack-config/init/default.onUnload.init b/data/dfhack-config/init/default.onUnload.init new file mode 100644 index 0000000000..712c35098f --- /dev/null +++ b/data/dfhack-config/init/default.onUnload.init @@ -0,0 +1,7 @@ +# Load DFHack defaults. +# +# If you delete this file, it will reappear when you restart DFHack. +# Instead, please comment out the following line if you do not want DFHack to +# load its default configuration. + +script hack/init/onUnload.default.init diff --git a/data/dfhack-config/init/dfhack.init b/data/dfhack-config/init/dfhack.init new file mode 100644 index 0000000000..b05598f988 --- /dev/null +++ b/data/dfhack-config/init/dfhack.init @@ -0,0 +1,5 @@ +# This file runs when DFHack is initialized, when Dwarf Fortress is first +# started, before any world or save data is loaded. +# +# You can extend or override DFHack's default configuration by adding commands +# to this file. diff --git a/data/dfhack-config/init/onLoad.init b/data/dfhack-config/init/onLoad.init new file mode 100644 index 0000000000..ef4fd97afe --- /dev/null +++ b/data/dfhack-config/init/onLoad.init @@ -0,0 +1,6 @@ +# This file runs when a world is loaded. This happens when you open a save file +# in fort, adventure, or legends mode. If a fort is being loaded, this file runs +# before any onMapLoad.init files. +# +# You can extend or override DFHack's default configuration by adding commands +# to this file. diff --git a/data/dfhack-config/init/onMapLoad.init b/data/dfhack-config/init/onMapLoad.init new file mode 100644 index 0000000000..90c6b9e140 --- /dev/null +++ b/data/dfhack-config/init/onMapLoad.init @@ -0,0 +1,5 @@ +# This file runs when a map is loaded in adventure or fort mode, after any +# onLoad.init files (which run earlier, when the world is loaded). +# +# You can extend or override DFHack's default configuration by adding commands +# to this file. diff --git a/data/dfhack-config/init/onMapUnload.init b/data/dfhack-config/init/onMapUnload.init new file mode 100644 index 0000000000..c513d9caea --- /dev/null +++ b/data/dfhack-config/init/onMapUnload.init @@ -0,0 +1,5 @@ +# This file runs when a fortress map is unloaded, before any onUnload.init files +# (which run later, when the world is unloaded). +# +# You can extend or override DFHack's default configuration by adding commands +# to this file. diff --git a/data/dfhack-config/init/onUnload.init b/data/dfhack-config/init/onUnload.init new file mode 100644 index 0000000000..c8ed3ab5b5 --- /dev/null +++ b/data/dfhack-config/init/onUnload.init @@ -0,0 +1,4 @@ +# This file runs when a world is unloaded. +# +# You can extend or override DFHack's default configuration by adding commands +# to this file. diff --git a/dfhack-config/script-paths.txt b/data/dfhack-config/script-paths.txt similarity index 100% rename from dfhack-config/script-paths.txt rename to data/dfhack-config/script-paths.txt diff --git a/data/dfhack-config/scripts/README.md b/data/dfhack-config/scripts/README.md new file mode 100644 index 0000000000..95b67b058d --- /dev/null +++ b/data/dfhack-config/scripts/README.md @@ -0,0 +1,7 @@ +You can put scripts you write or download in this folder and DFHack will find +them. + +If a script in this directory has the same name as a default DFHack script, the + script in this directory will take precedence. + +Everything you add to this folder will be kept safe when you upgrade DFHack. diff --git a/data/dfhack-config/stockpiles/README.md b/data/dfhack-config/stockpiles/README.md new file mode 100644 index 0000000000..593d45fb67 --- /dev/null +++ b/data/dfhack-config/stockpiles/README.md @@ -0,0 +1,5 @@ +This folder contains stockpile settings that can be applied by `stockpiles` and +`quickfort` tools. For more information, see: + +* [stockpiles documentation](https://docs.dfhack.org/en/latest/docs/tools/stockpiles.html) +* [quickfort documentation](https://docs.dfhack.org/en/latest/docs/guides/quickfort-user-guide.html) diff --git a/data/examples/README.md b/data/examples/README.md deleted file mode 100644 index fb2b8e3a12..0000000000 --- a/data/examples/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# The DFHack Example Configuration File Library - -This folder contains ready-to-use examples of various DFHack configuration -files. You can use them by copying them to appropriate folders where DFHack -and its plugins can find them. You can use them unmodified, or you can -customize them to better suit your preferences. - -For information on each of the files in this library, see the -[DFHack Example Configuration File Guide](https://docs.dfhack.org/en/stable/docs/guides/examples-guide.html). diff --git a/data/examples/init/onMapLoad_dreamfort.init b/data/examples/init/onMapLoad_dreamfort.init deleted file mode 100644 index 8e9c0134dd..0000000000 --- a/data/examples/init/onMapLoad_dreamfort.init +++ /dev/null @@ -1,83 +0,0 @@ -# This dfhack config file automates common tasks for your forts. -# It was written for the Dreamfort set of quickfort blueprints, but the -# configuration here is useful for any fort! Feed free to edit or override -# to your liking. - -# Disallow cooking of otherwise useful item types -on-new-fortress ban-cooking tallow; ban-cooking honey; ban-cooking oil; ban-cooking seeds; ban-cooking brew; ban-cooking fruit; ban-cooking mill; ban-cooking thread; ban-cooking milk; ban-cooking booze - -# Uncomment this next line if you want buildingplan (and quickfort) to use only -# blocks for construction. If you do uncomment, be sure to bring some blocks -# with you for starting workshops! -#on-new-fortress buildingplan set boulders false; buildingplan set logs false - -repeat -name warn-starving -time 10 -timeUnits days -command [ warn-starving ] -repeat -name burial -time 7 -timeUnits days -command [ burial -pets ] -repeat -name cleanowned -time 1 -timeUnits months -command [ cleanowned X ] -repeat -name clean -time 1 -timeUnits months -command [ clean all ] -repeat -name feeding-timers -time 1 -timeUnits months -command [ fix/feeding-timers ] -repeat -name stuckdoors -time 1 -timeUnits months -command [ fix/stuckdoors ] -repeat -name autoShearCreature -time 14 -timeUnits days -command [ workorder ShearCreature ] -repeat -name autoMilkCreature -time 14 -timeUnits days -command [ workorder "{\"job\":\"MilkCreature\",\"item_conditions\":[{\"condition\":\"AtLeast\",\"value\":2,\"flags\":[\"empty\"],\"item_type\":\"BUCKET\"}]}" ] -repeat -name orders-sort -time 1 -timeUnits days -command [ orders sort ] - -tweak fast-heat 100 -tweak do-job-now -fix/blood-del enable - -# manages crop assignment for farm plots -enable autofarm -autofarm default 30 -autofarm threshold 150 GRASS_TAIL_PIG - -# allows you to configure a stockpile to automatically mark items for melting -enable automelt - -# creates manager orders to produce replacements for worn clothing -enable tailor -tailor enable - -# auto-assigns nesting birds to nestbox zones -enable zone nestboxes -autonestbox start - -# manages seed stocks -enable seedwatch -seedwatch all 30 -seedwatch start - -# ensures important tasks get assigned to workers. -# otherwise these job types can get ignored in busy forts. -prioritize -a StoreItemInVehicle StoreItemInBag StoreItemInBarrel PullLever -prioritize -a StoreItemInLocation StoreItemInHospital -prioritize -a DestroyBuilding RemoveConstruction RecoverWounded DumpItem -prioritize -a CleanSelf SlaughterAnimal PrepareRawFish ExtractFromRawFish -prioritize -a TradeAtDepot BringItemToDepot CleanTrap ManageWorkOrders -prioritize -a --haul-labor=Food,Body StoreItemInStockpile -prioritize -a --reaction-name=TAN_A_HIDE CustomReaction - -# autobutcher settings are saved in the savegame, so we only need to set them once. -# this way, any custom settings you set during gameplay are not overwritten -# -# feel free to change this to "target 0 0 0 0" if you don't expect to want to raise -# any animals not listed here -- you can always change it anytime during the game -# later if you change your mind. -on-new-fortress autobutcher target 2 2 2 2 new -# dogs and cats. You should raise the limits for dogs if you will be training them -# for hunting or war. -on-new-fortress autobutcher target 2 2 2 2 DOG -on-new-fortress autobutcher target 1 1 2 2 CAT -# geese are our primary source of bones and leather. let the younglings grow up -# before we butcher so we get adult-scale products from them. BIRD_PEAFOWL_BLUE, -# BIRD_CHICKEN, and BIRD_TURKEY are also viable. feel free to change this to -# your bird of choice. -on-new-fortress autobutcher target 50 50 14 2 BIRD_GOOSE -# alpaca, sheep, and llamas give wool. we need to keep these numbers low, though, or -# else risk running out of grass for grazing. -on-new-fortress autobutcher target 2 2 4 2 ALPACA SHEEP LLAMA -# pigs give milk and meat and are zero-maintenance. -on-new-fortress autobutcher target 5 5 6 2 PIG -# generally unprofitable animals -on-new-fortress autobutcher target 0 0 0 0 HORSE YAK DONKEY WATER_BUFFALO GOAT CAVY BIRD_DUCK BIRD_GUINEAFOWL -# start it up! -on-new-fortress autobutcher start; autobutcher watch all; autobutcher autowatch diff --git a/data/init/dfhack.default.init b/data/init/dfhack.default.init new file mode 100644 index 0000000000..78dc70450a --- /dev/null +++ b/data/init/dfhack.default.init @@ -0,0 +1,8 @@ +# Default DFHack commands to run on program init + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/dfhack.init + +script hack/init/dfhack.keybindings.init +script hack/init/dfhack.tools.init diff --git a/data/init/dfhack.keybindings.init b/data/init/dfhack.keybindings.init new file mode 100644 index 0000000000..018c66ccde --- /dev/null +++ b/data/init/dfhack.keybindings.init @@ -0,0 +1,168 @@ +# Default DFHack keybindings + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/dfhack.init + +################### +# global bindings # +################### + +# the GUI command launcher (two bindings since some keyboards don't have "`") +keybinding add ` gui/launcher +keybinding add Ctrl-Shift-D gui/launcher +keybinding add Ctrl-Shift-P "gui/launcher --minimal" + +# show hotkey popup menu +keybinding add Ctrl-Shift-C hotkeys + +# control panel +keybinding add Ctrl-Shift-E gui/control-panel + +# on-screen keyboard +keybinding add Ctrl-Shift-K gui/cp437-table + +# customizable quick command list +keybinding add Ctrl-Shift-A gui/quickcmd + + +################### +# embark bindings # +################### + +keybinding add Ctrl-A@choose_start_site gui/embark-anywhere + + +################################## +# dwarfmode+dungeonmode bindings # +################################## + +# save the description of a selected unit or item to the `markdown_{YourWorldName}.md` file +# in the game root directory +keybinding add Ctrl-T@dwarfmode/ViewSheets/UNIT|dwarfmode/ViewSheets/ITEM|dungeonmode/ViewSheets/UNIT|dungeonmode/ViewSheets/ITEM markdown + +# gui/sitemap +keybinding add Ctrl-G@dwarfmode/Default|dungeonmode/Default gui/sitemap + +# toggle keyboard cursor +keybinding add Alt-K@dwarfmode|dungeonmode/Default|dungeonmode/Look toggle-kbd-cursor + +# gui/journal +keybinding add Ctrl-J@dwarfmode|dungeonmode gui/journal + + +###################### +# dwarfmode bindings # +###################### + +# quicksave +keybinding add Ctrl-Alt-S@dwarfmode quicksave + +# toggle spectate +keybinding add Ctrl-Shift-S@dwarfmode/Default "spectate toggle" + +# designate the whole vein for digging +keybinding add Ctrl-V@dwarfmode digv +keybinding add Ctrl-Shift-V@dwarfmode "digv x" + +# clean the selected tile of blood etc +keybinding add Ctrl-C@dwarfmode spotclean + +# destroy the selected item +keybinding add Ctrl-K@dwarfmode autodump-destroy-item + +# bring up the autodump UI +keybinding add Ctrl-H@dwarfmode gui/autodump + +# bring up the teleport UI +keybinding add Ctrl-Shift-T@dwarfmode gui/teleport + +# apply blueprints to the map +keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort + +# Stocks plugin +#keybinding add Ctrl-Shift-Z@dwarfmode/Default "stocks show" + +# open an overview window summarising some stocks (dfstatus) +#keybinding add Ctrl-Shift-I@dwarfmode/Default|dfhack/lua/dfstatus gui/dfstatus + +# set workorder item details (on workorder details screen press D again) +#keybinding add D@workquota_details gui/workorder-details + +# view combat reports for the selected unit/corpse/spatter +#keybinding add Ctrl-Shift-R@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist|workshop_profile view-unit-reports + +# view extra unit information +#keybinding add Alt-I@dwarfmode/ViewUnits|unitlist gui/unit-info-viewer + +# boost priority of jobs related to the selected entity +#keybinding add Alt-N@dwarfmode|job|joblist|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist|textviewer|item|layer_assigntrade|tradegoods|store|assign_display_item|treasurelist do-job-now + +# q->stockpile - copy & paste stockpiles +#keybinding add Alt-P@dwarfmode/QueryBuilding/Some/Stockpile copystock + +# q->stockpile - load and save stockpile settings out of game +#keybinding add Alt-L@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -load" +#keybinding add Alt-S@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -save" + +# q->workshop - duplicate the selected job +#keybinding add Ctrl-D job-duplicate + +# materials: q->workshop; b->select items +#keybinding add Shift-A "job-material ALUNITE" +#keybinding add Shift-M "job-material MICROCLINE" +#keybinding add Shift-D "job-material DACITE" +#keybinding add Shift-R "job-material RHYOLITE" +#keybinding add Shift-I "job-material CINNABAR" +#keybinding add Shift-B "job-material COBALTITE" +#keybinding add Shift-O "job-material OBSIDIAN" +#keybinding add Shift-T "job-material ORTHOCLASE" +#keybinding add Shift-G "job-material GLASS_GREEN" + +# browse rooms of same owner +#keybinding add Alt-R@dwarfmode/QueryBuilding/Some gui/room-list + +# machine power sensitive pressure plate construction +#keybinding add Ctrl-Shift-M@dwarfmode/Build/Position/Trap gui/power-meter + +# siege engine control +#keybinding add Alt-A@dwarfmode/QueryBuilding/Some/SiegeEngine gui/siege-engine + +# military weapon auto-select +#keybinding add Ctrl-W@layer_military/Equip/Customize/View gui/choose-weapons + +# military copy uniform +#keybinding add Ctrl-C@layer_military/Uniforms gui/clone-uniform + +# minecart Guide path +#keybinding add Alt-P@dwarfmode/Hauling/DefineStop/Cond/Guide gui/guide-path + +# workshop job details +#keybinding add Alt-A@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workshop-job + +# workflow front-end +#keybinding add Alt-W@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workflow +#keybinding add Alt-W@overallstatus "gui/workflow status" +# equivalent to the one above when gui/extended-status is enabled +#keybinding add Alt-W@dfhack/lua/status_overlay "gui/workflow status" + +# gui/rename script - rename units and buildings +#keybinding add Ctrl-Shift-N@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit|buildinglist gui/rename +#keybinding add Ctrl-Shift-T@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit "gui/rename unit-profession" + +# gui/design +keybinding add Ctrl-D@dwarfmode/Default gui/design +keybinding add Ctrl-M@dwarfmode/Default gui/mass-remove + + +######################## +# dungeonmode bindings # +######################## + +keybinding add Ctrl-A@setupadventure unretire-anyone + +#keybinding add Ctrl-B@dungeonmode adv-bodyswap +#keybinding add Ctrl-Shift-B@dungeonmode "adv-bodyswap force" +#keybinding add Shift-O@dungeonmode gui/companion-order +#keybinding add Ctrl-T@dungeonmode gui/advfort +keybinding add Ctrl-T@dungeonmode/Default flashstep diff --git a/data/init/dfhack.tools.init b/data/init/dfhack.tools.init new file mode 100644 index 0000000000..baa26d3ee4 --- /dev/null +++ b/data/init/dfhack.tools.init @@ -0,0 +1,19 @@ +# Default DFHack tool configuration + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/dfhack.init + +# Enable system services +enable buildingplan +enable burrow +enable logistics +enable overlay +enable preserve-rooms + +# aliases +alias add autounsuspend suspendmanager +alias add drain-aquifer aquifer drain --all +alias add gui/dig gui/design +alias add version help +alias add gui/pregnancy gui/family-affairs --pregnancy diff --git a/data/init/onLoad.default.init b/data/init/onLoad.default.init new file mode 100644 index 0000000000..e797f88ee7 --- /dev/null +++ b/data/init/onLoad.default.init @@ -0,0 +1,7 @@ +# Default DFHack commands to run when a world is loaded + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/onLoad.init + +lua require('quickfix').set_entity_race_references() diff --git a/data/init/onMapLoad.default.init b/data/init/onMapLoad.default.init new file mode 100644 index 0000000000..44986a044c --- /dev/null +++ b/data/init/onMapLoad.default.init @@ -0,0 +1,6 @@ +# Default DFHack commands to run when a map is loaded, either in +# adventure or fort mode. + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/onMapLoad.init diff --git a/data/init/onMapUnload.default.init b/data/init/onMapUnload.default.init new file mode 100644 index 0000000000..6441d72ffa --- /dev/null +++ b/data/init/onMapUnload.default.init @@ -0,0 +1,5 @@ +# Default DFHack commands to run when a map is unloaded + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/onMapUnload.init diff --git a/data/init/onUnload.default.init b/data/init/onUnload.default.init new file mode 100644 index 0000000000..9254a257bf --- /dev/null +++ b/data/init/onUnload.default.init @@ -0,0 +1,5 @@ +# Default DFHack commands to run when a world is unloaded + +# Please do not edit this file directly. It will be overwritten with new +# defaults when you update DFHack. Instead, add your configuration to +# dfhack-config/init/onUnload.init diff --git a/data/examples/orders/basic.json b/data/orders/basic.json similarity index 94% rename from data/examples/orders/basic.json rename to data/orders/basic.json index 8bd278f0cf..e1cd5ac8ff 100644 --- a/data/examples/orders/basic.json +++ b/data/orders/basic.json @@ -1,7 +1,7 @@ [ { - "amount_left" : 1, - "amount_total" : 1, + "amount_left" : 10, + "amount_total" : 10, "frequency" : "Daily", "id" : 0, "is_active" : false, @@ -25,7 +25,7 @@ "unrotten", "cookable" ], - "value" : 15 + "value" : 80 }, { "condition" : "AtMost", @@ -34,7 +34,7 @@ "unrotten" ], "item_type" : "FOOD", - "value" : 3500 + "value" : 2000 } ], "job" : "PrepareMeal", @@ -71,7 +71,7 @@ { "condition" : "AtMost", "item_type" : "DRINK", - "value" : 800 + "value" : 3000 } ], "job" : "CustomReaction", @@ -108,33 +108,12 @@ { "condition" : "AtMost", "item_type" : "DRINK", - "value" : 800 + "value" : 3000 } ], "job" : "CustomReaction", "reaction" : "BREW_DRINK_FROM_PLANT_GROWTH" }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 3, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "flags" : - [ - "unrotten", - "milk" - ], - "value" : 2 - } - ], - "job" : "MakeCheese" - }, { "amount_left" : 1, "amount_total" : 1, @@ -225,10 +204,9 @@ "condition" : "AtLeast", "flags" : [ - "empty", - "bag" + "empty" ], - "item_type" : "BOX", + "item_type" : "BAG", "value" : 5 } ], @@ -279,10 +257,9 @@ "condition" : "AtLeast", "flags" : [ - "empty", - "bag" + "empty" ], - "item_type" : "BOX", + "item_type" : "BAG", "value" : 5 } ], @@ -537,10 +514,9 @@ "condition" : "AtLeast", "flags" : [ - "collected", "dyeable" ], - "item_type" : "THREAD", + "item_type" : "CLOTH", "value" : 5 }, { @@ -550,10 +526,10 @@ "unrotten", "dye" ], - "value" : 15 + "value" : 3 } ], - "job" : "DyeThread" + "job" : "DyeCloth" }, { "amount_left" : 1, @@ -568,22 +544,27 @@ "condition" : "AtLeast", "flags" : [ - "dyeable" + "non_economic", + "hard" ], - "item_type" : "CLOTH", - "value" : 5 + "item_type" : "BOULDER", + "material" : "INORGANIC", + "value" : 20 }, { - "condition" : "AtLeast", + "condition" : "AtMost", "flags" : [ - "unrotten", - "dye" + "empty" ], - "value" : 15 + "item_subtype" : "ITEM_TOOL_LARGE_POT", + "item_type" : "TOOL", + "value" : 25 } ], - "job" : "DyeCloth" + "item_subtype" : "ITEM_TOOL_LARGE_POT", + "job" : "MakeTool", + "material" : "INORGANIC" }, { "amount_left" : 1, @@ -596,13 +577,37 @@ [ { "condition" : "AtLeast", + "item_type" : "WOOD", + "value" : 50 + }, + { + "condition" : "AtMost", "flags" : [ - "non_economic", - "hard" + "empty" ], - "item_type" : "BOULDER", - "material" : "INORGANIC", + "item_type" : "BIN", + "value" : 5 + } + ], + "job" : "ConstructBin", + "material_category" : + [ + "wood" + ] + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 19, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "WOOD", "value" : 20 }, { @@ -611,21 +616,23 @@ [ "empty" ], - "item_subtype" : "ITEM_TOOL_LARGE_POT", + "item_subtype" : "ITEM_TOOL_JUG", "item_type" : "TOOL", - "material" : "INORGANIC", - "value" : 25 + "value" : 10 } ], - "item_subtype" : "ITEM_TOOL_LARGE_POT", + "item_subtype" : "ITEM_TOOL_JUG", "job" : "MakeTool", - "material" : "INORGANIC" + "material_category" : + [ + "wood" + ] }, { "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 19, + "id" : 20, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -643,25 +650,18 @@ }, { "condition" : "AtMost", - "flags" : - [ - "empty" - ], - "item_subtype" : "ITEM_TOOL_JUG", - "item_type" : "TOOL", - "material" : "INORGANIC", + "item_type" : "GOBLET", "value" : 10 } ], - "item_subtype" : "ITEM_TOOL_JUG", - "job" : "MakeTool", + "job" : "MakeGoblet", "material" : "INORGANIC" }, { "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 20, + "id" : 21, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -689,7 +689,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 21, + "id" : 22, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -701,6 +701,10 @@ }, { "condition" : "AtMost", + "flags" : + [ + "empty" + ], "item_subtype" : "ITEM_TOOL_MINECART", "item_type" : "TOOL", "value" : 2 @@ -717,7 +721,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 22, + "id" : 23, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -747,7 +751,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 23, + "id" : 24, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -777,7 +781,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 24, + "id" : 25, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -806,7 +810,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 25, + "id" : 26, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -820,14 +824,13 @@ "condition" : "AtMost", "flags" : [ - "empty", - "sewn_imageless" + "empty" ], - "item_type" : "BOX", + "item_type" : "BAG", "value" : 30 } ], - "job" : "ConstructChest", + "job" : "ConstructBag", "material_category" : [ "leather" @@ -837,7 +840,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 26, + "id" : 27, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -856,14 +859,13 @@ "condition" : "AtMost", "flags" : [ - "empty", - "sewn_imageless" + "empty" ], - "item_type" : "BOX", + "item_type" : "BAG", "value" : 30 } ], - "job" : "ConstructChest", + "job" : "ConstructBag", "material_category" : [ "silk" @@ -873,7 +875,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 27, + "id" : 28, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -892,14 +894,13 @@ "condition" : "AtMost", "flags" : [ - "empty", - "sewn_imageless" + "empty" ], - "item_type" : "BOX", + "item_type" : "BAG", "value" : 30 } ], - "job" : "ConstructChest", + "job" : "ConstructBag", "material_category" : [ "cloth" @@ -909,7 +910,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 28, + "id" : 29, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -928,14 +929,13 @@ "condition" : "AtMost", "flags" : [ - "empty", - "sewn_imageless" + "empty" ], - "item_type" : "BOX", + "item_type" : "BAG", "value" : 30 } ], - "job" : "ConstructChest", + "job" : "ConstructBag", "material_category" : [ "yarn" @@ -945,7 +945,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 29, + "id" : 30, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -964,9 +964,9 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 30, + "id" : 31, "is_active" : false, - "is_validated" : true, + "is_validated" : false, "item_conditions" : [ { @@ -980,7 +980,8 @@ "value" : 2 } ], - "job" : "MakeCrafts", + "item_subtype" : "ITEM_PANTS_LEGGINGS", + "job" : "MakePants", "material_category" : [ "shell" @@ -990,7 +991,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 31, + "id" : 32, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1012,7 +1013,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 32, + "id" : 33, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1038,7 +1039,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 33, + "id" : 34, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1064,7 +1065,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 34, + "id" : 35, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1090,7 +1091,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 35, + "id" : 36, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1112,8 +1113,11 @@ }, { "condition" : "AtMost", - "item_type" : "LIQUID_MISC", - "material" : "LYE", + "contains" : + [ + "lye" + ], + "reaction_id" : "MAKE_SOAP_FROM_TALLOW", "value" : 5 } ], @@ -1123,7 +1127,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 36, + "id" : 37, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1141,8 +1145,11 @@ }, { "condition" : "AtLeast", - "item_type" : "LIQUID_MISC", - "material" : "LYE", + "contains" : + [ + "lye" + ], + "reaction_id" : "MAKE_SOAP_FROM_TALLOW", "value" : 3 }, { @@ -1162,7 +1169,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 37, + "id" : 38, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1175,8 +1182,11 @@ }, { "condition" : "AtLeast", - "item_type" : "LIQUID_MISC", - "material" : "LYE", + "contains" : + [ + "lye" + ], + "reaction_id" : "MAKE_SOAP_FROM_OIL", "value" : 3 }, { @@ -1196,7 +1206,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 38, + "id" : 39, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1219,7 +1229,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 39, + "id" : 40, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1243,7 +1253,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 40, + "id" : 41, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1277,7 +1287,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 41, + "id" : 42, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1306,7 +1316,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 42, + "id" : 43, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1335,9 +1345,9 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 43, + "id" : 44, "is_active" : false, - "is_validated" : true, + "is_validated" : false, "item_conditions" : [ { @@ -1366,7 +1376,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 44, + "id" : 45, "is_active" : false, "is_validated" : false, "item_conditions" : diff --git a/data/examples/orders/furnace.json b/data/orders/furnace.json similarity index 99% rename from data/examples/orders/furnace.json rename to data/orders/furnace.json index 54d7d758e5..62e389ded1 100644 --- a/data/examples/orders/furnace.json +++ b/data/orders/furnace.json @@ -152,10 +152,9 @@ "condition" : "AtLeast", "flags" : [ - "empty", - "bag" + "empty" ], - "item_type" : "BOX", + "item_type" : "BAG", "value" : 10 }, { diff --git a/data/examples/orders/glassstock.json b/data/orders/glassstock.json similarity index 100% rename from data/examples/orders/glassstock.json rename to data/orders/glassstock.json diff --git a/data/examples/orders/military.json b/data/orders/military.json similarity index 93% rename from data/examples/orders/military.json rename to data/orders/military.json index 536b2cd7a8..e461f0d3d7 100644 --- a/data/examples/orders/military.json +++ b/data/orders/military.json @@ -92,15 +92,16 @@ [ { "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", + "flags" : + [ + "silk" + ], + "item_type" : "CLOTH", + "min_dimension" : 10000, "value" : 10 }, { "condition" : "AtMost", - "flags" : - [ - "leather" - ], "item_subtype" : "ITEM_ARMOR_CLOAK", "item_type" : "ARMOR", "value" : 10 @@ -110,7 +111,7 @@ "job" : "MakeArmor", "material_category" : [ - "leather" + "silk" ] }, { @@ -152,25 +153,21 @@ [ { "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 25 + "item_type" : "WOOD", + "value" : 50 }, { "condition" : "AtMost", - "flags" : - [ - "leather" - ], "item_subtype" : "ITEM_SHIELD_SHIELD", "item_type" : "SHIELD", - "value" : 1 + "value" : 10 } ], "item_subtype" : "ITEM_SHIELD_SHIELD", "job" : "MakeShield", "material_category" : [ - "leather" + "wood" ] }, { @@ -191,7 +188,7 @@ "condition" : "AtMost", "item_subtype" : "ITEM_ARMOR_LEATHER", "item_type" : "ARMOR", - "value" : 1 + "value" : 10 } ], "item_subtype" : "ITEM_ARMOR_LEATHER", @@ -223,7 +220,7 @@ ], "item_subtype" : "ITEM_HELM_HELM", "item_type" : "HELM", - "value" : 1 + "value" : 10 } ], "item_subtype" : "ITEM_HELM_HELM", @@ -255,7 +252,7 @@ ], "item_subtype" : "ITEM_SHOES_BOOTS", "item_type" : "SHOES", - "value" : 2 + "value" : 20 } ], "item_subtype" : "ITEM_SHOES_BOOTS", @@ -287,7 +284,7 @@ ], "item_subtype" : "ITEM_PANTS_LEGGINGS", "item_type" : "PANTS", - "value" : 1 + "value" : 10 } ], "item_subtype" : "ITEM_PANTS_LEGGINGS", @@ -319,7 +316,7 @@ ], "item_subtype" : "ITEM_GLOVES_GLOVES", "item_type" : "GLOVES", - "value" : 2 + "value" : 20 } ], "item_subtype" : "ITEM_GLOVES_GLOVES", @@ -421,7 +418,7 @@ "condition" : "AtLeast", "item_type" : "BOULDER", "material" : "INORGANIC:CASSITERITE", - "value" : 5 + "value" : 25 }, { "condition" : "AtLeast", @@ -571,37 +568,6 @@ "is_active" : false, "is_validated" : false, "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:NATIVE_PLATINUM", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 10 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:NATIVE_PLATINUM" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 19, - "is_active" : false, - "is_validated" : false, - "item_conditions" : [ { "condition" : "AtLeast", @@ -629,7 +595,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 20, + "id" : 19, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -660,7 +626,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 21, + "id" : 20, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -691,7 +657,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 22, + "id" : 21, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -722,7 +688,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 23, + "id" : 22, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -731,7 +697,7 @@ "bearing" : "TIN", "condition" : "AtLeast", "item_type" : "BOULDER", - "value" : 5 + "value" : 25 }, { "bearing" : "COPPER", @@ -759,7 +725,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 24, + "id" : 23, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -792,7 +758,7 @@ "bearing" : "TIN", "condition" : "AtMost", "item_type" : "BOULDER", - "value" : 5 + "value" : 25 }, { "bearing" : "COPPER", @@ -808,7 +774,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 25, + "id" : 24, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -845,7 +811,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 26, + "id" : 25, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -888,7 +854,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 27, + "id" : 26, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -924,7 +890,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 28, + "id" : 27, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -967,7 +933,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 29, + "id" : 28, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1015,7 +981,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 30, + "id" : 29, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1070,232 +1036,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 31, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_MACE", - "item_type" : "WEAPON", - "material" : "INORGANIC:PLATINUM", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "job" : "MakeWeapon", - "material" : "INORGANIC:PLATINUM" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 32, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "item_type" : "WEAPON", - "material" : "INORGANIC:PLATINUM", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:PLATINUM" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 64, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "item_type" : "WEAPON", - "material" : "INORGANIC:PLATINUM", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "job" : "MakeWeapon", - "material" : "INORGANIC:PLATINUM" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 35, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "job" : "MakeWeapon", - "material" : "INORGANIC:SILVER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 35, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:SILVER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 64, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "job" : "MakeWeapon", - "material" : "INORGANIC:SILVER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 37, + "id" : 30, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1328,7 +1069,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 38, + "id" : 31, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1361,7 +1102,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 39, + "id" : 32, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1394,7 +1135,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 40, + "id" : 33, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1427,7 +1168,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 41, + "id" : 34, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1460,7 +1201,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 42, + "id" : 35, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1500,7 +1241,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 43, + "id" : 36, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1540,7 +1281,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 44, + "id" : 37, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1558,26 +1299,47 @@ "value" : 100 }, { - "condition" : "LessThan", + "condition" : "AtMost", + "item_subtype" : "ITEM_WEAPON_MACE", + "item_type" : "WEAPON", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "job" : "MakeWeapon", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 38, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 + "material" : "INORGANIC:STEEL", + "value" : 10 }, { - "condition" : "LessThan", + "condition" : "AtLeast", "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 + "material" : "COAL", + "value" : 100 }, { "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_MACE", + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", "item_type" : "WEAPON", "material" : "INORGANIC:STEEL", "value" : 10 } ], - "item_subtype" : "ITEM_WEAPON_MACE", + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", "job" : "MakeWeapon", "material" : "INORGANIC:STEEL" }, @@ -1585,7 +1347,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 45, + "id" : 39, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1603,26 +1365,47 @@ "value" : 100 }, { - "condition" : "LessThan", + "condition" : "AtMost", + "item_subtype" : "ITEM_WEAPON_SPEAR", + "item_type" : "WEAPON", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_SPEAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:STEEL" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 40, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 + "material" : "INORGANIC:STEEL", + "value" : 10 }, { - "condition" : "LessThan", + "condition" : "AtLeast", "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 + "material" : "COAL", + "value" : 100 }, { "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", "item_type" : "WEAPON", "material" : "INORGANIC:STEEL", "value" : 10 } ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", "job" : "MakeWeapon", "material" : "INORGANIC:STEEL" }, @@ -1630,7 +1413,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 46, + "id" : 41, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1649,13 +1432,13 @@ }, { "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_SPEAR", + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", "item_type" : "WEAPON", "material" : "INORGANIC:STEEL", "value" : 10 } ], - "item_subtype" : "ITEM_WEAPON_SPEAR", + "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", "job" : "MakeWeapon", "material" : "INORGANIC:STEEL" }, @@ -1663,7 +1446,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 47, + "id" : 42, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1672,7 +1455,7 @@ "condition" : "AtLeast", "item_type" : "BAR", "material" : "INORGANIC:STEEL", - "value" : 10 + "value" : 30 }, { "condition" : "AtLeast", @@ -1682,13 +1465,13 @@ }, { "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "item_subtype" : "ITEM_WEAPON_PICK", "item_type" : "WEAPON", "material" : "INORGANIC:STEEL", "value" : 10 } ], - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", + "item_subtype" : "ITEM_WEAPON_PICK", "job" : "MakeWeapon", "material" : "INORGANIC:STEEL" }, @@ -1696,7 +1479,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 48, + "id" : 43, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1705,7 +1488,7 @@ "condition" : "AtLeast", "item_type" : "BAR", "material" : "INORGANIC:STEEL", - "value" : 10 + "value" : 30 }, { "condition" : "AtLeast", @@ -1715,13 +1498,13 @@ }, { "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "item_subtype" : "ITEM_WEAPON_CROSSBOW", "item_type" : "WEAPON", "material" : "INORGANIC:STEEL", "value" : 10 } ], - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", + "item_subtype" : "ITEM_WEAPON_CROSSBOW", "job" : "MakeWeapon", "material" : "INORGANIC:STEEL" }, @@ -1729,7 +1512,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 49, + "id" : 44, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1737,8 +1520,8 @@ { "condition" : "AtLeast", "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 + "material" : "INORGANIC:SILVER", + "value" : 5 }, { "condition" : "AtLeast", @@ -1746,23 +1529,38 @@ "material" : "COAL", "value" : 100 }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, { "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_PICK", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_MACE", "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", "material" : "INORGANIC:STEEL", "value" : 10 } ], - "item_subtype" : "ITEM_WEAPON_PICK", + "item_subtype" : "ITEM_WEAPON_MACE", "job" : "MakeWeapon", - "material" : "INORGANIC:STEEL" + "material" : "INORGANIC:SILVER" }, { "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 50, + "id" : 45, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1770,8 +1568,8 @@ { "condition" : "AtLeast", "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 + "material" : "INORGANIC:SILVER", + "value" : 5 }, { "condition" : "AtLeast", @@ -1779,35 +1577,38 @@ "material" : "COAL", "value" : 100 }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, { "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", "item_type" : "WEAPON", - "material" : "INORGANIC:STEEL", "value" : 10 }, { "condition" : "LessThan", "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 + "material" : "INORGANIC:STEEL", + "value" : 10 } ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", "job" : "MakeWeapon", - "material" : "INORGANIC:STEEL" + "material" : "INORGANIC:SILVER" }, { "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 51, + "id" : 46, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1855,7 +1656,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 52, + "id" : 47, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1903,7 +1704,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 53, + "id" : 48, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1951,7 +1752,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 54, + "id" : 49, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1999,7 +1800,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 55, + "id" : 50, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2047,7 +1848,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 56, + "id" : 51, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2105,7 +1906,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 57, + "id" : 52, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2163,7 +1964,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 58, + "id" : 53, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2198,12 +1999,6 @@ "material" : "INORGANIC:SILVER", "value" : 5 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, { "condition" : "AtMost", "flags" : @@ -2223,7 +2018,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 59, + "id" : 54, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2258,12 +2053,6 @@ "material" : "INORGANIC:SILVER", "value" : 5 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, { "condition" : "AtMost", "flags" : @@ -2283,7 +2072,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 60, + "id" : 55, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2331,7 +2120,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 61, + "id" : 56, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2379,7 +2168,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 62, + "id" : 57, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2427,7 +2216,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 63, + "id" : 58, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2475,7 +2264,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 64, + "id" : 59, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2504,18 +2293,6 @@ "material" : "INORGANIC:STEEL", "value" : 30 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, { "condition" : "AtMost", "flags" : @@ -2535,7 +2312,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 79, + "id" : 74, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2583,7 +2360,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 80, + "id" : 75, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2631,7 +2408,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 81, + "id" : 76, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2679,7 +2456,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 82, + "id" : 77, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2727,7 +2504,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 83, + "id" : 78, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2775,7 +2552,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 84, + "id" : 79, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2833,7 +2610,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 85, + "id" : 80, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2891,7 +2668,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 72, + "id" : 67, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2936,12 +2713,6 @@ "item_type" : "BAR", "material" : "INORGANIC:SILVER", "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 } ], "item_subtype" : "ITEM_WEAPON_MACE", @@ -2952,7 +2723,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 87, + "id" : 82, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2987,12 +2758,6 @@ "material" : "INORGANIC:SILVER", "value" : 5 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, { "condition" : "AtMost", "flags" : @@ -3012,7 +2777,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 88, + "id" : 83, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3060,7 +2825,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 89, + "id" : 84, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3108,7 +2873,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 90, + "id" : 85, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3156,7 +2921,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 91, + "id" : 86, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3204,7 +2969,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 92, + "id" : 87, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3233,18 +2998,6 @@ "material" : "INORGANIC:STEEL", "value" : 30 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, { "condition" : "AtMost", "flags" : @@ -3264,7 +3017,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 79, + "id" : 74, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3318,7 +3071,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 80, + "id" : 75, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3372,7 +3125,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 81, + "id" : 76, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3426,7 +3179,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 82, + "id" : 77, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3480,7 +3233,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 83, + "id" : 78, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3534,7 +3287,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 84, + "id" : 79, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3598,7 +3351,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 85, + "id" : 80, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3662,7 +3415,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 86, + "id" : 81, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3697,12 +3450,6 @@ "material" : "INORGANIC:SILVER", "value" : 5 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, { "condition" : "AtMost", "flags" : @@ -3728,7 +3475,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 87, + "id" : 82, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3763,12 +3510,6 @@ "material" : "INORGANIC:SILVER", "value" : 5 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, { "condition" : "AtMost", "flags" : @@ -3794,7 +3535,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 88, + "id" : 83, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3848,7 +3589,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 89, + "id" : 84, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3902,7 +3643,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 90, + "id" : 85, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3956,7 +3697,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 91, + "id" : 86, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4010,7 +3751,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 92, + "id" : 87, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4039,18 +3780,6 @@ "material" : "INORGANIC:STEEL", "value" : 30 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, { "condition" : "AtMost", "flags" : @@ -4076,7 +3805,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 93, + "id" : 88, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4136,7 +3865,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 94, + "id" : 89, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4196,7 +3925,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 95, + "id" : 90, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4256,7 +3985,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 96, + "id" : 91, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4316,7 +4045,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 97, + "id" : 92, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4376,7 +4105,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 98, + "id" : 93, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4446,7 +4175,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 99, + "id" : 94, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4516,7 +4245,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 100, + "id" : 95, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4557,12 +4286,6 @@ "material" : "INORGANIC:SILVER", "value" : 5 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, { "condition" : "AtMost", "flags" : @@ -4588,7 +4311,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 101, + "id" : 96, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4629,12 +4352,6 @@ "material" : "INORGANIC:SILVER", "value" : 5 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, { "condition" : "LessThan", "item_type" : "BAR", @@ -4660,7 +4377,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 102, + "id" : 97, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4720,7 +4437,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 103, + "id" : 98, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4780,7 +4497,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 104, + "id" : 99, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4840,7 +4557,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 105, + "id" : 100, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4900,7 +4617,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 106, + "id" : 101, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4935,18 +4652,6 @@ "material" : "INORGANIC:STEEL", "value" : 30 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, { "condition" : "AtMost", "flags" : diff --git a/data/examples/orders/rockstock.json b/data/orders/rockstock.json similarity index 100% rename from data/examples/orders/rockstock.json rename to data/orders/rockstock.json diff --git a/data/examples/orders/smelting.json b/data/orders/smelting.json similarity index 99% rename from data/examples/orders/smelting.json rename to data/orders/smelting.json index fec6693243..781a52100d 100644 --- a/data/examples/orders/smelting.json +++ b/data/orders/smelting.json @@ -43,7 +43,7 @@ "condition" : "AtLeast", "item_type" : "BOULDER", "material" : "INORGANIC:CASSITERITE", - "value" : 5 + "value" : 25 }, { "condition" : "AtLeast", @@ -668,7 +668,7 @@ "bearing" : "TIN", "condition" : "AtLeast", "item_type" : "BOULDER", - "value" : 5 + "value" : 25 }, { "bearing" : "COPPER", @@ -729,7 +729,7 @@ "bearing" : "TIN", "condition" : "AtMost", "item_type" : "BOULDER", - "value" : 5 + "value" : 25 }, { "bearing" : "COPPER", @@ -791,13 +791,13 @@ "bearing" : "TIN", "condition" : "AtLeast", "item_type" : "BOULDER", - "value" : 5 + "value" : 25 }, { "bearing" : "COPPER", "condition" : "AtLeast", "item_type" : "BOULDER", - "value" : 5 + "value" : 25 }, { "condition" : "AtLeast", @@ -828,13 +828,13 @@ "condition" : "AtLeast", "item_type" : "BAR", "material" : "INORGANIC:TIN", - "value" : 5 + "value" : 25 }, { "condition" : "AtLeast", "item_type" : "BAR", "material" : "INORGANIC:COPPER", - "value" : 5 + "value" : 25 }, { "condition" : "AtLeast", @@ -1068,13 +1068,13 @@ "bearing" : "TIN", "condition" : "AtLeast", "item_type" : "BOULDER", - "value" : 5 + "value" : 25 }, { "bearing" : "COPPER", "condition" : "AtLeast", "item_type" : "BOULDER", - "value" : 5 + "value" : 25 }, { "condition" : "AtLeast", diff --git a/data/patches/README.md b/data/patches/README.md new file mode 100644 index 0000000000..599bbf47fb --- /dev/null +++ b/data/patches/README.md @@ -0,0 +1,13 @@ +Place IDA-exported `.dif` files for use by `binpatch` in subdirectories of this +directory. Each `.dif` file must be in a subdirectory named after the full +symbol table version string. For example, for DF version 51.05, you would use +these subdirectories: + +- "v0.51.05 linux64 CLASSIC" +- "v0.51.05 linux64 ITCH" +- "v0.51.05 linux64 STEAM" +- "v0.51.05 win64 CLASSIC" +- "v0.51.05 win64 ITCH" +- "v0.51.05 win64 STEAM" + +See https://docs.dfhack.org/en/stable/docs/dev/Binpatches.html for more details. diff --git a/data/examples/professions/Chef b/data/professions/Chef similarity index 86% rename from data/examples/professions/Chef rename to data/professions/Chef index 1f777c81a2..2dd8d8508f 100644 --- a/data/examples/professions/Chef +++ b/data/professions/Chef @@ -1,4 +1,4 @@ -NAME Chef +NAME library/Chef BUTCHER TANNER COOK @@ -17,4 +17,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Craftsdwarf b/data/professions/Craftsdwarf similarity index 88% rename from data/examples/professions/Craftsdwarf rename to data/professions/Craftsdwarf index 29ed1ad0d5..5b9d03ca84 100644 --- a/data/examples/professions/Craftsdwarf +++ b/data/professions/Craftsdwarf @@ -1,4 +1,4 @@ -NAME Craftsdwarf +NAME library/Craftsdwarf WOOD_CRAFT STONE_CRAFT BONE_CARVE @@ -24,4 +24,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Doctor b/data/professions/Doctor similarity index 89% rename from data/examples/professions/Doctor rename to data/professions/Doctor index 893708947d..b15ff96b22 100644 --- a/data/examples/professions/Doctor +++ b/data/professions/Doctor @@ -1,4 +1,4 @@ -NAME Doctor +NAME library/Doctor ANIMALCARE DIAGNOSE SURGERY @@ -21,4 +21,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Farmer b/data/professions/Farmer similarity index 83% rename from data/examples/professions/Farmer rename to data/professions/Farmer index 149b3c3689..0b2801f4c2 100644 --- a/data/examples/professions/Farmer +++ b/data/professions/Farmer @@ -1,4 +1,4 @@ -NAME Farmer +NAME library/Farmer PLANT MILLER BREWER diff --git a/data/examples/professions/Fisherdwarf b/data/professions/Fisherdwarf similarity index 84% rename from data/examples/professions/Fisherdwarf rename to data/professions/Fisherdwarf index 3c369e61d8..6c2106e6a2 100644 --- a/data/examples/professions/Fisherdwarf +++ b/data/professions/Fisherdwarf @@ -1,4 +1,4 @@ -NAME Fisherdwarf +NAME library/Fisherdwarf FISH CLEAN_FISH DISSECT_FISH @@ -17,4 +17,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Hauler b/data/professions/Hauler similarity index 88% rename from data/examples/professions/Hauler rename to data/professions/Hauler index a108b1bfd0..36e7f400ab 100644 --- a/data/examples/professions/Hauler +++ b/data/professions/Hauler @@ -1,4 +1,4 @@ -NAME Hauler +NAME library/Hauler FEED_WATER_CIVILIANS SIEGEOPERATE MECHANIC @@ -19,4 +19,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Laborer b/data/professions/Laborer similarity index 87% rename from data/examples/professions/Laborer rename to data/professions/Laborer index bca22a302a..d9b9e7f498 100644 --- a/data/examples/professions/Laborer +++ b/data/professions/Laborer @@ -1,4 +1,4 @@ -NAME Laborer +NAME library/Laborer SOAP_MAKER BURN_WOOD POTASH_MAKING @@ -19,4 +19,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Marksdwarf b/data/professions/Marksdwarf similarity index 83% rename from data/examples/professions/Marksdwarf rename to data/professions/Marksdwarf index 583afd08e2..1c9153f02f 100644 --- a/data/examples/professions/Marksdwarf +++ b/data/professions/Marksdwarf @@ -1,4 +1,4 @@ -NAME Marksdwarf +NAME library/Marksdwarf MECHANIC HAUL_STONE HAUL_WOOD @@ -15,4 +15,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Mason b/data/professions/Mason similarity index 86% rename from data/examples/professions/Mason rename to data/professions/Mason index 5f996f4481..cd01d9a443 100644 --- a/data/examples/professions/Mason +++ b/data/professions/Mason @@ -1,4 +1,4 @@ -NAME Mason +NAME library/Mason MASON CUT_GEM ENCRUST_GEM @@ -17,4 +17,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Meleedwarf b/data/professions/Meleedwarf similarity index 84% rename from data/examples/professions/Meleedwarf rename to data/professions/Meleedwarf index 8eac5ffd6b..75b2196dfb 100644 --- a/data/examples/professions/Meleedwarf +++ b/data/professions/Meleedwarf @@ -1,4 +1,4 @@ -NAME Meleedwarf +NAME library/Meleedwarf RECOVER_WOUNDED MECHANIC HAUL_STONE @@ -16,4 +16,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Migrant b/data/professions/Migrant similarity index 88% rename from data/examples/professions/Migrant rename to data/professions/Migrant index 59fd70405c..bc59555b96 100644 --- a/data/examples/professions/Migrant +++ b/data/professions/Migrant @@ -1,4 +1,4 @@ -NAME Migrant +NAME library/Migrant FEED_WATER_CIVILIANS SIEGEOPERATE MECHANIC @@ -19,4 +19,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Miner b/data/professions/Miner similarity index 66% rename from data/examples/professions/Miner rename to data/professions/Miner index 7be84512d6..3170969d94 100644 --- a/data/examples/professions/Miner +++ b/data/professions/Miner @@ -1,4 +1,4 @@ -NAME Miner +NAME library/Miner MINE DETAIL RECOVER_WOUNDED diff --git a/data/examples/professions/Outdoorsdwarf b/data/professions/Outdoorsdwarf similarity index 88% rename from data/examples/professions/Outdoorsdwarf rename to data/professions/Outdoorsdwarf index a3f696419c..2b3006fdef 100644 --- a/data/examples/professions/Outdoorsdwarf +++ b/data/professions/Outdoorsdwarf @@ -1,4 +1,4 @@ -NAME Outdoorsdwarf +NAME library/Outdoorsdwarf CARPENTER BOWYER CUTWOOD @@ -25,4 +25,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Smith b/data/professions/Smith similarity index 88% rename from data/examples/professions/Smith rename to data/professions/Smith index f5fe0f9822..26574f80bf 100644 --- a/data/examples/professions/Smith +++ b/data/professions/Smith @@ -1,4 +1,4 @@ -NAME Smith +NAME library/Smith FORGE_WEAPON FORGE_ARMOR FORGE_FURNITURE @@ -18,4 +18,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/StartManager b/data/professions/StartManager similarity index 94% rename from data/examples/professions/StartManager rename to data/professions/StartManager index 751d75cc91..36519bce56 100644 --- a/data/examples/professions/StartManager +++ b/data/professions/StartManager @@ -1,4 +1,4 @@ -NAME StartManager +NAME library/StartManager CUTWOOD ANIMALCARE DIAGNOSE @@ -55,4 +55,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/examples/professions/Tailor b/data/professions/Tailor similarity index 86% rename from data/examples/professions/Tailor rename to data/professions/Tailor index 74ac03a93d..fc1b04bd4c 100644 --- a/data/examples/professions/Tailor +++ b/data/professions/Tailor @@ -1,4 +1,4 @@ -NAME Tailor +NAME library/Tailor DYER LEATHER WEAVER @@ -18,4 +18,3 @@ CLEAN PULL_LEVER BUILD_ROAD BUILD_CONSTRUCTION -REMOVE_CONSTRUCTION diff --git a/data/quickfort/aliases-common.txt b/data/quickfort/aliases-common.txt deleted file mode 100644 index e918b28a91..0000000000 --- a/data/quickfort/aliases-common.txt +++ /dev/null @@ -1,490 +0,0 @@ -# Standard library of aliases for quickfort query mode blueprints. -# -# Please DO NOT EDIT this file directly. It will get overwritten when DFHack -# is updated. Instead, custom aliases should be added to -# dfhack-config/quickfort/aliases.txt -# Custom alias definitions will take precedence over aliases in this file. -# -# Please see -# https://docs.dfhack.org/en/latest/docs/guides/quickfort-alias-guide.html -# or -# hack/docs/docs/guides/quickfort-alias-guide.html -# in your DF installation directory for alias syntax documentation and -# documentation for the aliases in this file. - -################################## -# naming aliases -################################## - -name: {Empty} -givename: !n{name}& -namezone: ^i{givename}^q - - -################################## -# quantum stockpile aliases -################################## - -# Allows the standard stockpile config aliases to also be used to configure -# hauling routes. -enter_sp_config: {enter_sp_config_default} -enter_sp_config_default: s -enter_sp_config_hauling: & - -quantum_enable: {enableanimals}{enablefood}{enablefurniture}{enablestone}{enableammo}{enablecoins}{enablebars}{enablegems}{enablefinishedgoods}{enableleather}{enablecloth}{enablewood}{enableweapons}{enablearmor}{enablesheet} -quantum: {linksonly}{nocontainers}{quantum_enable}{givename} - -stop_name: {Empty} -route_enable: {quantum_enable}{enablecorpses}{enablerefuse} -sp_link: s{move}p{move_back} -sp_links: {sp_link} -quantumstop: ^hrn{name}&sn{stop_name}&&xxx{route_enable enter_sp_config={enter_sp_config_hauling}}{sp_links}^^q -quantumstopfromeast: {quantumstop move={Right} move_back={Left}} -quantumstopfromsouth: {quantumstop move={Down} move_back={Up}} -quantumstopfromwest: {quantumstop move={Left} move_back={Right}} -quantumstopfromnorth: {quantumstop move={Up} move_back={Down}} - - -################################## -# farm plots -################################## - -growlastcropall: a/&b/&c/&d/& -growfirstcropall: a&b&c&d& - - -######################################## -# stockpile utility aliases -######################################## - -linksonly: a -maxbins: V -maxbarrels: R -nobins: C -nobarrels: E -nocontainers: {nobins}{nobarrels} - -give: g{move}& -give2up: {give move={Up 2}} -give2down: {give move={Down 2}} -give2left: {give move={Left 2}} -give2right: {give move={Right 2}} -give10up: {give move={Up 10}} -give10down: {give move={Down 10}} -give10left: {give move={Left 10}} -give10right: {give move={Right 10}} - -togglesequence: &{Down} -togglesequence2: &{Down 2} - -masterworkonly: {prefix}{Right}{Up 2}f{Right}{Up 2}&^ -artifactonly: {prefix}{Right}{Up 2}f{Right}{Up}&^ - -togglemasterwork: {prefix}{Right}{Up 2}{Right}{Up 2}&^ -toggleartifact: {prefix}{Right}{Up 2}{Right}{Up}&^ - - -################################## -# animal stockpile adjustments -################################## - -animalsprefix: {enter_sp_config} -enableanimals: {animalsprefix}e^ -disableanimals: {animalsprefix}d^ - -cages: {animalsprefix}bu^ -traps: {animalsprefix}bj^ - -forbidcages: {animalsprefix}u^ -forbidtraps: {animalsprefix}j^ - -permitcages: {forbidcages} -permittraps: {forbidtraps} - - -################################## -# food stockpile adjustments -################################## - -foodprefix: {enter_sp_config}{Down} -enablefood: {foodprefix}e^ -disablefood: {foodprefix}d^ - -preparedfood: {foodprefix}bu^ -unpreparedfish: {foodprefix}b{Right}{Down 2}p^ -plants: {foodprefix}b{Right}{Down 4}p^ -booze: {foodprefix}b{Right}{Down 5}p{Down}p^ -seeds: {foodprefix}b{Right}{Down 9}p^ -dye: {foodprefix}b{Right}{Down 11}{Right}{Down 28}{togglesequence 4}^ -tallow: {foodprefix}b{Right}{Down 13}{Right}stallow&p^ -miscliquid: {foodprefix}b{Right}{Down 18}p^ -wax: {foodprefix}b{Right}{Down 15}{Right}{Down 6}&^ - -forbidpreparedfood: {foodprefix}u^ -forbidunpreparedfish: {foodprefix}{Right}{Down 2}f^ -forbidplants: {foodprefix}{Right}{Down 4}f^ -forbidbooze: {foodprefix}{Right}{Down 5}f{Down}f^ -forbidseeds: {foodprefix}{Right}{Down 9}f^ -forbiddye: {foodprefix}{Right}{Down 11}{Right}{Down 28}{togglesequence 4}^ -forbidtallow: {foodprefix}{Right}{Down 13}{Right}stallow&f^ -forbidmiscliquid: {foodprefix}{Right}{Down 18}f^ -forbidwax: {foodprefix}{Right}{Down 15}{Right}{Down 6}&^ - -permitpreparedfood: {forbidpreparedfood} -permitunpreparedfish: {foodprefix}{Right}{Down 2}p^ -permitplants: {foodprefix}{Right}{Down 4}p^ -permitbooze: {foodprefix}{Right}{Down 5}p{Down}p^ -permitseeds: {foodprefix}{Right}{Down 9}p^ -permitdye: {forbiddye} -permittallow: {foodprefix}{Right}{Down 13}{Right}stallow&p^ -permitmiscliquid: {foodprefix}{Right}{Down 18}p^ -permitwax: {forbidwax} - -# the next two aliases are for compatibility with previous implementations of -# Quickfort and are not documented. -# enables everything but seeds -noseeds: {disablefood}{enablefood}{forbidseeds} -# enables all food except for the types listed above -food: {noseeds}{forbidpreparedfood}{forbidunpreparedfish}{forbidplants}{forbidbooze}{forbiddye}{forbidtallow}{forbidmiscliquid} - - -################################## -# furniture stockpile adjustments -################################## - -furnitureprefix: {enter_sp_config}{Down 2} -enablefurniture: {furnitureprefix}e^ -disablefurniture: {furnitureprefix}d^ - -pots: {furnitureprefix}de{Right}f{Right}{Up 5}&^ -bags: {furnitureprefix}de{Right}f{Right}{Up 10}&{Left}{Down}f{Down}f{Down}f{Right}{Down}&{Down 6}&{Down}&{Down 6}&^ -buckets: {furnitureprefix}de{Right}f{Right}{Up 12}&^ -sand: {furnitureprefix}de{Right}f{Right}{Up}&^ - -forbidpots: {furnitureprefix}{Right 2}{Up 5}&^ -forbidbuckets: {furnitureprefix}{Right 2}{Up 12}&^ -forbidsand: {furnitureprefix}{Right 2}{Up}&^ - -permitpots: {forbidpots} -permitbuckets: {forbidbuckets} -permitsand: {forbidsand} - -masterworkfurniture: {masterworkonly prefix={furnitureprefix}} -artifactfurniture: {artifactonly prefix={furnitureprefix}} - -forbidmasterworkfurniture: {togglemasterwork prefix={furnitureprefix}} -forbidartifactfurniture: {toggleartifact prefix={furnitureprefix}} - -permitmasterworkfurniture: {togglemasterwork prefix={furnitureprefix}} -permitartifactfurniture: {toggleartifact prefix={furnitureprefix}} - - -########################################### -# corpses and refuse stockpile adjustments -########################################### - -corpsesprefix: {enter_sp_config}{Down 3} -enablecorpses: {corpsesprefix}e^ -disablecorpses: {corpsesprefix}d{Up}d^ - -refuseprefix: {enter_sp_config}{Down 4} -enablerefuse: {refuseprefix}e^ -disablerefuse: {refuseprefix}d^ - -corpses: {refuseprefix}b{Right}{Down}p^ -rawhides: {refuseprefix}b{Right 2}{Down}&^ -tannedhides: {refuseprefix}b{Right 2}{Down 53}&^ -skulls: {refuseprefix}b{Right}{Down 3}p^ -bones: {refuseprefix}b{Right}{Down 4}p^ -shells: {refuseprefix}b{Right}{Down 5}p^ -teeth: {refuseprefix}b{Right}{Down 6}p^ -horns: {refuseprefix}b{Right}{Down 7}p^ -hair: {refuseprefix}b{Right}{Down 8}p^ -craftrefuse: {skulls}{permitbones}{permitshells}{permitteeth}{permithorns}{permithair} - -forbidcorpses: {refuseprefix}{Right}{Down}f^ -forbidrawhides: {refuseprefix}{Right 2}{Down}&^ -forbidtannedhides: {refuseprefix}{Right 2}{Down 53}&^ -forbidskulls: {refuseprefix}{Right}{Down 3}f^ -forbidbones: {refuseprefix}{Right}{Down 4}f^ -forbidshells: {refuseprefix}{Right}{Down 5}f^ -forbidteeth: {refuseprefix}{Right}{Down 6}f^ -forbidhorns: {refuseprefix}{Right}{Down 7}f^ -forbidhair: {refuseprefix}{Right}{Down 8}f^ -forbidcraftrefuse: {forbidskulls}{forbidbones}{forbidshells}{forbidteeth}{forbidhorns}{forbidhair} - -permitcorpses: {refuseprefix}{Right}{Down}p^ -permitrawhides: {forbidrawhides} -permittannedhides: {forbidtannedhides} -permitskulls: {refuseprefix}{Right}{Down 3}p^ -permitbones: {refuseprefix}{Right}{Down 4}p^ -permitshells: {refuseprefix}{Right}{Down 5}p^ -permitteeth: {refuseprefix}{Right}{Down 6}p^ -permithorns: {refuseprefix}{Right}{Down 7}p^ -permithair: {refuseprefix}{Right}{Down 8}p^ -permitcraftrefuse: {permitskulls}{permitbones}{permitshells}{permitteeth}{permithorns}{permithair} - - -################################## -# stone stockpile adjustments -################################## - -stoneprefix: {enter_sp_config}{Down 5} -enablestone: {stoneprefix}e^ -disablestone: {stoneprefix}d^ - -metal: {stoneprefix}b{Right}p^ -iron: {stoneprefix}b{Right}{Right}&{Down}&{Down 13}&^ -economic: {stoneprefix}b{Right}{Down}p^ -flux: {stoneprefix}b{Right}{Down}{Right}{togglesequence 4}{Down 4}&^ -plaster: {stoneprefix}b{Right}{Down}{Right}{Down 6}&{Down 3}{togglesequence 3}^ -coalproducing: {stoneprefix}b{Right}{Down}{Right}{Down 4}{togglesequence 2}^ -otherstone: {stoneprefix}b{Right}{Down 2}p^ -bauxite: {stoneprefix}b{Right}{Down 2}{Right}{Down 42}&^ -clay: {stoneprefix}b{Right}{Down 3}p^ - -forbidmetal: {stoneprefix}{Right}f^ -forbidiron: {stoneprefix}{Right}{Right}&{Down}&{Down 13}&^ -forbideconomic: {stoneprefix}{Right}{Down}f^ -forbidflux: {stoneprefix}{Right}{Down}{Right}{togglesequence 4}{Down 4}&^ -forbidplaster: {stoneprefix}{Right}{Down}{Right}{Down 6}&{Down 3}{togglesequence 3}^ -forbidcoalproducing: {stoneprefix}{Right}{Down}{Right}{Down 4}{togglesequence 2}^ -forbidotherstone: {stoneprefix}{Right}{Down 2}f^ -forbidbauxite: {stoneprefix}{Right}{Down 2}{Right}{Down 42}&^ -forbidclay: {stoneprefix}{Right}{Down 3}f^ - -permitmetal: {stoneprefix}{Right}p^ -permitiron: {forbidiron} -permiteconomic: {stoneprefix}{Right}{Down}p^ -permitflux: {forbidflux} -permitplaster: {forbidplaster} -permitcoalproducing: {forbidcoalproducing} -permitotherstone: {stoneprefix}{Right}{Down 2}p^ -permitbauxite: {forbidbauxite} -permitclay: {stoneprefix}{Right}{Down 3}p^ - - -################################## -# ammo stockpile adjustments -################################## - -ammoprefix: {enter_sp_config}{Down 6} -enableammo: {ammoprefix}e^ -disableammo: {ammoprefix}d^ - -bolts: {ammoprefix}a{Right 2}f&^ - -forbidmetalbolts: {ammoprefix}{Right}{Down}f^ -forbidwoodenbolts: {ammoprefix}{Right}{Down 2}{Right}&^ -forbidbonebolts: {ammoprefix}{Right}{Down 2}{Right}{Down}&^ - -masterworkammo: {masterworkonly prefix={ammoprefix}} -artifactammo: {artifactonly prefix={ammoprefix}} - -forbidmasterworkammo: {togglemasterwork prefix={ammoprefix}} -forbidartifactammo: {toggleartifact prefix={ammoprefix}} - -permitmasterworkammo: {togglemasterwork prefix={ammoprefix}} -permitartifactammo: {toggleartifact prefix={ammoprefix}} - - -################################## -# bar stockpile adjustments -################################## - -barsprefix: {enter_sp_config}{Down 8} -enablebars: {barsprefix}e^ -disablebars: {barsprefix}d^ - -bars: {barsprefix}b{Right}p{Down}p^ -metalbars: {barsprefix}b{Right}p^ -ironbars: {barsprefix}b{Right 2}&^ -steelbars: {barsprefix}b{Right 2}{Down 8}&^ -pigironbars: {barsprefix}b{Right 2}{Down 9}&^ -otherbars: {barsprefix}b{Right}{Down}p^ -coal: {barsprefix}b{Right}{Down}{Right}&^ -potash: {barsprefix}b{Right}{Down}{Right}{Down}&^ -ash: {barsprefix}b{Right}{Down}{Right}{Down 2}&^ -pearlash: {barsprefix}b{Right}{Down}{Right}{Down 3}&^ -soap: {barsprefix}b{Right}{Down}{Right}{Down 4}&^ -blocks: {barsprefix}b{Down 2}p{Down}p{Down}p^ - -forbidbars: {barsprefix}{Right}f{Down}f^ -forbidmetalbars: {barsprefix}{Right}f^ -forbidironbars: {barsprefix}{Right 2}&^ -forbidsteelbars: {barsprefix}{Right 2}{Down 8}&^ -forbidpigironbars: {barsprefix}{Right 2}{Down 9}&^ -forbidotherbars: {barsprefix}{Right}{Down}f^ -forbidcoal: {barsprefix}{Right}{Down}{Right}&^ -forbidpotash: {barsprefix}{Right}{Down}{Right}{Down}&^ -forbidash: {barsprefix}{Right}{Down}{Right}{Down 2}&^ -forbidpearlash: {barsprefix}{Right}{Down}{Right}{Down 3}&^ -forbidsoap: {barsprefix}{Right}{Down}{Right}{Down 4}&^ -forbidblocks: {barsprefix}{Down 2}f{Down}f{Down}f^ - - -################################## -# gem stockpile adjustments -################################## - -gemsprefix: {enter_sp_config}{Down 9} -enablegems: {gemsprefix}e^ -disablegems: {gemsprefix}d^ - -roughgems: {gemsprefix}b{Right}p^ -roughglass: {gemsprefix}b{Right}{Down}p^ -cutgems: {gemsprefix}b{Right}{Down 2}p^ -cutglass: {gemsprefix}b{Right}{Down 3}p^ -cutstone: {gemsprefix}b{Right}{Down 4}p^ - -forbidroughgems: {gemsprefix}{Right}f^ -forbidroughglass: {gemsprefix}{Right}{Down}f^ -forbidcutgems: {gemsprefix}{Right}{Down 2}f^ -forbidcutglass: {gemsprefix}{Right}{Down 3}f^ -forbidcutstone: {gemsprefix}{Right}{Down 4}f^ - - -####################################### -# finished goods stockpile adjustments -####################################### - -finishedgoodsprefix: {enter_sp_config}{Down 10} -enablefinishedgoods: {finishedgoodsprefix}e^ -disablefinishedgoods: {finishedgoodsprefix}d^ - -crafts: {finishedgoodsprefix}{Right}f{Right}{Down 9}{togglesequence 9}^ -goblets: {finishedgoodsprefix}{Right}f{Right}{Down 2}&^ -jugs: {finishedgoodsprefix}{Right}f{Right}{Up 2}&{Left}{Down 2}f{Down}f{Down}f^ - -forbidcrafts: {finishedgoodsprefix}{Right 2}{Down 9}{togglesequence 9}^ -forbidgoblets: {finishedgoodsprefix}{Right 2}{Down 2}&^ - -permitcrafts: {forbidcrafts} -permitgoblets: {forbidgoblets} - -masterworkfinishedgoods: {masterworkonly prefix={finishedgoodsprefix}} -artifactfinishedgoods: {artifactonly prefix={finishedgoodsprefix}} - -forbidmasterworkfinishedgoods: {togglemasterwork prefix={finishedgoodsprefix}} -forbidartifactfinishedgoods: {toggleartifact prefix={finishedgoodsprefix}} - -permitmasterworkfinishedgoods: {togglemasterwork prefix={finishedgoodsprefix}} -permitartifactfinishedgoods: {toggleartifact prefix={finishedgoodsprefix}} - - -################################## -# cloth -################################## - -clothprefix: {enter_sp_config}{Down 12} -enablecloth: {clothprefix}e^ -disablecloth: {clothprefix}d^ - -thread: {clothprefix}b{Right}p{Down}p{Down}p^ -adamantinethread: {clothprefix}b{Right}{Down 3}p^ -cloth: {clothprefix}b{Right}{Down 4}p{Down}p{Down}p^ -adamantinecloth: {clothprefix}b{Right}{Up}p^ - - -################################## -# weapon stockpile adjustments -################################## - -weaponsprefix: {enter_sp_config}{Down 14} -enableweapons: {weaponsprefix}e^ -disableweapons: {weaponsprefix}d^ - -metalweapons: {forbidtrapcomponents}{forbidstoneweapons}{forbidotherweapons} -ironweapons: {metalweapons}{forbidmetalweapons}{permitironweapons} -bronzeweapons: {metalweapons}{forbidmetalweapons}{permitbronzeweapons} -copperweapons: {metalweapons}{forbidmetalweapons}{permitcopperweapons} -steelweapons: {metalweapons}{forbidmetalweapons}{permitsteelweapons} - -forbidweapons: {weaponsprefix}{Right}f^ -forbidtrapcomponents: {weaponsprefix}{Right}{Down}f^ -forbidmetalweapons: {weaponsprefix}{Right}{Down 2}f^ -forbidstoneweapons: {weaponsprefix}{Right}{Down 3}f^ -forbidotherweapons: {weaponsprefix}{Right}{Down 4}f^ -forbidironweapons: {weaponsprefix}{Right}{Down 2}{Right}&^ -forbidbronzeweapons: {weaponsprefix}{Right}{Down 2}{Right}{Down 6}&^ -forbidcopperweapons: {weaponsprefix}{Right}{Down 2}{Right}{Down 3}&^ -forbidsteelweapons: {weaponsprefix}{Right}{Down 2}{Right}{Down 8}&^ - -permitweapons: {weaponsprefix}{Right}p^ -permittrapcomponents: {weaponsprefix}{Right}{Down}p^ -permitmetalweapons: {weaponsprefix}{Right}{Down 2}p^ -permitstoneweapons: {weaponsprefix}{Right}{Down 3}p^ -permitotherweapons: {weaponsprefix}{Right}{Down 4}p^ -permitironweapons: {forbidironweapons} -permitbronzeweapons: {forbidbronzeweapons} -permitcopperweapons: {forbidcopperweapons} -permitsteelweapons: {forbidsteelweapons} - -masterworkweapons: {masterworkonly prefix={weaponsprefix}} -artifactweapons: {artifactonly prefix={weaponsprefix}} - -forbidmasterworkweapons: {togglemasterwork prefix={weaponsprefix}} -forbidartifactweapons: {toggleartifact prefix={weaponsprefix}} - -permitmasterworkweapons: {togglemasterwork prefix={weaponsprefix}} -permitartifactweapons: {toggleartifact prefix={weaponsprefix}} - - -################################## -# armor stockpile adjustments -################################## - -armorprefix: {enter_sp_config}{Down 15} -enablearmor: {armorprefix}e^ -disablearmor: {armorprefix}d^ - -metalarmor: {forbidotherarmor} -otherarmor: {forbidmetalarmor} -ironarmor: {metalarmor}{forbidmetalarmor}{permitironarmor} -bronzearmor: {metalarmor}{forbidmetalarmor}{permitbronzearmor} -copperarmor: {metalarmor}{forbidmetalarmor}{permitcopperarmor} -steelarmor: {metalarmor}{forbidmetalarmor}{permitsteelarmor} - -forbidmetalarmor: {armorprefix}{Right}{Down 6}f^ -forbidotherarmor: {armorprefix}{Right}{Down 7}f^ -forbidironarmor: {armorprefix}{Right}{Down 6}{Right}&^ -forbidbronzearmor: {armorprefix}{Right}{Down 6}{Right}{Down 6}&^ -forbidcopperarmor: {armorprefix}{Right}{Down 6}{Right}{Down 3}&^ -forbidsteelarmor: {armorprefix}{Right}{Down 6}{Right}{Down 8}&^ - -permitmetalarmor: {armorprefix}{Right}{Down 6}p^ -permitotherarmor: {armorprefix}{Right}{Down 7}p^ -permitironarmor: {forbidironarmor} -permitbronzearmor: {forbidbronzearmor} -permitcopperarmor: {forbidcopperarmor} -permitsteelarmor: {forbidsteelarmor} - -masterworkarmor: {masterworkonly prefix={armorprefix}} -artifactarmor: {artifactonly prefix={armorprefix}} - -forbidmasterworkarmor: {togglemasterwork prefix={armorprefix}} -forbidartifactarmor: {toggleartifact prefix={armorprefix}} - -permitmasterworkarmor: {togglemasterwork prefix={armorprefix}} -permitartifactarmor: {toggleartifact prefix={armorprefix}} - - -################################## -# others -################################## - -coinsprefix: {enter_sp_config}{Down 7} -enablecoins: {coinsprefix}e^ -disablecoins: {coinsprefix}d^ - -leatherprefix: {enter_sp_config}{Down 11} -enableleather: {leatherprefix}e^ -disableleather: {leatherprefix}d^ - -woodprefix: {enter_sp_config}{Down 13} -enablewood: {woodprefix}e^ -disablewood: {woodprefix}d^ - -sheetprefix: {enter_sp_config}{Down 16} -enablesheet: {sheetprefix}e^ -disablesheet: {sheetprefix}d^ diff --git a/data/stockpiles/adamantinecloth.dfstock b/data/stockpiles/adamantinecloth.dfstock new file mode 100644 index 0000000000..38781d3130 --- /dev/null +++ b/data/stockpiles/adamantinecloth.dfstock @@ -0,0 +1 @@ +rBINORGANIC:ADAMANTINE \ No newline at end of file diff --git a/data/stockpiles/adamantinethread.dfstock b/data/stockpiles/adamantinethread.dfstock new file mode 100644 index 0000000000..2231b389f5 --- /dev/null +++ b/data/stockpiles/adamantinethread.dfstock @@ -0,0 +1 @@ +r"INORGANIC:ADAMANTINE \ No newline at end of file diff --git a/data/stockpiles/adamantineweapons.dfstock b/data/stockpiles/adamantineweapons.dfstock new file mode 100644 index 0000000000..6236196f0e Binary files /dev/null and b/data/stockpiles/adamantineweapons.dfstock differ diff --git a/data/stockpiles/all.dfstock b/data/stockpiles/all.dfstock new file mode 100644 index 0000000000..eace9c53dd Binary files /dev/null and b/data/stockpiles/all.dfstock differ diff --git a/data/stockpiles/artifacts.dfstock b/data/stockpiles/artifacts.dfstock new file mode 100644 index 0000000000..1c7315dfe8 Binary files /dev/null and b/data/stockpiles/artifacts.dfstock differ diff --git a/data/stockpiles/ash.dfstock b/data/stockpiles/ash.dfstock new file mode 100644 index 0000000000..d313e0096d --- /dev/null +++ b/data/stockpiles/ash.dfstock @@ -0,0 +1,2 @@ +R +ASH \ No newline at end of file diff --git a/data/stockpiles/bags.dfstock b/data/stockpiles/bags.dfstock new file mode 100644 index 0000000000..3bfa1a1a17 --- /dev/null +++ b/data/stockpiles/bags.dfstock @@ -0,0 +1,2 @@ + +BAG \ No newline at end of file diff --git a/data/stockpiles/barrels.dfstock b/data/stockpiles/barrels.dfstock new file mode 100644 index 0000000000..70a7239035 --- /dev/null +++ b/data/stockpiles/barrels.dfstock @@ -0,0 +1,2 @@ + +BARREL \ No newline at end of file diff --git a/data/stockpiles/bars.dfstock b/data/stockpiles/bars.dfstock new file mode 100644 index 0000000000..c292dcf562 --- /dev/null +++ b/data/stockpiles/bars.dfstock @@ -0,0 +1,6 @@ +Rõ +COAL +POTASH +ASH +PEARLASH +SOAPINORGANIC:IRONINORGANIC:SILVERINORGANIC:COPPERINORGANIC:NICKELINORGANIC:ZINCINORGANIC:BRONZEINORGANIC:BRASSINORGANIC:STEELINORGANIC:PIG_IRONINORGANIC:PLATINUMINORGANIC:ELECTRUM INORGANIC:TININORGANIC:PEWTER_FINEINORGANIC:PEWTER_TRIFLEINORGANIC:PEWTER_LAYINORGANIC:LEADINORGANIC:ALUMINUMINORGANIC:NICKEL_SILVERINORGANIC:BILLONINORGANIC:STERLING_SILVERINORGANIC:BLACK_BRONZEINORGANIC:ROSE_GOLDINORGANIC:BISMUTHINORGANIC:BISMUTH_BRONZEINORGANIC:ADAMANTINEINORGANIC:GOLDINORGANIC:DIVINE_1INORGANIC:DIVINE_3INORGANIC:DIVINE_5INORGANIC:DIVINE_7INORGANIC:DIVINE_9INORGANIC:DIVINE_11INORGANIC:DIVINE_13INORGANIC:DIVINE_15INORGANIC:DIVINE_17INORGANIC:DIVINE_19 \ No newline at end of file diff --git a/data/stockpiles/bauxite.dfstock b/data/stockpiles/bauxite.dfstock new file mode 100644 index 0000000000..83a49cb5b4 --- /dev/null +++ b/data/stockpiles/bauxite.dfstock @@ -0,0 +1,2 @@ +2 +INORGANIC:BAUXITE \ No newline at end of file diff --git a/data/stockpiles/blocks.dfstock b/data/stockpiles/blocks.dfstock new file mode 100644 index 0000000000..cd08d93338 --- /dev/null +++ b/data/stockpiles/blocks.dfstock @@ -0,0 +1 @@ +Rã GREEN_GLASS CLEAR_GLASS CRYSTAL_GLASSWOOD"INORGANIC:IRON"INORGANIC:SILVER"INORGANIC:COPPER"INORGANIC:NICKEL"INORGANIC:ZINC"INORGANIC:BRONZE"INORGANIC:BRASS"INORGANIC:STEEL"INORGANIC:PIG_IRON"INORGANIC:PLATINUM"INORGANIC:ELECTRUM" INORGANIC:TIN"INORGANIC:PEWTER_FINE"INORGANIC:PEWTER_TRIFLE"INORGANIC:PEWTER_LAY"INORGANIC:LEAD"INORGANIC:ALUMINUM"INORGANIC:NICKEL_SILVER"INORGANIC:BILLON"INORGANIC:STERLING_SILVER"INORGANIC:BLACK_BRONZE"INORGANIC:ROSE_GOLD"INORGANIC:BISMUTH"INORGANIC:BISMUTH_BRONZE"INORGANIC:ADAMANTINE"INORGANIC:PLASTER"INORGANIC:CERAMIC_EARTHENWARE"INORGANIC:CERAMIC_STONEWARE"INORGANIC:CERAMIC_PORCELAIN"INORGANIC:ASH_GLAZE"INORGANIC:TIN_GLAZE"INORGANIC:SANDSTONE"INORGANIC:SILTSTONE"INORGANIC:MUDSTONE"INORGANIC:SHALE"INORGANIC:CLAYSTONE"INORGANIC:ROCK_SALT"INORGANIC:LIMESTONE"INORGANIC:CONGLOMERATE"INORGANIC:DOLOMITE"INORGANIC:CHERT"INORGANIC:CHALK"INORGANIC:GRANITE"INORGANIC:DIORITE"INORGANIC:GABBRO"INORGANIC:RHYOLITE"INORGANIC:BASALT"INORGANIC:ANDESITE"INORGANIC:DACITE"INORGANIC:OBSIDIAN"INORGANIC:QUARTZITE"INORGANIC:SLATE"INORGANIC:PHYLLITE"INORGANIC:SCHIST"INORGANIC:GNEISS"INORGANIC:MARBLE"INORGANIC:HEMATITE"INORGANIC:LIMONITE"INORGANIC:GARNIERITE"INORGANIC:NATIVE_GOLD"INORGANIC:NATIVE_SILVER"INORGANIC:NATIVE_COPPER"INORGANIC:MALACHITE"INORGANIC:GALENA"INORGANIC:SPHALERITE"INORGANIC:CASSITERITE"INORGANIC:COAL_BITUMINOUS"INORGANIC:LIGNITE"INORGANIC:NATIVE_PLATINUM"INORGANIC:CINNABAR"INORGANIC:COBALTITE"INORGANIC:TETRAHEDRITE"INORGANIC:HORN_SILVER"INORGANIC:GYPSUM"INORGANIC:TALC" INORGANIC:JET"INORGANIC:PUDDINGSTONE"INORGANIC:PETRIFIED_WOOD"INORGANIC:GRAPHITE"INORGANIC:BRIMSTONE"INORGANIC:KIMBERLITE"INORGANIC:BISMUTHINITE"INORGANIC:REALGAR"INORGANIC:ORPIMENT"INORGANIC:STIBNITE"INORGANIC:MARCASITE"INORGANIC:SYLVITE"INORGANIC:CRYOLITE"INORGANIC:PERICLASE"INORGANIC:ILMENITE"INORGANIC:RUTILE"INORGANIC:MAGNETITE"INORGANIC:CHROMITE"INORGANIC:PYROLUSITE"INORGANIC:PITCHBLENDE"INORGANIC:BAUXITE"INORGANIC:NATIVE_ALUMINUM"INORGANIC:BORAX"INORGANIC:OLIVINE"INORGANIC:HORNBLENDE"INORGANIC:KAOLINITE"INORGANIC:SERPENTINE"INORGANIC:ORTHOCLASE"INORGANIC:MICROCLINE"INORGANIC:MICA"INORGANIC:CALCITE"INORGANIC:SALTPETER"INORGANIC:ALABASTER"INORGANIC:SELENITE"INORGANIC:SATINSPAR"INORGANIC:ANHYDRITE"INORGANIC:ALUNITE"INORGANIC:RAW_ADAMANTINE"INORGANIC:SLADE" INORGANIC:BROMS_CLEAN_CORPSEDUST"INORGANIC:GOLD"INORGANIC:DIVINE_1"INORGANIC:DIVINE_3"INORGANIC:DIVINE_5"INORGANIC:DIVINE_7"INORGANIC:DIVINE_9"INORGANIC:DIVINE_11"INORGANIC:DIVINE_13"INORGANIC:DIVINE_15"INORGANIC:DIVINE_17"INORGANIC:DIVINE_19 \ No newline at end of file diff --git a/data/stockpiles/bolts.dfstock b/data/stockpiles/bolts.dfstock new file mode 100644 index 0000000000..2e5bd4b4b8 --- /dev/null +++ b/data/stockpiles/bolts.dfstock @@ -0,0 +1,2 @@ +B +AMMO:ITEM_AMMO_BOLTS \ No newline at end of file diff --git a/data/stockpiles/boneammo.dfstock b/data/stockpiles/boneammo.dfstock new file mode 100644 index 0000000000..909c67d1df --- /dev/null +++ b/data/stockpiles/boneammo.dfstock @@ -0,0 +1 @@ +BBONE \ No newline at end of file diff --git a/data/stockpiles/booze.dfstock b/data/stockpiles/booze.dfstock new file mode 100644 index 0000000000..736560f988 Binary files /dev/null and b/data/stockpiles/booze.dfstock differ diff --git a/data/stockpiles/bronzearmor.dfstock b/data/stockpiles/bronzearmor.dfstock new file mode 100644 index 0000000000..22dda4155e Binary files /dev/null and b/data/stockpiles/bronzearmor.dfstock differ diff --git a/data/stockpiles/bronzeweapons.dfstock b/data/stockpiles/bronzeweapons.dfstock new file mode 100644 index 0000000000..54cd87d110 Binary files /dev/null and b/data/stockpiles/bronzeweapons.dfstock differ diff --git a/data/stockpiles/buckets.dfstock b/data/stockpiles/buckets.dfstock new file mode 100644 index 0000000000..cb6b8c4bb5 --- /dev/null +++ b/data/stockpiles/buckets.dfstock @@ -0,0 +1,2 @@ + +BUCKET \ No newline at end of file diff --git a/data/stockpiles/cages.dfstock b/data/stockpiles/cages.dfstock new file mode 100644 index 0000000000..0ca677985c Binary files /dev/null and b/data/stockpiles/cages.dfstock differ diff --git a/data/stockpiles/cat_ammo.dfstock b/data/stockpiles/cat_ammo.dfstock new file mode 100644 index 0000000000..55a20e7e65 --- /dev/null +++ b/data/stockpiles/cat_ammo.dfstock @@ -0,0 +1 @@ +B0 \ No newline at end of file diff --git a/data/stockpiles/cat_animals.dfstock b/data/stockpiles/cat_animals.dfstock new file mode 100644 index 0000000000..9796e4535c --- /dev/null +++ b/data/stockpiles/cat_animals.dfstock @@ -0,0 +1,2 @@ + +  \ No newline at end of file diff --git a/data/stockpiles/cat_armor.dfstock b/data/stockpiles/cat_armor.dfstock new file mode 100644 index 0000000000..54a2d54eee --- /dev/null +++ b/data/stockpiles/cat_armor.dfstock @@ -0,0 +1 @@ +Šh \ No newline at end of file diff --git a/data/stockpiles/cat_bars_blocks.dfstock b/data/stockpiles/cat_bars_blocks.dfstock new file mode 100644 index 0000000000..b7ae54bb1f --- /dev/null +++ b/data/stockpiles/cat_bars_blocks.dfstock @@ -0,0 +1 @@ +R( \ No newline at end of file diff --git a/data/stockpiles/cat_cloth.dfstock b/data/stockpiles/cat_cloth.dfstock new file mode 100644 index 0000000000..d88106c6b8 --- /dev/null +++ b/data/stockpiles/cat_cloth.dfstock @@ -0,0 +1 @@ +rH \ No newline at end of file diff --git a/data/stockpiles/cat_coins.dfstock b/data/stockpiles/cat_coins.dfstock new file mode 100644 index 0000000000..a48133ac40 --- /dev/null +++ b/data/stockpiles/cat_coins.dfstock @@ -0,0 +1 @@ +J \ No newline at end of file diff --git a/data/stockpiles/cat_corpses.dfstock b/data/stockpiles/cat_corpses.dfstock new file mode 100644 index 0000000000..f4edc7ff85 --- /dev/null +++ b/data/stockpiles/cat_corpses.dfstock @@ -0,0 +1 @@ +Ê \ No newline at end of file diff --git a/data/stockpiles/cat_finished_goods.dfstock b/data/stockpiles/cat_finished_goods.dfstock new file mode 100644 index 0000000000..68a2d90531 --- /dev/null +++ b/data/stockpiles/cat_finished_goods.dfstock @@ -0,0 +1 @@ +b0 \ No newline at end of file diff --git a/data/stockpiles/cat_food.dfstock b/data/stockpiles/cat_food.dfstock new file mode 100644 index 0000000000..32829f6776 --- /dev/null +++ b/data/stockpiles/cat_food.dfstock @@ -0,0 +1 @@ +¨ \ No newline at end of file diff --git a/data/stockpiles/cat_furniture.dfstock b/data/stockpiles/cat_furniture.dfstock new file mode 100644 index 0000000000..fdec022edf --- /dev/null +++ b/data/stockpiles/cat_furniture.dfstock @@ -0,0 +1 @@ +8 \ No newline at end of file diff --git a/data/stockpiles/cat_gems.dfstock b/data/stockpiles/cat_gems.dfstock new file mode 100644 index 0000000000..8a6483e26e --- /dev/null +++ b/data/stockpiles/cat_gems.dfstock @@ -0,0 +1 @@ +Z( \ No newline at end of file diff --git a/data/stockpiles/cat_leather.dfstock b/data/stockpiles/cat_leather.dfstock new file mode 100644 index 0000000000..357287897c --- /dev/null +++ b/data/stockpiles/cat_leather.dfstock @@ -0,0 +1 @@ +j \ No newline at end of file diff --git a/data/stockpiles/cat_refuse.dfstock b/data/stockpiles/cat_refuse.dfstock new file mode 100644 index 0000000000..a6219a81af --- /dev/null +++ b/data/stockpiles/cat_refuse.dfstock @@ -0,0 +1 @@ +*` \ No newline at end of file diff --git a/data/stockpiles/cat_sheets.dfstock b/data/stockpiles/cat_sheets.dfstock new file mode 100644 index 0000000000..0230086d80 --- /dev/null +++ b/data/stockpiles/cat_sheets.dfstock @@ -0,0 +1 @@ +Ò \ No newline at end of file diff --git a/data/stockpiles/cat_stone.dfstock b/data/stockpiles/cat_stone.dfstock new file mode 100644 index 0000000000..29bcd227e4 --- /dev/null +++ b/data/stockpiles/cat_stone.dfstock @@ -0,0 +1 @@ +2 \ No newline at end of file diff --git a/data/stockpiles/cat_weapons.dfstock b/data/stockpiles/cat_weapons.dfstock new file mode 100644 index 0000000000..8f46ee6199 --- /dev/null +++ b/data/stockpiles/cat_weapons.dfstock @@ -0,0 +1 @@ +‚H \ No newline at end of file diff --git a/data/stockpiles/cat_wood.dfstock b/data/stockpiles/cat_wood.dfstock new file mode 100644 index 0000000000..5613a0f077 --- /dev/null +++ b/data/stockpiles/cat_wood.dfstock @@ -0,0 +1 @@ +z \ No newline at end of file diff --git a/data/stockpiles/clay.dfstock b/data/stockpiles/clay.dfstock new file mode 100644 index 0000000000..e01c7abaf7 --- /dev/null +++ b/data/stockpiles/clay.dfstock @@ -0,0 +1,6 @@ +2f +INORGANIC:CLAY +INORGANIC:SILTY_CLAY +INORGANIC:SANDY_CLAY +INORGANIC:CLAY_LOAM +INORGANIC:FIRE_CLAY \ No newline at end of file diff --git a/data/stockpiles/cloth.dfstock b/data/stockpiles/cloth.dfstock new file mode 100644 index 0000000000..26c4c52f30 --- /dev/null +++ b/data/stockpiles/cloth.dfstock @@ -0,0 +1 @@ +rŽ'*"CREATURE:SPIDER_BROWN_RECLUSE:SILK*&CREATURE:BROWN_RECLUSE_SPIDER_MAN:SILK*(CREATURE:GIANT_BROWN_RECLUSE_SPIDER:SILK*CREATURE:SPIDER_PHANTOM:SILK*CREATURE:SPIDER_CAVE_GIANT:SILK*CREATURE:SPIDER_CAVE:SILK*INORGANIC:DIVINE_2*INORGANIC:DIVINE_4*INORGANIC:DIVINE_6*INORGANIC:DIVINE_8*INORGANIC:DIVINE_10*INORGANIC:DIVINE_12*INORGANIC:DIVINE_14*INORGANIC:DIVINE_16*INORGANIC:DIVINE_18*INORGANIC:DIVINE_20*CREATURE:FORGOTTEN_BEAST_4:SILK* CREATURE:FORGOTTEN_BEAST_22:SILK* CREATURE:FORGOTTEN_BEAST_33:SILK* CREATURE:FORGOTTEN_BEAST_51:SILK* CREATURE:FORGOTTEN_BEAST_56:SILK* CREATURE:FORGOTTEN_BEAST_58:SILK* CREATURE:FORGOTTEN_BEAST_62:SILK* CREATURE:FORGOTTEN_BEAST_74:SILK* CREATURE:FORGOTTEN_BEAST_80:SILK* CREATURE:FORGOTTEN_BEAST_87:SILK* CREATURE:FORGOTTEN_BEAST_90:SILK*!CREATURE:FORGOTTEN_BEAST_106:SILK*!CREATURE:FORGOTTEN_BEAST_109:SILK*!CREATURE:FORGOTTEN_BEAST_127:SILK*!CREATURE:FORGOTTEN_BEAST_131:SILK*!CREATURE:FORGOTTEN_BEAST_143:SILK*!CREATURE:FORGOTTEN_BEAST_145:SILK*!CREATURE:FORGOTTEN_BEAST_163:SILK*!CREATURE:FORGOTTEN_BEAST_177:SILK*!CREATURE:FORGOTTEN_BEAST_189:SILK*!CREATURE:FORGOTTEN_BEAST_194:SILK*!CREATURE:FORGOTTEN_BEAST_197:SILK*!CREATURE:FORGOTTEN_BEAST_200:SILK*!CREATURE:FORGOTTEN_BEAST_201:SILK*!CREATURE:FORGOTTEN_BEAST_202:SILK*!CREATURE:FORGOTTEN_BEAST_217:SILK*!CREATURE:FORGOTTEN_BEAST_224:SILK*!CREATURE:FORGOTTEN_BEAST_234:SILK*!CREATURE:FORGOTTEN_BEAST_242:SILK*!CREATURE:FORGOTTEN_BEAST_246:SILK*!CREATURE:FORGOTTEN_BEAST_250:SILK*!CREATURE:FORGOTTEN_BEAST_270:SILK*!CREATURE:FORGOTTEN_BEAST_271:SILK*!CREATURE:FORGOTTEN_BEAST_286:SILK*!CREATURE:FORGOTTEN_BEAST_291:SILK*!CREATURE:FORGOTTEN_BEAST_296:SILK*!CREATURE:FORGOTTEN_BEAST_329:SILK*!CREATURE:FORGOTTEN_BEAST_350:SILK*!CREATURE:FORGOTTEN_BEAST_351:SILK*!CREATURE:FORGOTTEN_BEAST_359:SILK*!CREATURE:FORGOTTEN_BEAST_365:SILK*!CREATURE:FORGOTTEN_BEAST_375:SILK*!CREATURE:FORGOTTEN_BEAST_376:SILK*!CREATURE:FORGOTTEN_BEAST_377:SILK*!CREATURE:FORGOTTEN_BEAST_383:SILK*!CREATURE:FORGOTTEN_BEAST_387:SILK*!CREATURE:FORGOTTEN_BEAST_398:SILK*!CREATURE:FORGOTTEN_BEAST_400:SILK*!CREATURE:FORGOTTEN_BEAST_406:SILK*!CREATURE:FORGOTTEN_BEAST_410:SILK*!CREATURE:FORGOTTEN_BEAST_417:SILK*!CREATURE:FORGOTTEN_BEAST_428:SILK*!CREATURE:FORGOTTEN_BEAST_429:SILK*!CREATURE:FORGOTTEN_BEAST_432:SILK*!CREATURE:FORGOTTEN_BEAST_442:SILK*!CREATURE:FORGOTTEN_BEAST_448:SILK*!CREATURE:FORGOTTEN_BEAST_452:SILK*!CREATURE:FORGOTTEN_BEAST_457:SILK*!CREATURE:FORGOTTEN_BEAST_468:SILK*!CREATURE:FORGOTTEN_BEAST_472:SILK*!CREATURE:FORGOTTEN_BEAST_479:SILK*!CREATURE:FORGOTTEN_BEAST_482:SILK*!CREATURE:FORGOTTEN_BEAST_492:SILK*!CREATURE:FORGOTTEN_BEAST_504:SILK*!CREATURE:FORGOTTEN_BEAST_512:SILK*!CREATURE:FORGOTTEN_BEAST_519:SILK*!CREATURE:FORGOTTEN_BEAST_537:SILK*!CREATURE:FORGOTTEN_BEAST_550:SILK*!CREATURE:FORGOTTEN_BEAST_556:SILK*!CREATURE:FORGOTTEN_BEAST_557:SILK*!CREATURE:FORGOTTEN_BEAST_563:SILK*!CREATURE:FORGOTTEN_BEAST_573:SILK*!CREATURE:FORGOTTEN_BEAST_583:SILK*!CREATURE:FORGOTTEN_BEAST_588:SILK*!CREATURE:FORGOTTEN_BEAST_599:SILK*!CREATURE:FORGOTTEN_BEAST_602:SILK*!CREATURE:FORGOTTEN_BEAST_605:SILK*!CREATURE:FORGOTTEN_BEAST_607:SILK*!CREATURE:FORGOTTEN_BEAST_611:SILK*!CREATURE:FORGOTTEN_BEAST_618:SILK*!CREATURE:FORGOTTEN_BEAST_621:SILK*!CREATURE:FORGOTTEN_BEAST_627:SILK*!CREATURE:FORGOTTEN_BEAST_638:SILK*!CREATURE:FORGOTTEN_BEAST_639:SILK*!CREATURE:FORGOTTEN_BEAST_651:SILK*!CREATURE:FORGOTTEN_BEAST_659:SILK*!CREATURE:FORGOTTEN_BEAST_670:SILK*!CREATURE:FORGOTTEN_BEAST_686:SILK*!CREATURE:FORGOTTEN_BEAST_692:SILK*!CREATURE:FORGOTTEN_BEAST_695:SILK*!CREATURE:FORGOTTEN_BEAST_697:SILK*!CREATURE:FORGOTTEN_BEAST_699:SILK*!CREATURE:FORGOTTEN_BEAST_707:SILK*!CREATURE:FORGOTTEN_BEAST_713:SILK*!CREATURE:FORGOTTEN_BEAST_723:SILK*!CREATURE:FORGOTTEN_BEAST_733:SILK*!CREATURE:FORGOTTEN_BEAST_740:SILK*!CREATURE:FORGOTTEN_BEAST_741:SILK*!CREATURE:FORGOTTEN_BEAST_747:SILK*!CREATURE:FORGOTTEN_BEAST_758:SILK*!CREATURE:FORGOTTEN_BEAST_766:SILK*!CREATURE:FORGOTTEN_BEAST_769:SILK*!CREATURE:FORGOTTEN_BEAST_771:SILK*!CREATURE:FORGOTTEN_BEAST_790:SILK*!CREATURE:FORGOTTEN_BEAST_794:SILK*!CREATURE:FORGOTTEN_BEAST_826:SILK*!CREATURE:FORGOTTEN_BEAST_827:SILK*!CREATURE:FORGOTTEN_BEAST_837:SILK*!CREATURE:FORGOTTEN_BEAST_839:SILK*!CREATURE:FORGOTTEN_BEAST_846:SILK*!CREATURE:FORGOTTEN_BEAST_847:SILK*!CREATURE:FORGOTTEN_BEAST_849:SILK*!CREATURE:FORGOTTEN_BEAST_850:SILK*!CREATURE:FORGOTTEN_BEAST_855:SILK*CREATURE:TITAN_1:SILK*CREATURE:TITAN_5:SILK*CREATURE:TITAN_18:SILK*CREATURE:TITAN_24:SILK*CREATURE:TITAN_28:SILK*CREATURE:TITAN_29:SILK*CREATURE:TITAN_30:SILK*CREATURE:TITAN_31:SILK*CREATURE:DEMON_13:SILK*CREATURE:DEMON_15:SILK*CREATURE:DEMON_43:SILK*CREATURE:DEMON_46:SILK*CREATURE:DEMON_49:SILK*CREATURE:DEMON_50:SILK*CREATURE:DEMON_52:SILK2PLANT:FLAX:THREAD2PLANT:JUTE:THREAD2PLANT:HEMP:THREAD2PLANT:COTTON:THREAD2PLANT:RAMIE:THREAD2PLANT:KENAF:THREAD2PLANT:GRASS_TAIL_PIG:THREAD2PLANT:REED_ROPE:THREAD:CREATURE:SHEEP:HAIR:CREATURE:LLAMA:HAIR:CREATURE:ALPACA:HAIR:CREATURE:TROLL:HAIR \ No newline at end of file diff --git a/data/stockpiles/coal.dfstock b/data/stockpiles/coal.dfstock new file mode 100644 index 0000000000..8e9ec16e04 --- /dev/null +++ b/data/stockpiles/coal.dfstock @@ -0,0 +1,2 @@ +R +COAL \ No newline at end of file diff --git a/data/stockpiles/coalproducing.dfstock b/data/stockpiles/coalproducing.dfstock new file mode 100644 index 0000000000..30d6f7adf1 --- /dev/null +++ b/data/stockpiles/coalproducing.dfstock @@ -0,0 +1,3 @@ +2. +INORGANIC:COAL_BITUMINOUS +INORGANIC:LIGNITE \ No newline at end of file diff --git a/data/stockpiles/copperarmor.dfstock b/data/stockpiles/copperarmor.dfstock new file mode 100644 index 0000000000..bc7b8ec58e Binary files /dev/null and b/data/stockpiles/copperarmor.dfstock differ diff --git a/data/stockpiles/copperweapons.dfstock b/data/stockpiles/copperweapons.dfstock new file mode 100644 index 0000000000..a30c53107a Binary files /dev/null and b/data/stockpiles/copperweapons.dfstock differ diff --git a/data/stockpiles/crafts.dfstock b/data/stockpiles/crafts.dfstock new file mode 100644 index 0000000000..633dd9f1f2 --- /dev/null +++ b/data/stockpiles/crafts.dfstock @@ -0,0 +1,10 @@ +bG +FIGURINE +AMULET +SCEPTER +CROWN +RING +EARRING +BRACELET +GEM +TOTEM \ No newline at end of file diff --git a/data/stockpiles/cutgems.dfstock b/data/stockpiles/cutgems.dfstock new file mode 100644 index 0000000000..1049acd673 --- /dev/null +++ b/data/stockpiles/cutgems.dfstock @@ -0,0 +1 @@ +ZÃ"INORGANIC:ONYX"INORGANIC:MORION"INORGANIC:SCHORL"INORGANIC:LACE AGATE"INORGANIC:BLUE JADE"INORGANIC:LAPIS LAZULI"INORGANIC:PRASE"INORGANIC:PRASE OPAL"INORGANIC:BLOODSTONE"INORGANIC:MOSS AGATE"INORGANIC:MOSS OPAL"INORGANIC:VARISCITE"INORGANIC:CHRYSOPRASE"INORGANIC:CHRYSOCOLLA"INORGANIC:SARD"INORGANIC:CARNELIAN"INORGANIC:BANDED AGATE"INORGANIC:SARDONYX"INORGANIC:CHERRY OPAL"INORGANIC:LAVENDER JADE"INORGANIC:PINK JADE"INORGANIC:TUBE AGATE"INORGANIC:FIRE AGATE"INORGANIC:PLUME AGATE"INORGANIC:BROWN JASPER"INORGANIC:PICTURE JASPER"INORGANIC:SMOKY QUARTZ"INORGANIC:WAX OPAL"INORGANIC:WOOD OPAL"INORGANIC:AMBER OPAL"INORGANIC:GOLD OPAL"INORGANIC:CITRINE"INORGANIC:YELLOW JASPER"INORGANIC:TIGEREYE"INORGANIC:TIGER IRON"INORGANIC:SUNSTONE"INORGANIC:RESIN OPAL"INORGANIC:PYRITE"INORGANIC:CLEAR TOURMALINE"INORGANIC:GRAY CHALCEDONY"INORGANIC:DENDRITIC AGATE"INORGANIC:SHELL OPAL"INORGANIC:BONE OPAL"INORGANIC:WHITE CHALCEDONY"INORGANIC:FORTIFICATION AGATE"INORGANIC:MILK QUARTZ"INORGANIC:MOONSTONE"INORGANIC:WHITE JADE"INORGANIC:JASPER OPAL"INORGANIC:PINEAPPLE OPAL"INORGANIC:ONYX OPAL"INORGANIC:MILK OPAL"INORGANIC:PIPE OPAL"INORGANIC:AVENTURINE"INORGANIC:TURQUOISE"INORGANIC:QUARTZ_ROSE"INORGANIC:CRYSTAL_ROCK"INORGANIC:BLACK ZIRCON"INORGANIC:BLACK PYROPE"INORGANIC:MELANITE"INORGANIC:INDIGO TOURMALINE"INORGANIC:BLUE GARNET"INORGANIC:TSAVORITE"INORGANIC:GREEN TOURMALINE"INORGANIC:DEMANTOID"INORGANIC:GREEN ZIRCON"INORGANIC:GREEN JADE"INORGANIC:HELIODOR"INORGANIC:PERIDOT"INORGANIC:RED ZIRCON"INORGANIC:RED TOURMALINE"INORGANIC:RED PYROPE"INORGANIC:ALMANDINE"INORGANIC:RED GROSSULAR"INORGANIC:PINK TOURMALINE"INORGANIC:RED BERYL"INORGANIC:FIRE OPAL"INORGANIC:RHODOLITE"INORGANIC:SPINEL_PURPLE"INORGANIC:ALEXANDRITE"INORGANIC:TANZANITE"INORGANIC:MORGANITE"INORGANIC:VIOLET SPESSARTINE"INORGANIC:PINK GARNET"INORGANIC:KUNZITE"INORGANIC:CINNAMON GROSSULAR"INORGANIC:HONEY YELLOW BERYL"INORGANIC:JELLY OPAL"INORGANIC:BROWN ZIRCON"INORGANIC:YELLOW ZIRCON"INORGANIC:GOLDEN BERYL"INORGANIC:YELLOW SPESSARTINE"INORGANIC:TOPAZ"INORGANIC:TOPAZOLITE"INORGANIC:YELLOW GROSSULAR"INORGANIC:RUBICELLE"INORGANIC:CLEAR GARNET"INORGANIC:GOSHENITE"INORGANIC:CAT'S EYE"INORGANIC:CLEAR ZIRCON"INORGANIC:AMETHYST"INORGANIC:AQUAMARINE"INORGANIC:SPINEL_RED"INORGANIC:CHRYSOBERYL"INORGANIC:OPAL_PFIRE"INORGANIC:OPAL_REDFLASH"INORGANIC:OPAL_BLACK"INORGANIC:OPAL_WHITE"INORGANIC:OPAL_CRYSTAL"INORGANIC:OPAL_CLARO"INORGANIC:OPAL_LEVIN"INORGANIC:OPAL_HARLEQUIN"INORGANIC:OPAL_PINFIRE"INORGANIC:OPAL_BANDFIRE"INORGANIC:DIAMOND_LY"INORGANIC:DIAMOND_FY"INORGANIC:EMERALD"INORGANIC:RUBY"INORGANIC:SAPPHIRE"INORGANIC:DIAMOND_CLEAR"INORGANIC:DIAMOND_RED"INORGANIC:DIAMOND_GREEN"INORGANIC:DIAMOND_BLUE"INORGANIC:DIAMOND_YELLOW"INORGANIC:DIAMOND_BLACK"INORGANIC:SAPPHIRE_STAR"INORGANIC:RUBY_STAR \ No newline at end of file diff --git a/data/stockpiles/cutglass.dfstock b/data/stockpiles/cutglass.dfstock new file mode 100644 index 0000000000..6997d42acd --- /dev/null +++ b/data/stockpiles/cutglass.dfstock @@ -0,0 +1 @@ +Z) GLASS_GREEN GLASS_CLEAR GLASS_CRYSTAL \ No newline at end of file diff --git a/data/stockpiles/cutstone.dfstock b/data/stockpiles/cutstone.dfstock new file mode 100644 index 0000000000..5e0f3f881b --- /dev/null +++ b/data/stockpiles/cutstone.dfstock @@ -0,0 +1 @@ +Zâ"INORGANIC:PLASTER"INORGANIC:CERAMIC_EARTHENWARE"INORGANIC:CERAMIC_STONEWARE"INORGANIC:CERAMIC_PORCELAIN"INORGANIC:ASH_GLAZE"INORGANIC:TIN_GLAZE"INORGANIC:SANDSTONE"INORGANIC:SILTSTONE"INORGANIC:MUDSTONE"INORGANIC:SHALE"INORGANIC:CLAYSTONE"INORGANIC:ROCK_SALT"INORGANIC:LIMESTONE"INORGANIC:CONGLOMERATE"INORGANIC:DOLOMITE"INORGANIC:CHERT"INORGANIC:CHALK"INORGANIC:GRANITE"INORGANIC:DIORITE"INORGANIC:GABBRO"INORGANIC:RHYOLITE"INORGANIC:BASALT"INORGANIC:ANDESITE"INORGANIC:DACITE"INORGANIC:OBSIDIAN"INORGANIC:QUARTZITE"INORGANIC:SLATE"INORGANIC:PHYLLITE"INORGANIC:SCHIST"INORGANIC:GNEISS"INORGANIC:MARBLE"INORGANIC:HEMATITE"INORGANIC:LIMONITE"INORGANIC:GARNIERITE"INORGANIC:NATIVE_GOLD"INORGANIC:NATIVE_SILVER"INORGANIC:NATIVE_COPPER"INORGANIC:MALACHITE"INORGANIC:GALENA"INORGANIC:SPHALERITE"INORGANIC:CASSITERITE"INORGANIC:COAL_BITUMINOUS"INORGANIC:LIGNITE"INORGANIC:NATIVE_PLATINUM"INORGANIC:CINNABAR"INORGANIC:COBALTITE"INORGANIC:TETRAHEDRITE"INORGANIC:HORN_SILVER"INORGANIC:GYPSUM"INORGANIC:TALC" INORGANIC:JET"INORGANIC:PUDDINGSTONE"INORGANIC:PETRIFIED_WOOD"INORGANIC:GRAPHITE"INORGANIC:BRIMSTONE"INORGANIC:KIMBERLITE"INORGANIC:BISMUTHINITE"INORGANIC:REALGAR"INORGANIC:ORPIMENT"INORGANIC:STIBNITE"INORGANIC:MARCASITE"INORGANIC:SYLVITE"INORGANIC:CRYOLITE"INORGANIC:PERICLASE"INORGANIC:ILMENITE"INORGANIC:RUTILE"INORGANIC:MAGNETITE"INORGANIC:CHROMITE"INORGANIC:PYROLUSITE"INORGANIC:PITCHBLENDE"INORGANIC:BAUXITE"INORGANIC:NATIVE_ALUMINUM"INORGANIC:BORAX"INORGANIC:OLIVINE"INORGANIC:HORNBLENDE"INORGANIC:KAOLINITE"INORGANIC:SERPENTINE"INORGANIC:ORTHOCLASE"INORGANIC:MICROCLINE"INORGANIC:MICA"INORGANIC:CALCITE"INORGANIC:SALTPETER"INORGANIC:ALABASTER"INORGANIC:SELENITE"INORGANIC:SATINSPAR"INORGANIC:ANHYDRITE"INORGANIC:ALUNITE"INORGANIC:RAW_ADAMANTINE"INORGANIC:SLADE" INORGANIC:BROMS_CLEAN_CORPSEDUST \ No newline at end of file diff --git a/data/stockpiles/dye.dfstock b/data/stockpiles/dye.dfstock new file mode 100644 index 0000000000..67b785d203 Binary files /dev/null and b/data/stockpiles/dye.dfstock differ diff --git a/data/stockpiles/economic.dfstock b/data/stockpiles/economic.dfstock new file mode 100644 index 0000000000..976f4cc11f --- /dev/null +++ b/data/stockpiles/economic.dfstock @@ -0,0 +1,13 @@ +2ò +INORGANIC:LIMESTONE +INORGANIC:DOLOMITE +INORGANIC:CHALK +INORGANIC:MARBLE +INORGANIC:COAL_BITUMINOUS +INORGANIC:LIGNITE +INORGANIC:GYPSUM +INORGANIC:KAOLINITE +INORGANIC:CALCITE +INORGANIC:ALABASTER +INORGANIC:SELENITE +INORGANIC:SATINSPAR \ No newline at end of file diff --git a/data/stockpiles/everything.dfstock b/data/stockpiles/everything.dfstock new file mode 100644 index 0000000000..c0fcb60519 Binary files /dev/null and b/data/stockpiles/everything.dfstock differ diff --git a/data/stockpiles/flux.dfstock b/data/stockpiles/flux.dfstock new file mode 100644 index 0000000000..ec86187db1 --- /dev/null +++ b/data/stockpiles/flux.dfstock @@ -0,0 +1,6 @@ +2_ +INORGANIC:LIMESTONE +INORGANIC:DOLOMITE +INORGANIC:CHALK +INORGANIC:MARBLE +INORGANIC:CALCITE \ No newline at end of file diff --git a/data/stockpiles/goblets.dfstock b/data/stockpiles/goblets.dfstock new file mode 100644 index 0000000000..bff4f8a6d3 --- /dev/null +++ b/data/stockpiles/goblets.dfstock @@ -0,0 +1,2 @@ +b +GOBLET \ No newline at end of file diff --git a/data/stockpiles/ironarmor.dfstock b/data/stockpiles/ironarmor.dfstock new file mode 100644 index 0000000000..9474bd69f3 Binary files /dev/null and b/data/stockpiles/ironarmor.dfstock differ diff --git a/data/stockpiles/ironbars.dfstock b/data/stockpiles/ironbars.dfstock new file mode 100644 index 0000000000..2cb77c0e35 --- /dev/null +++ b/data/stockpiles/ironbars.dfstock @@ -0,0 +1 @@ +RINORGANIC:IRON \ No newline at end of file diff --git a/data/stockpiles/ironore.dfstock b/data/stockpiles/ironore.dfstock new file mode 100644 index 0000000000..2108b60ac3 --- /dev/null +++ b/data/stockpiles/ironore.dfstock @@ -0,0 +1,4 @@ +2= +INORGANIC:HEMATITE +INORGANIC:LIMONITE +INORGANIC:MAGNETITE \ No newline at end of file diff --git a/data/stockpiles/ironweapons.dfstock b/data/stockpiles/ironweapons.dfstock new file mode 100644 index 0000000000..8c0afecd16 Binary files /dev/null and b/data/stockpiles/ironweapons.dfstock differ diff --git a/data/stockpiles/masterworks.dfstock b/data/stockpiles/masterworks.dfstock new file mode 100644 index 0000000000..fa94c86a93 Binary files /dev/null and b/data/stockpiles/masterworks.dfstock differ diff --git a/data/stockpiles/metalammo.dfstock b/data/stockpiles/metalammo.dfstock new file mode 100644 index 0000000000..f1d9cdee9c --- /dev/null +++ b/data/stockpiles/metalammo.dfstock @@ -0,0 +1 @@ +BÒINORGANIC:IRONINORGANIC:SILVERINORGANIC:COPPERINORGANIC:NICKELINORGANIC:ZINCINORGANIC:BRONZEINORGANIC:BRASSINORGANIC:STEELINORGANIC:PIG_IRONINORGANIC:PLATINUMINORGANIC:ELECTRUM INORGANIC:TININORGANIC:PEWTER_FINEINORGANIC:PEWTER_TRIFLEINORGANIC:PEWTER_LAYINORGANIC:LEADINORGANIC:ALUMINUMINORGANIC:NICKEL_SILVERINORGANIC:BILLONINORGANIC:STERLING_SILVERINORGANIC:BLACK_BRONZEINORGANIC:ROSE_GOLDINORGANIC:BISMUTHINORGANIC:BISMUTH_BRONZEINORGANIC:ADAMANTINEINORGANIC:GOLDINORGANIC:DIVINE_1INORGANIC:DIVINE_3INORGANIC:DIVINE_5INORGANIC:DIVINE_7INORGANIC:DIVINE_9INORGANIC:DIVINE_11INORGANIC:DIVINE_13INORGANIC:DIVINE_15INORGANIC:DIVINE_17INORGANIC:DIVINE_19 \ No newline at end of file diff --git a/data/stockpiles/metalarmor.dfstock b/data/stockpiles/metalarmor.dfstock new file mode 100644 index 0000000000..f3a00646aa Binary files /dev/null and b/data/stockpiles/metalarmor.dfstock differ diff --git a/data/stockpiles/metalbars.dfstock b/data/stockpiles/metalbars.dfstock new file mode 100644 index 0000000000..103619c508 --- /dev/null +++ b/data/stockpiles/metalbars.dfstock @@ -0,0 +1 @@ +RÒINORGANIC:IRONINORGANIC:SILVERINORGANIC:COPPERINORGANIC:NICKELINORGANIC:ZINCINORGANIC:BRONZEINORGANIC:BRASSINORGANIC:STEELINORGANIC:PIG_IRONINORGANIC:PLATINUMINORGANIC:ELECTRUM INORGANIC:TININORGANIC:PEWTER_FINEINORGANIC:PEWTER_TRIFLEINORGANIC:PEWTER_LAYINORGANIC:LEADINORGANIC:ALUMINUMINORGANIC:NICKEL_SILVERINORGANIC:BILLONINORGANIC:STERLING_SILVERINORGANIC:BLACK_BRONZEINORGANIC:ROSE_GOLDINORGANIC:BISMUTHINORGANIC:BISMUTH_BRONZEINORGANIC:ADAMANTINEINORGANIC:GOLDINORGANIC:DIVINE_1INORGANIC:DIVINE_3INORGANIC:DIVINE_5INORGANIC:DIVINE_7INORGANIC:DIVINE_9INORGANIC:DIVINE_11INORGANIC:DIVINE_13INORGANIC:DIVINE_15INORGANIC:DIVINE_17INORGANIC:DIVINE_19 \ No newline at end of file diff --git a/data/stockpiles/metalore.dfstock b/data/stockpiles/metalore.dfstock new file mode 100644 index 0000000000..8cbb60959e --- /dev/null +++ b/data/stockpiles/metalore.dfstock @@ -0,0 +1,17 @@ +2í +INORGANIC:HEMATITE +INORGANIC:LIMONITE +INORGANIC:GARNIERITE +INORGANIC:NATIVE_GOLD +INORGANIC:NATIVE_SILVER +INORGANIC:NATIVE_COPPER +INORGANIC:MALACHITE +INORGANIC:GALENA +INORGANIC:SPHALERITE +INORGANIC:CASSITERITE +INORGANIC:NATIVE_PLATINUM +INORGANIC:TETRAHEDRITE +INORGANIC:HORN_SILVER +INORGANIC:BISMUTHINITE +INORGANIC:MAGNETITE +INORGANIC:NATIVE_ALUMINUM \ No newline at end of file diff --git a/data/stockpiles/metalweapons.dfstock b/data/stockpiles/metalweapons.dfstock new file mode 100644 index 0000000000..b9cd665117 Binary files /dev/null and b/data/stockpiles/metalweapons.dfstock differ diff --git a/data/stockpiles/miscliquid.dfstock b/data/stockpiles/miscliquid.dfstock new file mode 100644 index 0000000000..dbf75a072e Binary files /dev/null and b/data/stockpiles/miscliquid.dfstock differ diff --git a/data/stockpiles/organic.dfstock b/data/stockpiles/organic.dfstock new file mode 100644 index 0000000000..70f0496ca3 Binary files /dev/null and b/data/stockpiles/organic.dfstock differ diff --git a/data/stockpiles/otherarmor.dfstock b/data/stockpiles/otherarmor.dfstock new file mode 100644 index 0000000000..ec857e0cc3 Binary files /dev/null and b/data/stockpiles/otherarmor.dfstock differ diff --git a/data/stockpiles/otherbars.dfstock b/data/stockpiles/otherbars.dfstock new file mode 100644 index 0000000000..4cbcc1c8f9 --- /dev/null +++ b/data/stockpiles/otherbars.dfstock @@ -0,0 +1,6 @@ +R# +COAL +POTASH +ASH +PEARLASH +SOAP \ No newline at end of file diff --git a/data/stockpiles/otherstone.dfstock b/data/stockpiles/otherstone.dfstock new file mode 100644 index 0000000000..1f9f867edf --- /dev/null +++ b/data/stockpiles/otherstone.dfstock @@ -0,0 +1,56 @@ +2Ë +INORGANIC:SANDSTONE +INORGANIC:SILTSTONE +INORGANIC:MUDSTONE +INORGANIC:SHALE +INORGANIC:CLAYSTONE +INORGANIC:ROCK_SALT +INORGANIC:CONGLOMERATE +INORGANIC:CHERT +INORGANIC:GRANITE +INORGANIC:DIORITE +INORGANIC:GABBRO +INORGANIC:RHYOLITE +INORGANIC:BASALT +INORGANIC:ANDESITE +INORGANIC:DACITE +INORGANIC:OBSIDIAN +INORGANIC:QUARTZITE +INORGANIC:SLATE +INORGANIC:PHYLLITE +INORGANIC:SCHIST +INORGANIC:GNEISS +INORGANIC:CINNABAR +INORGANIC:COBALTITE +INORGANIC:TALC + INORGANIC:JET +INORGANIC:PUDDINGSTONE +INORGANIC:PETRIFIED_WOOD +INORGANIC:GRAPHITE +INORGANIC:BRIMSTONE +INORGANIC:KIMBERLITE +INORGANIC:REALGAR +INORGANIC:ORPIMENT +INORGANIC:STIBNITE +INORGANIC:MARCASITE +INORGANIC:SYLVITE +INORGANIC:CRYOLITE +INORGANIC:PERICLASE +INORGANIC:ILMENITE +INORGANIC:RUTILE +INORGANIC:CHROMITE +INORGANIC:PYROLUSITE +INORGANIC:PITCHBLENDE +INORGANIC:BAUXITE +INORGANIC:BORAX +INORGANIC:OLIVINE +INORGANIC:HORNBLENDE +INORGANIC:SERPENTINE +INORGANIC:ORTHOCLASE +INORGANIC:MICROCLINE +INORGANIC:MICA +INORGANIC:SALTPETER +INORGANIC:ANHYDRITE +INORGANIC:ALUNITE +INORGANIC:RAW_ADAMANTINE +INORGANIC:SLADE \ No newline at end of file diff --git a/data/stockpiles/otherweapons.dfstock b/data/stockpiles/otherweapons.dfstock new file mode 100644 index 0000000000..f1127a7841 Binary files /dev/null and b/data/stockpiles/otherweapons.dfstock differ diff --git a/data/stockpiles/pearlash.dfstock b/data/stockpiles/pearlash.dfstock new file mode 100644 index 0000000000..3cea5164da --- /dev/null +++ b/data/stockpiles/pearlash.dfstock @@ -0,0 +1,3 @@ +R + +PEARLASH \ No newline at end of file diff --git a/data/stockpiles/pigironbars.dfstock b/data/stockpiles/pigironbars.dfstock new file mode 100644 index 0000000000..f07b1def24 --- /dev/null +++ b/data/stockpiles/pigironbars.dfstock @@ -0,0 +1 @@ +RINORGANIC:PIG_IRON \ No newline at end of file diff --git a/data/stockpiles/plants.dfstock b/data/stockpiles/plants.dfstock new file mode 100644 index 0000000000..ca55f19f98 Binary files /dev/null and b/data/stockpiles/plants.dfstock differ diff --git a/data/stockpiles/plasterproducing.dfstock b/data/stockpiles/plasterproducing.dfstock new file mode 100644 index 0000000000..2764150a3f --- /dev/null +++ b/data/stockpiles/plasterproducing.dfstock @@ -0,0 +1,5 @@ +2P +INORGANIC:GYPSUM +INORGANIC:ALABASTER +INORGANIC:SELENITE +INORGANIC:SATINSPAR \ No newline at end of file diff --git a/data/stockpiles/platinumweapons.dfstock b/data/stockpiles/platinumweapons.dfstock new file mode 100644 index 0000000000..162865512b Binary files /dev/null and b/data/stockpiles/platinumweapons.dfstock differ diff --git a/data/stockpiles/potash.dfstock b/data/stockpiles/potash.dfstock new file mode 100644 index 0000000000..8a09e446fe --- /dev/null +++ b/data/stockpiles/potash.dfstock @@ -0,0 +1,2 @@ +R +POTASH \ No newline at end of file diff --git a/data/stockpiles/pots.dfstock b/data/stockpiles/pots.dfstock new file mode 100644 index 0000000000..2c1fe0e5ca --- /dev/null +++ b/data/stockpiles/pots.dfstock @@ -0,0 +1,2 @@ + + FOOD_STORAGE \ No newline at end of file diff --git a/data/stockpiles/preparedmeals.dfstock b/data/stockpiles/preparedmeals.dfstock new file mode 100644 index 0000000000..657c93f389 --- /dev/null +++ b/data/stockpiles/preparedmeals.dfstock @@ -0,0 +1 @@ +˜ \ No newline at end of file diff --git a/data/stockpiles/rawhides.dfstock b/data/stockpiles/rawhides.dfstock new file mode 100644 index 0000000000..eedc71760d Binary files /dev/null and b/data/stockpiles/rawhides.dfstock differ diff --git a/data/stockpiles/roughgems.dfstock b/data/stockpiles/roughgems.dfstock new file mode 100644 index 0000000000..fdad4be1ad --- /dev/null +++ b/data/stockpiles/roughgems.dfstock @@ -0,0 +1 @@ +ZÃINORGANIC:ONYXINORGANIC:MORIONINORGANIC:SCHORLINORGANIC:LACE AGATEINORGANIC:BLUE JADEINORGANIC:LAPIS LAZULIINORGANIC:PRASEINORGANIC:PRASE OPALINORGANIC:BLOODSTONEINORGANIC:MOSS AGATEINORGANIC:MOSS OPALINORGANIC:VARISCITEINORGANIC:CHRYSOPRASEINORGANIC:CHRYSOCOLLAINORGANIC:SARDINORGANIC:CARNELIANINORGANIC:BANDED AGATEINORGANIC:SARDONYXINORGANIC:CHERRY OPALINORGANIC:LAVENDER JADEINORGANIC:PINK JADEINORGANIC:TUBE AGATEINORGANIC:FIRE AGATEINORGANIC:PLUME AGATEINORGANIC:BROWN JASPERINORGANIC:PICTURE JASPERINORGANIC:SMOKY QUARTZINORGANIC:WAX OPALINORGANIC:WOOD OPALINORGANIC:AMBER OPALINORGANIC:GOLD OPALINORGANIC:CITRINEINORGANIC:YELLOW JASPERINORGANIC:TIGEREYEINORGANIC:TIGER IRONINORGANIC:SUNSTONEINORGANIC:RESIN OPALINORGANIC:PYRITEINORGANIC:CLEAR TOURMALINEINORGANIC:GRAY CHALCEDONYINORGANIC:DENDRITIC AGATEINORGANIC:SHELL OPALINORGANIC:BONE OPALINORGANIC:WHITE CHALCEDONYINORGANIC:FORTIFICATION AGATEINORGANIC:MILK QUARTZINORGANIC:MOONSTONEINORGANIC:WHITE JADEINORGANIC:JASPER OPALINORGANIC:PINEAPPLE OPALINORGANIC:ONYX OPALINORGANIC:MILK OPALINORGANIC:PIPE OPALINORGANIC:AVENTURINEINORGANIC:TURQUOISEINORGANIC:QUARTZ_ROSEINORGANIC:CRYSTAL_ROCKINORGANIC:BLACK ZIRCONINORGANIC:BLACK PYROPEINORGANIC:MELANITEINORGANIC:INDIGO TOURMALINEINORGANIC:BLUE GARNETINORGANIC:TSAVORITEINORGANIC:GREEN TOURMALINEINORGANIC:DEMANTOIDINORGANIC:GREEN ZIRCONINORGANIC:GREEN JADEINORGANIC:HELIODORINORGANIC:PERIDOTINORGANIC:RED ZIRCONINORGANIC:RED TOURMALINEINORGANIC:RED PYROPEINORGANIC:ALMANDINEINORGANIC:RED GROSSULARINORGANIC:PINK TOURMALINEINORGANIC:RED BERYLINORGANIC:FIRE OPALINORGANIC:RHODOLITEINORGANIC:SPINEL_PURPLEINORGANIC:ALEXANDRITEINORGANIC:TANZANITEINORGANIC:MORGANITEINORGANIC:VIOLET SPESSARTINEINORGANIC:PINK GARNETINORGANIC:KUNZITEINORGANIC:CINNAMON GROSSULARINORGANIC:HONEY YELLOW BERYLINORGANIC:JELLY OPALINORGANIC:BROWN ZIRCONINORGANIC:YELLOW ZIRCONINORGANIC:GOLDEN BERYLINORGANIC:YELLOW SPESSARTINEINORGANIC:TOPAZINORGANIC:TOPAZOLITEINORGANIC:YELLOW GROSSULARINORGANIC:RUBICELLEINORGANIC:CLEAR GARNETINORGANIC:GOSHENITEINORGANIC:CAT'S EYEINORGANIC:CLEAR ZIRCONINORGANIC:AMETHYSTINORGANIC:AQUAMARINEINORGANIC:SPINEL_REDINORGANIC:CHRYSOBERYLINORGANIC:OPAL_PFIREINORGANIC:OPAL_REDFLASHINORGANIC:OPAL_BLACKINORGANIC:OPAL_WHITEINORGANIC:OPAL_CRYSTALINORGANIC:OPAL_CLAROINORGANIC:OPAL_LEVININORGANIC:OPAL_HARLEQUININORGANIC:OPAL_PINFIREINORGANIC:OPAL_BANDFIREINORGANIC:DIAMOND_LYINORGANIC:DIAMOND_FYINORGANIC:EMERALDINORGANIC:RUBYINORGANIC:SAPPHIREINORGANIC:DIAMOND_CLEARINORGANIC:DIAMOND_REDINORGANIC:DIAMOND_GREENINORGANIC:DIAMOND_BLUEINORGANIC:DIAMOND_YELLOWINORGANIC:DIAMOND_BLACKINORGANIC:SAPPHIRE_STARINORGANIC:RUBY_STAR \ No newline at end of file diff --git a/data/stockpiles/roughglass.dfstock b/data/stockpiles/roughglass.dfstock new file mode 100644 index 0000000000..23b95b81ac --- /dev/null +++ b/data/stockpiles/roughglass.dfstock @@ -0,0 +1,4 @@ +Z) + GLASS_GREEN + GLASS_CLEAR + GLASS_CRYSTAL \ No newline at end of file diff --git a/data/stockpiles/sand.dfstock b/data/stockpiles/sand.dfstock new file mode 100644 index 0000000000..b97921e81e --- /dev/null +++ b/data/stockpiles/sand.dfstock @@ -0,0 +1,3 @@ + + +SAND_BAG \ No newline at end of file diff --git a/data/stockpiles/seeds.dfstock b/data/stockpiles/seeds.dfstock new file mode 100644 index 0000000000..ce9d0a4c22 Binary files /dev/null and b/data/stockpiles/seeds.dfstock differ diff --git a/data/stockpiles/silverweapons.dfstock b/data/stockpiles/silverweapons.dfstock new file mode 100644 index 0000000000..de517d0ab6 Binary files /dev/null and b/data/stockpiles/silverweapons.dfstock differ diff --git a/data/stockpiles/soap.dfstock b/data/stockpiles/soap.dfstock new file mode 100644 index 0000000000..0436f1e7a2 --- /dev/null +++ b/data/stockpiles/soap.dfstock @@ -0,0 +1,2 @@ +R +SOAP \ No newline at end of file diff --git a/data/stockpiles/steelarmor.dfstock b/data/stockpiles/steelarmor.dfstock new file mode 100644 index 0000000000..c2ba86fcbb Binary files /dev/null and b/data/stockpiles/steelarmor.dfstock differ diff --git a/data/stockpiles/steelbars.dfstock b/data/stockpiles/steelbars.dfstock new file mode 100644 index 0000000000..888f32e53a --- /dev/null +++ b/data/stockpiles/steelbars.dfstock @@ -0,0 +1 @@ +RINORGANIC:STEEL \ No newline at end of file diff --git a/data/stockpiles/steelweapons.dfstock b/data/stockpiles/steelweapons.dfstock new file mode 100644 index 0000000000..fc52339252 Binary files /dev/null and b/data/stockpiles/steelweapons.dfstock differ diff --git a/data/stockpiles/stonetools.dfstock b/data/stockpiles/stonetools.dfstock new file mode 100644 index 0000000000..dee961a743 --- /dev/null +++ b/data/stockpiles/stonetools.dfstock @@ -0,0 +1,2 @@ +bÆ +TOOLINORGANIC:PLASTERINORGANIC:CERAMIC_EARTHENWAREINORGANIC:CERAMIC_STONEWAREINORGANIC:CERAMIC_PORCELAININORGANIC:ASH_GLAZEINORGANIC:TIN_GLAZEINORGANIC:SANDSTONEINORGANIC:SILTSTONEINORGANIC:MUDSTONEINORGANIC:SHALEINORGANIC:CLAYSTONEINORGANIC:ROCK_SALTINORGANIC:LIMESTONEINORGANIC:CONGLOMERATEINORGANIC:DOLOMITEINORGANIC:CHERTINORGANIC:CHALKINORGANIC:GRANITEINORGANIC:DIORITEINORGANIC:GABBROINORGANIC:RHYOLITEINORGANIC:BASALTINORGANIC:ANDESITEINORGANIC:DACITEINORGANIC:OBSIDIANINORGANIC:QUARTZITEINORGANIC:SLATEINORGANIC:PHYLLITEINORGANIC:SCHISTINORGANIC:GNEISSINORGANIC:MARBLEINORGANIC:HEMATITEINORGANIC:LIMONITEINORGANIC:GARNIERITEINORGANIC:NATIVE_GOLDINORGANIC:NATIVE_SILVERINORGANIC:NATIVE_COPPERINORGANIC:MALACHITEINORGANIC:GALENAINORGANIC:SPHALERITEINORGANIC:CASSITERITEINORGANIC:COAL_BITUMINOUSINORGANIC:LIGNITEINORGANIC:NATIVE_PLATINUMINORGANIC:CINNABARINORGANIC:COBALTITEINORGANIC:TETRAHEDRITEINORGANIC:HORN_SILVERINORGANIC:GYPSUMINORGANIC:TALC INORGANIC:JETINORGANIC:PUDDINGSTONEINORGANIC:PETRIFIED_WOODINORGANIC:GRAPHITEINORGANIC:BRIMSTONEINORGANIC:KIMBERLITEINORGANIC:BISMUTHINITEINORGANIC:REALGARINORGANIC:ORPIMENTINORGANIC:STIBNITEINORGANIC:MARCASITEINORGANIC:SYLVITEINORGANIC:CRYOLITEINORGANIC:PERICLASEINORGANIC:ILMENITEINORGANIC:RUTILEINORGANIC:MAGNETITEINORGANIC:CHROMITEINORGANIC:PYROLUSITEINORGANIC:PITCHBLENDEINORGANIC:BAUXITEINORGANIC:NATIVE_ALUMINUMINORGANIC:BORAXINORGANIC:OLIVINEINORGANIC:HORNBLENDEINORGANIC:KAOLINITEINORGANIC:SERPENTINEINORGANIC:ORTHOCLASEINORGANIC:MICROCLINEINORGANIC:MICAINORGANIC:CALCITEINORGANIC:SALTPETERINORGANIC:ALABASTERINORGANIC:SELENITEINORGANIC:SATINSPARINORGANIC:ANHYDRITEINORGANIC:ALUNITEINORGANIC:RAW_ADAMANTINEINORGANIC:SLADE \ No newline at end of file diff --git a/data/stockpiles/stoneweapons.dfstock b/data/stockpiles/stoneweapons.dfstock new file mode 100644 index 0000000000..acba2374c1 Binary files /dev/null and b/data/stockpiles/stoneweapons.dfstock differ diff --git a/data/stockpiles/tannedhides.dfstock b/data/stockpiles/tannedhides.dfstock new file mode 100644 index 0000000000..9c58d41ce6 Binary files /dev/null and b/data/stockpiles/tannedhides.dfstock differ diff --git a/data/stockpiles/thread.dfstock b/data/stockpiles/thread.dfstock new file mode 100644 index 0000000000..2774f50e8a --- /dev/null +++ b/data/stockpiles/thread.dfstock @@ -0,0 +1,146 @@ +rŽ' +"CREATURE:SPIDER_BROWN_RECLUSE:SILK +&CREATURE:BROWN_RECLUSE_SPIDER_MAN:SILK +(CREATURE:GIANT_BROWN_RECLUSE_SPIDER:SILK +CREATURE:SPIDER_PHANTOM:SILK +CREATURE:SPIDER_CAVE_GIANT:SILK +CREATURE:SPIDER_CAVE:SILK +INORGANIC:DIVINE_2 +INORGANIC:DIVINE_4 +INORGANIC:DIVINE_6 +INORGANIC:DIVINE_8 +INORGANIC:DIVINE_10 +INORGANIC:DIVINE_12 +INORGANIC:DIVINE_14 +INORGANIC:DIVINE_16 +INORGANIC:DIVINE_18 +INORGANIC:DIVINE_20 +CREATURE:FORGOTTEN_BEAST_4:SILK + CREATURE:FORGOTTEN_BEAST_22:SILK + CREATURE:FORGOTTEN_BEAST_33:SILK + CREATURE:FORGOTTEN_BEAST_51:SILK + CREATURE:FORGOTTEN_BEAST_56:SILK + CREATURE:FORGOTTEN_BEAST_58:SILK + CREATURE:FORGOTTEN_BEAST_62:SILK + CREATURE:FORGOTTEN_BEAST_74:SILK + CREATURE:FORGOTTEN_BEAST_80:SILK + CREATURE:FORGOTTEN_BEAST_87:SILK + CREATURE:FORGOTTEN_BEAST_90:SILK +!CREATURE:FORGOTTEN_BEAST_106:SILK +!CREATURE:FORGOTTEN_BEAST_109:SILK +!CREATURE:FORGOTTEN_BEAST_127:SILK +!CREATURE:FORGOTTEN_BEAST_131:SILK +!CREATURE:FORGOTTEN_BEAST_143:SILK +!CREATURE:FORGOTTEN_BEAST_145:SILK +!CREATURE:FORGOTTEN_BEAST_163:SILK +!CREATURE:FORGOTTEN_BEAST_177:SILK +!CREATURE:FORGOTTEN_BEAST_189:SILK +!CREATURE:FORGOTTEN_BEAST_194:SILK +!CREATURE:FORGOTTEN_BEAST_197:SILK +!CREATURE:FORGOTTEN_BEAST_200:SILK +!CREATURE:FORGOTTEN_BEAST_201:SILK +!CREATURE:FORGOTTEN_BEAST_202:SILK +!CREATURE:FORGOTTEN_BEAST_217:SILK +!CREATURE:FORGOTTEN_BEAST_224:SILK +!CREATURE:FORGOTTEN_BEAST_234:SILK +!CREATURE:FORGOTTEN_BEAST_242:SILK +!CREATURE:FORGOTTEN_BEAST_246:SILK +!CREATURE:FORGOTTEN_BEAST_250:SILK +!CREATURE:FORGOTTEN_BEAST_270:SILK +!CREATURE:FORGOTTEN_BEAST_271:SILK +!CREATURE:FORGOTTEN_BEAST_286:SILK +!CREATURE:FORGOTTEN_BEAST_291:SILK +!CREATURE:FORGOTTEN_BEAST_296:SILK +!CREATURE:FORGOTTEN_BEAST_329:SILK +!CREATURE:FORGOTTEN_BEAST_350:SILK +!CREATURE:FORGOTTEN_BEAST_351:SILK +!CREATURE:FORGOTTEN_BEAST_359:SILK +!CREATURE:FORGOTTEN_BEAST_365:SILK +!CREATURE:FORGOTTEN_BEAST_375:SILK +!CREATURE:FORGOTTEN_BEAST_376:SILK +!CREATURE:FORGOTTEN_BEAST_377:SILK +!CREATURE:FORGOTTEN_BEAST_383:SILK +!CREATURE:FORGOTTEN_BEAST_387:SILK +!CREATURE:FORGOTTEN_BEAST_398:SILK +!CREATURE:FORGOTTEN_BEAST_400:SILK +!CREATURE:FORGOTTEN_BEAST_406:SILK +!CREATURE:FORGOTTEN_BEAST_410:SILK +!CREATURE:FORGOTTEN_BEAST_417:SILK +!CREATURE:FORGOTTEN_BEAST_428:SILK +!CREATURE:FORGOTTEN_BEAST_429:SILK +!CREATURE:FORGOTTEN_BEAST_432:SILK +!CREATURE:FORGOTTEN_BEAST_442:SILK +!CREATURE:FORGOTTEN_BEAST_448:SILK +!CREATURE:FORGOTTEN_BEAST_452:SILK +!CREATURE:FORGOTTEN_BEAST_457:SILK +!CREATURE:FORGOTTEN_BEAST_468:SILK +!CREATURE:FORGOTTEN_BEAST_472:SILK +!CREATURE:FORGOTTEN_BEAST_479:SILK +!CREATURE:FORGOTTEN_BEAST_482:SILK +!CREATURE:FORGOTTEN_BEAST_492:SILK +!CREATURE:FORGOTTEN_BEAST_504:SILK +!CREATURE:FORGOTTEN_BEAST_512:SILK +!CREATURE:FORGOTTEN_BEAST_519:SILK +!CREATURE:FORGOTTEN_BEAST_537:SILK +!CREATURE:FORGOTTEN_BEAST_550:SILK +!CREATURE:FORGOTTEN_BEAST_556:SILK +!CREATURE:FORGOTTEN_BEAST_557:SILK +!CREATURE:FORGOTTEN_BEAST_563:SILK +!CREATURE:FORGOTTEN_BEAST_573:SILK +!CREATURE:FORGOTTEN_BEAST_583:SILK +!CREATURE:FORGOTTEN_BEAST_588:SILK +!CREATURE:FORGOTTEN_BEAST_599:SILK +!CREATURE:FORGOTTEN_BEAST_602:SILK +!CREATURE:FORGOTTEN_BEAST_605:SILK +!CREATURE:FORGOTTEN_BEAST_607:SILK +!CREATURE:FORGOTTEN_BEAST_611:SILK +!CREATURE:FORGOTTEN_BEAST_618:SILK +!CREATURE:FORGOTTEN_BEAST_621:SILK +!CREATURE:FORGOTTEN_BEAST_627:SILK +!CREATURE:FORGOTTEN_BEAST_638:SILK +!CREATURE:FORGOTTEN_BEAST_639:SILK +!CREATURE:FORGOTTEN_BEAST_651:SILK +!CREATURE:FORGOTTEN_BEAST_659:SILK +!CREATURE:FORGOTTEN_BEAST_670:SILK +!CREATURE:FORGOTTEN_BEAST_686:SILK +!CREATURE:FORGOTTEN_BEAST_692:SILK +!CREATURE:FORGOTTEN_BEAST_695:SILK +!CREATURE:FORGOTTEN_BEAST_697:SILK +!CREATURE:FORGOTTEN_BEAST_699:SILK +!CREATURE:FORGOTTEN_BEAST_707:SILK +!CREATURE:FORGOTTEN_BEAST_713:SILK +!CREATURE:FORGOTTEN_BEAST_723:SILK +!CREATURE:FORGOTTEN_BEAST_733:SILK +!CREATURE:FORGOTTEN_BEAST_740:SILK +!CREATURE:FORGOTTEN_BEAST_741:SILK +!CREATURE:FORGOTTEN_BEAST_747:SILK +!CREATURE:FORGOTTEN_BEAST_758:SILK +!CREATURE:FORGOTTEN_BEAST_766:SILK +!CREATURE:FORGOTTEN_BEAST_769:SILK +!CREATURE:FORGOTTEN_BEAST_771:SILK +!CREATURE:FORGOTTEN_BEAST_790:SILK +!CREATURE:FORGOTTEN_BEAST_794:SILK +!CREATURE:FORGOTTEN_BEAST_826:SILK +!CREATURE:FORGOTTEN_BEAST_827:SILK +!CREATURE:FORGOTTEN_BEAST_837:SILK +!CREATURE:FORGOTTEN_BEAST_839:SILK +!CREATURE:FORGOTTEN_BEAST_846:SILK +!CREATURE:FORGOTTEN_BEAST_847:SILK +!CREATURE:FORGOTTEN_BEAST_849:SILK +!CREATURE:FORGOTTEN_BEAST_850:SILK +!CREATURE:FORGOTTEN_BEAST_855:SILK +CREATURE:TITAN_1:SILK +CREATURE:TITAN_5:SILK +CREATURE:TITAN_18:SILK +CREATURE:TITAN_24:SILK +CREATURE:TITAN_28:SILK +CREATURE:TITAN_29:SILK +CREATURE:TITAN_30:SILK +CREATURE:TITAN_31:SILK +CREATURE:DEMON_13:SILK +CREATURE:DEMON_15:SILK +CREATURE:DEMON_43:SILK +CREATURE:DEMON_46:SILK +CREATURE:DEMON_49:SILK +CREATURE:DEMON_50:SILK +CREATURE:DEMON_52:SILKPLANT:FLAX:THREADPLANT:JUTE:THREADPLANT:HEMP:THREADPLANT:COTTON:THREADPLANT:RAMIE:THREADPLANT:KENAF:THREADPLANT:GRASS_TAIL_PIG:THREADPLANT:REED_ROPE:THREADCREATURE:SHEEP:HAIRCREATURE:LLAMA:HAIRCREATURE:ALPACA:HAIRCREATURE:TROLL:HAIR \ No newline at end of file diff --git a/data/stockpiles/toys.dfstock b/data/stockpiles/toys.dfstock new file mode 100644 index 0000000000..a90eab591a --- /dev/null +++ b/data/stockpiles/toys.dfstock @@ -0,0 +1,2 @@ +b +TOY \ No newline at end of file diff --git a/data/stockpiles/trapcomponents.dfstock b/data/stockpiles/trapcomponents.dfstock new file mode 100644 index 0000000000..475b530d4c Binary files /dev/null and b/data/stockpiles/trapcomponents.dfstock differ diff --git a/data/stockpiles/traps.dfstock b/data/stockpiles/traps.dfstock new file mode 100644 index 0000000000..ed1ba67763 Binary files /dev/null and b/data/stockpiles/traps.dfstock differ diff --git a/data/stockpiles/unpreparedfish.dfstock b/data/stockpiles/unpreparedfish.dfstock new file mode 100644 index 0000000000..13841da901 Binary files /dev/null and b/data/stockpiles/unpreparedfish.dfstock differ diff --git a/data/stockpiles/unusablearmor.dfstock b/data/stockpiles/unusablearmor.dfstock new file mode 100644 index 0000000000..d5b2e9c649 Binary files /dev/null and b/data/stockpiles/unusablearmor.dfstock differ diff --git a/data/stockpiles/unusableweapons.dfstock b/data/stockpiles/unusableweapons.dfstock new file mode 100644 index 0000000000..6af8d1b5a2 Binary files /dev/null and b/data/stockpiles/unusableweapons.dfstock differ diff --git a/data/stockpiles/usablearmor.dfstock b/data/stockpiles/usablearmor.dfstock new file mode 100644 index 0000000000..58c9296de9 Binary files /dev/null and b/data/stockpiles/usablearmor.dfstock differ diff --git a/data/stockpiles/usablehair.dfstock b/data/stockpiles/usablehair.dfstock new file mode 100644 index 0000000000..2082d7dcf6 Binary files /dev/null and b/data/stockpiles/usablehair.dfstock differ diff --git a/data/stockpiles/usableweapons.dfstock b/data/stockpiles/usableweapons.dfstock new file mode 100644 index 0000000000..248610ae94 Binary files /dev/null and b/data/stockpiles/usableweapons.dfstock differ diff --git a/data/stockpiles/wax.dfstock b/data/stockpiles/wax.dfstock new file mode 100644 index 0000000000..35c69f6ca8 Binary files /dev/null and b/data/stockpiles/wax.dfstock differ diff --git a/data/stockpiles/woodammo.dfstock b/data/stockpiles/woodammo.dfstock new file mode 100644 index 0000000000..6bec8b1e58 --- /dev/null +++ b/data/stockpiles/woodammo.dfstock @@ -0,0 +1 @@ +BWOOD \ No newline at end of file diff --git a/data/stockpiles/woodtools.dfstock b/data/stockpiles/woodtools.dfstock new file mode 100644 index 0000000000..86eb0d0c81 --- /dev/null +++ b/data/stockpiles/woodtools.dfstock @@ -0,0 +1,2 @@ +b +TOOLWOOD \ No newline at end of file diff --git a/depends/CMakeLists.txt b/depends/CMakeLists.txt index f42955e7d7..41996294c6 100644 --- a/depends/CMakeLists.txt +++ b/depends/CMakeLists.txt @@ -1,29 +1,43 @@ # list depends here. +add_subdirectory(dfhooks) +install(TARGETS dfhooks LIBRARY DESTINATION . RUNTIME DESTINATION .) + add_subdirectory(lodepng) add_subdirectory(lua) add_subdirectory(md5) add_subdirectory(protobuf) +target_include_directories(protobuf-lite INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/protobuf) + +if(UNIX) + set_target_properties(lua PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-deprecated-enum-enum-conversion") + set_target_properties(protoc PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") + set_target_properties(protoc-bin PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") + set_target_properties(protobuf-lite PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") + set_target_properties(protobuf PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") +endif() + +option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" OFF) +add_subdirectory(googletest) # Don't build tinyxml if it's being externally linked against. if(NOT TinyXML_FOUND) add_subdirectory(tinyxml) + target_include_directories(dfhack-tinyxml INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/tinyxml) endif() -add_subdirectory(tthread) option(JSONCPP_WITH_TESTS "Compile and (for jsoncpp_check) run JsonCpp test executables" OFF) option(JSONCPP_WITH_POST_BUILD_UNITTEST "Automatically run unit-tests as a post build step" OFF) +option(JSONCPP_BUILD_SHARED_LIBS "Build jsoncpp_lib as a shared library." OFF) +option(JSONCPP_BUILD_OBJECT_LIBS "Build jsoncpp_lib as a object library." OFF) +option(JSONCPP_WITH_CMAKE_PACKAGE "Generate and install cmake package files" OFF) + add_subdirectory(jsoncpp-sub EXCLUDE_FROM_ALL) -if(UNIX) - set_target_properties(jsoncpp_lib_static PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations") -endif() # build clsocket static and only as a dependency. Setting those options here overrides its own default settings. option(CLSOCKET_SHARED "Build clsocket lib as shared." OFF) option(CLSOCKET_DEP_ONLY "Build for use inside other CMake projects as dependency." ON) add_subdirectory(clsocket) ide_folder(clsocket "Depends") -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/luacov/src/luacov/ DESTINATION ${DFHACK_DATA_DESTINATION}/lua/luacov) - # set the default values of libexpat options - the descriptions are left empty # because later option() calls *do* override those set(EXPAT_BUILD_EXAMPLES OFF CACHE BOOL "") @@ -33,11 +47,16 @@ set(EXPAT_SHARED_LIBS OFF CACHE BOOL "") set(EXPAT_BUILD_DOCS OFF CACHE BOOL "") set(EXPAT_ENABLE_INSTALL OFF CACHE BOOL "") add_subdirectory(libexpat/expat) +if(UNIX) + set_target_properties(expat PROPERTIES COMPILE_FLAGS "-Wno-maybe-uninitialized") +endif() +set(CMAKE_REQUIRED_QUIET ON) set(LIBZIP_BUILD_DOC OFF CACHE BOOL "") set(LIBZIP_BUILD_EXAMPLES OFF CACHE BOOL "") set(LIBZIP_BUILD_REGRESS OFF CACHE BOOL "") set(LIBZIP_BUILD_SHARED_LIBS OFF CACHE BOOL "") +set(LIBZIP_BUILD_OSSFUZZ OFF CACHE BOOL "") set(LIBZIP_BUILD_TOOLS OFF CACHE BOOL "") set(LIBZIP_ENABLE_BZIP2 OFF CACHE BOOL "") set(LIBZIP_ENABLE_COMMONCRYPTO OFF CACHE BOOL "") @@ -50,6 +69,8 @@ set(LIBZIP_DO_INSTALL OFF CACHE BOOL "") add_subdirectory(libzip) if(MSVC) target_compile_options(zip PRIVATE /wd4244) +elseif(UNIX) + set_target_properties(zip PROPERTIES COMPILE_FLAGS "-Wno-stringop-truncation -Wno-stringop-overflow") endif() set(XLSXIO_USE_DFHACK_LIBS ON CACHE BOOL "") @@ -68,3 +89,5 @@ if(MSVC) target_compile_options(xlsxio_read_STATIC PRIVATE /wd4013 /wd4244) target_compile_options(xlsxio_write_STATIC PRIVATE /wd4013 /wd4244) endif() +target_include_directories(xlsxio_read_STATIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/xlsxio/include) +target_include_directories(xlsxio_write_STATIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/xlsxio/include) diff --git a/depends/clsocket b/depends/clsocket index 8340c07802..00c3267aac 160000 --- a/depends/clsocket +++ b/depends/clsocket @@ -1 +1 @@ -Subproject commit 8340c07802078d905e60e294211a1807ec6f0161 +Subproject commit 00c3267aacc9c10c5864c7fce856df0de52d72a8 diff --git a/depends/dfhooks b/depends/dfhooks new file mode 160000 index 0000000000..5a904e30a8 --- /dev/null +++ b/depends/dfhooks @@ -0,0 +1 @@ +Subproject commit 5a904e30a8bace81c662b44ec7ff076b92edafd1 diff --git a/depends/googletest b/depends/googletest new file mode 160000 index 0000000000..b514bdc898 --- /dev/null +++ b/depends/googletest @@ -0,0 +1 @@ +Subproject commit b514bdc898e2951020cbdca1304b75f5950d1f59 diff --git a/depends/jsoncpp-sub b/depends/jsoncpp-sub index ddabf50f72..3a5d4ff058 160000 --- a/depends/jsoncpp-sub +++ b/depends/jsoncpp-sub @@ -1 +1 @@ -Subproject commit ddabf50f72cf369bf652a95c4d9fe31a1865a781 +Subproject commit 3a5d4ff0583ce7dd5abbf92bdf49dca2177459ef diff --git a/depends/libexpat b/depends/libexpat index 3c0f2e86ce..e3ea446907 160000 --- a/depends/libexpat +++ b/depends/libexpat @@ -1 +1 @@ -Subproject commit 3c0f2e86ce4e7a3a3b30e765087d02a68bba7e6f +Subproject commit e3ea4469079702ddf352bb3333bf85130c5346c2 diff --git a/depends/libzip b/depends/libzip index da0d18ae59..011e45e125 160000 --- a/depends/libzip +++ b/depends/libzip @@ -1 +1 @@ -Subproject commit da0d18ae59ef2699013316b703cdc93809414c93 +Subproject commit 011e45e125631cff73c0d6a5d19e0232dfc4df6f diff --git a/depends/lua/CMakeLists.txt b/depends/lua/CMakeLists.txt index c3ff0c16f2..44b16e56cc 100644 --- a/depends/lua/CMakeLists.txt +++ b/depends/lua/CMakeLists.txt @@ -1,5 +1,5 @@ project(lua CXX) -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.21) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLUA_USE_APICHECK") @@ -93,7 +93,9 @@ set_source_files_properties(${SRC_LIBLUA} PROPERTIES LANGUAGE CXX) list(APPEND SRC_LIBLUA ${HDR_LIBLUA}) add_library(lua SHARED ${SRC_LIBLUA}) +set_target_properties(lua PROPERTIES OUTPUT_NAME lua53) target_link_libraries(lua ${LIBS}) +target_include_directories(lua INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) if(MSVC) # need no space to prevent /FI from being stripped: https://github.com/DFHack/dfhack/issues/1455 diff --git a/depends/lua/include/dfhack_llimits.h b/depends/lua/include/dfhack_llimits.h index f8ca518190..73aa52ef0b 100644 --- a/depends/lua/include/dfhack_llimits.h +++ b/depends/lua/include/dfhack_llimits.h @@ -54,8 +54,19 @@ struct lua_extra_state { #define lua_lock(L) EnterCriticalSection(luai_mutex(L)) #define lua_unlock(L) LeaveCriticalSection(luai_mutex(L)) #else -#define luai_userstateopen(L) luai_mutex(L) = (mutex_t*)malloc(sizeof(mutex_t)); *luai_mutex(L) = PTHREAD_MUTEX_INITIALIZER -#define luai_userstateclose(L) lua_unlock(L); pthread_mutex_destroy(luai_mutex(L)); free(luai_mutex(L)) +#define luai_userstateopen(L) do { \ + luai_mutex(L) = (mutex_t*)malloc(sizeof(mutex_t)); \ + pthread_mutexattr_t attr; \ + pthread_mutexattr_init(&attr); \ + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \ + pthread_mutex_init(luai_mutex(L), &attr); \ + pthread_mutexattr_destroy(&attr); \ + } while (0) +#define luai_userstateclose(L) do { \ + lua_unlock(L); \ + pthread_mutex_destroy(luai_mutex(L)); \ + free(luai_mutex(L)); \ + } while (0) #define lua_lock(L) pthread_mutex_lock(luai_mutex(L)) #define lua_unlock(L) pthread_mutex_unlock(luai_mutex(L)) #endif diff --git a/depends/lua/src/lapi.c b/depends/lua/src/lapi.c index 711895b395..aa01148ab1 100644 --- a/depends/lua/src/lapi.c +++ b/depends/lua/src/lapi.c @@ -395,7 +395,7 @@ LUA_API size_t lua_rawlen (lua_State *L, int idx) { case LUA_TSHRSTR: return tsvalue(o)->shrlen; case LUA_TLNGSTR: return tsvalue(o)->u.lnglen; case LUA_TUSERDATA: return uvalue(o)->len; - case LUA_TTABLE: return luaH_getn(hvalue(o)); + case LUA_TTABLE: return size_t(luaH_getn(hvalue(o))); default: return 0; } } diff --git a/depends/lua/src/ldo.c b/depends/lua/src/ldo.c index 316e45c8fe..65158df0b7 100644 --- a/depends/lua/src/ldo.c +++ b/depends/lua/src/ldo.c @@ -767,14 +767,14 @@ static void f_parser (lua_State *L, void *ud) { LClosure *cl; struct SParser *p = cast(struct SParser *, ud); int c = zgetc(p->z); /* read first character */ - if (c == LUA_SIGNATURE[0]) { - checkmode(L, p->mode, "binary"); - cl = luaU_undump(L, p->z, p->name); - } - else { + // if (c == LUA_SIGNATURE[0]) { + // checkmode(L, p->mode, "binary"); + // cl = luaU_undump(L, p->z, p->name); + // } + // else { checkmode(L, p->mode, "text"); cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c); - } + // } lua_assert(cl->nupvalues == cl->p->sizeupvalues); luaF_initupvals(L, cl); } diff --git a/depends/luacov b/depends/luacov index 87d6ae018c..e09ee3fa2e 160000 --- a/depends/luacov +++ b/depends/luacov @@ -1 +1 @@ -Subproject commit 87d6ae018cb8d288d854f632e9d8d959d75d7db4 +Subproject commit e09ee3fa2e3366d148f94c6a5969c9896126e83a diff --git a/depends/md5/CMakeLists.txt b/depends/md5/CMakeLists.txt index 747963c454..55c0bf6c1b 100644 --- a/depends/md5/CMakeLists.txt +++ b/depends/md5/CMakeLists.txt @@ -1,5 +1,6 @@ project(dfhack-md5) add_library(dfhack-md5 STATIC EXCLUDE_FROM_ALL md5.cpp md5wrapper.cpp) +target_include_directories(dfhack-md5 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) ide_folder(dfhack-md5 "Depends") if(UNIX) set_target_properties(dfhack-md5 PROPERTIES COMPILE_FLAGS "-Wno-strict-aliasing") diff --git a/depends/md5/md5.cpp b/depends/md5/md5.cpp index 044df259e2..8aa9ba38c8 100644 --- a/depends/md5/md5.cpp +++ b/depends/md5/md5.cpp @@ -158,7 +158,7 @@ void MD5Final(unsigned char digest[16], MD5Context *ctx) */ void MD5Transform(uint32_t buf[4], uint32_t in[16]) { - register uint32_t a, b, c, d; + uint32_t a, b, c, d; a = buf[0]; b = buf[1]; diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt index b12230b71e..1d1796d1c8 100644 --- a/depends/protobuf/CMakeLists.txt +++ b/depends/protobuf/CMakeLists.txt @@ -149,7 +149,7 @@ if(CMAKE_COMPILER_IS_GNUCC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-result -Wno-unused-local-typedefs -Wno-misleading-indentation -Wno-class-memaccess -Wno-sign-compare") elseif(MSVC) # Disable warnings for integer conversion to smaller type - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267 /wd4273") endif() include_directories(${CMAKE_CURRENT_SOURCE_DIR}) @@ -159,15 +159,11 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) # Protobuf shared libraries -add_library(protobuf SHARED ${LIBPROTOBUF_FULL_SRCS} ${LIBPROTOBUF_FULL_HDRS}) -ide_folder(protobuf "Depends") add_library(protobuf-lite SHARED ${LIBPROTOBUF_LITE_SRCS} ${LIBPROTOBUF_LITE_HDRS}) ide_folder(protobuf-lite "Depends") -set_target_properties(protobuf PROPERTIES COMPILE_DEFINITIONS LIBPROTOBUF_EXPORTS) set_target_properties(protobuf-lite PROPERTIES COMPILE_DEFINITIONS LIBPROTOBUF_EXPORTS) -target_link_libraries(protobuf ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES}) target_link_libraries(protobuf-lite ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES}) install(TARGETS protobuf-lite @@ -175,6 +171,11 @@ install(TARGETS protobuf-lite RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION}) if(NOT CMAKE_CROSSCOMPILING) + add_library(protobuf SHARED ${LIBPROTOBUF_FULL_SRCS} ${LIBPROTOBUF_FULL_HDRS}) + ide_folder(protobuf "Depends") + set_target_properties(protobuf PROPERTIES COMPILE_DEFINITIONS LIBPROTOBUF_EXPORTS) + target_link_libraries(protobuf ${CMAKE_THREAD_LIBS_INIT} ${ZLIB_LIBRARIES}) + # Protobuf compiler shared library add_library(protoc SHARED ${LIBPROTOC_SRCS} ${LIBPROTOC_HDRS}) diff --git a/depends/protobuf/google/protobuf/repeated_field.h b/depends/protobuf/google/protobuf/repeated_field.h index aed4ce9f25..6377082540 100644 --- a/depends/protobuf/google/protobuf/repeated_field.h +++ b/depends/protobuf/google/protobuf/repeated_field.h @@ -46,6 +46,10 @@ #ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__ #define GOOGLE_PROTOBUF_REPEATED_FIELD_H__ +#ifdef __GNUC__ +#pragma GCC system_header +#endif + #include #include #include diff --git a/depends/protobuf/google/protobuf/stubs/hash.h b/depends/protobuf/google/protobuf/stubs/hash.h index b4b2da5743..0ee778563e 100644 --- a/depends/protobuf/google/protobuf/stubs/hash.h +++ b/depends/protobuf/google/protobuf/stubs/hash.h @@ -104,7 +104,14 @@ // And.. they are moved back to stdext in MSVC 2013 (haven't checked 2012). That // said, use unordered_map for MSVC 2010 and beyond is our safest bet. #elif defined(_MSC_VER) -# if _MSC_VER >= 1600 // Since Visual Studio 2010 +# if _MSC_VER >= 1900 // Since Visual Studio 2019 +# define GOOGLE_PROTOBUF_HASH_NAMESPACE std +# include +# define GOOGLE_PROTOBUF_HASH_MAP_CLASS unordered_map +# include +# define GOOGLE_PROTOBUF_HASH_SET_CLASS unordered_set + +# elif _MSC_VER >= 1600 // Since Visual Studio 2010 # define GOOGLE_PROTOBUF_HAS_CXX11_HASH # define GOOGLE_PROTOBUF_HASH_COMPARE std::hash_compare # elif _MSC_VER >= 1500 // Since Visual Studio 2008 @@ -233,7 +240,7 @@ namespace google { HashFcn hash_function() const { return HashFcn(); } }; -#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION) +#elif defined(_MSC_VER) && _MSC_VER < 1900 && !defined(_STLPORT_VERSION) template struct hash : public GOOGLE_PROTOBUF_HASH_COMPARE { @@ -435,4 +442,4 @@ namespace google { } // namespace protobuf } // namespace google -#endif // GOOGLE_PROTOBUF_STUBS_HASH_H__ \ No newline at end of file +#endif // GOOGLE_PROTOBUF_STUBS_HASH_H__ diff --git a/depends/tthread/CMakeLists.txt b/depends/tthread/CMakeLists.txt deleted file mode 100644 index dfb1d9901c..0000000000 --- a/depends/tthread/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -project(dfhack-tinythread) -add_library(dfhack-tinythread STATIC EXCLUDE_FROM_ALL tinythread.cpp tinythread.h) -if(UNIX) - target_link_libraries(dfhack-tinythread pthread) -endif() -ide_folder(dfhack-tinythread "Depends") diff --git a/depends/tthread/tinythread.cpp b/depends/tthread/tinythread.cpp deleted file mode 100644 index 176bc2ac88..0000000000 --- a/depends/tthread/tinythread.cpp +++ /dev/null @@ -1,313 +0,0 @@ -/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- -Copyright (c) 2010-2012 Marcus Geelnard - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#include -#include "tinythread.h" - -#if defined(_TTHREAD_POSIX_) - #include - #include -#elif defined(_TTHREAD_WIN32_) - #include -#endif - - -namespace tthread { - -//------------------------------------------------------------------------------ -// condition_variable -//------------------------------------------------------------------------------ -// NOTE 1: The Win32 implementation of the condition_variable class is based on -// the corresponding implementation in GLFW, which in turn is based on a -// description by Douglas C. Schmidt and Irfan Pyarali: -// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html -// -// NOTE 2: Windows Vista actually has native support for condition variables -// (InitializeConditionVariable, WakeConditionVariable, etc), but we want to -// be portable with pre-Vista Windows versions, so TinyThread++ does not use -// Vista condition variables. -//------------------------------------------------------------------------------ - -#if defined(_TTHREAD_WIN32_) - #define _CONDITION_EVENT_ONE 0 - #define _CONDITION_EVENT_ALL 1 -#endif - -#if defined(_TTHREAD_WIN32_) -condition_variable::condition_variable() : mWaitersCount(0) -{ - mEvents[_CONDITION_EVENT_ONE] = CreateEvent(NULL, FALSE, FALSE, NULL); - mEvents[_CONDITION_EVENT_ALL] = CreateEvent(NULL, TRUE, FALSE, NULL); - InitializeCriticalSection(&mWaitersCountLock); -} -#endif - -#if defined(_TTHREAD_WIN32_) -condition_variable::~condition_variable() -{ - CloseHandle(mEvents[_CONDITION_EVENT_ONE]); - CloseHandle(mEvents[_CONDITION_EVENT_ALL]); - DeleteCriticalSection(&mWaitersCountLock); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::_wait() -{ - // Wait for either event to become signaled due to notify_one() or - // notify_all() being called - int result = WaitForMultipleObjects(2, mEvents, FALSE, INFINITE); - - // Check if we are the last waiter - EnterCriticalSection(&mWaitersCountLock); - -- mWaitersCount; - bool lastWaiter = (result == (WAIT_OBJECT_0 + _CONDITION_EVENT_ALL)) && - (mWaitersCount == 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we are the last waiter to be notified to stop waiting, reset the event - if(lastWaiter) - ResetEvent(mEvents[_CONDITION_EVENT_ALL]); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::notify_one() -{ - // Are there any waiters? - EnterCriticalSection(&mWaitersCountLock); - bool haveWaiters = (mWaitersCount > 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we have any waiting threads, send them a signal - if(haveWaiters) - SetEvent(mEvents[_CONDITION_EVENT_ONE]); -} -#endif - -#if defined(_TTHREAD_WIN32_) -void condition_variable::notify_all() -{ - // Are there any waiters? - EnterCriticalSection(&mWaitersCountLock); - bool haveWaiters = (mWaitersCount > 0); - LeaveCriticalSection(&mWaitersCountLock); - - // If we have any waiting threads, send them a signal - if(haveWaiters) - SetEvent(mEvents[_CONDITION_EVENT_ALL]); -} -#endif - - -//------------------------------------------------------------------------------ -// POSIX pthread_t to unique thread::id mapping logic. -// Note: Here we use a global thread safe std::map to convert instances of -// pthread_t to small thread identifier numbers (unique within one process). -// This method should be portable across different POSIX implementations. -//------------------------------------------------------------------------------ - -#if defined(_TTHREAD_POSIX_) -static thread::id _pthread_t_to_ID(const pthread_t &aHandle) -{ - static mutex idMapLock; - static std::map idMap; - static unsigned long int idCount(1); - - lock_guard guard(idMapLock); - if(idMap.find(aHandle) == idMap.end()) - idMap[aHandle] = idCount ++; - return thread::id(idMap[aHandle]); -} -#endif // _TTHREAD_POSIX_ - - -//------------------------------------------------------------------------------ -// thread -//------------------------------------------------------------------------------ - -/// Information to pass to the new thread (what to run). -struct _thread_start_info { - void (*mFunction)(void *); ///< Pointer to the function to be executed. - void * mArg; ///< Function argument for the thread function. - thread * mThread; ///< Pointer to the thread object. -}; - -// Thread wrapper function. -#if defined(_TTHREAD_WIN32_) -unsigned WINAPI thread::wrapper_function(void * aArg) -#elif defined(_TTHREAD_POSIX_) -void * thread::wrapper_function(void * aArg) -#endif -{ - // Get thread startup information - _thread_start_info * ti = (_thread_start_info *) aArg; - - try - { - // Call the actual client thread function - ti->mFunction(ti->mArg); - } - catch(...) - { - // Uncaught exceptions will terminate the application (default behavior - // according to C++11) - std::terminate(); - } - -#if 0 - // DFHack fix: this code prevents join from freeing thread resources. - - // The thread is no longer executing - lock_guard guard(ti->mThread->mDataMutex); - ti->mThread->mNotAThread = true; -#endif - - // The thread is responsible for freeing the startup information - delete ti; - - return 0; -} - -thread::thread(void (*aFunction)(void *), void * aArg) -{ - // Serialize access to this thread structure - lock_guard guard(mDataMutex); - - // Fill out the thread startup information (passed to the thread wrapper, - // which will eventually free it) - _thread_start_info * ti = new _thread_start_info; - ti->mFunction = aFunction; - ti->mArg = aArg; - ti->mThread = this; - - // The thread is now alive - mNotAThread = false; - - // Create the thread -#if defined(_TTHREAD_WIN32_) - mHandle = (HANDLE) _beginthreadex(0, 0, wrapper_function, (void *) ti, 0, &mWin32ThreadID); -#elif defined(_TTHREAD_POSIX_) - if(pthread_create(&mHandle, NULL, wrapper_function, (void *) ti) != 0) - mHandle = 0; -#endif - - // Did we fail to create the thread? - if(!mHandle) - { - mNotAThread = true; - delete ti; - } -} - -thread::~thread() -{ - if(joinable()) - std::terminate(); -} - -void thread::join() -{ - if(joinable()) - { -#if defined(_TTHREAD_WIN32_) - WaitForSingleObject(mHandle, INFINITE); - CloseHandle(mHandle); -#elif defined(_TTHREAD_POSIX_) - pthread_join(mHandle, NULL); -#endif - -#if 1 - // DFHack patch: moved here from the wrapper function - lock_guard guard(mDataMutex); - mNotAThread = true; -#endif - } -} - -bool thread::joinable() const -{ - mDataMutex.lock(); - bool result = !mNotAThread; - mDataMutex.unlock(); - return result; -} - -void thread::detach() -{ - mDataMutex.lock(); - if(!mNotAThread) - { -#if defined(_TTHREAD_WIN32_) - CloseHandle(mHandle); -#elif defined(_TTHREAD_POSIX_) - pthread_detach(mHandle); -#endif - mNotAThread = true; - } - mDataMutex.unlock(); -} - -thread::id thread::get_id() const -{ - if(!joinable()) - return id(); -#if defined(_TTHREAD_WIN32_) - return id((unsigned long int) mWin32ThreadID); -#elif defined(_TTHREAD_POSIX_) - return _pthread_t_to_ID(mHandle); -#endif -} - -unsigned thread::hardware_concurrency() -{ -#if defined(_TTHREAD_WIN32_) - SYSTEM_INFO si; - GetSystemInfo(&si); - return (int) si.dwNumberOfProcessors; -#elif defined(_SC_NPROCESSORS_ONLN) - return (int) sysconf(_SC_NPROCESSORS_ONLN); -#elif defined(_SC_NPROC_ONLN) - return (int) sysconf(_SC_NPROC_ONLN); -#else - // The standard requires this function to return zero if the number of - // hardware cores could not be determined. - return 0; -#endif -} - - -//------------------------------------------------------------------------------ -// this_thread -//------------------------------------------------------------------------------ - -thread::id this_thread::get_id() -{ -#if defined(_TTHREAD_WIN32_) - return thread::id((unsigned long int) GetCurrentThreadId()); -#elif defined(_TTHREAD_POSIX_) - return _pthread_t_to_ID(pthread_self()); -#endif -} - -} diff --git a/depends/tthread/tinythread.h b/depends/tthread/tinythread.h deleted file mode 100644 index b5ff2f0771..0000000000 --- a/depends/tthread/tinythread.h +++ /dev/null @@ -1,714 +0,0 @@ -/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- -Copyright (c) 2010-2012 Marcus Geelnard - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ - -#ifndef _TINYTHREAD_H_ -#define _TINYTHREAD_H_ - -/// @file -/// @mainpage TinyThread++ API Reference -/// -/// @section intro_sec Introduction -/// TinyThread++ is a minimal, portable implementation of basic threading -/// classes for C++. -/// -/// They closely mimic the functionality and naming of the C++11 standard, and -/// should be easily replaceable with the corresponding std:: variants. -/// -/// @section port_sec Portability -/// The Win32 variant uses the native Win32 API for implementing the thread -/// classes, while for other systems, the POSIX threads API (pthread) is used. -/// -/// @section class_sec Classes -/// In order to mimic the threading API of the C++11 standard, subsets of -/// several classes are provided. The fundamental classes are: -/// @li tthread::thread -/// @li tthread::mutex -/// @li tthread::recursive_mutex -/// @li tthread::condition_variable -/// @li tthread::lock_guard -/// -/// @section misc_sec Miscellaneous -/// The following special keywords are available: #thread_local. -/// -/// For more detailed information (including additional classes), browse the -/// different sections of this documentation. A good place to start is: -/// tinythread.h. - -// Which platform are we on? -#if !defined(_TTHREAD_PLATFORM_DEFINED_) - #if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__) - #define _TTHREAD_WIN32_ - #else - #define _TTHREAD_POSIX_ - #endif - #define _TTHREAD_PLATFORM_DEFINED_ -#endif - -// Platform specific includes -#if defined(_TTHREAD_WIN32_) - #define NOMINMAX - #ifndef WIN32_LEAN_AND_MEAN - #define WIN32_LEAN_AND_MEAN - #define __UNDEF_LEAN_AND_MEAN - #endif - #include - #ifdef __UNDEF_LEAN_AND_MEAN - #undef WIN32_LEAN_AND_MEAN - #undef __UNDEF_LEAN_AND_MEAN - #endif -#else - #include - #include - #include - #include -#endif - -// Generic includes -#include - -/// TinyThread++ version (major number). -#define TINYTHREAD_VERSION_MAJOR 1 -/// TinyThread++ version (minor number). -#define TINYTHREAD_VERSION_MINOR 1 -/// TinyThread++ version (full version). -#define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR) - -// Do we have a fully featured C++11 compiler? -#if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L)) - #define _TTHREAD_CPP11_ -#endif - -// ...at least partial C++11? -#if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__) - #define _TTHREAD_CPP11_PARTIAL_ -#endif - -// Macro for disabling assignments of objects. -#ifdef _TTHREAD_CPP11_PARTIAL_ - #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ - name(const name&) = delete; \ - name& operator=(const name&) = delete; -#else - #define _TTHREAD_DISABLE_ASSIGNMENT(name) \ - name(const name&); \ - name& operator=(const name&); -#endif - -/// @def thread_local -/// Thread local storage keyword. -/// A variable that is declared with the @c thread_local keyword makes the -/// value of the variable local to each thread (known as thread-local storage, -/// or TLS). Example usage: -/// @code -/// // This variable is local to each thread. -/// thread_local int variable; -/// @endcode -/// @note The @c thread_local keyword is a macro that maps to the corresponding -/// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard -/// allows for non-trivial types (e.g. classes with constructors and -/// destructors) to be declared with the @c thread_local keyword, most pre-C++11 -/// compilers only allow for trivial types (e.g. @c int). So, to guarantee -/// portable code, only use trivial types for thread local storage. -/// @note This directive is currently not supported on Mac OS X (it will give -/// a compiler error), since compile-time TLS is not supported in the Mac OS X -/// executable format. Also, some older versions of MinGW (before GCC 4.x) do -/// not support this directive. -/// @hideinitializer - -#if !defined(_TTHREAD_CPP11_) && !defined(thread_local) - #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) - #define thread_local __thread - #else - #define thread_local __declspec(thread) - #endif -#endif - - -/// Main name space for TinyThread++. -/// This namespace is more or less equivalent to the @c std namespace for the -/// C++11 thread classes. For instance, the tthread::mutex class corresponds to -/// the std::mutex class. -namespace tthread { - -/// Mutex class. -/// This is a mutual exclusion object for synchronizing access to shared -/// memory areas for several threads. The mutex is non-recursive (i.e. a -/// program may deadlock if the thread that owns a mutex object calls lock() -/// on that object). -/// @see recursive_mutex -class mutex { - public: - /// Constructor. - mutex() -#if defined(_TTHREAD_WIN32_) - : mAlreadyLocked(false) -#endif - { -#if defined(_TTHREAD_WIN32_) - InitializeCriticalSection(&mHandle); -#else - pthread_mutex_init(&mHandle, NULL); -#endif - } - - /// Destructor. - ~mutex() - { -#if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mHandle); -#else - pthread_mutex_destroy(&mHandle); -#endif - } - - /// Lock the mutex. - /// The method will block the calling thread until a lock on the mutex can - /// be obtained. The mutex remains locked until @c unlock() is called. - /// @see lock_guard - inline void lock() - { -#if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mHandle); - while(mAlreadyLocked) Sleep(1000); // Simulate deadlock... - mAlreadyLocked = true; -#else - pthread_mutex_lock(&mHandle); -#endif - } - - /// Try to lock the mutex. - /// The method will try to lock the mutex. If it fails, the function will - /// return immediately (non-blocking). - /// @return @c true if the lock was acquired, or @c false if the lock could - /// not be acquired. - inline bool try_lock() - { -#if defined(_TTHREAD_WIN32_) - bool ret = (TryEnterCriticalSection(&mHandle) ? true : false); - if(ret && mAlreadyLocked) - { - LeaveCriticalSection(&mHandle); - ret = false; - } - return ret; -#else - return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; -#endif - } - - /// Unlock the mutex. - /// If any threads are waiting for the lock on this mutex, one of them will - /// be unblocked. - inline void unlock() - { -#if defined(_TTHREAD_WIN32_) - mAlreadyLocked = false; - LeaveCriticalSection(&mHandle); -#else - pthread_mutex_unlock(&mHandle); -#endif - } - - _TTHREAD_DISABLE_ASSIGNMENT(mutex) - - private: -#if defined(_TTHREAD_WIN32_) - CRITICAL_SECTION mHandle; - bool mAlreadyLocked; -#else - pthread_mutex_t mHandle; -#endif - - friend class condition_variable; -}; - -/// Recursive mutex class. -/// This is a mutual exclusion object for synchronizing access to shared -/// memory areas for several threads. The mutex is recursive (i.e. a thread -/// may lock the mutex several times, as long as it unlocks the mutex the same -/// number of times). -/// @see mutex -class recursive_mutex { - public: - /// Constructor. - recursive_mutex() - { -#if defined(_TTHREAD_WIN32_) - InitializeCriticalSection(&mHandle); -#else - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&mHandle, &attr); -#endif - } - - /// Destructor. - ~recursive_mutex() - { -#if defined(_TTHREAD_WIN32_) - DeleteCriticalSection(&mHandle); -#else - pthread_mutex_destroy(&mHandle); -#endif - } - - /// Lock the mutex. - /// The method will block the calling thread until a lock on the mutex can - /// be obtained. The mutex remains locked until @c unlock() is called. - /// @see lock_guard - inline void lock() - { -#if defined(_TTHREAD_WIN32_) - EnterCriticalSection(&mHandle); -#else - pthread_mutex_lock(&mHandle); -#endif - } - - /// Try to lock the mutex. - /// The method will try to lock the mutex. If it fails, the function will - /// return immediately (non-blocking). - /// @return @c true if the lock was acquired, or @c false if the lock could - /// not be acquired. - inline bool try_lock() - { -#if defined(_TTHREAD_WIN32_) - return TryEnterCriticalSection(&mHandle) ? true : false; -#else - return (pthread_mutex_trylock(&mHandle) == 0) ? true : false; -#endif - } - - /// Unlock the mutex. - /// If any threads are waiting for the lock on this mutex, one of them will - /// be unblocked. - inline void unlock() - { -#if defined(_TTHREAD_WIN32_) - LeaveCriticalSection(&mHandle); -#else - pthread_mutex_unlock(&mHandle); -#endif - } - - _TTHREAD_DISABLE_ASSIGNMENT(recursive_mutex) - - private: -#if defined(_TTHREAD_WIN32_) - CRITICAL_SECTION mHandle; -#else - pthread_mutex_t mHandle; -#endif - - friend class condition_variable; -}; - -/// Lock guard class. -/// The constructor locks the mutex, and the destructor unlocks the mutex, so -/// the mutex will automatically be unlocked when the lock guard goes out of -/// scope. Example usage: -/// @code -/// mutex m; -/// int counter; -/// -/// void increment() -/// { -/// lock_guard guard(m); -/// ++ counter; -/// } -/// @endcode - -template -class lock_guard { - public: - typedef T mutex_type; - - lock_guard() : mMutex(0) {} - - /// The constructor locks the mutex. - explicit lock_guard(mutex_type &aMutex) - { - mMutex = &aMutex; - mMutex->lock(); - } - - /// The destructor unlocks the mutex. - ~lock_guard() - { - if(mMutex) - mMutex->unlock(); - } - - private: - mutex_type * mMutex; -}; - -/// Condition variable class. -/// This is a signalling object for synchronizing the execution flow for -/// several threads. Example usage: -/// @code -/// // Shared data and associated mutex and condition variable objects -/// int count; -/// mutex m; -/// condition_variable cond; -/// -/// // Wait for the counter to reach a certain number -/// void wait_counter(int targetCount) -/// { -/// lock_guard guard(m); -/// while(count < targetCount) -/// cond.wait(m); -/// } -/// -/// // Increment the counter, and notify waiting threads -/// void increment() -/// { -/// lock_guard guard(m); -/// ++ count; -/// cond.notify_all(); -/// } -/// @endcode -class condition_variable { - public: - /// Constructor. -#if defined(_TTHREAD_WIN32_) - condition_variable(); -#else - condition_variable() - { - pthread_cond_init(&mHandle, NULL); - } -#endif - - /// Destructor. -#if defined(_TTHREAD_WIN32_) - ~condition_variable(); -#else - ~condition_variable() - { - pthread_cond_destroy(&mHandle); - } -#endif - - /// Wait for the condition. - /// The function will block the calling thread until the condition variable - /// is woken by @c notify_one(), @c notify_all() or a spurious wake up. - /// @param[in] aMutex A mutex that will be unlocked when the wait operation - /// starts, an locked again as soon as the wait operation is finished. - template - inline void wait(_mutexT &aMutex) - { -#if defined(_TTHREAD_WIN32_) - // Increment number of waiters - EnterCriticalSection(&mWaitersCountLock); - ++ mWaitersCount; - LeaveCriticalSection(&mWaitersCountLock); - - // Release the mutex while waiting for the condition (will decrease - // the number of waiters when done)... - aMutex.unlock(); - _wait(); - aMutex.lock(); -#else - pthread_cond_wait(&mHandle, &aMutex.mHandle); -#endif - } - - /// Notify one thread that is waiting for the condition. - /// If at least one thread is blocked waiting for this condition variable, - /// one will be woken up. - /// @note Only threads that started waiting prior to this call will be - /// woken up. -#if defined(_TTHREAD_WIN32_) - void notify_one(); -#else - inline void notify_one() - { - pthread_cond_signal(&mHandle); - } -#endif - - /// Notify all threads that are waiting for the condition. - /// All threads that are blocked waiting for this condition variable will - /// be woken up. - /// @note Only threads that started waiting prior to this call will be - /// woken up. -#if defined(_TTHREAD_WIN32_) - void notify_all(); -#else - inline void notify_all() - { - pthread_cond_broadcast(&mHandle); - } -#endif - - _TTHREAD_DISABLE_ASSIGNMENT(condition_variable) - - private: -#if defined(_TTHREAD_WIN32_) - void _wait(); - HANDLE mEvents[2]; ///< Signal and broadcast event HANDLEs. - unsigned int mWaitersCount; ///< Count of the number of waiters. - CRITICAL_SECTION mWaitersCountLock; ///< Serialize access to mWaitersCount. -#else - pthread_cond_t mHandle; -#endif -}; - - -/// Thread class. -class thread { - public: -#if defined(_TTHREAD_WIN32_) - typedef HANDLE native_handle_type; -#else - typedef pthread_t native_handle_type; -#endif - - class id; - - /// Default constructor. - /// Construct a @c thread object without an associated thread of execution - /// (i.e. non-joinable). - thread() : mHandle(0), mNotAThread(true) -#if defined(_TTHREAD_WIN32_) - , mWin32ThreadID(0) -#endif - {} - - /// Thread starting constructor. - /// Construct a @c thread object with a new thread of execution. - /// @param[in] aFunction A function pointer to a function of type: - /// void fun(void * arg) - /// @param[in] aArg Argument to the thread function. - /// @note This constructor is not fully compatible with the standard C++ - /// thread class. It is more similar to the pthread_create() (POSIX) and - /// CreateThread() (Windows) functions. - thread(void (*aFunction)(void *), void * aArg); - - /// Destructor. - /// @note If the thread is joinable upon destruction, @c std::terminate() - /// will be called, which terminates the process. It is always wise to do - /// @c join() before deleting a thread object. - ~thread(); - - /// Wait for the thread to finish (join execution flows). - /// After calling @c join(), the thread object is no longer associated with - /// a thread of execution (i.e. it is not joinable, and you may not join - /// with it nor detach from it). - void join(); - - /// Check if the thread is joinable. - /// A thread object is joinable if it has an associated thread of execution. - bool joinable() const; - - /// Detach from the thread. - /// After calling @c detach(), the thread object is no longer assicated with - /// a thread of execution (i.e. it is not joinable). The thread continues - /// execution without the calling thread blocking, and when the thread - /// ends execution, any owned resources are released. - void detach(); - - /// Return the thread ID of a thread object. - id get_id() const; - - /// Get the native handle for this thread. - /// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this - /// is a @c pthread_t. - inline native_handle_type native_handle() - { - return mHandle; - } - - /// Determine the number of threads which can possibly execute concurrently. - /// This function is useful for determining the optimal number of threads to - /// use for a task. - /// @return The number of hardware thread contexts in the system. - /// @note If this value is not defined, the function returns zero (0). - static unsigned hardware_concurrency(); - - _TTHREAD_DISABLE_ASSIGNMENT(thread) - - private: - native_handle_type mHandle; ///< Thread handle. - mutable mutex mDataMutex; ///< Serializer for access to the thread private data. - bool mNotAThread; ///< True if this object is not a thread of execution. -#if defined(_TTHREAD_WIN32_) - unsigned int mWin32ThreadID; ///< Unique thread ID (filled out by _beginthreadex). -#endif - - // This is the internal thread wrapper function. -#if defined(_TTHREAD_WIN32_) - static unsigned WINAPI wrapper_function(void * aArg); -#else - static void * wrapper_function(void * aArg); -#endif -}; - -/// Thread ID. -/// The thread ID is a unique identifier for each thread. -/// @see thread::get_id() -class thread::id { - public: - /// Default constructor. - /// The default constructed ID is that of thread without a thread of - /// execution. - id() : mId(0) {}; - - id(unsigned long int aId) : mId(aId) {}; - - id(const id& aId) : mId(aId.mId) {}; - - inline id & operator=(const id &aId) - { - mId = aId.mId; - return *this; - } - - inline friend bool operator==(const id &aId1, const id &aId2) - { - return (aId1.mId == aId2.mId); - } - - inline friend bool operator!=(const id &aId1, const id &aId2) - { - return (aId1.mId != aId2.mId); - } - - inline friend bool operator<=(const id &aId1, const id &aId2) - { - return (aId1.mId <= aId2.mId); - } - - inline friend bool operator<(const id &aId1, const id &aId2) - { - return (aId1.mId < aId2.mId); - } - - inline friend bool operator>=(const id &aId1, const id &aId2) - { - return (aId1.mId >= aId2.mId); - } - - inline friend bool operator>(const id &aId1, const id &aId2) - { - return (aId1.mId > aId2.mId); - } - - inline friend std::ostream& operator <<(std::ostream &os, const id &obj) - { - os << obj.mId; - return os; - } - - private: - unsigned long int mId; -}; - - -// Related to - minimal to be able to support chrono. -typedef long long __intmax_t; - -/// Minimal implementation of the @c ratio class. This class provides enough -/// functionality to implement some basic @c chrono classes. -template <__intmax_t N, __intmax_t D = 1> class ratio { - public: - static double _as_double() { return double(N) / double(D); } -}; - -/// Minimal implementation of the @c chrono namespace. -/// The @c chrono namespace provides types for specifying time intervals. -namespace chrono { - /// Duration template class. This class provides enough functionality to - /// implement @c this_thread::sleep_for(). - template > class duration { - private: - _Rep rep_; - public: - typedef _Rep rep; - typedef _Period period; - - /// Construct a duration object with the given duration. - template - explicit duration(const _Rep2& r) : rep_(r) {}; - - /// Return the value of the duration object. - rep count() const - { - return rep_; - } - }; - - // Standard duration types. - typedef duration<__intmax_t, ratio<1, 1000000000> > nanoseconds; ///< Duration with the unit nanoseconds. - typedef duration<__intmax_t, ratio<1, 1000000> > microseconds; ///< Duration with the unit microseconds. - typedef duration<__intmax_t, ratio<1, 1000> > milliseconds; ///< Duration with the unit milliseconds. - typedef duration<__intmax_t> seconds; ///< Duration with the unit seconds. - typedef duration<__intmax_t, ratio<60> > minutes; ///< Duration with the unit minutes. - typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours. -} - -/// The namespace @c this_thread provides methods for dealing with the -/// calling thread. -namespace this_thread { - /// Return the thread ID of the calling thread. - thread::id get_id(); - - /// Yield execution to another thread. - /// Offers the operating system the opportunity to schedule another thread - /// that is ready to run on the current processor. - inline void yield() - { -#if defined(_TTHREAD_WIN32_) - Sleep(0); -#else - sched_yield(); -#endif - } - - /// Blocks the calling thread for a period of time. - /// @param[in] aTime Minimum time to put the thread to sleep. - /// Example usage: - /// @code - /// // Sleep for 100 milliseconds - /// this_thread::sleep_for(chrono::milliseconds(100)); - /// @endcode - /// @note Supported duration types are: nanoseconds, microseconds, - /// milliseconds, seconds, minutes and hours. - template void sleep_for(const chrono::duration<_Rep, _Period>& aTime) - { -#if defined(_TTHREAD_WIN32_) - Sleep(int(double(aTime.count()) * (1000.0 * _Period::_as_double()) + 0.5)); -#else - usleep(int(double(aTime.count()) * (1000000.0 * _Period::_as_double()) + 0.5)); -#endif - } -} - -} - -// Define/macro cleanup -#undef _TTHREAD_DISABLE_ASSIGNMENT - -#endif // _TINYTHREAD_H_ diff --git a/depends/xlsxio b/depends/xlsxio index 4056226fe0..e3ed11f6b4 160000 --- a/depends/xlsxio +++ b/depends/xlsxio @@ -1 +1 @@ -Subproject commit 4056226fe0df6bff4593ee2353cca07c2b7f327e +Subproject commit e3ed11f6b40bf68b48afc8fc3131ea2b4a22d5b1 diff --git a/depends/zlib/lib/win32/.gitignore b/depends/zlib/lib/.gitignore similarity index 100% rename from depends/zlib/lib/win32/.gitignore rename to depends/zlib/lib/.gitignore diff --git a/depends/zlib/lib/win64/.gitignore b/depends/zlib/lib/win64/.gitignore deleted file mode 100644 index 683bf139fb..0000000000 --- a/depends/zlib/lib/win64/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.lib diff --git a/dfhack-config/autonick.txt b/dfhack-config/autonick.txt deleted file mode 100644 index 79cfefb0a9..0000000000 --- a/dfhack-config/autonick.txt +++ /dev/null @@ -1,153 +0,0 @@ -# autonick config file -# every line in this file that is not empty and does -# not start with "#" will be used as a nickname by the -# autonick script. - -# nicknames can be multiple words -Toady One -Threetoe - -# animals -Mouse -Otter -Snake -Owl -Bat -Fox -Mole -Cat -Badger -Squirrel -Kit -Wren -Jay -Crow -Raven -Sparrow - -# colours -Flash -Red -Gray -Blue -Shadow -Indigo -Jade -Umber -Silver - -# planets -Mars -Jupiter -Saturn - -# nature -Blaze -River -Snow -Bones -Rain -Reed -Lake -Briar -Brook -Sky -Storm -Clay -Ember -Marsh -Star - -# trees -Ash -Oak -Rowan -Aspen -Alder -Apple -Beech -Birch -Box -Cedar -Cypress -Elder -Elm -Larch -Fir -Juniper -Lime -Pine -Poplar -Spruce -Yew - -# seasons -Spring -Summer -Autumn -Winter - -# cardinals -North -South -East -West - -# other -Ink -Echo -Mint -Mel -X -Sam -Tango -Gadget -Brum -Wall -Beam -Ud -Tal -Ren -Aki -Jun -Kei -Lynn -Lex -Cid -Miles -Rotor -Mesa -Verse - -# from the "300 list" -Aiden -Arden -Auden -August -Avery -Avis -Bay -Blake -Erin -Ezra -Kai -Lane -Leah -Noel -Pat -Ray -Remi -Roan -Robyn -Salem -Sean -Tate -Tobin -Tori -True -Val -Wilder -Wisdom -Wyatt -Zephyr - diff --git a/dfhack-config/dwarfmonitor.json b/dfhack-config/dwarfmonitor.json deleted file mode 100644 index 3fd365e746..0000000000 --- a/dfhack-config/dwarfmonitor.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "widgets": [ - { - "type": "weather", - "x": 1, - "y": -1 - }, - { - "type": "date", - "x": -30, - "y": 0, - "format": "Y-M-D" - }, - { - "type": "misery", - "x": -2, - "y": -1, - "anchor": "right" - } - ] -} diff --git a/dfhack-config/quickfort/aliases.txt b/dfhack-config/quickfort/aliases.txt deleted file mode 100644 index a3e52052d1..0000000000 --- a/dfhack-config/quickfort/aliases.txt +++ /dev/null @@ -1,17 +0,0 @@ -# Custom aliases for quickfort query mode blueprints -# -# This file defines custom key sequence shortcuts for query mode blueprints. -# Definitions in this file take precedence over any definitions in the -# baseline aliases configuration file in -# hack/data/quickfort/aliases-common.txt -# -# Please see -# https://docs.dfhack.org/en/latest/docs/guides/quickfort-alias-guide.html -# or -# hack/docs/docs/guides/quickfort-alias-guide.html -# in your DF installation directory for alias syntax documentation and an -# overview of the DFHack alias standard library. -# -# -# Add your custom aliases here. Example: -# food_stash: {foodprefix}b{Right}{Down 11}p^{permitplants} diff --git a/dfhack-config/quickfort/quickfort.txt b/dfhack-config/quickfort/quickfort.txt deleted file mode 100644 index 3a57bfbaf1..0000000000 --- a/dfhack-config/quickfort/quickfort.txt +++ /dev/null @@ -1,37 +0,0 @@ -# quickfort main configuration file -# -# Set startup defaults for the quickfort script in this file. Settings can be -# temporarily overridden in the active session with the `quickfort set` command. -# -# If you have edited this file but want to revert to "factory defaults", delete -# this file and a fresh one will be copied from -# dfhack-config/default/quickfort/quickfort.txt the next time you start DFHack. - -# Directory tree to search for blueprints. Can be set to an absolute or relative -# path. If set to a relative path, resolves to a directory under the DF folder. -# Note that if you change this directory, you will not automatically pick up -# blueprints written by the DFHack "blueprint" plugin (which always writes to -# the "blueprints" dir). -blueprints_dir=blueprints - -# Set to "true" or "false". If true, will designate all dig blueprints in marker -# mode. If false, only cells with dig codes explicitly prefixed with an "m" will -# be designated in marker mode. -force_marker_mode=false - -# Skip query blueprint sanity checks that detect common blueprint errors and -# halt or skip keycode playback. Checks include ensuring a configurable building -# exists at the designated cursor position and verifying the active UI screen is -# the same before and after sending keys for the cursor position. Temporarily -# enable this if you are running a query blueprint that sends a key sequence -# that is *not* related to stockpile or building configuration. -query_unsafe=false - -# Set to the maximum number of resources you want assigned to stockpiles of the -# relevant types. Set to -1 for DF defaults (number of stockpile tiles for -# stockpiles that take barrels and bins, 1 wheelbarrow for stone stockpiles). -# The default here for wheelbarrows is 0 since using wheelbarrows normally -# *decreases* the efficiency of your fort. -stockpiles_max_barrels=-1 -stockpiles_max_bins=-1 -stockpiles_max_wheelbarrows=0 diff --git a/dfhack.init-example b/dfhack.init-example deleted file mode 100644 index 702ce5276a..0000000000 --- a/dfhack.init-example +++ /dev/null @@ -1,293 +0,0 @@ -############################## -# Generic dwarfmode bindings # -############################## - -# show all current key bindings -keybinding add Ctrl-F1 hotkeys -keybinding add Alt-F1 hotkeys - -# toggle the display of water level as 1-7 tiles -keybinding add Ctrl-W twaterlvl - -# with cursor: - -# designate the whole vein for digging -keybinding add Ctrl-V digv -keybinding add Ctrl-Shift-V "digv x" - -# clean the selected tile of blood etc -keybinding add Ctrl-C spotclean - -# destroy items designated for dump in the selected tile -keybinding add Ctrl-Shift-K autodump-destroy-here - -# set the zone or cage under the cursor as the default -keybinding add Alt-Shift-I@dwarfmode/Zones "zone set" - -# with an item selected: - -# destroy the selected item -keybinding add Ctrl-K autodump-destroy-item - -# scripts: - -# quicksave, only in main dwarfmode screen and menu page -keybinding add Ctrl-Alt-S@dwarfmode/Default quicksave - -# gui/rename script - rename units and buildings -keybinding add Ctrl-Shift-N gui/rename -keybinding add Ctrl-Shift-T "gui/rename unit-profession" - -# a dfhack prompt in df. Sublime text like. -keybinding add Ctrl-Shift-P command-prompt - -# show information collected by dwarfmonitor -keybinding add Alt-M@dwarfmode/Default "dwarfmonitor prefs" -keybinding add Ctrl-F@dwarfmode/Default "dwarfmonitor stats" - -# export a Dwarf's preferences screen in BBCode to post to a forum -keybinding add Ctrl-Shift-F@dwarfmode forum-dwarves - -# an in-game init file editor -keybinding add Alt-S@title gui/settings-manager -keybinding add Alt-S@dwarfmode/Default gui/settings-manager - -# change quantity of manager orders -keybinding add Alt-Q@jobmanagement/Main gui/manager-quantity - -# re-check manager orders -keybinding add Alt-R@jobmanagement/Main workorder-recheck - -# view combat reports for the selected unit/corpse/spatter -keybinding add Ctrl-Shift-R view-unit-reports - -# view extra unit information -keybinding add Alt-I@dwarfmode/ViewUnits|unitlist gui/unit-info-viewer - -############################## -# Generic adv mode bindings # -############################## - -keybinding add Ctrl-B@dungeonmode adv-bodyswap -keybinding add Ctrl-Shift-B@dungeonmode "adv-bodyswap force" -keybinding add Shift-O@dungeonmode gui/companion-order -keybinding add Ctrl-T@dungeonmode gui/advfort -keybinding add Ctrl-A@dungeonmode/ConversationSpeak adv-rumors - -############################## -# Generic legends bindings # -############################## - -# export all information, or just the detailed maps (doesn't handle site maps) -keybinding add Ctrl-A@legends "exportlegends all" - -############################# -# Context-specific bindings # -############################# - -# Stocks plugin -keybinding add Ctrl-Shift-Z@dwarfmode/Default "stocks show" - -# open an overview window summarising some stocks (dfstatus) -keybinding add Ctrl-Shift-I@dwarfmode/Default "gui/dfstatus" -keybinding add Ctrl-Shift-I@dfhack/lua/dfstatus "gui/dfstatus" - -# q->stockpile - copy & paste stockpiles -keybinding add Alt-P copystock - -# q->stockpile - load and save stockpile settings out of game -keybinding add Alt-L@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -load" -keybinding add Alt-S@dwarfmode/QueryBuilding/Some/Stockpile "gui/stockpiles -save" - -# q->workshop - duplicate the selected job -keybinding add Ctrl-D job-duplicate - -# materials: q->workshop; b->select items -keybinding add Shift-A "job-material ALUNITE" -keybinding add Shift-M "job-material MICROCLINE" -keybinding add Shift-D "job-material DACITE" -keybinding add Shift-R "job-material RHYOLITE" -keybinding add Shift-I "job-material CINNABAR" -keybinding add Shift-B "job-material COBALTITE" -keybinding add Shift-O "job-material OBSIDIAN" -keybinding add Shift-T "job-material ORTHOCLASE" -keybinding add Shift-G "job-material GLASS_GREEN" - -# sort units and items in the on-screen list -keybinding add Alt-Shift-N "sort-units name" "sort-items description" -keybinding add Alt-Shift-R "sort-units arrival" -keybinding add Alt-Shift-T "sort-units profession" "sort-items type material" -keybinding add Alt-Shift-Q "sort-units squad_position" "sort-items quality" - -# browse linked mechanisms -keybinding add Ctrl-M@dwarfmode/QueryBuilding/Some gui/mechanisms - -# browse rooms of same owner -keybinding add Alt-R@dwarfmode/QueryBuilding/Some gui/room-list - -# interface for the liquids plugin - spawn water/magma/obsidian -keybinding add Alt-L@dwarfmode/LookAround gui/liquids - -# machine power sensitive pressure plate construction -keybinding add Ctrl-Shift-M@dwarfmode/Build/Position/Trap gui/power-meter - -# siege engine control -keybinding add Alt-A@dwarfmode/QueryBuilding/Some/SiegeEngine gui/siege-engine - -# military weapon auto-select -keybinding add Ctrl-W@layer_military/Equip/Customize/View gui/choose-weapons - -# military copy uniform -keybinding add Ctrl-C@layer_military/Uniforms gui/clone-uniform - -# minecart Guide path -keybinding add Alt-P@dwarfmode/Hauling/DefineStop/Cond/Guide gui/guide-path - -# workshop job details -keybinding add Alt-A@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workshop-job - -# workflow front-end -keybinding add Alt-W@dwarfmode/QueryBuilding/Some/Workshop/Job gui/workflow -keybinding add Alt-W@overallstatus "gui/workflow status" -# equivalent to the one above when gui/extended-status is enabled -keybinding add Alt-W@dfhack/lua/status_overlay "gui/workflow status" - -# autobutcher front-end -keybinding add Shift-B@pet/List/Unit "gui/autobutcher" - -# assign weapon racks to squads so that they can be used -keybinding add P@dwarfmode/QueryBuilding/Some/Weaponrack gui/assign-rack - -# view pathable tiles from active cursor -keybinding add Alt-Shift-P@dwarfmode/LookAround gui/pathable - -############################ -# UI and game logic tweaks # -############################ - -# stabilize the cursor of dwarfmode when switching menus -tweak stable-cursor - -# stop stacked liquid/bar/thread/cloth items from lasting forever -# if used in reactions that use only a fraction of the dimension. -# might be fixed by DF -# tweak fix-dimensions - -# make reactions requiring containers usable in advmode - the issue is -# that the screen asks for those reagents to be selected directly -tweak advmode-contained - -# support Shift-Enter in Trade and Move Goods to Depot screens for faster -# selection; it selects the current item or stack and scrolls down one line -tweak fast-trade - -# stop the right list in military->positions from resetting to top all the time -tweak military-stable-assign -# in same list, color units already assigned to squads in brown & green -tweak military-color-assigned - -# remove inverse dependency of squad training speed on unit list size and use more sparring -# tweak military-training - -# make crafted cloth items wear out with time like in old versions (bug 6003) -tweak craft-age-wear - -# stop adamantine clothing from wearing out (bug 6481) -#tweak adamantine-cloth-wear - -# Add "Select all" and "Deselect all" options to farm plot menus -tweak farm-plot-select - -# Add Shift-Left/Right controls to import agreement screen -tweak import-priority-category - -# Fixes a crash in the work order contition material list (bug 9905). -tweak condition-material - -# Adds an option to clear currently-bound hotkeys -tweak hotkey-clear - -# Allows lowercase letters in embark profile names, and allows exiting the name prompt without saving -tweak embark-profile-name - -# Misc. UI tweaks -tweak block-labors # Prevents labors that can't be used from being toggled -tweak burrow-name-cancel -tweak cage-butcher -tweak civ-view-agreement -tweak eggs-fertile -tweak fps-min -tweak hide-priority -tweak kitchen-prefs-all -tweak kitchen-prefs-empty -tweak max-wheelbarrow -tweak shift-8-scroll -tweak stone-status-all -tweak title-start-rename -tweak tradereq-pet-gender - -########################### -# Globally acting plugins # -########################### - -# Display DFHack version on title screen -enable title-version - -# Dwarf Manipulator (simple in-game Dwarf Therapist replacement) -enable manipulator - -# Search tool in various screens (by falconne) -enable search - -# Improved build material selection interface (by falconne) -enable automaterial - -# Other interface improvement tools -enable \ - confirm \ - dwarfmonitor \ - mousequery \ - autogems \ - autodump \ - automelt \ - autotrade \ - buildingplan \ - resume \ - trackstop \ - zone \ - stocks \ - autochop \ - stockpiles -#end a line with a backslash to make it continue to the next line. The \ is deleted for the final command. -# Multiline commands are ONLY supported for scripts like dfhack.init. You cannot do multiline command manually on the DFHack console. -# You cannot extend a commented line. -# You can comment out the extension of a line. - -# enable mouse controls and sand indicator in embark screen -embark-tools enable sticky sand mouse - -# enable option to enter embark assistant -enable embark-assistant - -########### -# Scripts # -########### - -# write extra information to the gamelog -modtools/extra-gamelog enable - -# extended status screen (bedrooms page) -enable gui/extended-status - -# add information to item viewscreens -view-item-info enable - -# a replacement for the "load game" screen -gui/load-screen enable - -############################## -# Extra DFHack command files # -############################## - -# Run commands in this file when a world loads -sc-script add SC_WORLD_LOADED onLoad.init-example diff --git a/docs/Compile.rst b/docs/Compile.rst deleted file mode 100644 index a0b4fe5e71..0000000000 --- a/docs/Compile.rst +++ /dev/null @@ -1,723 +0,0 @@ -.. highlight:: shell - -.. _compile: - -################ -Compiling DFHack -################ - -DFHack builds are available for all supported platforms; see `installing` for -installation instructions. If you are a DFHack end-user, modder, or plan on -writing scripts (not plugins), it is generally recommended (and easier) to use -these builds instead of compiling DFHack from source. - -However, if you are looking to develop plugins, work on the DFHack core, make -complex changes to DF-structures, or anything else that requires compiling -DFHack from source, this document will walk you through the build process. Note -that some steps may be unconventional compared to other projects, so be sure to -pay close attention if this is your first time compiling DFHack. - -.. contents:: Contents - :local: - :depth: 1 - -.. _compile-how-to-get-the-code: - -How to get the code -=================== -DFHack uses Git for source control; instructions for installing Git can be found -in the platform-specific sections below. The code is hosted on -`GitHub `_, and can be downloaded with:: - - git clone --recursive https://github.com/DFHack/dfhack - cd dfhack - -If your version of Git does not support the ``--recursive`` flag, you will need -to omit it and run ``git submodule update --init`` after entering the dfhack -directory. - -This will check out the code on the default branch of the GitHub repo, currently -``develop``, which may be unstable. If you want code for the latest stable -release, you can check out the ``master`` branch instead:: - - git checkout master - git submodule update - -In general, a single DFHack clone is suitable for development - most Git -operations such as switching branches can be done on an existing clone. If you -find yourself cloning DFHack frequently as part of your development process, or -getting stuck on anything else Git-related, feel free to reach out to us for -assistance. - -.. admonition:: Offline builds - - If you plan to build DFHack on a machine without an internet connection (or - with an unreliable connection), see `note-offline-builds` for additional - instructions. - -.. admonition:: Working with submodules - - DFHack uses submodules extensively to manage its subprojects (including the - ``scripts`` folder and DF-structures in ``library/xml``). Failing to keep - submodules in sync when switching between branches can result in build errors - or scripts that don't work. In general, you should always update submodules - whenever you switch between branches in the main DFHack repo with - ``git submodule update``. (If you are working on bleeding-edge DFHack and - have checked out the master branch of some submodules, running ``git pull`` - in those submodules is also an option.) - - Rarely, we add or remove submodules. If there are any changes to the existence - of submodules when you switch between branches, you should run - ``git submodule update --init`` instead (adding ``--init`` to the above - command). - - Some common errors that can arise when failing to update submodules include: - - * ``fatal: does not exist`` when performing Git operations - * Build errors, particularly referring to structures in the ``df::`` namespace - or the ``library/include/df`` folder - * ``Not a known DF version`` when starting DF - * ``Run 'git submodule update --init'`` when running CMake - - Submodules are a particularly confusing feature of Git. The - `Git Book `_ has a - thorough explanation of them (as well as of many other aspects of Git) and - is a recommended resource if you run into any issues. Other DFHack developers - are also able to help with any submodule-related (or Git-related) issues - you may encounter. - - -Contributing to DFHack ----------------------- - -For details on contributing to DFHack, including pull requests, code -format, and more, please see `contributing-code`. - - -Build settings -============== - -This section describes build configuration options that apply to all platforms. -If you don't have a working build environment set up yet, follow the instructions -in the platform-specific sections below first, then come back here. - -Generator ---------- - -The ``Ninja`` CMake build generator is the preferred build method on Linux and -macOS, instead of ``Unix Makefiles``, which is the default. You can select Ninja -by passing ``-G Ninja`` to CMake. Incremental builds using Unix Makefiles can be -much slower than Ninja builds. Note that you will probably need to install -Ninja; see the platform-specific sections for details. - -:: - - cmake .. -G Ninja - -.. warning:: - - Most other CMake settings can be changed by running ``cmake`` again, but the - generator cannot be changed after ``cmake`` has been run without creating a - new build folder. Do not forget to specify this option. - - CMake versions 3.6 and older, and possibly as recent as 3.9, are known to - produce project files with dependency cycles that fail to build - (see :issue:`1369`). Obtaining a recent version of CMake is recommended, either from - `cmake.org `_ or through a package manager. See - the sections below for more platform-specific directions for installing CMake. - -Build type ----------- - -``cmake`` allows you to pick a build type by changing the ``CMAKE_BUILD_TYPE`` variable:: - - cmake .. -DCMAKE_BUILD_TYPE:string=BUILD_TYPE - -Valid and useful build types include 'Release' and 'RelWithDebInfo'. The default -build type is 'Release'. - -Target architecture (32-bit vs. 64-bit) ---------------------------------------- - -Set DFHACK_BUILD_ARCH to either ``32`` or ``64`` to build a 32-bit or 64-bit -version of DFHack (respectively). The default is currently ``64``, so you will -need to specify this explicitly for 32-bit builds. Specifying it is a good idea -in any case. - -:: - - cmake .. -DDFHACK_BUILD_ARCH=32 - -*or* -:: - - cmake .. -DDFHACK_BUILD_ARCH=64 - -Note that the scripts in the "build" folder on Windows will set the architecture -automatically. - -.. _compile-build-options: - -Other settings --------------- -There are a variety of other settings which you can find in CMakeCache.txt in -your build folder or by running ``ccmake`` (or another CMake GUI). Most -DFHack-specific settings begin with ``BUILD_`` and control which parts of DFHack -are built. - - -.. _compile-linux: - -Linux -===== -On Linux, DFHack acts as a library that shadows parts of the SDL API using LD_PRELOAD. - -Dependencies ------------- -DFHack is meant to be installed into an existing DF folder, so get one ready. - -We assume that any Linux platform will have ``git`` available (though it may -need to be installed with your package manager.) - -To build DFHack, you need GCC 4.8 or newer. GCC 4.8 has the benefit of avoiding -`libstdc++ compatibility issues `, but can be hard -to obtain on modern distributions, and working around these issues is done -automatically by the ``dfhack`` launcher script. As long as your system-provided -GCC is new enough, it should work. Note that extremely new GCC versions may not -have been used to build DFHack yet, so if you run into issues with these, please -let us know (e.g. by opening a GitHub issue). - -Before you can build anything, you'll also need ``cmake``. It is advisable to -also get ``ccmake`` on distributions that split the cmake package into multiple -parts. As mentioned above, ``ninja`` is recommended (many distributions call -this package ``ninja-build``). - -You will need pthread; most systems should have this already. Note that older -CMake versions may have trouble detecting pthread, so if you run into -pthread-related errors and pthread is installed, you may need to upgrade CMake, -either by downloading it from `cmake.org `_ or -through your package manager, if possible. - -You also need zlib, libsdl (1.2, not sdl2, like DF), perl, and the XML::LibXML -and XML::LibXSLT perl packages (for the code generation parts). You should be -able to find them in your distribution's repositories. - -To build `stonesense`, you'll also need OpenGL headers. - -Here are some package install commands for various distributions: - -* On Arch linux: - - * For the required Perl modules: ``perl-xml-libxml`` and ``perl-xml-libxslt`` (or through ``cpan``) - -* On Ubuntu:: - - apt-get install gcc cmake ninja-build git zlib1g-dev libsdl1.2-dev libxml-libxml-perl libxml-libxslt-perl - - * Other Debian-based distributions should have similar requirements. - -* On Fedora:: - - yum install gcc-c++ cmake ninja-build git zlib-devel SDL-devel perl-core perl-XML-LibXML perl-XML-LibXSLT ruby - - -Multilib dependencies ---------------------- -If you want to compile 32-bit DFHack on 64-bit distributions, you'll need the -multilib development tools and libraries: - -* ``gcc-multilib`` and ``g++-multilib`` -* If you have installed a non-default version of GCC - for example, GCC 4.8 on a - distribution that defaults to 5.x - you may need to add the version number to - the multilib packages. - - * For example, ``gcc-4.8-multilib`` and ``g++-4.8-multilib`` if installing for GCC 4.8 - on a system that uses a later GCC version. - * This is definitely required on Ubuntu/Debian, check if using a different distribution. - -* ``zlib1g-dev:i386`` (or a similar i386 zlib-dev package) - -Note that installing a 32-bit GCC on 64-bit systems (e.g. ``gcc:i386`` on -Debian) will typically *not* work, as it depends on several other 32-bit -libraries that conflict with system libraries. Alternatively, you might be able -to use ``lxc`` to -:forums:`create a virtual 32-bit environment <139553.msg5435310#msg5435310>`. - -Build ------ -Building is fairly straightforward. Enter the ``build`` folder (or create an -empty folder in the DFHack directory to use instead) and start the build like this:: - - cd build - cmake .. -G Ninja -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX= - ninja install # or ninja -jX install to specify the number of cores (X) to use - - should be a path to a copy of Dwarf Fortress, of the appropriate -version for the DFHack you are building. This will build the library along -with the normal set of plugins and install them into your DF folder. - -Alternatively, you can use ccmake instead of cmake:: - - cd build - ccmake .. -G Ninja - ninja install - -This will show a curses-based interface that lets you set all of the -extra options. You can also use a cmake-friendly IDE like KDevelop 4 -or the cmake-gui program. - -.. _linux-incompatible-libstdcxx: - -Incompatible libstdc++ -~~~~~~~~~~~~~~~~~~~~~~ -When compiling DFHack yourself, it builds against your system libstdc++. When -Dwarf Fortress runs, it uses a libstdc++ shipped in the ``libs`` folder, which -comes from GCC 4.8 and is incompatible with code compiled with newer GCC -versions. As of DFHack 0.42.05-alpha1, the ``dfhack`` launcher script attempts -to fix this by automatically removing the DF-provided libstdc++ on startup. -In rare cases, this may fail and cause errors such as: - -.. code-block:: text - - ./libs/Dwarf_Fortress: /pathToDF/libs/libstdc++.so.6: version - `GLIBCXX_3.4.18' not found (required by ./hack/libdfhack.so) - -The easiest way to fix this is generally removing the libstdc++ shipped with -DF, which causes DF to use your system libstdc++ instead:: - - cd /path/to/DF/ - rm libs/libstdc++.so.6 - -Note that distributing binaries compiled with newer GCC versions may result in -the opposite compatibily issue: users with *older* GCC versions may encounter -similar errors. This is why DFHack distributes both GCC 4.8 and GCC 7 builds. If -you are planning on distributing binaries to other users, we recommend using an -older GCC (but still at least 4.8) version if possible. - - -.. _compile-macos: - -macOS -===== -DFHack functions similarly on macOS and Linux, and the majority of the -information above regarding the build process (CMake and Ninja) applies here -as well. - -DFHack can officially be built on macOS only with GCC 4.8 or 7. Anything newer than 7 -will require you to perform extra steps to get DFHack to run (see `osx-new-gcc-notes`), -and your build will likely not be redistributable. - -.. _osx-new-gcc-notes: - -Notes for GCC 8+ or OS X 10.10+ users -------------------------------------- - -If none of these situations apply to you, skip to `osx-setup`. - -If you have issues building on OS X 10.10 (Yosemite) or above, try definining -the following environment variable:: - - export MACOSX_DEPLOYMENT_TARGET=10.9 - -If you build with a GCC version newer than 7, DFHack will probably crash -immediately on startup, or soon after. To fix this, you will need to replace -``hack/libstdc++.6.dylib`` with a symlink to the ``libstdc++.6.dylib`` included -in your version of GCC:: - - cd /hack && mv libstdc++.6.dylib libstdc++.6.dylib.orig && - ln -s [PATH_TO_LIBSTDC++] . - -For example, with GCC 6.3.0, ``PATH_TO_LIBSTDC++`` would be:: - - /usr/local/Cellar/gcc@6/6.3.0/lib/gcc/6/libstdc++.6.dylib # for 64-bit DFHack - /usr/local/Cellar/gcc@6/6.3.0/lib/gcc/6/i386/libstdc++.6.dylib # for 32-bit DFHack - -**Note:** If you build with a version of GCC that requires this, your DFHack -build will *not* be redistributable. (Even if you copy the ``libstdc++.6.dylib`` -from your GCC version and distribute that too, it will fail on older OS X -versions.) For this reason, if you plan on distributing DFHack, it is highly -recommended to use GCC 4.8 or 7. - -.. _osx-m1-notes: - -Notes for M1 users ------------------- - -Alongside the above, you will need to follow these additional steps to get it -running on Apple silicon. - -Install an x86 copy of ``homebrew`` alongside your existing one. `This -stackoverflow answer `__ describes the -process. - -Follow the normal macOS steps to install ``cmake`` and ``gcc`` via your x86 copy of -``homebrew``. Note that this will install a GCC version newer than 7, so see -`osx-new-gcc-notes`. - -In your terminal, ensure you have your path set to the correct homebrew in -addition to the normal ``CC`` and ``CXX`` flags above:: - - export PATH=/usr/local/bin:$PATH - -.. _osx-setup: - -Dependencies and system set-up ------------------------------- - -#. Download and unpack a copy of the latest DF -#. Install Xcode from the Mac App Store - -#. Install the XCode Command Line Tools by running the following command:: - - xcode-select --install - -#. Install dependencies - - It is recommended to use Homebrew instead of MacPorts, as it is generally - cleaner, quicker, and smarter. For example, installing MacPort's GCC will - install more than twice as many dependencies as Homebrew's will, and all in - both 32-bit and 64-bit variants. Homebrew also doesn't require constant use - of ``sudo``. - - Using `Homebrew `_ (recommended):: - - brew tap homebrew/versions - brew install git - brew install cmake - brew install ninja - brew install gcc@7 - - Using `MacPorts `_:: - - sudo port install gcc7 +universal cmake +universal git-core +universal ninja +universal - - Macports will take some time - maybe hours. At some point it may ask - you to install a Java environment; let it do so. - -#. Install Perl dependencies - - * Using system Perl - - * ``sudo cpan`` - - If this is the first time you've run cpan, you will need to go through the setup - process. Just stick with the defaults for everything and you'll be fine. - - If you are running OS X 10.6 (Snow Leopard) or earlier, good luck! - You'll need to open a separate Terminal window and run:: - - sudo ln -s /usr/include/libxml2/libxml /usr/include/libxml - - * ``install XML::LibXML`` - * ``install XML::LibXSLT`` - - * In a separate, local Perl install - - Rather than using system Perl, you might also want to consider - the Perl manager, `Perlbrew `_. - - This manages Perl 5 locally under ``~/perl5/``, providing an easy - way to install Perl and run CPAN against it without ``sudo``. - It can maintain multiple Perl installs and being local has the - benefit of easy migration and insulation from OS issues and upgrades. - - See https://perlbrew.pl/ for more details. - -Building --------- - -* Get the DFHack source as per section `compile-how-to-get-the-code`, above. -* Set environment variables - - Homebrew (if installed elsewhere, replace /usr/local with ``$(brew --prefix)``):: - - export CC=/usr/local/bin/gcc-7 - export CXX=/usr/local/bin/g++-7 - - Macports:: - - export CC=/opt/local/bin/gcc-mp-7 - export CXX=/opt/local/bin/g++-mp-7 - - Change the version numbers appropriately if you installed a different version of GCC. - - If you are confident that you have GCC in your path, you can omit the absolute paths:: - - export CC=gcc-7 - export CXX=g++-7 - - (adjust as needed for different GCC installations) - -* Build DFHack:: - - mkdir build-osx - cd build-osx - cmake .. -G Ninja -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX= - ninja install # or ninja -jX install to specify the number of cores (X) to use - - should be a path to a copy of Dwarf Fortress, of the appropriate - version for the DFHack you are building. - - -.. _compile-windows: - -Windows -======= -On Windows, DFHack replaces the SDL library distributed with DF. - -Dependencies ------------- -You will need the following: - -* Microsoft Visual C++ 2015 or 2017 -* Git -* CMake -* Perl with XML::LibXML and XML::LibXSLT - - * It is recommended to install StrawberryPerl, which includes both. - -* Python (for documentation; optional, except for release builds) - -Microsoft Visual Studio 2015 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -DFHack has to be compiled with the Microsoft Visual C++ 2015 or 2017 toolchain on Windows; -other versions won't work against Dwarf Fortress due to ABI and STL incompatibilities. - -You can install Visual Studio 2015_ or 2017_ Community edition for free, which -include all the features needed by DFHack. You can also download just the -`build tools`_ if you aren't going to use Visual Studio to edit code. - -.. _2015: https://visualstudio.microsoft.com/vs/older-downloads/#visual-studio-2015-and-other-products -.. _2017: https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&rel=15 -.. _build tools: https://visualstudio.microsoft.com/vs/older-downloads/#microsoft-build-tools-2015-update-3 - -Additional dependencies: installing with the Chocolatey Package Manager -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The remainder of dependencies - Git, CMake, StrawberryPerl, and Python - can be -most easily installed using the Chocolatey Package Manger. Chocolatey is a -\*nix-style package manager for Windows. It's fast, small (8-20MB on disk) -and very capable. Think "``apt-get`` for Windows." - -Chocolatey is a recommended way of installing the required dependencies -as it's quicker, requires less effort, and will install known-good utilities -guaranteed to have the correct setup (especially PATH). - -To install Chocolatey and the required dependencies: - -* Go to https://chocolatey.org in a web browser -* At the top of the page it will give you the install command to copy - - * Copy the first one, which starts ``@powershell ...`` - * It won't be repeated here in case it changes in future Chocolatey releases. - -* Open an elevated (Admin) ``cmd.exe`` window - - * On Windows 8 and later this can be easily achieved by: - - * right-clicking on the Start Menu, or pressing Win+X. - * choosing "Command Prompt (Admin)" - - * On earlier Windows: find ``cmd.exe`` in Start Menu, right click - and choose Open As Administrator. - -* Paste in the Chocolatey install command and hit enter -* Close this ``cmd.exe`` window and open another Admin ``cmd.exe`` in the same way -* Run the following command:: - - choco install git cmake.portable strawberryperl -y - -* Close the Admin ``cmd.exe`` window; you're done! - -You can now use all of these utilities from any normal ``cmd.exe`` window. -You only need Admin/elevated ``cmd.exe`` for running ``choco install`` commands; -for all other purposes, including compiling DFHack, you should use -a normal ``cmd.exe`` (or, better, an improved terminal like `Cmder `_; -details below, under Build.) - -**NOTE**: you can run the above ``choco install`` command even if you already have -Git, CMake or StrawberryPerl installed. Chocolatey will inform you if any software -is already installed and won't re-install it. In that case, please check the PATHs -are correct for that utility as listed in the manual instructions below. Or, better, -manually uninstall the version you have already and re-install via Chocolatey, -which will ensure the PATH are set up right and will allow Chocolatey to manage -that program for you in future. - -Additional dependencies: installing manually -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you prefer to install manually rather than using Chocolatey, details and -requirements are as below. If you do install manually, please ensure you -have all PATHs set up correctly. - -Git -^^^ -Some examples: - -* `Git for Windows `_ (command-line and GUI) -* `tortoisegit `_ (GUI and File Explorer integration) - -CMake -^^^^^ -You can get the win32 installer version from -`the official site `_. -It has the usual installer wizard. Make sure you let it add its binary folder -to your binary search PATH so the tool can be later run from anywhere. - -Perl / Strawberry Perl -^^^^^^^^^^^^^^^^^^^^^^ -For the code generation stage of the build process, you'll need Perl 5 with -XML::LibXML and XML::LibXSLT. `Strawberry Perl `_ is -recommended as it includes all of the required packages in a single, easy -install. - -After install, ensure Perl is in your user's PATH. This can be edited from -``Control Panel -> System -> Advanced System Settings -> Environment Variables``. - -The following directories must be in your PATH, in this order: - -* ``\c\bin`` -* ``\perl\site\bin`` -* ``\perl\bin`` -* ``\perl\vendor\lib\auto\XML\LibXML`` (may only be required on some systems) - -Be sure to close and re-open any existing ``cmd.exe`` windows after updating -your PATH. - -If you already have a different version of Perl installed (for example, from Cygwin), -you can run into some trouble. Either remove the other Perl install from PATH, or -install XML::LibXML and XML::LibXSLT for it using CPAN. - -Build ------ -There are several different batch files in the ``win32`` and ``win64`` -subfolders in the ``build`` folder, along with a script that's used for picking -the DF path. Use the subfolder corresponding to the architecture that you want -to build for. - -First, run ``set_df_path.vbs`` and point the dialog that pops up at -a suitable DF installation which is of the appropriate version for the DFHack -you are compiling. The result is the creation of the file ``DF_PATH.txt`` in -the build directory. It contains the full path to the destination directory. -You could therefore also create this file manually - or copy in a pre-prepared -version - if you prefer. - -Next, run one of the scripts with ``generate`` prefix. These create the MSVC -solution file(s): - -* ``all`` will create a solution with everything enabled (and the kitchen sink). -* ``gui`` will pop up the CMake GUI and let you choose what to build. - This is probably what you want most of the time. Set the options you are interested - in, then hit configure, then generate. More options can appear after the configure step. -* ``minimal`` will create a minimal solution with just the bare necessities - - the main library and standard plugins. -* ``release`` will create a solution with everything that should be included in - release builds of DFHack. Note that this includes documentation, which requires - Python. - -Then you can either open the solution with MSVC or use one of the msbuild scripts: - -Building/installing from the command line: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In the build directory you will find several ``.bat`` files: - -* Scripts with ``build`` prefix will only build DFHack. -* Scripts with ``install`` prefix will build DFHack and install it to the previously selected DF path. -* Scripts with ``package`` prefix will build and create a .zip package of DFHack. - -Compiling from the command line is generally the quickest and easiest option. -However be aware that due to the limitations of ``cmd.exe`` - especially in -versions of Windows prior to Windows 10 - it can be very hard to see what happens -during a build. If you get a failure, you may miss important errors or warnings -due to the tiny window size and extremely limited scrollback. For that reason you -may prefer to compile in the IDE which will always show all build output. - -Alternatively (or additionally), consider installing an improved Windows terminal -such as `Cmder `_. Easily installed through Chocolatey with: -``choco install cmder -y``. - -**Note for Cygwin/msysgit users**: It is also possible to compile DFHack from a -Bash command line. This has three potential benefits: - -* When you've installed Git and are using its Bash, but haven't added Git to your path: - - * You can load Git's Bash and as long as it can access Perl and CMake, you can - use it for compile without adding Git to your system path. - -* When you've installed Cygwin and its SSH server: - - * You can now SSH in to your Windows install and compile from a remote terminal; - very useful if your Windows installation is a local VM on a \*nix host OS. - -* In general: you can use Bash as your compilation terminal, meaning you have a decent - sized window, scrollback, etc. - - * Whether you're accessing it locally as with Git's Bash, or remotely through - Cygwin's SSH server, this is far superior to using ``cmd.exe``. - -You don't need to do anything special to compile from Bash. As long as your PATHs -are set up correctly, you can run the same generate- and build/install/package- bat -files as detailed above. - -Building/installing from the Visual Studio IDE: -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -After running the CMake generate script you will have a new folder called VC2015 -or VC2015_32, depending on the architecture you specified. Open the file -``dfhack.sln`` inside that folder. If you have multiple versions of Visual -Studio installed, make sure you open with Visual Studio 2015. - -The first thing you must then do is change the build type. It defaults to Debug, -but this cannot be used on Windows. Debug is not binary-compatible with DF. -If you try to use a debug build with DF, you'll only get crashes and for this -reason the Windows "debug" scripts actually do RelWithDebInfo builds. -After loading the Solution, change the Build Type to either ``Release`` -or ``RelWithDebInfo``. - -Then build the ``INSTALL`` target listed under ``CMakePredefinedTargets``. - - -Building the documentation -========================== - -The steps above will not build DFHack's documentation by default. If you are -editing documentation, see `documentation` for details on how to build it. - -Misc. Notes -=========== - -.. _note-offline-builds: - -Note on building DFHack offline -------------------------------- - -As of 0.43.05, DFHack downloads several files during the build process, depending -on your target OS and architecture. If your build machine's internet connection -is unreliable, or nonexistent, you can download these files in advance. - -First, you must locate the files you will need. These can be found in the -`dfhack-bin repo `_. Look for the -most recent version number *before or equal to* the DF version which you are -building for. For example, suppose "0.43.05" and "0.43.07" are listed. You should -choose "0.43.05" if you are building for 0.43.05 or 0.43.06, and "0.43.07" if -you are building for 0.43.07 or 0.43.08. - -Then, download all of the files you need, and save them to ``/CMake/downloads/``. The destination filename you choose -does not matter, as long as the files end up in the ``CMake/downloads`` folder. -You need to download all of the files for the architecture(s) you are building -for. For example, if you are building for 32-bit Linux and 64-bit Windows, -download all files starting with ``linux32`` and ``win64``. GitHub should sort -files alphabetically, so all the files you need should be next to each other. - -.. note:: - - * Any files containing "allegro" in their filename are only necessary for - building `stonesense`. If you are not building Stonesense, you don't have to - download these, as they are larger than any other listed files. - -It is recommended that you create a build folder and run CMake to verify that -you have downloaded everything at this point, assuming your download machine has -CMake installed. This involves running a "generate" batch script on Windows, or -a command starting with ``cmake .. -G Ninja`` on Linux and macOS, following the -instructions in the sections above. CMake should automatically locate files that -you placed in ``CMake/downloads``, and use them instead of attempting to -download them. diff --git a/docs/Core.rst b/docs/Core.rst index 1c0db77246..b386e5ea04 100644 --- a/docs/Core.rst +++ b/docs/Core.rst @@ -9,10 +9,9 @@ DFHack Core :depth: 2 -Command Implementation +Command implementation ====================== -DFHack commands can be implemented in three ways, all of which -are used in the same way: +DFHack commands can be implemented in any of three ways: :builtin: commands are implemented by the core of DFHack. They manage other DFHack tools, interpret commands, and control basic @@ -22,13 +21,15 @@ are used in the same way: same version of DFHack. They are less flexible than scripts, but used for complex or ongoing tasks because they run faster. -:scripts: are Ruby or Lua scripts stored in ``hack/scripts/``. - Because they don't need to be compiled, scripts are - more flexible about versions, and easier to distribute. - Most third-party DFHack addons are scripts. +:scripts: are Lua scripts stored in ``hack/scripts/`` or other + directories in the `script-paths`. Because they don't need to + be compiled, scripts are more flexible about versions, and + they are easier to distribute. Most third-party DFHack addons + are scripts. +All tools distributed with DFHack are documented `here `. -Using DFHack Commands +Using DFHack commands ===================== DFHack commands can be executed in a number of ways: @@ -37,8 +38,10 @@ DFHack commands can be executed in a number of ways: #. Pressing a key combination set up with `keybinding` #. From one of several `init-files`, automatically #. Using `script` to run a batch of commands from a file +#. From an in-game command launcher interface like `gui/launcher`, the + `hotkeys` overlay widget, or `gui/quickcmd`. -The DFHack Console +The DFHack console ------------------ The command line has some nice line editing capabilities, including history that's preserved between different runs of DF - use :kbd:`↑` and :kbd:`↓` @@ -50,7 +53,7 @@ double quotes. To include a double quote character, use ``\"``. If the first non-whitespace character is ``:``, the command is parsed in an alternative mode. The non-whitespace characters following the ``:`` are the command name, and the remaining part of the line is used verbatim as -the first argument. This is very useful for the `lua` and `rb` commands. +the first argument. This is very useful for the `lua` command. As an example, the following two command lines are exactly equivalent:: :foo a b "c d" e f @@ -113,269 +116,27 @@ second (Windows) example uses `kill-lua` to stop a Lua script. you have multiple copies of DF running simultaneously. To assign a different port, see `remote-server-config`. +.. _dfhack-config: -Built-in Commands -================= -The following commands are provided by the 'core' components -of DFHack, rather than plugins or scripts. - -.. contents:: - :local: - - -.. _alias: - -alias ------ -The ``alias`` command allows configuring aliases to other DFHack commands. -Aliases are resolved immediately after built-in commands, which means that an -alias cannot override a built-in command, but can override a command implemented -by a plugin or script. - -Usage: - -:``alias list``: lists all configured aliases -:``alias add [arguments...]``: adds an alias -:``alias replace [arguments...]``: replaces an existing - alias with a new command, or adds the alias if it does not already exist -:``alias delete ``: removes the specified alias - -Aliases can be given additional arguments when created and invoked, which will -be passed to the underlying command in order. An example with `devel/print-args`:: - - [DFHack]# alias add pargs devel/print-args example - [DFHack]# pargs text - example - text - - -.. _cls: - -cls ---- -Clear the terminal. Does not delete command history. - - -.. _die: - -die ---- -Instantly kills DF without saving. - - -.. _disable: - -.. _enable: - -enable ------- -Many plugins can be in a distinct enabled or disabled state. Some of -them activate and deactivate automatically depending on the contents -of the world raws. Others store their state in world data. However a -number of them have to be enabled globally, and the init file is the -right place to do it. - -Most such plugins or scripts support the built-in ``enable`` and ``disable`` -commands. Calling them at any time without arguments prints a list -of enabled and disabled plugins, and shows whether that can be changed -through the same commands. Passing plugin names to these commands will enable -or disable the specified plugins. For example, to enable the `manipulator` -plugin:: - - enable manipulator - -It is also possible to enable or disable multiple plugins at once:: - - enable manipulator search - - -.. _fpause: - -fpause ------- -Forces DF to pause. This is useful when your FPS drops below 1 and you lose -control of the game. - - -.. _help: - -help ----- -Most commands support using the ``help `` built-in command -to retrieve further help without having to look at this document. -``? `` and ``man `` are aliases. - -Some commands (including many scripts) instead take ``help`` or ``?`` -as an option on their command line - ie `` help``. - - -.. _hide: - -hide ----- -Hides the DFHack terminal window. Only available on Windows. - - -.. _keybinding: - -keybinding ----------- -To set keybindings, use the built-in ``keybinding`` command. Like any other -command it can be used at any time from the console, but bindings are not -remembered between runs of the game unless re-created in `dfhack.init`. - -Currently, any combinations of Ctrl/Alt/Shift with A-Z, 0-9, or F1-F12 are supported. - -Possible ways to call the command: - -``keybinding list `` - List bindings active for the key combination. -``keybinding clear ...`` - Remove bindings for the specified keys. -``keybinding add "cmdline" "cmdline"...`` - Add bindings for the specified key. -``keybinding set "cmdline" "cmdline"...`` - Clear, and then add bindings for the specified key. - -The ```` parameter above has the following *case-sensitive* syntax:: - - [Ctrl-][Alt-][Shift-]KEY[@context[|context...]] - -where the *KEY* part can be any recognized key and [] denote optional parts. - -When multiple commands are bound to the same key combination, DFHack selects -the first applicable one. Later ``add`` commands, and earlier entries within one -``add`` command have priority. Commands that are not specifically intended for use -as a hotkey are always considered applicable. - -The ``context`` part in the key specifier above can be used to explicitly restrict -the UI state where the binding would be applicable. If called without parameters, -the ``keybinding`` command among other things prints the current context string. - -Only bindings with a ``context`` tag that either matches the current context fully, -or is a prefix ending at a ``/`` boundary would be considered for execution, i.e. -when in context ``foo/bar/baz``, keybindings restricted to any of ``@foo/bar/baz``, -``@foo/bar``, ``@foo`` or none will be active. - -Multiple contexts can be specified by separating them with a -pipe (``|``) - for example, ``@foo|bar|baz/foo`` would match -anything under ``@foo``, ``@bar``, or ``@baz/foo``. - -Interactive commands like `liquids` cannot be used as hotkeys. - - -.. _kill-lua: - -kill-lua --------- -Stops any currently-running Lua scripts. By default, scripts can -only be interrupted every 256 instructions. Use ``kill-lua force`` -to interrupt the next instruction. - - -.. _load: -.. _unload: -.. _reload: - -load ----- -``load``, ``unload``, and ``reload`` control whether a plugin is loaded -into memory - note that plugins are loaded but disabled unless you do -something. Usage:: - - load|unload|reload PLUGIN|(-a|--all) - -Allows dealing with plugins individually by name, or all at once. - -Note that plugins do not maintain their enabled state if they are reloaded, so -you may need to use `enable` to re-enable a plugin after reloading it. - - -.. _ls: - -ls --- -``ls`` does not list files like the Unix command, but rather -available commands - first built in commands, then plugins, -and scripts at the end. Usage: - -:ls -a: Also list scripts in subdirectories of ``hack/scripts/``, - which are generally not intended for direct use. -:ls : List subcommands for the given plugin. - - -.. _plug: - -plug ----- -Lists available plugins, including their state and detailed description. - -``plug`` - Lists available plugins (*not* commands implemented by plugins) -``plug [PLUGIN] [PLUGIN] ...`` - List state and detailed description of the given plugins, - including commands implemented by the plugin. - - -.. _sc-script: - -sc-script ---------- -Allows additional scripts to be run when certain events occur -(similar to onLoad*.init scripts) - - -.. _script: - -script ------- -Reads a text file, and runs each line as a DFHack command -as if it had been typed in by the user - treating the -input like `an init file `. - -Some other tools, such as `autobutcher` and `workflow`, export -their settings as the commands to create them - which are later -loaded with ``script`` - - -.. _show: - -show ----- -Shows the terminal window after it has been `hidden `. -Only available on Windows. You'll need to use it from a -`keybinding` set beforehand, or the in-game `command-prompt`. - -.. _type: - -type ----- -``type command`` shows where ``command`` is implemented. - -Other Commands --------------- -The following commands are *not* built-in, but offer similarly useful functions. - -* `command-prompt` -* `hotkeys` -* `lua` -* `multicmd` -* `nopause` -* `quicksave` -* `rb` -* `repeat` +Configuration files +=================== +Most DFHack settings can be changed by modifying files in the ``dfhack-config`` +folder (which is in the DF folder). The default versions of these files, if they +exist, are in ``dfhack-config/default`` and are installed when DFHack starts if +necessary. .. _init-files: -Init Files -========== +Init files +---------- .. contents:: :local: DFHack allows users to automatically run commonly-used DFHack commands -when DF is first loaded, when a game is loaded, and when a game is unloaded. +when DF is first loaded, when a world is loaded, when a map is loaded, when a +map is unloaded, and when a world is unloaded. Init scripts function the same way they would if the user manually typed in their contents, but are much more convenient. In order to facilitate @@ -383,86 +144,84 @@ savegave portability, mod merging, and general organization of init files, DFHack supports multiple init files both in the main DF directory and save-specific init files in the save folders. -DFHack looks for init files in three places each time they could be run: +DFHack looks for init files in two places each time they could be run: -#. The main DF directory -#. :file:`data/save/{world}/raw`, where ``world`` is the current save, and -#. :file:`data/save/{world}/raw/objects` +#. The :file:`dfhack-config/init` subdirectory in the main DF directory and +#. :file:`save/{world}/init`, where ``{world}`` is the current save -When reading commands from dfhack.init or with the `script` command, if the final -character on a line is a backslash then the next uncommented line is considered a -continuation of that line, with the backslash deleted. Commented lines are skipped, -so it is possible to comment out parts of a command with the ``#`` character. +For each of those directories, all matching init files will be executed in +alphabetical order. +Before running matched init scripts in any of those locations, the +:file:`dfhack-config/init/default.*` file that matches the event will be run to +load DFHack defaults. Only the :file:`dfhack-config/init` directory is checked +for this file, not any :file:`save` directories. If you want DFHack to load +without running any of its default configuration commands, edit the +:file:`dfhack-config/init/default.*` files and comment out the commands you see +there. -.. _dfhack.init: - -dfhack*.init ------------- -If your DF folder contains at least one file named ``dfhack*.init`` -(where ``*`` is a placeholder for any string), then all such files -are executed in alphabetical order when DF is first started. +When reading commands from the init files or with the `script` command, if the +final character on a line is a backslash then the next uncommented line is +considered a continuation of that line, with the backslash deleted. Commented +lines are skipped, so it is possible to comment out parts of a command with the +``#`` character. -DFHack is distributed with :download:`/dfhack.init-example` as an example -with an up-to-date collection of basic commands; mostly setting standard -keybindings and `enabling ` plugins. You are encouraged to look -through this file to learn which features it makes available under which -key combinations. You may also customise it and rename it to ``dfhack.init``. +.. _dfhack.init: -If your DF folder does not contain any ``dfhack*.init`` files, the example -will be run as a fallback. +dfhack\*.init +............. +On startup, DFHack looks for files of the form ``dfhack*.init`` (where ``*`` is +a placeholder for any string, including the empty string). -These files are best used for keybindings and enabling persistent plugins +These files are best used for keybindings and enabling persistent tools which do not require a world to be loaded. .. _onLoad.init: -onLoad*.init ------------- +onLoad\*.init +............. When a world is loaded, DFHack looks for files of the form ``onLoad*.init``, where ``*`` can be any string, including the empty string. -All matching init files will be executed in alphabetical order. A world being loaded can mean a fortress, an adventurer, or legends mode. These files are best used for non-persistent commands, such as setting -a `fix ` script to run on `repeat`. +a `bugfix-tag-index` script to run on `repeat`. -.. _onUnload.init: +.. _onMapLoad.init: -onUnload*.init --------------- -When a world is unloaded, DFHack looks for files of the form ``onUnload*.init``. -Again, these files may be in any of the above three places. -All matching init files will be executed in alphebetical order. +onMapLoad\*.init +................ +When a map is loaded, either in adventure or fort mode, DFHack looks for files +of the form ``onMapLoad*.init``, where ``*`` can be any string, including the +empty string. -Modders often use such scripts to disable tools which should not affect -an unmodded save. +These files are best used for commands that are only relevant once there is a +game map loaded. -.. _other_init_files: -Other init files ----------------- +.. _onMapUnload.init: +.. _onUnload.init: -* ``onMapLoad*.init`` and ``onMapUnload*.init`` are run when a map, - distinct from a world, is loaded. This is good for map-affecting - commands (e.g. `clean`), or avoiding issues in Legends mode. +onMapUnload\*.init and onUnload\*.init +...................................... +When a map or world is unloaded, DFHack looks for files of the form +``onMapUnload*.init`` or ``onUnload*.init``, respectively. -* Any lua script named ``raw/init.d/*.lua``, in the save or main DF - directory, will be run when any world or that save is loaded. +Modders often use unload init scripts to disable tools which should not run +after a modded save is unloaded. -.. _dfhack-config: +.. _other_init_files: -Configuration Files -=================== +init.d/\*.lua +............. + +Any lua script named ``init.d/*.lua``, in the save or main DF directory, +will be run when any world or that save is loaded. -Some DFHack settings can be changed by modifying files in the ``dfhack-config`` -folder (which is in the DF folder). The default versions of these files, if they -exist, are in ``dfhack-config/default`` and are installed when DFHack starts if -necessary. .. _script-paths: @@ -473,12 +232,59 @@ Script paths are folders that DFHack searches to find a script when a command is run. By default, the following folders are searched, in order (relative to the root DF folder): -1. :file:`data/save/{}/raw/scripts` (only if a save is loaded) -2. :file:`raw/scripts` -3. :file:`hack/scripts` +#. :file:`dfhack-config/scripts` +#. :file:`save/{world}/scripts` (only if a save is loaded) +#. :file:`hack/scripts` +#. :file:`data/installed_mods/...` (see below) For example, if ``teleport`` is run, these folders are searched in order for -``teleport.lua`` or ``teleport.rb``, and the first matching file is run. +``teleport.lua``, and the first matching file is run. + +Scripts in installed mods +......................... + +Scripts in mods are automatically added to the script path. The following +directories are searched for mods:: + + ../../workshop/content/975370/ (the DF Steam workshop directory) + mods/ + data/installed_mods/ + +Each mod can have two directories that contain scripts: + +- ``scripts_modactive/`` is added to the script path if and only if the mod is + active in the loaded world. +- ``scripts_modinstalled/`` is added to the script path as long as the mod is + installed in one of the searched mod directories. + +Multiple versions of a mod may be installed at the same time. If a mod is +active in a loaded world, then the scripts for the version of the mod that is +active will be added to the script path. Otherwise, the latest version of each +mod is added to the script path. + +Scripts for active mods take precedence according to their load order when you +generated the current world. + +Scripts for non-active mods are ordered by their containing mod's ID. + +For example, the search paths for mods might look like this:: + + activemod_last_in_load_order/scripts_modactive + activemod_last_in_load_order/scripts_modinstalled + activemod_second_to_last_in_load_order/scripts_modactive + activemod_second_to_last_in_load_order/scripts_modinstalled + ... + inactivemod1/scripts_modinstalled + inactivemod2/scripts_modinstalled + ... + +Not all mods will have script directories, of course, and those mods will not be +added to the script search path. Mods are re-scanned whenever a world is loaded +or unloaded. For more information on scripts and mods, check out the +`modding-guide`. + +Custom script paths +................... Script paths can be added by modifying :file:`dfhack-config/script-paths.txt`. Each line should start with one of these characters: @@ -497,12 +303,67 @@ the root DF folder. This will allow you to make changes in the repo and have them take effect immediately, without needing to re-install or copy scripts over manually. +Note that ``script-paths.txt`` is only read at startup, but the paths can also be +modified programmatically at any time through the `Lua API `. + +Commandline options +=================== -Script paths can also be modified programmatically through the `Lua API `. +In addition to `Using an OS terminal`_ to execute commands on startup, DFHack +also recognizes a few commandline options. + +Options passed to Dwarf Fortress +-------------------------------- + +These options can be passed to Dwarf Fortress and will be intercepted by +DFHack. If you are launching Dwarf Fortress from Steam, you can set your +options in the "Launch Options" text box in the properties for the Dwarf +Fortress app (**NOT the DFHack app**). Note that these launch options will be +used regardless of whether you run Dwarf Fortress from its own app or DFHack's. + +- ``--disable-dfhack``: If set, then DFHack will be disabled for the session. + You will have to restart Dwarf Fortress without specifying this option in + order to use DFHack. Note that even if DFHack is disabled, :file:`stdout.txt` + and :file:`stderr.txt` will still be redirected to :file:`stdout.log` and + :file:`stderr.log`, respectively. + +- ``--nosteam-dfhack``: If set, then the DFHack stub launcher will not execute + when you launch DF from its own app in the Steam client. This will prevent + your settings from being restored or backed up with Steam Cloud Save. This is + probably not what you want. If you want to just not have the DFHack playtime + counted towards your hours, see the DFHack stub launcher ``--nowait`` option + below. + +- ``--skip-size-check``: DFHack normally verifies the sizes of important game + on startup and shuts down if a discrepancy is detected. This is intended to + reduce the risk of misalignments in these structures leading to crashes or + other misbehavior. This option bypasses the check. This option should + normally only be used to facilitate DFHack development. This option will + **not** enable DFHack to be used usefully with a version of DF with which + DFHack has not been aligned. + +Options passed to the DFHack Steam stub launcher +------------------------------------------------ + +These options can be passed to the DFHack stub launcher that executes when you +run the DFHack app from the Steam client. You can set your options in the +"Launch Options" text box in the properties for the DFHack app (**NOT the Dwarf +Fortress app**). Note that these launch options will be used regardless of +whether you run Dwarf Fortress from its own app or DFHack's. + +- ``--nowait``: If set, the DFHack stub launcher will not wait for DF to exit + before exiting itself. This may be desired by players who do not want their + playtime "double counted". However, using this option means that your DFHack + settings that get backed up to the cloud will always be out of sync. The stub + launcher normally downloads updated settings from Steam Cloud Save when DF + launches, and then backs up changed settings when DF exits. If this option is + used, then your settings will still be reconciled when DF launches, but + changes made during your play session will not be saved when DF exits. Please + use with caution -- you may lose data. .. _env-vars: -Environment Variables +Environment variables ===================== DFHack's behavior can be adjusted with some environment variables. For example, @@ -512,14 +373,20 @@ on UNIX-like systems: DFHACK_SOME_VAR=1 ./dfhack +- ``DFHACK_DISABLE``: if set, DFHack will not initialize, not even to redirect + standard output or standard error. This is provided as an alternative + to the ``--disable-dfhack`` commandline parameter above for when environment + variables are more convenient. + - ``DFHACK_PORT``: the port to use for the RPC server (used by ``dfhack-run`` and `remotefortressreader` among others) instead of the default ``5000``. As with the default, if this port cannot be used, the server is not started. See `remote` for more details. -- ``DFHACK_DISABLE_CONSOLE``: if set, the DFHack console is not set up. This is - the default behavior if ``PRINT_MODE:TEXT`` is set in ``data/init/init.txt``. - Intended for situations where DFHack cannot run in a terminal window. +- ``DFHACK_DISABLE_CONSOLE``: if set, DFHack's external console is not set up. + This is the default behavior if ``PRINT_MODE:TEXT`` is set in + ``data/init/init.txt``. Intended for situations where DFHack cannot run in a + terminal window. - ``DFHACK_HEADLESS``: if set, and ``PRINT_MODE:TEXT`` is set, DF's display will be hidden, and the console will be started unless ``DFHACK_DISABLE_CONSOLE`` @@ -548,18 +415,57 @@ Other (non-DFHack-specific) variables that affect DFHack: sensitive), ``DF2CONSOLE()`` will produce UTF-8-encoded text. Note that this should be the case in most UTF-8-capable \*nix terminal emulators already. -Miscellaneous Notes -=================== -This section is for odd but important notes that don't fit anywhere else. +Core preferences +================ + +Settings that control DFHack's runtime behavior can be changed dynamically via +the "Preferences" tab in `gui/control-panel` or on the commandline with +`control-panel`. The two most important settings for the core are: + +- ``HIDE_CONSOLE_ON_STARTUP``: On Windows, this controls whether to hide the + external DFHack terminal window on startup. The console is hidden by default + so it does not get in the way of gameplay, but it can be useful to enable for + debugging purposes or if you just prefer to use the external console instead + of the in-game `gui/launcher`. When you change this setting, the new behavior + will take effect the next time you start the game. If you are running the + native Linux version of DF (and DFHack), the terminal that you run the game + from becomes the DFHack console and this setting has no effect. + +- ``HIDE_ARMOK_TOOLS``: Whether to hide "armok" tools in command lists. Also + known as "Mortal mode", this setting keeps god-mode tools out of sight and + out of mind. Highly recommended for players who would prefer if the god-mode + tools were not quite as obvious and accessible. + +.. _performance-monitoring: + +Performance monitoring +====================== + +Though DFHack tools are generally performant, they do take some amount of time +to run. DFHack tracks its impact on DF game speed so the DFHack team can be +aware of (and fix) tools that are taking more than their fair share of +processing time. + +The target threshold for DFHack CPU utilization during unpaused gameplay with +all overlays and automation tools enabled is 10%. This is about the level where +players would notice the impact. In general, DFHack will have even less impact +for most players, since it is not common for every single DFHack tool to be +enabled at once. + +DFHack will record a performance report with the savegame files named +``dfhack-perf-counters.dat``. The report contains measurements from when the +game was loaded to the time when it was saved. By default, only unpaused time is +measured (since processing done while the game is paused doesn't slow anything +down from the player's perspective). You can display a live report at any time +by running:: + + :lua require('script-manager').print_timers() + +You can reset the timers to start a new measurement session by running:: -* If a DF :kbd:`H` hotkey is named with a DFHack command, pressing - the corresponding :kbd:`Fx` button will run that command, instead of - zooming to the set location. - *This feature will be removed in a future version.* (see :issue:`731`) + :lua dfhack.internal.resetPerfCounters() -* The binaries for 0.40.15-r1 to 0.34.11-r4 are on DFFD_. - Older versions are available here_. - *These files will eventually be migrated to GitHub.* (see :issue:`473`) +If you want to record performance over all elapsed time, not just unpaused +time, then instead run:: - .. _DFFD: https://dffd.bay12games.com/search.php?string=DFHack&id=15&limit=1000 - .. _here: https://dethware.org/dfhack/download + :lua dfhack.internal.resetPerfCounters(true) diff --git a/docs/Dev-intro.rst b/docs/Dev-intro.rst deleted file mode 100644 index 758bf225f6..0000000000 --- a/docs/Dev-intro.rst +++ /dev/null @@ -1,82 +0,0 @@ -=========================== -DFHack development overview -=========================== - -DFHack has various components; this page provides an overview of some. If you -are looking to develop a tool for DFHack, developing a script or plugin is -likely the most straightforward choice. - -Other pages that may be relevant include: - -- `contributing` -- `documentation` -- `license` - - -.. contents:: Contents - :local: - - -Plugins -------- - -DFHack plugins are written in C++ and located in the ``plugins`` folder. -Currently, documentation on how to write plugins is somewhat sparse. There are -templates that you can use to get started in the ``plugins/skeleton`` -folder, and the source code of existing plugins can also be helpful. - -If you want to compile a plugin that you have just added, you will need to add a -call to ``DFHACK_PLUGIN`` in ``plugins/CMakeLists.txt``. - -Plugins have the ability to make one or more commands available to users of the -DFHack console. Examples include `3dveins` (which implements the ``3dveins`` -command) and `reveal` (which implements ``reveal``, ``unreveal``, and several -other commands). - -Plugins can also register handlers to run on every tick, and can interface with -the built-in `enable` and `disable` commands. For the full plugin API, see the -skeleton plugins or ``PluginManager.cpp``. - -Installed plugins live in the ``hack/plugins`` folder of a DFHack installation, -and the `load` family of commands can be used to load a recompiled plugin -without restarting DF. - -See `plugins-index` for a list of all plugins included in DFHack. - -Scripts -------- - -DFHack scripts can currently be written in Lua or Ruby. The `Lua API ` -is more complete and currently better-documented, however. Referring to existing -scripts as well as the API documentation can be helpful when developing new -scripts. - -`Scripts included in DFHack ` live in a separate `scripts repository `_. -This can be found in the ``scripts`` submodule if you have -`cloned DFHack `, or the ``hack/scripts`` folder -of an installed copy of DFHack. - -Core ----- - -The `DFHack core ` has a variety of low-level functions. It is -responsible for hooking into DF (via SDL), providing a console, and providing an -interface for plugins and scripts to interact with DF. - -Modules -------- - -A lot of shared code to interact with DF in more complicated ways is contained -in **modules**. For example, the Units module contains functions for checking -various traits of units, changing nicknames properly, and more. Generally, code -that is useful to multiple plugins and scripts should go in the appropriate -module, if there is one. - -Several modules are also `exposed to Lua `, although -some functions (and some entire modules) are currently only available in C++. - -Remote access interface ------------------------ - -DFHack provides a remote access interface that external tools can connect to and -use to interact with DF. See `remote` for more information. diff --git a/docs/Documentation.rst b/docs/Documentation.rst deleted file mode 100644 index be4511ba83..0000000000 --- a/docs/Documentation.rst +++ /dev/null @@ -1,364 +0,0 @@ -.. _documentation: - -########################### -DFHack Documentation System -########################### - - -DFHack documentation, like the file you are reading now, is created as ``.rst`` files, -which are in `reStructuredText (reST) `_ format. -This is a documentation format common in the Python community. It is very -similar in concept - and in syntax - to Markdown, as found on GitHub and many other -places. However it is more advanced than Markdown, with more features available when -compiled to HTML, such as automatic tables of contents, cross-linking, special -external links (forum, wiki, etc) and more. The documentation is compiled by a -Python tool, `Sphinx `_. - -The DFHack build process will compile the documentation, but this is disabled -by default due to the additional Python and Sphinx requirements. You typically -only need to build the docs if you're changing them, or perhaps -if you want a local HTML copy; otherwise, you can read an -`online version hosted by ReadTheDocs `_. - -(Note that even if you do want a local copy, it is certainly not necessary to -compile the documentation in order to read it. Like Markdown, reST documents are -designed to be just as readable in a plain-text editor as they are in HTML format. -The main thing you lose in plain text format is hyperlinking.) - -.. contents:: Contents - :local: - -.. _docs-standards: - -Documentation standards -======================= - -Whether you're adding new code or just fixing old documentation (and there's plenty), -there are a few important standards for completeness and consistent style. Treat -this section as a guide rather than iron law, match the surrounding text, and you'll -be fine. - -Command documentation ---------------------- - -Each command should have a short (~54 character) help string, which is shown -by the `ls` command. For scripts, this is a comment on the first line -(the comment marker and whitespace is stripped). For plugins it's the second -argument to ``PluginCommand``. Please make this brief but descriptive! - -Everything should be documented! If it's not clear *where* a particular -thing should be documented, ask on IRC or in the DFHack thread on Bay12 - -as well as getting help, you'll be providing valuable feedback that -makes it easier for future readers! - -Scripts can use a custom autodoc function, based on the Sphinx ``include`` -directive - anything between the tokens is copied into the appropriate scripts -documentation page. For Ruby, we follow the built-in docstring convention -(``=begin`` and ``=end``). For Lua, the tokens are ``[====[`` and ``]====]`` -- ordinary multi-line strings. It is highly encouraged to reuse this string -as the in-console documentation by (e.g.) printing it when a ``-help`` argument -is given. - -The docs **must** have a heading which exactly matches the command, underlined -with ``=====`` to the same length. For example, a lua file would have: - -.. code-block:: lua - - local helpstr = [====[ - - add-thought - =========== - Adds a thought or emotion to the selected unit. Can be used by other scripts, - or the gui invoked by running ``add-thought gui`` with a unit selected. - - ]====] - - -.. highlight:: rst - -Where the heading for a section is also the name of a command, the spelling -and case should exactly match the command to enter in the DFHack command line. - -Try to keep lines within 80-100 characters, so it's readable in plain text -in the terminal - Sphinx (our documentation system) will make sure -paragraphs flow. - -Command usage -------------- - -If there aren't many options or examples to show, they can go in a paragraph of -text. Use double-backticks to put commands in monospaced font, like this:: - - You can use ``cleanowned scattered x`` to dump tattered or abandoned items. - -If the command takes more than three arguments, format the list as a table -called Usage. The table *only* lists arguments, not full commands. -Input values are specified in angle brackets. Example:: - - Usage: - - :arg1: A simple argument. - :arg2 : Does something based on the input value. - :Very long argument: - Is very specific. - -To demonstrate usage - useful mainly when the syntax is complicated, list the -full command with arguments in monospaced font, then indent the next line and -describe the effect:: - - ``resume all`` - Resumes all suspended constructions. - -Links ------ - -If it would be helpful to mention another DFHack command, don't just type the -name - add a hyperlink! Specify the link target in backticks, and it will be -replaced with the corresponding title and linked: e.g. ```autolabor``` -=> `autolabor`. Link targets should be equivalent to the command -described (without file extension), and placed above the heading of that -section like this:: - - .. _autolabor: - - autolabor - ========= - -Add link targets if you need them, but otherwise plain headings are preferred. -Scripts have link targets created automatically. - -Note that the DFHack documentation is configured so that single backticks (with -no prefix or suffix) produce links to internal link targets, such as the -``autolabor`` target shown above. This is different from the reStructuredText -default behavior of rendering such text in italics (as a reference to a title). -For alternative link behaviors, see: - -- `The reStructuredText documentation on roles `__ -- `The reStructuredText documentation on external links `__ -- `The Sphinx documentation on roles `__ - - - ``:doc:`` is useful for linking to another document - -Required dependencies -===================== - -.. highlight:: shell - -In order to build the documentation, you must have Python with Sphinx -version |sphinx_min_version| or later. Python 3 is recommended. - -When installing Sphinx from OS package managers, be aware that there is -another program called Sphinx, completely unrelated to documentation management. -Be sure you are installing the right Sphinx; it may be called ``python-sphinx``, -for example. To avoid doubt, ``pip`` can be used instead as detailed below. - -Once you have installed Sphinx, ``sphinx-build --version`` should report the -version of Sphinx that you have installed. If this works, CMake should also be -able to find Sphinx. - -For more detailed platform-specific instructions, see the sections below: - -.. contents:: - :local: - :backlinks: none - - -Linux ------ -Most Linux distributions will include Python by default. If not, start by -installing Python (preferably Python 3). On Debian-based distros:: - - sudo apt install python3 - -Check your package manager to see if Sphinx |sphinx_min_version| or later is -available. On Debian-based distros, this package is named ``python3-sphinx``. -If this package is new enough, you can install it directly. If not, or if you -want to use a newer Sphinx version (which may result in faster builds), you -can install Sphinx through the ``pip`` package manager instead. On Debian-based -distros, you can install pip with:: - - sudo apt install python3-pip - -Once pip is available, you can then install Sphinx with:: - - pip3 install sphinx - -If you run this as an unprivileged user, it may install a local copy of Sphinx -for your user only. The ``sphinx-build`` executable will typically end up in -``~/.local/bin/`` in this case. Alternatively, you can install Sphinx -system-wide by running pip with ``sudo``. In any case, you will need the folder -containing ``sphinx-build`` to be in your ``$PATH``. - -macOS ------ -macOS has Python 2.7 installed by default, but it does not have the pip package manager. - -You can install Homebrew's Python 3, which includes pip, and then install the -latest Sphinx using pip:: - - brew install python3 - pip3 install sphinx - -Alternatively, you can simply install Sphinx directly from Homebrew:: - - brew install sphinx-doc - -This will install Sphinx for macOS's system Python 2.7, without needing pip. - -Either method works; if you plan to use Python for other purposes, it might best -to install Homebrew's Python 3 so that you have the latest Python as well as pip. -If not, just installing sphinx-doc for macOS's system Python 2.7 is fine. - - -Windows -------- -Python for Windows can be downloaded `from python.org `_. -The latest version of Python 3 is recommended, as it includes pip already. - -You can also install Python and pip through the Chocolatey package manager. -After installing Chocolatey as outlined in the `Windows compilation instructions `, -run the following command from an elevated (admin) command prompt (e.g. ``cmd.exe``):: - - choco install python pip -y - -Once you have pip available, you can install Sphinx with the following command:: - - pip install sphinx - -Note that this may require opening a new (admin) command prompt if you just -installed pip from the same command prompt. - -Building the documentation -========================== - -Once the required dependencies are installed, there are multiple ways to run -Sphinx to build the docs: - -Using CMake ------------ - -Enabling the ``BUILD_DOCS`` CMake option will cause the documentation to be built -whenever it changes as part of the normal DFHack build process. There are several -ways to do this: - -* When initially running CMake, add ``-DBUILD_DOCS:bool=ON`` to your ``cmake`` - command. For example:: - - cmake .. -DCMAKE_BUILD_TYPE:string=Release -DBUILD_DOCS:bool=ON -DCMAKE_INSTALL_PREFIX= - -* If you have already run CMake, you can simply run it again from your build - folder to update your configuration:: - - cmake .. -DBUILD_DOCS:bool=ON - -* You can edit the ``BUILD_DOCS`` setting in CMakeCache.txt directly - -* You can use the CMake GUI or ``ccmake`` to change the ``BUILD_DOCS`` setting - -* On Windows, if you prefer to use the batch scripts, you can run - ``generate-msvc-gui.bat`` and set ``BUILD_DOCS`` through the GUI. If you are - running another file, such as ``generate-msvc-all.bat``, you will need to edit - it to add the flag. You can also run ``cmake`` on the command line, similar to - other platforms. - -The generated documentation will be stored in ``docs/html`` in the root DFHack -folder, and will be installed to ``hack/docs`` when you next install DFHack in a -DF folder. - -Running Sphinx manually ------------------------ - -You can also build the documentation without running CMake - this is faster if -you only want to rebuild the documentation regardless of any code changes. There -is a ``docs/build.sh`` script provided for Linux and macOS that will run -essentially the same command that CMake runs when building the docs - see the -script for additional options. - -To build the documentation with default options, run the following command from -the root DFHack folder:: - - sphinx-build . docs/html - -The resulting documentation will be stored in ``docs/html`` (you can specify -a different path when running ``sphinx-build`` manually, but be warned that -Sphinx may overwrite existing files in this folder). - -Sphinx has many options to enable clean builds, parallel builds, logging, and -more - run ``sphinx-build --help`` for details. - -Building a PDF version ----------------------- - -ReadTheDocs automatically builds a PDF version of the documentation (available -under the "Downloads" section when clicking on the release selector). If you -want to build a PDF version locally, you will need ``pdflatex``, which is part -of a TeX distribution. The following command will then build a PDF, located in -``docs/pdf/latex/DFHack.pdf``, with default options:: - - sphinx-build -M latexpdf . docs/pdf - -There is a ``docs/build-pdf.sh`` script provided for Linux and macOS that runs -this command for convenience - see the script for additional options. - -.. _build-changelog: - -Building the changelogs -======================= -If you have Python installed, you can build just the changelogs without building -the rest of the documentation by running the ``docs/gen_changelog.py`` script. -This script provides additional options, including one to build individual -changelogs for all DFHack versions - run ``python docs/gen_changelog.py --help`` -for details. - -Changelog entries are obtained from ``changelog.txt`` files in multiple repos. -This allows changes to be listed in the same repo where they were made. These -changelogs are combined as part of the changelog build process: - -* ``docs/changelog.txt`` for changes in the main ``dfhack`` repo -* ``scripts/changelog.txt`` for changes made to scripts in the ``scripts`` repo -* ``library/xml/changelog.txt`` for changes made in the ``df-structures`` repo - -Building the changelogs generates two files: ``docs/_auto/news.rst`` and -``docs/_auto/news-dev.rst``. These correspond to `changelog` and `dev-changelog` -and contain changes organized by stable and development DFHack releases, -respectively. For example, an entry listed under "0.44.05-alpha1" in -changelog.txt will be listed under that version in the development changelog as -well, but under "0.44.05-r1" in the stable changelog (assuming that is the -closest stable release after 0.44.05-alpha1). An entry listed under a stable -release like "0.44.05-r1" in changelog.txt will be listed under that release in -both the stable changelog and the development changelog. - - -Changelog syntax ----------------- - -.. include:: /docs/changelog.txt - :start-after: ===help - :end-before: ===end - -.. _docs-ci: - -GitHub Actions -============== - -Documentation is built automatically with GitHub Actions (a GitHub-provided -continuous integration service) for all pull requests and commits in the -"dfhack" and "scripts" repositories. These builds run with strict settings, i.e. -warnings are treated as errors. If a build fails, you will see a red "x" next to -the relevant commit or pull request. You can view detailed output from Sphinx in -a few ways: - -* Click on the red "x" (or green checkmark), then click "Details" next to - the "Build / docs" entry -* For pull requests only: navigate to the "Checks" tab, then click on "Build" in - the sidebar to expand it, then "docs" under it - -Sphinx output will be visible under the step named "Build docs". If a different -step failed, or you aren't sure how to interpret the output, leave a comment -on the pull request (or commit). - -You can also download the "docs" artifact from the summary page (typically -accessible by clicking "Build") if the build succeeded. This is a way to -visually inspect what the documentation looks like when built without installing -Sphinx locally, although we recommend installing Sphinx if you are planning to -do any significant work on the documentation. diff --git a/docs/History.rst b/docs/History.rst deleted file mode 100644 index dc02d02b07..0000000000 --- a/docs/History.rst +++ /dev/null @@ -1,1603 +0,0 @@ -:orphan: - -.. _History: - -##################### -Historical changelogs -##################### - -This file is where old changelogs live, so the `current changelog ` -doesn't get too long. Some of these changelogs are also formatted differently -from current changelogs and would be difficult for the current `changelog -generation system ` to handle. - -.. contents:: Contents - :local: - :depth: 1 - -DFHack 0.43.05-r3 -================= - -Internals ---------- -- Fixed an uncommon crash that could occur when printing text to the console -- Added lots of previously-missing DF classes -- More names for fields: https://github.com/DFHack/df-structures/compare/0.43.05-r2...0.43.05 - -Fixes ------ -- Linux: fixed argument to ``setarch`` in the ``dfhack`` launcher script -- Ruby: fixed an error that occurred when the DF path contained an apostrophe -- `diggingInvaders` now compiles again and is included -- `labormanager`: - - - stopped waiting for on-duty military dwarves with minor injuries to obtain care - - stopped waiting for meetings when participant(s) are dead - - fixed a crash for dwarves with no cultural identity - -- `luasocket`: fixed ``receive()`` with a byte count -- `orders`: fixed an error when importing orders with material categories -- `siren`: fixed an error -- `stockpiles`: fixed serialization of barrel and bin counts -- `view-item-info`: fixed a ``CHEESE_MAT``-related error - -Misc Improvements ------------------ -- `devel/export-dt-ini`: added more offsets for new DT versions -- `digfort`: added support for changing z-levels -- `exportlegends`: suppressed ABSTRACT_BUILDING warning -- `gui/dfstatus`: excluded logs in constructions -- `labormanager`: - - - stopped assigning woodcutting jobs to elves - - "recover wounded" jobs now weighted based on altruism - -- `remotefortressreader`: added support for buildings, grass, riders, and - hair/beard styles - - -DFHack 0.43.05-r2 -================= - -Internals ---------- -- Rebuilding DFHack can be faster if nothing Git-related has changed -- Plugins can now hook Screen::readTile() -- Improved Lua compatibility with plugins that hook into GUI functions (like TWBT) -- Expanded focus strings for jobmanagement and workquota_condition viewscreens -- ``Gui::getAnyUnit()``: added support for viewscreen_unitst, - viewscreen_textviewerst, viewscreen_layer_unit_relationshipst -- Fixed (limited) keybinding support in PRINT_MODE:TEXT on macOS -- Added a new standardized ``Gui::refreshSidebar()`` function to fix behavior of - some plugins on the lowest z-level -- New ``Buildings`` module functions: ``markedForRemoval()``, ``getCageOccupants()`` -- Limited recursive command invocations to 20 to prevent crashes -- Added an ``onLoad.init-example`` file - -Lua ---- -- Improved C++ exception handling for some native functions that aren't direct - wrappers around C++ functions (in this case, error messages could be nil and - cause the Lua interpreter to quit) -- Added support for a ``key_pen`` option in Label widgets -- Fixed ``to_first`` argument to ``dfhack.screen.dismiss()`` -- Added optional ``map`` parameters to some screen functions -- Exposed some more functions to Lua: - - - ``dfhack.gui.refreshSidebar()`` - - ``dfhack.gui.getAnyUnit()`` - - ``dfhack.gui.getAnyBuilding()`` - - ``dfhack.gui.getAnyItem()`` - - ``dfhack.gui.getAnyPlant()`` - - ``dfhack.gui.getDepthAt()`` - - ``dfhack.units.getUnitsInBox()`` - - ``dfhack.units.isVisible()`` - - ``dfhack.maps.isTileVisible()`` - - ``dfhack.buildings.markedForRemoval()`` - - ``dfhack.buildings.getCageOccupants()`` - - ``dfhack.internal.md5()`` - - ``dfhack.internal.md5File()`` - - ``dfhack.internal.threadid()`` - -- New function: ``widgets.Pages:getSelectedPage()`` -- Added a ``key`` option to EditField and FilteredList widgets -- Fixed an issue preventing ``repeatUtil.cancel()`` from working when called - from the callback - -Ruby ----- -- Fixed a crash when creating new instances of DF virtual classes (e.g. fixes a - `lever` crash) -- Ruby scripts can now be loaded from any script paths specified (from script- - paths.txt or registered through the Lua API) -- ``unit_find()`` now uses ``Gui::getSelectedUnit()`` and works in more places - (e.g. `exterminate` now works from more screens, like `command-prompt`) - -New Internal Commands ---------------------- -- `alias`: allows configuring aliases for other commands - -New Plugins ------------ -- `orders`: Manipulate manager orders -- `pathable`: Back-end for `gui/pathable` - -New Scripts ------------ -- `clear-smoke`: Removes all smoke from the map -- `empty-bin`: Empty a bin onto the floor -- `fix/retrieve-units`: Spawns stuck invaders/guests -- `fix/stuck-merchants`: Dismisses stuck merchants that haven't entered the map yet -- `gui/pathable`: View whether tiles on the map can be pathed to -- `gui/teleport`: A front-end for the `teleport` script -- `warn-stuck-trees`: Detects citizens stuck in trees - -New Tweaks ----------- -- `tweak` burrow-name-cancel: Implements the "back" option when renaming a - burrow, which currently does nothing (:bug:`1518`) -- `tweak` cage-butcher: Adds an option to butcher units when viewing cages with "q" - -Fixes ------ -- Enforced use of ``stdout.log`` and ``stderr.log`` (instead of their ``.txt`` - counterparts) on Windows -- Fixed ``getItemBaseValue()`` for cheese, sheets and instruments -- Fixed alignment in: - - - ``viewscreen_choose_start_sitest`` - - ``viewscreen_export_graphical_mapst`` - - ``viewscreen_setupadventurest`` - - ``viewscreen_setupdwarfgamest`` - -- `adv-max-skills`: fixed error due to viewscreen changes -- `autolabor`: fixed a crash when assigning haulers while traders are active -- `buildingplan`: fixed an issue that prevented certain numbers from being used - in building names -- `confirm`: - - - dialogs are now closed permanently when disabled from the settings UI - - fixed an issue that could have prevented closing dialogs opened by pressing "s" - -- `embark-tools`: stopped the sand indicator from overlapping dialogs -- `exportlegends`: fixed some crashes and site map issues -- `devel/find-offsets`: fixed ``current_weather`` scan -- `gui/extended-status`: fixed an error when no beds are available -- `gui/family-affairs`: fixed issues with assigning lovers -- `gui/gm-editor`: - - - made keybinding display order consistent - - stopped keys from performing actions in help screen - -- `gui/manager-quantity`: - - - now allows orders with a limit of 0 - - fixed screen detection - -- `gui/mechanisms`, `gui/room-list`: fixed an issue when recentering the map when exiting -- `lever`: prevented pulling non-lever buildings, which can cause crashes -- `markdown`: fixed file encoding -- `modtools/create-unit`: - - - fixed when popup announcements are present - - added checks to ensure that the current game mode is restored - -- `resume`: stopped drawing on the map border -- `show-unit-syndromes`: fixed an error when handling some syndromes -- `strangemood`: fixed some issues with material searches -- `view-item-info`: fixed a color-related error for some materials - -Misc Improvements ------------------ -- Docs: prevented automatic hyphenation in some browsers, which was producing - excessive hyphenation sometimes -- `command-prompt`: invoking ``command-prompt`` a second time now hides the prompt -- `gui/extended-status`: added an option to assign/replace the manager -- `gui/load-screen`: - - - adjusted dialog width for long folder names - - added modification times and DF versions to dialog - -- `gui/mechanisms`, `gui/room-list`, `gui/siege-engine`: add and list "exit to map" options -- `lever`: added support for pulling levers at high priority -- `markdown`: now recognizes ``-n`` in addition to ``/n`` -- `remotefortressreader`: more data exported, used by Armok Vision v0.17.0 -- `resume`, `siege-engine`: improved compatibility with GUI-hooking plugins (like TWBT) -- `sc-script`: improved help text -- `teleport`: can now be used as a module -- `tweak` embark-profile-name: now enabled in ``dfhack.init-example`` -- `tweak` hotkey-clear: fixed display on larger screens - - -DFHack 0.43.05-r1 -================= - -Internals ---------- -- 64-bit support on all platforms -- Several structure fixes to match 64-bit DF's memory layout -- Added ``DFHack::Job::removeJob()`` function -- New module: ``Designations`` - handles designation creation (currently for plants only) -- Added ``Gui::getSelectedPlant()`` -- Added ``Units::getMainSocialActivity()``, ``Units::getMainSocialEvent()`` -- Visual Studio 2015 now required to build on Windows instead of 2010 -- GCC 4.8 or newer required to build on Linux and OS X (and now supported on OS X) -- Updated TinyXML from 2.5.3 to 2.6.2 -- Added the ability to download files manually before building - -Lua ---- -- Lua has been updated to 5.3 - see https://www.lua.org/manual/5.3/readme.html for details - - - Floats are no longer implicitly converted to integers in DFHack API calls - -- ``df.new()`` supports more types: ``char``, ``intptr_t``, ``uintptr_t``, ``long``, ``unsigned long`` -- String representations of vectors and a few other containers now include their lengths -- Added a ``tile-material`` module -- Added a ``Painter:key_string()`` method -- Made ``dfhack.gui.revealInDwarfmodeMap()`` available - -Ruby ----- -- Added support for loading ruby 2.x libraries - -New Plugins ------------ -- `dwarfvet` enables animal caretaking -- `generated-creature-renamer`: Renames generated creature IDs for use with graphics packs -- `labormanager` (formerly autolabor2): a more advanced alternative to `autolabor` -- `misery`: re-added and updated for the 0.4x series -- `title-folder`: shows DF folder name in window title bar when enabled - -New Scripts ------------ -- `adv-rumors`: improves the "Bring up specific incident or rumor" menu in adventure mode -- `fix/tile-occupancy`: Clears bad occupancy flags on the selected tile. -- `install-info`: Logs basic troubleshooting information about the current DFHack installation -- `load-save`: loads a save non-interactively -- `modtools/change-build-menu`: Edit the build mode sidebar menus -- `modtools/if-entity`: Run a command if the current entity matches a given ID -- `season-palette`: Swap color palettes with the changes of the seasons -- `unforbid`: Unforbids all items - -New Tweaks ----------- -- `tweak condition-material `: fixes a crash in the work order condition material list -- `tweak hotkey-clear `: adds an option to clear bindings from DF hotkeys - -Fixes ------ -- The DF path on OS X can now contain spaces and ``:`` characters -- Buildings::setOwner() changes now persist properly when saved -- ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable -- Fixed ``plug`` output alignment for plugins with long names -- `add-thought`: fixed support for emotion names -- `autochop`: - - - fixed several issues with job creation and removal - - stopped designating the center tile (unreachable) for large trees - - stopped options from moving when enabling and disabling burrows - - fixed display of unnamed burrows - -- `devel/find-offsets`: fixed a crash when vtables used by globals aren't available -- `getplants`: - - - fixed several issues with job creation and removal - - stopped designating the center tile (unreachable) for large trees - -- `gui/workflow`: added extra keybinding to work with `gui/extended-status` -- `manipulator`: - - - Fixed crash when selecting a profession from an empty list - - Custom professions are now sorted alphabetically more reliably - -- `modtools/create-item`: - - - made gloves usable by specifying handedness - - now creates pairs of boots and gloves - -- `modtools/create-unit`: - - - stopped permanently overwriting the creature creation menu in arena mode - - now uses non-English names - - added ``-setUnitToFort`` option to make a unit a civ/group member more easily - - fixed some issues where units would appear in unrevealed areas of the map - -- `modtools/item-trigger`: fixed errors with plant growths -- `remotefortressreader`: fixed a crash when serializing the local map -- `ruby`: fixed a crash when unloading the plugin on Windows -- `stonesense`: disabled overlay in STANDARD-based print modes to prevent crashes -- `title-version`: now hidden when loading an arena - -Misc Improvements ------------------ -- Documented all default keybindings (from :file:`dfhack.init-example`) in the - docs for the relevant commands; updates enforced by build system. -- `autounsuspend`: reduced update frequency to address potential performance issues -- `gui/extended-status`: added a feature to queue beds -- `lua` and `gui/gm-editor` now support the same aliases (``scr``, ``unit``, etc.) -- `manipulator`: added social activities to job column -- `remotefortressreader`: Added support for - - - world map snow coverage - - spatters - - wall info - - site towers, world buildings - - surface material - - building items - - DF version info - -- `title-version`: Added a prerelease indicator -- `workflow`: Re-added ``Alt-W`` keybindings - - -DFHack 0.43.05-beta2 -==================== - -Fixes ------ -- Fixed Buildings::updateBuildings(), along with building creation/deletion events -- Fixed ``plug`` output alignment for plugins with long names -- Fixed a crash that happened when a ``LUA_PATH`` environment variable was set -- `add-thought`: fixed number conversion -- `gui/workflow`: fixed range editing producing the wrong results for certain numbers -- `modtools/create-unit`: now uses non-English names -- `modtools/item-trigger`: fixed errors with plant growths -- `remotefortressreader`: fixed a crash when serializing the local map -- `stockflow`: fixed an issue with non-integer manager order limits -- `title-folder`: fixed compatibility issues with certain SDL libraries on macOS - -Structures ----------- -- Added some missing renderer VTable addresses on macOS -- ``entity.resources.organic``: identified ``parchment`` -- ``entity_sell_category``: added ``Parchment`` and ``CupsMugsGoblets`` -- ``ui_advmode_menu``: added ``Build`` -- ``ui_unit_view_mode``: added ``PrefOccupation`` -- ``unit_skill``: identified ``natural_skill_lvl`` (was ``unk_1c``) -- ``viewscreen_jobmanagementst``: identified ``max_workshops`` -- ``viewscreen_overallstatusst``: made ``visible_pages`` an enum -- ``viewscreen_pricest``: identified fields -- ``viewscreen_workquota_conditionst``: gave some fields ``unk`` names - -API Changes ------------ -- Allowed the Lua API to accept integer-like floats and strings when expecting an integer -- Lua: New ``Painter:key_string()`` method -- Lua: Added ``dfhack.getArchitecture()`` and ``dfhack.getArchitectureName()`` - -Additions/Removals: -------------------- -- Added `adv-rumors` script: improves the "Bring up specific incident or rumor" menu in adventure mode -- Added `install-info` script for basic troubleshooting -- Added `tweak condition-material `: fixes a crash in the work order condition material list -- Added `tweak hotkey-clear `: adds an option to clear bindings from DF hotkeys -- `autofarm`: reverted local biome detection (from 0.43.05-alpha3) - -Other Changes -------------- -- Added a DOWNLOAD_RUBY CMake option, to allow use of a system/external ruby library -- Added the ability to download files manually before building -- `gui/extended-status`: added a feature to queue beds -- `remotefortressreader`: added building items, DF version info -- `stonesense`: Added support for 64-bit macOS and Linux - -DFHack 0.43.05-beta1 -==================== - -Fixes ------ -- Fixed various crashes on 64-bit Windows related to DFHack screens, notably `manipulator` -- Fixed addresses of next_id globals on 64-bit Linux (fixes an `automaterial`/box-select crash) -- ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable -- `modtools/create-unit`: stopped permanently overwriting the creature creation - menu in arena mode -- `season-palette`: fixed an issue where only part of the screen was redrawn - after changing the color scheme -- `title-version`: now hidden when loading an arena - -Structures ----------- -- ``file_compressorst``: fixed field sizes on x64 -- ``historical_entity``: fixed alignment on x64 -- ``ui_sidebar_menus.command_line``: fixed field sizes on x64 -- ``viewscreen_choose_start_sitest``: added 3 missing fields, renamed ``in_embark_only_warning`` -- ``viewscreen_layer_arena_creaturest``: identified more fields -- ``world.math``: identified -- ``world.murky_pools``: identified - -Additions/Removals ------------------- -- `generated-creature-renamer`: Renames generated creature IDs for use with graphics packs - -Other Changes -------------- -- `title-version`: Added a prerelease indicator - -DFHack 0.43.05-alpha4 -===================== - -Fixes ------ -- Fixed an issue with uninitialized bitfields that was causing several issues - (disappearing buildings in `buildingplan`'s planning mode, strange behavior in - the extended `stocks` screen, and likely other problems). This issue was - introduced in 0.43.05-alpha3. -- `stockflow`: Fixed an "integer expected" error - -Structures ----------- -- Located several globals on 64-bit Linux: flows, timed_events, ui_advmode, - ui_building_assign_type, ui_building_assign_is_marked, - ui_building_assign_units, ui_building_assign_items, and ui_look_list. This - fixes `search-plugin`, `zone`, and `force`, among others. -- ``ui_sidebar_menus``: Fixed some x64 alignment issues - -Additions/Removals ------------------- -- Added `fix/tile-occupancy`: Clears bad occupancy flags on the selected tile. - Useful for fixing blocked tiles introduced by the above buildingplan issue. -- Added a Lua ``tile-material`` module - -Other Changes -------------- -- `labormanager`: Add support for shell crafts -- `manipulator`: Custom professions are now sorted alphabetically more reliably - -DFHack 0.43.05-alpha3 -===================== - -Fixes ------ -- `add-thought`: fixed support for emotion names -- `autofarm`: Made surface farms detect local biome -- `devel/export-dt-ini`: fixed squad_schedule_entry size -- `labormanager`: - - - Now accounts for unit attributes - - Made instrument-building jobs work (constructed instruments) - - Fixed deconstructing constructed instruments - - Fixed jobs in bowyer's shops - - Fixed trap component jobs - - Fixed multi-material construction jobs - - Fixed deconstruction of buildings containing items - - Fixed interference caused by "store item in vehicle" jobs - -- `manipulator`: Fixed crash when selecting a profession from an empty list -- `ruby`: - - - Fixed crash on Win64 due to truncated global addresses - - Fixed compilation on Win64 - - Use correct raw string length with encodings - -Structures ----------- -- Changed many ``comment`` XML attributes with version numbers to use new - ``since`` attribute instead -- ``activity_event_conflictst.sides``: named many fields -- ``building_def.build_key``: fixed size on 64-bit Linux and OS X -- ``historical_kills``: - - - ``unk_30`` -> ``killed_underground_region`` - - ``unk_40`` -> ``killed_region`` - -- ``historical_kills.killed_undead``: removed ``skeletal`` flag -- ``ui_advmode``: aligned enough so that it doesn't crash (64-bit OS X/Linux) -- ``ui_advmode.show_menu``: changed from bool to enum -- ``unit_personality.emotions.flags``: now a bitfield - -API Changes ------------ -- Added ``DFHack::Job::removeJob()`` function -- C++: Removed bitfield constructors that take an initial value. These kept - bitfields from being used in unions. Set ``bitfield.whole`` directly instead. -- Lua: ``bitfield.whole`` now returns an integer, not a decimal - -Additions/Removals ------------------- -- Removed source for treefarm plugin (wasn't built) -- Added `modtools/change-build-menu`: Edit the build mode sidebar menus -- Added `modtools/if-entity`: Run a command if the current entity matches a - given ID -- Added `season-palette`: Swap color palettes with the changes of the seasons - -Other changes -------------- -- Changed minimum GCC version to 4.8 on OS X and Linux (earlier versions - wouldn't have worked on Linux anyway) -- Updated TinyXML from 2.5.3 to 2.6.2 - -DFHack 0.43.03-r1 -================= - -Lua ---- -- Label widgets can now easily register handlers for mouse clicks - -New Features ------------- -- `add-thought`: allow syndrome name as ``-thought`` argument -- `gui/gm-editor` - - - Added ability to insert default types into containers. For primitive types leave the type entry empty, and for references use ``*``. - - Added ``shift-esc`` binding to fully exit from editor - - Added ``gui/gm-editor toggle`` command to toggle editor visibility (saving position) - -- `modtools/create-unit`: - - - Added an option to attach units to an existing wild animal population - - Added an option to attach units to a map feature - -Fixes ------ -- `autofarm`: Can now handle crops that grow for more than a season -- `combine-plants`: Fixed recursion into sub-containers -- `createitem`: Now moves multiple created items to cursor correctly -- `exportlegends`: Improved handling of unknown enum items (fixes many errors) -- `gui/create-item`: Fixed quality when creating multiple items -- `gui/mod-manager`: Fixed error when mods folder doesn't exist -- `modtools/item-trigger`: Fixed handling of items with subtypes -- `reveal`: ``revflood`` now handles constructed stairs with floors in generated fortresses -- `stockflow`: - - - Can order metal mechanisms - - Fixed material category of thread-spinning jobs - -Misc Improvements ------------------ -- The built-in ``ls`` command now wraps the descriptions of commands -- `catsplosion`: now a lua script instead of a plugin -- `fix/diplomats`: replaces ``fixdiplomats`` -- `fix/merchants`: replaces ``fixmerchants`` -- `prefchange`: added a ``help`` option -- `probe`: now displays raw tiletype names -- Unified script documentation and in-terminal help options - -Removed -------- -- `tweak` manager-quantity: no longer needed - -DFHack 0.42.06-r1 -================= - -Internals ---------- -- Commands to run on startup can be specified on the command line with ``+`` - - Example:: - - ./dfhack +devel/print-args example - "Dwarf Fortress.exe" +devel/print-args example - -- Prevented plugins with active viewscreens from being unloaded and causing a crash -- Additional script search paths can be specified in dfhack-config/script-paths.txt - -Lua ---- -- `building-hacks` now supports ``auto_gears`` flags. It automatically finds and animates gears in building definition -- Changed how `eventful` triggers reaction complete. Now it has ``onReactionComplete`` and ``onReactionCompleting``. Second one can be canceled - -New Plugins ------------ -- `autogems`: Creates a new Workshop Order setting, automatically cutting rough gems - -New Scripts ------------ -- `devel/save-version`: Displays DF version information about the current save -- `modtools/extra-gamelog`: replaces ``log-region``, ``soundsense-season``, and ``soundsense`` - -New Features ------------- -- `buildingplan`: Support for floodgates, grates, and bars -- `colonies`: new ``place`` subcommand and supports any vermin (default honey bees) -- `confirm`: Added a confirmation for retiring locations -- `exportlegends`: Exports more information (poetic/musical/dance forms, written/artifact content, landmasses, extra histfig information, and more) -- `search-plugin`: Support for new screens: - - - location occupation assignment - - civilization animal training knowledge - - animal trainer assignment - -- `tweak`: - - - ``tweak block-labors``: Prevents labors that can't be used from being toggled - - ``tweak hide-priority``: Adds an option to hide designation priority indicators - - ``tweak title-start-rename``: Adds a safe rename option to the title screen "Start Playing" menu - -- `zone`: - - - Added ``unassign`` subcommand - - Added ``only`` option to ``assign`` subcommand - -Fixes ------ -- Fixed a crash bug caused by the historical figures DFHack uses to store persistent data. -- More plugins should recognize non-dwarf citizens -- Fixed a possible crash from cloning jobs -- moveToBuilding() now sets flags for items that aren't a structural part of the building properly -- `autotrade`, `stocks`: Made trading work when multiple caravans are present but only some can trade -- `confirm` note-delete: No longer interferes with name entry -- `exportlegends`: Handles entities without specific races, and a few other fixes for things new to v0.42 -- `fastdwarf`: Fixed a bug involving teleporting mothers but not the babies they're holding. -- `gaydar`: Fixed text display on OS X/Linux and failure with soul-less creatures -- `manipulator`: - - - allowed editing of non-dwarf citizens - - stopped ghosts and visitors from being editable - - fixed applying last custom profession - -- `modtools/create-unit`: Stopped making units without civs historical figures -- `modtools/force`: - - - Removed siege option - - Prevented a crash resulting from a bad civilization option - -- `showmood`: Fixed name display on OS X/Linux -- `view-item-info`: Fixed density units - -Misc Improvements ------------------ -- `autochop`: Can now edit log minimum/maximum directly and remove limit entirely -- `autolabor`, `autohauler`, `manipulator`: Added support for new jobs/labors/skills -- `colonies`: now implemented by a script -- `createitem`: Can now create items anywhere without specifying a unit, as long as a unit exists on the map -- `devel/export-dt-ini`: Updated for 0.42.06 -- `devel/find-offsets`: Automated several more scans -- `gui/gm-editor`: Now supports finding some items with a numeric ID (with ``i``) -- `lua`: Now supports some built-in variables like `gui/gm-editor`, e.g. ``unit``, ``screen`` -- `remotefortressreader`: Can now trigger keyboard events -- `stockflow`: Now offers better control over individual craft jobs -- `weather`: now implemented by a script -- `zone`: colored output - -Removed -------- -- DFusion: legacy script system, obsolete or replaced by better alternatives - - -DFHack 0.40.24-r5 -================= - -New Features ------------- -- `confirm`: - - - Added a ``uniform-delete`` option for military uniform deletion - - Added a basic in-game configuration UI - -Fixes ------ -- Fixed a rare crash that could result from running `keybinding` in onLoadWorld.init -- Script help that doesn't start with a space is now recognized correctly -- `confirm`: Fixed issues with haul-delete, route-delete, and squad-disband confirmations intercepting keys too aggressively -- `emigration` should work now -- `fix-unit-occupancy`: Significantly optimized - up to 2,000 times faster in large fortresses -- `gui/create-item`: Allow exiting quantity prompt -- `gui/family-affairs`: Fixed an issue where lack of relationships wasn't recognized and other issues -- `modtools/create-unit`: Fixed a possible issue in reclaim fortress mode -- `search-plugin`: Fixed a crash on the military screen -- `tweak` max-wheelbarrow: Fixed a minor display issue with large numbers -- `workflow`: Fixed a crash related to job postings (and added a fix for existing, broken jobs) - -Misc Improvements ------------------ -- Unrecognized command feedback now includes more information about plugins -- `fix/dry-buckets`: replaces the ``drybuckets`` plugin -- `feature`: now implemented by a script - -DFHack 0.40.24-r4 -================= - -Internals ---------- -- A method for caching screen output is now available to Lua (and C++) -- Developer plugins can be ignored on startup by setting the ``DFHACK_NO_DEV_PLUGINS`` environment variable -- The console on Linux and OS X now recognizes keyboard input between prompts -- JSON libraries available (C++ and Lua) -- More DFHack build information used in plugin version checks and available to plugins and lua scripts -- Fixed a rare overflow issue that could cause crashes on Linux and OS X -- Stopped DF window from receiving input when unfocused on OS X -- Fixed issues with keybindings involving :kbd:`Ctrl`:kbd:`A` and :kbd:`Ctrl`:kbd:`Z`, - as well as :kbd:`Alt`:kbd:`E`/:kbd:`U`/:kbd:`N` on OS X -- Multiple contexts can now be specified when adding keybindings -- Keybindings can now use :kbd:`F10`-:kbd:`F12` and :kbd:`0`-:kbd:`9` -- Plugin system is no longer restricted to plugins that exist on startup -- :file:`dfhack.init` file locations significantly generalized - -Lua ---- -- Scripts can be enabled with the built-in `enable`/`disable ` commands -- A new function, ``reqscript()``, is available as a safer alternative to ``script_environment()`` -- Lua viewscreens can choose not to intercept the OPTIONS keybinding - -New internal commands ---------------------- -- `kill-lua`: Interrupt running Lua scripts -- `type`: Show where a command is implemented - -New plugins ------------ -- `confirm`: Adds confirmation dialogs for several potentially dangerous actions -- `fix-unit-occupancy`: Fixes issues with unit occupancy, such as faulty "unit blocking tile" messages (:bug:`3499`) -- `title-version` (formerly ``vshook``): Display DFHack version on title screen - -New scripts ------------ -- `armoks-blessing`: Adjust all attributes, personality, age and skills of all dwarves in play -- `brainwash`: brainwash a dwarf (modifying their personality) -- `burial`: sets all unowned coffins to allow burial ("-pets" to allow pets too) -- `deteriorateclothes`: make worn clothes on the ground wear far faster to boost FPS -- `deterioratecorpses`: make body parts wear away far faster to boost FPS -- `deterioratefood`: make food vanish after a few months if not used -- `elevate-mental`: elevate all the mental attributes of a unit -- `elevate-physical`: elevate all the physical attributes of a unit -- `emigration`: stressed dwarves may leave your fortress if they see a chance -- `fix-ster`: changes fertility/sterility of animals or dwarves -- `gui/family-affairs`: investigate and alter romantic relationships -- `make-legendary`: modify skill(s) of a single unit -- `modtools/create-unit`: create new units from nothing -- `modtools/equip-item`: a script to equip items on units -- `points`: set number of points available at embark screen -- `pref-adjust`: Adjust all preferences of all dwarves in play -- `rejuvenate`: make any "old" dwarf 20 years old -- `starvingdead`: make undead weaken after one month on the map, and crumble after six -- `view-item-info`: adds information and customisable descriptions to item viewscreens -- `warn-starving`: check for starving, thirsty, or very drowsy units and pause with warning if any are found - -New tweaks ----------- -- embark-profile-name: Allows the use of lowercase letters when saving embark profiles -- kitchen-keys: Fixes DF kitchen meal keybindings -- kitchen-prefs-color: Changes color of enabled items to green in kitchen preferences -- kitchen-prefs-empty: Fixes a layout issue with empty kitchen tabs - -Fixes ------ -- Plugins with vmethod hooks can now be reloaded on OS X -- Lua's ``os.system()`` now works on OS X -- Fixed default arguments in Lua gametype detection functions -- Circular lua dependencies (reqscript/script_environment) fixed -- Prevented crash in ``Items::createItem()`` -- `buildingplan`: Now supports hatch covers -- `gui/create-item`: fixed assigning quality to items, made :kbd:`Esc` work properly -- `gui/gm-editor`: handles lua tables properly -- `help`: now recognizes built-in commands, like ``help`` -- `manipulator`: fixed crash when selecting custom professions when none are found -- `remotefortressreader`: fixed crash when attempting to send map info when no map was loaded -- `search-plugin`: fixed crash in unit list after cancelling a job; fixed crash when disabling stockpile category after searching in a subcategory -- `stockpiles`: now checks/sanitizes filenames when saving -- `stocks`: fixed a crash when right-clicking -- `steam-engine`: fixed a crash on arena load; number keys (e.g. 2/8) take priority over cursor keys when applicable -- tweak fps-min fixed -- tweak farm-plot-select: Stopped controls from appearing when plots weren't fully built -- `workflow`: Fixed some issues with stuck jobs. Existing stuck jobs must be cancelled and re-added -- `zone`: Fixed a crash when using ``zone set`` (and a few other potential crashes) - -Misc Improvements ------------------ -- DFHack documentation: - - - massively reorganised, into files of more readable size - - added many missing entries - - indexes, internal links, offline search all documents - - includes documentation of linked projects (df-structures, third-party scripts) - - better HTML generation with Sphinx - - documentation for scripts now located in source files - -- `autolabor`: - - - Stopped modification of labors that shouldn't be modified for brokers/diplomats - - Prioritize skilled dwarves more efficiently - - Prevent dwarves from running away with tools from previous jobs - -- `automaterial`: Fixed several issues with constructions being allowed/disallowed incorrectly when using box-select -- `dwarfmonitor`: - - - widgets' positions, formats, etc. are now customizable - - weather display now separated from the date display - - New mouse cursor widget - -- `gui/dfstatus`: Can enable/disable individual categories and customize metal bar list -- `full-heal`: ``-r`` option removes corpses -- `gui/gm-editor` - - - Pointers can now be displaced - - Added some useful aliases: "item" for the selected item, "screen" for the current screen, etc. - - Now avoids errors with unrecognized types - -- `gui/hack-wish`: renamed to `gui/create-item` -- `keybinding list ` accepts a context -- `lever`: - - - Lists lever names - - ``lever pull`` can be used to pull the currently-selected lever - -- ``memview``: Fixed display issue -- `modtools/create-item`: arguments are named more clearly, and you can specify the creator to be the unit with id ``df.global.unit_next_id-1`` (useful in conjunction with `modtools/create-unit`) -- ``nyan``: Can now be stopped with dfhack-run -- `plug`: lists all plugins; shows state and number of commands in plugins -- `prospect`: works from within command-prompt -- `quicksave`: Restricted to fortress mode -- `remotefortressreader`: Exposes more information -- `search-plugin`: - - - Supports noble suggestion screen (e.g. suggesting a baron) - - Supports fortress mode loo[k] menu - - Recognizes ? and ; keys - -- `stocks`: can now match beginning and end of item names -- `teleport`: Fixed cursor recognition -- `tidlers`, `twaterlvl`: now implemented by scripts instead of a plugin -- `tweak`: - - - debug output now logged to stderr.log instead of console - makes DFHack start faster - - farm-plot-select: Fixed issues with selecting undiscovered crops - -- `workflow`: Improved handling of plant reactions - -Removed -------- -- `embark-tools` nano: 1x1 embarks are now possible in vanilla 0.40.24 - -DFHack 0.40.24-r3 -================= - -Internals ---------- -- Ruby library now included on OS X - Ruby scripts should work on OS X 10.10 -- libstdc++ should work with older versions of OS X -- Added support for `onMapLoad.init / onMapUnload.init ` scripts -- game type detection functions are now available in the World module -- The ``DFHACK_LOG_MEM_RANGES`` environment variable can be used to log information to ``stderr.log`` on OS X -- Fixed adventure mode menu names -- Fixed command usage information for some commands - -Lua ---- -- Lua scripts will only be reloaded if necessary -- Added a ``df2console()`` wrapper, useful for printing DF (CP437-encoded) text to the console in a portable way -- Added a ``strerror()`` wrapper - -New Internal Commands ---------------------- -- `hide`, `show`: hide and show the console on Windows -- `sc-script`: Allows additional scripts to be run when certain events occur (similar to `onLoad.init` scripts) - -New Plugins ------------ -- `autohauler`: A hauling-only version of autolabor - -New Scripts ------------ -- `modtools/reaction-product-trigger`: triggers callbacks when products are produced (contrast with when reactions complete) - -New Tweaks ----------- -- `fps-min `: Fixes the in-game minimum FPS setting -- `shift-8-scroll `: Gives Shift+8 (or ``*``) priority when scrolling menus, instead of scrolling the map -- `tradereq-pet-gender `: Displays pet genders on the trade request screen - -Fixes ------ -- Fixed game type detection in `3dveins`, `gui/create-item`, `reveal`, `seedwatch` -- ``PRELOAD_LIB``: More extensible on Linux -- `add-spatter`, `eventful`: Fixed crash on world load -- `add-thought`: Now has a proper subthought arg. -- `building-hacks`: Made buildings produce/consume correct amount of power -- `fix-armory`: compiles and is available again (albeit with issues) -- `gui/gm-editor`: Added search option (accessible with "s") -- `hack-wish `: Made items stack properly. -- `modtools/skill-change`: Made level granularity work properly. -- `show-unit-syndromes`: should work -- `stockflow`: - - - Fixed error message in Arena mode - - no longer checks the DF version - - fixed ballistic arrow head orders - - convinces the bookkeeper to update records more often - -- `zone`: Stopped crash when scrolling cage owner list - -Misc Improvements ------------------ -- `autolabor`: A negative pool size can be specified to use the most unskilled dwarves -- `building-hacks`: - - - Added a way to allow building to work even if it consumes more power than is available. - - Added setPower/getPower functions. - -- `catsplosion`: Can now trigger pregnancies in (most) other creatures -- `exportlegends`: ``info`` and ``all`` options export ``legends_plus.xml`` with more data for legends utilities -- `manipulator`: - - - Added ability to edit nicknames/profession names - - added "Job" as a View Type, in addition to "Profession" and "Squad" - - added custom profession templates with masking - -- `remotefortressreader`: Exposes more information - - -DFHack 0.40.24-r2 -================= - -Internals ---------- -- Lua scripts can set environment variables of each other with ``dfhack.run_script_with_env`` -- Lua scripts can now call each others internal nonlocal functions with ``dfhack.script_environment(scriptName).functionName(arg1,arg2)`` -- `eventful`: Lua reactions no longer require LUA_HOOK as a prefix; you can register a callback for the completion of any reaction with a name -- Filesystem module now provides file access/modification times and can list directories (normally and recursively) -- Units Module: New functions:: - - isWar - isHunter - isAvailableForAdoption - isOwnCiv - isOwnRace - getRaceName - getRaceNamePlural - getRaceBabyName - getRaceChildName - isBaby - isChild - isAdult - isEggLayer - isGrazer - isMilkable - isTrainableWar - isTrainableHunting - isTamable - isMale - isFemale - isMerchant - isForest - isMarkedForSlaughter - -- Buildings Module: New Functions:: - - isActivityZone - isPenPasture - isPitPond - isActive - findPenPitAt - -Fixes ------ -- ``dfhack.run_script`` should correctly find save-specific scripts now. -- `add-thought`: updated to properly affect stress. -- `hfs-pit`: should work now -- `autobutcher`: takes gelding into account -- :file:`init.lua` existence checks should be more reliable (notably when using non-English locales) - -Misc Improvements ------------------ -Multiline commands are now possible inside dfhack.init scripts. See :file:`dfhack.init-example` for example usage. - - -DFHack 0.40.24-r1 -================= - -Internals ---------- -CMake shouldn't cache DFHACK_RELEASE anymore. People may need to manually update/delete their CMake cache files to get rid of it. - - -DFHack 0.40.24-r0 -================= - -Internals ---------- -- `EventManager`: fixed crash error with EQUIPMENT_CHANGE event. -- key modifier state exposed to Lua (ie :kbd:`Ctrl`, :kbd:`Alt`, :kbd:`Shift`) - -Fixes ------ -``dfhack.sh`` can now be run from other directories on OS X - -New Plugins ------------ -- `blueprint`: export part of your fortress to quickfort .csv files - -New Scripts ------------ -- `hotkey-notes`: print key, name, and jump position of hotkeys - -Removed -------- -- needs_porting/* - -Misc Improvements ------------------ -- Added support for searching more lists - -DFHack 0.40.23-r1 -================= - -Internals ---------- -- plugins will not be loaded if globals they specify as required are not located (should prevent some crashes) - -Fixes ------ -- Fixed numerous (mostly Lua-related) crashes on OS X by including a more up-to-date libstdc++ -- :kbd:`Alt` should no longer get stuck on Windows (and perhaps other platforms as well) -- `gui/advfort` works again -- `autobutcher`: takes sexualities into account -- devel/export-dt-ini: Updated for 0.40.20+ -- `digfort`: now checks file type and existence -- `exportlegends`: Fixed map export -- `full-heal`: Fixed a problem with selecting units in the GUI -- `gui/hack-wish`: Fixed restrictive material filters -- `mousequery`: Changed box-select key to Alt+M -- `dwarfmonitor`: correct date display (month index, separator) -- `putontable`: added to the readme -- `siren` should work again -- stderr.log: removed excessive debug output on OS X -- `trackstop`: No longer prevents cancelling the removal of a track stop or roller. -- Fixed a display issue with ``PRINT_MODE:TEXT`` -- Fixed a symbol error (MapExtras::BiomeInfo::MAX_LAYERS) when compiling DFHack in Debug mode - -New Plugins ------------ -- `fortplan`: designate construction of (limited) buildings from .csv file, quickfort-style - -New Scripts ------------ -- `gui/stockpiles`: an in-game interface for saving and loading stockpile settings files. -- `position`: Reports the current date, time, month, and season, plus some location info. Port/update of position.py -- `hfs-pit`: Digs a hole to hell under the cursor. Replaces needs_porting/hellhole.cpp - -Removed -------- -- embark.lua: Obsolete, use `embark-tools` - -New tweaks ----------- -- `eggs-fertile `: Displays an egg fertility indicator on nestboxes -- `max-wheelbarrow `: Allows assigning more than 3 wheelbarrows to a stockpile - -Misc Improvements ------------------ -- `embark-tools`: Added basic mouse support on the local map -- Made some adventure mode keybindings in :file:`dfhack.init-example` only work in adventure mode -- `gui/companion-order`: added a default keybinding -- further work on needs_porting - - -DFHack 0.40.19-r1 -================= - -Fixes ------ -- `modtools/reaction-trigger`: fixed typo -- `modtools/item-trigger`: should now work with item types - -New plugins ------------ -- `savestock, loadstock `: save and load stockpile settings across worlds and saves - -New scripts ------------ -- `remove-stress`: set selected or all units unit to -1,000,000 stress (this script replaces removebadthoughts) - -Misc improvements ------------------ -- `command-prompt`: can now access selected items, units, and buildings -- `autolabor`: add an optional talent pool parameter - - -DFHack 0.40.16-r1 -================= - -Internals ---------- -- `EventManager` should handle INTERACTION triggers a little better. It still can get confused about who did what but only rarely. -- `EventManager` should no longer trigger REPORT events for old reports after loading a save. -- lua/persist-table: a convenient way of using persistent tables of arbitrary structure and dimension in Lua - -Fixes ------ -- `mousequery`: Disabled when linking levers -- `stocks`: Melting should work now -- `full-heal`: Updated with proper argument handling -- `modtools/reaction-trigger-transition`: should produce the correct syntax now -- `superdwarf`: should work better now -- `forum-dwarves`: update for new df-structures changes - -New Scripts ------------ -- `adaptation`: view or set the cavern adaptation level of your citizens -- `add-thought`: allows the user to add thoughts to creatures. -- `gaydar`: detect the sexual orientation of units on the map -- `markdown`: Save a copy of a text screen in markdown (for reddit among others). -- devel/all-bob: renames everyone Bob to help test interaction-trigger - -Misc Improvements ------------------ -- `autodump`: Can now mark a stockpile for auto-dumping (similar to `automelt` and `autotrade`) -- `buildingplan`: Can now auto-allocate rooms to dwarves with specific positions (e.g. expedition leader, mayor) -- `dwarfmonitor`: now displays a weather indicator and date -- lua/syndrome-util, `modtools/add-syndrome`: now you can remove syndromes by SYN_CLASS -- No longer write empty :file:`.history` files - - -DFHack 0.40.15-r1 -================= - -Fixes ------ -- mousequery: Fixed behavior when selecting a tile on the lowest z-level - -Misc Improvements ------------------ -- `EventManager`: deals with frame_counter getting reset properly now. -- `modtools/item-trigger`: fixed equip/unequip bug and corrected minor documentation error -- `teleport`: Updated with proper argument handling and proper unit-at-destination handling. -- `autotrade`: Removed the newly obsolete :guilabel:`Mark all` functionality. -- `search-plugin`: Adapts to the new trade screen column width -- `tweak fast-trade `: Switching the fast-trade keybinding to Shift-Up/Shift-Down, due to Select All conflict - - -DFHack 0.40.14-r1 -================= - -Internals ---------- -- The DFHack console can now be disabled by setting the DFHACK_DISABLE_CONSOLE environment variable: ``DFHACK_DISABLE_CONSOLE=1 ./dfhack`` - -Fixes ------ -- Stopped duplicate load/unload events when unloading a world -- Stopped ``-e`` from being echoed when DFHack quits on Linux -- `automelt`: now uses a faster method to locate items -- `autotrade`: "Mark all" no longer double-marks bin contents -- `drain-aquifer`: new script replaces the buggy plugin -- `embark-tools`: no longer conflicts with keys on the notes screen -- `fastdwarf`: Fixed problems with combat/attacks -- `forum-dwarves`: should work now -- `manipulator`: now uses a stable sort, allowing sorting by multiple categories -- `rendermax`: updated to work with 0.40 - -New Plugins ------------ -- `trackstop`: Shows track stop friction and dump direction in its :kbd:`q` menu - -New Tweaks ----------- -- farm-plot-select: Adds "Select all" and "Deselect all" options to farm plot menus -- import-priority-category: Allows changing the priority of all goods in a category when discussing an import agreement with the liaison -- manager-quantity: Removes the limit of 30 jobs per manager order -- civ-view-agreement: Fixes overlapping text on the "view agreement" screen -- nestbox-color: Fixes the color of built nestboxes - -Misc Improvements ------------------ -- `exportlegends`: can now handle site maps - - -DFHack 0.40.13-r1 -================= - -Internals ---------- -- unified spatter structs -- added ruby df.print_color(color, string) method for dfhack console - -Fixes ------ -- no more ``-e`` after terminating -- fixed `superdwarf` - - -DFHack 0.40.12-r1 -================= - -Internals ---------- -- support for global `onLoad.init` and `onUnload.init` files, called when loading and unloading a world -- Close file after loading a `binary patch `. - -New Plugins ------------ -- `hotkeys`: Shows ingame viewscreen with all dfhack keybindings active in current mode. -- `automelt`: allows marking stockpiles so any items placed in them will be designated for melting - -Fixes ------ -- possible crash fixed for `gui/hack-wish` -- `search-plugin`: updated to not conflict with BUILDJOB_SUSPEND -- `workflow`: job_material_category -> dfhack_material_category - -Misc Improvements ------------------ -- now you can use ``@`` to print things in interactive Lua with subtley different semantics -- optimizations for stockpiles for `autotrade` and `stockflow` -- updated `exportlegends` to work with new maps, dfhack 40.11 r1+ - - -DFHack 0.40.11-r1 -================= - -Internals ---------- -- Plugins on OS X now use ``.plug.dylib`` as an extension instead of ``.plug.so`` - -Fixes ------ -- `3dveins`: should no longer hang/crash on specific maps -- `autotrade`, `search-plugin`: fixed some layout issues -- `deathcause`: updated -- `gui/hack-wish`: should work now -- `reveal`: no longer allocates data for nonexistent map blocks -- Various documentation fixes and updates - - -DFHack v0.40.10-r1 -================== - -A few bugfixes. - -DFHack v0.40.08-r2 -================== - -Internals ---------- -- supported per save script folders -- Items module: added createItem function -- Sorted CMakeList for plugins and plugins/devel -- `diggingInvaders` no longer builds if plugin building is disabled -- `EventManager`: EQUIPMENT_CHANGE now triggers for new units. New events:: - - ON_REPORT - UNIT_ATTACK - UNLOAD - INTERACTION - -New Scripts ------------ -- lua/repeat-util: makes it easier to make things repeat indefinitely -- lua/syndrome-util: makes it easier to deal with unit syndromes -- `forum-dwarves`: helps copy df viewscreens to a file -- `full-heal`: fully heal a unit -- `remove-wear`: removes wear from all items in the fort -- `repeat`: repeatedly calls a script or a plugin -- ShowUnitSyndromes: shows syndromes affecting units and other relevant info -- `teleport`: teleports units -- `devel/print-args` -- `fix/blood-del`: makes it so civs don't bring barrels full of blood ichor or goo -- `fix/feeding-timers`: reset the feeding timers of all units -- `gui/hack-wish`: creates items out of any material -- `gui/unit-info-viewer`: displays information about units -- `modtools/add-syndrome`: add a syndrome to a unit or remove one -- `modtools/anonymous-script`: execute an lua script defined by a string. Useful for the ``*-trigger`` scripts. -- `modtools/force`: forces events: caravan, migrants, diplomat, megabeast, curiousbeast, mischievousbeast, flier, siege, nightcreature -- `modtools/item-trigger`: triggers commands based on equipping, unequipping, and wounding units with items -- `modtools/interaction-trigger`: triggers commands when interactions happen -- `modtools/invader-item-destroyer`: destroys invaders' items when they die -- `modtools/moddable-gods`: standardized version of Putnam's moddable gods script -- `modtools/projectile-trigger`: standardized version of projectileExpansion -- `modtools/reaction-trigger`: trigger commands when custom reactions complete; replaces autoSyndrome -- `modtools/reaction-trigger-transition`: a tool for converting mods from autoSyndrome to reaction-trigger -- `modtools/random-trigger`: triggers random scripts that you register -- `modtools/skill-change`: for incrementing and setting skills -- `modtools/spawn-flow`: creates flows, like mist or dragonfire -- `modtools/syndrome-trigger`: trigger commands when syndromes happen -- `modtools/transform-unit`: shapeshifts a unit, possibly permanently - -Misc improvements ------------------ -- new function in utils.lua for standardized argument processing - -Removed -------- -- digmat.rb: digFlood does the same functionality with less FPS impact -- invasionNow: `modtools/force` does it better -- autoSyndrome replaced with `modtools/reaction-trigger` -- syndromeTrigger replaced with `modtools/syndrome-trigger` -- devel/printArgs plugin converted to `devel/print-args` -- outsideOnly plugin replaced by `modtools/outside-only` - - -DFHack v0.40.08-r1 -================== - -Was a mistake. Don't use it. - -DFHack v0.34.11-r5 -================== - -Internals ---------- -- support for calling a lua function via a protobuf request (demonstrated by dfhack-run --lua). -- support for basic filesystem operations (e.g. chdir, mkdir, rmdir, stat) in C++ and Lua -- Lua API for listing files in directory. Needed for `gui/mod-manager` -- Lua API for creating unit combat reports and writing to gamelog. -- Lua API for running arbitrary DFHack commands -- support for multiple ``raw/init.d/*.lua`` init scripts in one save. -- eventful now has a more friendly way of making custom sidebars -- on Linux and OS X the console now supports moving the cursor back and forward by a whole word. - -New scripts ------------ -- `gui/mod-manager`: allows installing/uninstalling mods into df from ``df/mods`` directory. -- `gui/clone-uniform`: duplicates the currently selected uniform in the military screen. -- `fix/build-location`: partial work-around for :bug:`5991` (trying to build wall while standing on it) -- `undump-buildings`: removes dump designation from materials used in buildings. -- `exportlegends`: exports data from legends mode, allowing a set-and-forget export of large worlds. -- log-region: each time a fort is loaded identifying information will be written to the gamelog. -- `dfstatus `: show an overview of critical stock quantities, including food, drinks, wood, and bars. -- `command-prompt`: a dfhack command prompt in df. - -New plugins ------------ -- `rendermax`: replace the renderer with something else, eg ``rendermax light``- a lighting engine -- `automelt`: allows marking stockpiles for automelt (i.e. any items placed in stocpile will be designated for melting) -- `embark-tools`: implementations of Embark Anywhere, Nano Embark, and a few other embark-related utilities -- `building-hacks`: Allows to add custom functionality and/or animations to buildings. -- `petcapRemover`: triggers pregnancies in creatures so that you can effectively raise the default pet population cap -- `plant create `: spawn a new shrub under the cursor - -New tweaks ----------- -- craft-age-wear: make crafted items wear out with time like in old versions (:bug:`6003`) -- adamantine-cloth-wear: stop adamantine clothing from wearing out (:bug:`6481`) -- confirm-embark: adds a prompt before embarking (on the "prepare carefully" screen) - -Misc improvements ------------------ -- `plant`: move the 'grow', 'extirpate' and 'immolate' commands as 'plant' subcommands -- `digfort`: improved csv parsing, add start() comment handling -- `exterminate`: allow specifying a caste (exterminate gob:male) -- `createitem`: in adventure mode it now defaults to the controlled unit as maker. -- `autotrade`: adds "(Un)mark All" options to both panes of trade screen. -- `mousequery`: several usability improvements; show live overlay (in menu area) of what's on the tile under the mouse cursor. -- `search`: workshop profile search added. -- `dwarfmonitor`: add screen to summarise preferences of fortress dwarfs. -- `getplants`: add autochop function to automate woodcutting. -- `stocks`: added more filtering and display options. - -- `siege-engine`: - - - engine quality and distance to target now affect accuracy - - firing the siege engine at a target produces a combat report - - improved movement speed computation for meandering units - - operators in Prepare To Fire mode are released from duty once hungry/thirsty if there is a free replacement - - -DFHack v0.34.11-r4 -================== - -New commands ------------- -- `diggingInvaders` - allows invaders to dig and/or deconstruct walls and buildings in order to get at your dwarves. -- `digFlood` - automatically dig out specified veins as they are revealed -- `enable, disable ` - Built-in commands that can be used to enable/disable many plugins. -- `restrictice` - Restrict traffic on squares above visible ice. -- `restrictliquids` - Restrict traffic on every visible square with liquid. -- treefarm - automatically chop trees and dig obsidian - -New Scripts ------------ -- `autobutcher`: A GUI front-end for the autobutcher plugin. -- invasionNow: trigger an invasion, or many -- `locate-ore`: scan the map for unmined ore veins -- `masspit`: designate caged creatures in a zone for pitting -- `multicmd`: run a sequence of dfhack commands, separated by ';' -- `startdwarf`: change the number of dwarves for a new embark -- digmat: dig veins/layers tile by tile, as discovered - -Misc improvements ------------------ -- autoSyndrome: - - - disable by default - - reorganized special tags - - minimized error spam - - reset policies: if the target already has an instance of the syndrome you can skip, - add another instance, reset the timer, or add the full duration to the time remaining - -- core: fix SC_WORLD_(UN)LOADED event for arena mode -- `exterminate`: renamed from slayrace, add help message, add butcher mode -- `fastdwarf`: fixed bug involving fastdwarf and teledwarf being on at the same time -- magmasource: rename to `source`, allow water/magma sources/drains -- Add df.dfhack_run "somecommand" to Ruby -- syndromeTrigger: replaces and extends trueTransformation. Can trigger things when syndromes are added for any reason. -- `tiletypes`: support changing tile material to arbitrary stone. -- `workNow`: can optionally look for jobs when jobs are completed - -New tweaks ----------- -- hive-crash: Prevent crash if bees die in a hive with ungathered products (:bug:`6368`). - -New plugins ------------ -- `3dveins`: Reshapes all veins on the map in a way that flows between Z levels. May be unstable. Backup before using. -- `autotrade`: Automatically send items in marked stockpiles to trade depot, when trading is possible. -- `buildingplan`: Place furniture before it's built -- `dwarfmonitor`: Records dwarf activity to measure fort efficiency -- `mousequery`: Look and poke at the map elements with the mouse. -- outsideOnly: make raw-specified buildings impossible to build inside -- `resume`: A plugin to help display and resume suspended constructions conveniently -- `stocks`: An improved stocks display screen. - -Internals ---------- -- Core: there is now a per-save dfhack.init file for when the save is loaded, and another for when it is unloaded -- EventManager: fixed job completion detection, fixed removal of TICK events, added EQUIPMENT_CHANGE event -- Lua API for a better `random number generator ` and perlin noise functions. -- Once: easy way to make sure something happens once per run of DF, such as an error message - - -DFHack v0.34.11-r3 -================== - -Internals ---------- -- support for displaying active keybindings properly. -- support for reusable widgets in lua screen library. -- Maps::canStepBetween: returns whether you can walk between two tiles in one step. -- EventManager: monitors various in game events centrally so that individual plugins - don't have to monitor the same things redundantly. -- Now works with OS X 10.6.8 - -Notable bugfixes ----------------- -- `autobutcher` can be re-enabled again after being stopped. -- stopped `Dwarf Manipulator ` from unmasking vampires. -- `stonesense` is now fixed on OS X - -Misc improvements ------------------ -- `fastdwarf`: new mode using debug flags, and some internal consistency fixes. -- added a small stand-alone utility for applying and removing `binary patches `. -- removebadthoughts: add --dry-run option -- `superdwarf`: work in adventure mode too -- `tweak` stable-cursor: carries cursor location from/to Build menu. -- `deathcause`: allow selection from the unitlist screen -- slayrace: allow targetting undeads -- `workflow` plugin: - - - properly considers minecarts assigned to routes busy. - - code for deducing job outputs rewritten in lua for flexibility. - - logic fix: collecting webs produces silk, and ungathered webs are not thread. - - items assigned to squads are considered busy, even if not in inventory. - - shearing and milking jobs are supported, but only with generic MILK or YARN outputs. - - workflow announces when the stock level gets very low once a season. - -- Auto syndrome plugin: A way of automatically applying boiling rock syndromes and calling dfhack commands controlled by raws. -- `infiniteSky` plugin: Create new z-levels automatically or on request. -- True transformation plugin: A better way of doing permanent transformations that allows later transformations. -- `workNow` plugin: Makes the game assign jobs every time you pause. - -New tweaks ----------- -- tweak military-training: speed up melee squad training up to 10x (normally 3-5x). - -New scripts ------------ -- `binpatch`: the same as the stand-alone binpatch.exe, but works at runtime. -- region-pops: displays animal populations of the region and allows tweaking them. -- `lua`: lua interpreter front-end converted to a script from a native command. -- dfusion: misc scripts with a text based menu. -- embark: lets you embark anywhere. -- `lever`: list and pull fort levers from the dfhack console. -- `stripcaged`: mark items inside cages for dumping, eg caged goblin weapons. -- soundsense-season: writes the correct season to gamelog.txt on world load. -- create-items: spawn items -- fix/cloth-stockpile: fixes :bug:`5739`; needs to be run after savegame load every time. - -New GUI scripts ---------------- -- `gui/guide-path`: displays the cached path for minecart Guide orders. -- `gui/workshop-job`: displays inputs of a workshop job and allows tweaking them. -- `gui/workflow`: a front-end for the workflow plugin (part inspired by falconne). -- `gui/assign-rack`: works together with a binary patch to fix weapon racks. -- `gui/gm-editor`: an universal editor for lots of dfhack things. -- `gui/companion-order`: a adventure mode command interface for your companions. -- `gui/advfort`: a way to do jobs with your adventurer (e.g. build fort). - -New binary patches ------------------- -(for use with `binpatch`) - -- armorstand-capacity: doubles the capacity of armor stands. -- custom-reagent-size: lets custom reactions use small amounts of inputs. -- deconstruct-heapfall: stops some items still falling on head when deconstructing. -- deconstruct-teleport: stops items from 16x16 block teleporting when deconstructing. -- hospital-overstocking: stops hospital overstocking with supplies. -- training-ammo: lets dwarves with quiver full of combat-only ammo train. -- weaponrack-unassign: fixes bug that negates work done by gui/assign-rack. - -New Plugins ------------ -- `fix-armory`: Together with a couple of binary patches and the `gui/assign-rack` script, this plugin makes weapon racks, armor stands, chests and cabinets in properly designated barracks be used again for storage of squad equipment. -- `search`: Adds an incremental search function to the Stocks, Trading, Stockpile and Unit List screens. -- `automaterial`: Makes building constructions (walls, floors, fortifications, etc) a little bit easier by saving you from having to trawl through long lists of materials each time you place one. -- Dfusion: Reworked to make use of lua modules, now all the scripts can be used from other scripts. -- Eventful: A collection of lua events, that will allow new ways to interact with df world. - -DFHack v0.34.11-r2 -================== - -Internals ---------- -- full support for Mac OS X. -- a plugin that adds scripting in `ruby `. -- support for interposing virtual methods in DF from C++ plugins. -- support for creating new interface screens from C++ and lua. -- added various other API functions. - -Notable bugfixes ----------------- -- better terminal reset after exit on linux. -- `seedwatch` now works on reclaim. -- the sort plugin won't crash on cages anymore. - -Misc improvements ------------------ -- `autodump`: can move items to any walkable tile, not just floors. -- `stripcaged`: by default keep armor, new dumparmor option. -- `zone`: allow non-domesticated birds in nestboxes. -- `workflow`: quality range in constraints. -- cleanplants: new command to remove rain water from plants. -- `liquids`: can paint permaflow, i.e. what makes rivers power water wheels. -- `prospect`: pre-embark prospector accounts for caves & magma sea in its estimate. -- `rename`: supports renaming stockpiles, workshops, traps, siege engines. -- `fastdwarf`: now has an additional option to make dwarves teleport to their destination. -- `autolabor`: - - - can set nonidle hauler percentage. - - broker excluded from all labors when needed at depot. - - likewise, anybody with a scheduled diplomat meeting. - -New commands ------------- -- misery: multiplies every negative thought gained (2x by default). -- `digtype`: designates every tile of the same type of vein on the map for 'digging' (any dig designation). - -New tweaks ----------- -- tweak stable-cursor: keeps exact cursor position between d/k/t/q/v etc menus. -- tweak patrol-duty: makes Train orders reduce patrol timer, like the binary patch does. -- tweak readable-build-plate: fix unreadable truncation in unit pressure plate build ui. -- tweak stable-temp: fixes bug 6012; may improve FPS by 50-100% on a slow item-heavy fort. -- tweak fast-heat: speeds up item heating & cooling, thus making stable-temp act faster. -- tweak fix-dimensions: fixes subtracting small amounts from stacked liquids etc. -- tweak advmode-contained: fixes UI bug in custom reactions with container inputs in advmode. -- tweak fast-trade: Shift-Enter for selecting items quckly in Trade and Move to Depot screens. -- tweak military-stable-assign: Stop rightmost list of military->Positions from jumping to top. -- tweak military-color-assigned: In same list, color already assigned units in brown & green. - -New scripts ------------ -- `fixnaked`: removes thoughts about nakedness. -- `setfps`: set FPS cap at runtime, in case you want slow motion or speed-up. -- `siren`: wakes up units, stops breaks and parties - but causes bad thoughts. -- `fix/population-cap`: run after every migrant wave to prevent exceeding the cap. -- `fix/stable-temp`: counts items with temperature updates; does instant one-shot stable-temp. -- `fix/loyaltycascade`: fix units allegiance, eg after ordering a dwarf merchant kill. -- `deathcause`: shows the circumstances of death for a given body. -- `digfort`: designate areas to dig from a csv file. -- `drain-aquifer`: remove aquifers from the map. -- `growcrops`: cheat to make farm crops instantly grow. -- magmasource: continuously spawn magma from any map tile. -- removebadthoughts: delete all negative thoughts from your dwarves. -- slayrace: instakill all units of a given race, optionally with magma. -- `superdwarf`: per-creature `fastdwarf`. -- `gui/mechanisms`: browse mechanism links of the current building. -- `gui/room-list`: browse other rooms owned by the unit when assigning one. -- `gui/liquids`: a GUI front-end for the liquids plugin. -- `gui/rename`: renaming stockpiles, workshops and units via an in-game dialog. -- `gui/power-meter`: front-end for the Power Meter plugin. -- `gui/siege-engine`: front-end for the Siege Engine plugin. -- `gui/choose-weapons`: auto-choose matching weapons in the military equip screen. - -New Plugins ------------ -- `manipulator`: a Dwarf Therapist like UI in the game (:kbd:`u`:kbd:`l`) -- `steam-engine`: an alternative to Water Reactors which make more sense. - See ``hack/raw/*_steam_engine.txt`` for the necessary raw definitions. -- `power-meter`: a pressure plate modification to detect powered gear - boxes on adjacent tiles. `gui/power-meter` implements - the build configuration UI. -- `siege-engine`: massive overhaul for siege engines, configured via `gui/siege-engine` -- `add-spatter`: allows poison coatings via raw reactions, among other things. diff --git a/docs/Installing.rst b/docs/Installing.rst index 5b564f45f9..a687498e7e 100644 --- a/docs/Installing.rst +++ b/docs/Installing.rst @@ -1,168 +1,174 @@ .. _installing: -================= -Installing DFHack -================= +========== +Installing +========== .. contents:: :local: - Requirements ============ -DFHack supports Windows, Linux, and macOS, and both 64-bit and 32-bit builds -of Dwarf Fortress. +DFHack supports all operating systems and platforms that Dwarf Fortress itself +supports, which at the moment is the 64-bit versions of Windows and Linux. +The Windows build of DFHack also works well under ``wine`` for platforms that +can't run a native version. When running via ``wine``, use the following commandline:: + + wine64 explorer Dwarf\ Fortress.exe .. _installing-df-version: DFHack releases generally only support the version of Dwarf Fortress that they -are named after. For example, DFHack 0.40.24-r5 only supported DF 0.40.24. -DFHack releases *never* support newer versions of DF, because DFHack requires -data about DF that is only possible to obtain after DF has been released. -Occasionally, DFHack releases will be able to maintain support for older -versions of DF - for example, DFHack 0.34.11-r5 supported both DF 0.34.11 and -0.34.10. For maximum stability, you should usually use the latest versions of -both DF and DFHack. +are named after. For example, DFHack 50.05 only supported DF 50.05. DFHack +releases *never* support newer versions of DF -- DFHack requires data about DF +that is only possible to obtain after DF has been released. Occasionally, +DFHack releases will be able to maintain support for older versions of DF - for +example, DFHack 0.34.11-r5 supported both DF 0.34.11 and 0.34.10. For maximum +stability, you should use the latest versions of both DF and DFHack. -Windows -------- +.. _downloading: -* DFHack only supports the SDL version of Dwarf Fortress. The "legacy" version - will *not* work with DFHack (the "small" SDL version is acceptable, however). -* Windows XP and older are *not* supported, due in part to a - `Visual C++ 2015 bug `_ +Downloading DFHack +================== -The Windows build of DFHack should work under Wine on other operating systems, -although this is not tested very often. It is recommended to use the native -build for your operating system instead. +Stable builds of DFHack are available on +`Steam `__ +or from our `GitHub `__. Either +location will give you exactly the same package. -.. _installing-reqs-linux: +On Steam, note that DFHack is a separate app, not a DF Steam Workshop mod. You +can run DF with DFHack by launching either the DFHack app or the original Dwarf +Fortress app. -Linux ------ +Even if you have a non-Steam version of DF (i.e. Itch or Classic), you can +still install DFHack from Steam to get the benefits of automatic updates and +Steam cloud backups. In this case, install DFHack from Steam and then move your +DF installation into the Steam-created ``Dwarf Fortress`` directory. You have +to run DF via the DFHack app in the Steam client in order to benefit from the +Steam cloud backup features. -Generally, DFHack should work on any modern Linux distribution. There are -multiple release binaries provided - as of DFHack 0.47.04-r1, there are built -with GCC 7 and GCC 4.8 (as indicated by the ``gcc`` component of their -filenames). Using the newest build that works on your system is recommended. -The GCC 4.8 build is built on Ubuntu 14.04 and targets an older glibc, so it -should work on older distributions. +If you download from GitHub, downloads are available at the bottom of the +release notes for each release, under a section named "Assets" (which you may +have to expand). The name of the file indicates which DF version, platform, and +architecture the build supports - the platform and architecture (64-bit or +32-bit) **must** match your build of DF. The DF version should also match your +DF version - see `above ` for details. For example: -In the event that none of the provided binaries work on your distribution, -you may need to `compile DFHack from source `. +* ``dfhack-50.07-r1-Windows-64bit.zip`` supports 64-bit DF on Windows -macOS ------ +.. warning:: -OS X 10.6.8 or later is required. + Do *not* download the source code from GitHub, either from the releases page + or by clicking "Download ZIP" on the repo homepage. This will give you an + incomplete copy of the DFHack source code, which will not work as-is. (If + you want to compile DFHack instead of using a pre-built release, please see + `building-dfhack-index` for instructions.) +Beta releases +------------- -.. _downloading: +In between stable releases, we may create beta releases to test new features. +These are available via the ``beta`` release channel on Steam or from our +regular Github page as a pre-release tagged with a "beta" or "rc" ("release +candidate") suffix. -Downloading DFHack -================== +Development builds +------------------ -Stable builds of DFHack are available on `GitHub `_. -GitHub has been known to change their layout periodically, but as of July 2020, -downloads are available at the bottom of the release notes for each release, under a section -named "Assets" (which you may have to expand). The name of the file indicates -which DF version, platform, and architecture the build supports - the platform -and architecture (64-bit or 32-bit) **must** match your build of DF. The DF -version should also match your DF version - see `above ` -for details. For example: +If you are actively working with the DFHack team on testing a feature, you may +want to download and install a development build. They are available via the +``testing`` release channel on Steam or can be downloaded from the build +artifact list on GitHub for specific repository commits. -* ``dfhack-0.47.04-r1-Windows-64bit.zip`` supports 64-bit DF on Windows -* ``dfhack-0.47.04-r1-Linux-32bit-gcc-7.tar.bz2`` supports 32-bit DF on Linux - (see `installing-reqs-linux` for details on the GCC version indicator) +To download a development build from GitHub: -The `DFHack website `_ also provides links to -unstable builds. These files have a different naming scheme, but the same -restrictions apply (e.g. a file named ``Windows64`` is for 64-bit Windows DF). +- Ensure you are logged into your GitHub account +- Go to https://github.com/DFHack/dfhack/actions/workflows/build.yml?query=branch%3Adevelop+event%3Apush+is%3Asuccess +- Click on the first entry (it should have a green checkmark next to it) +- Click the number under "Artifacts" (or scroll down) +- Click on the ``dfhack-*-build-*`` artifact for your platform to download -.. warning:: +The artifacts are "double-zipped". That is, you will have to extract the +initial zip file to get to the package archive. You can extract this second +package the same as if you are doing a manual install (see the next section). - Do *not* download the source code from GitHub, either from the releases page - or by clicking "Download ZIP" on the repo homepage. This will give you an - incomplete copy of the DFHack source code, which will not work as-is. (If - you want to compile DFHack instead of using a pre-built release, see - `compile` for instructions.) +Older releases +-------------- + +If you are downloading DFHack for very old versions of DF, the binaries for +0.40.15-r1 to 0.34.11-r4 are on DFFD_. Even older versions are available here_. + +.. _DFFD: https://dffd.bay12games.com/search.php?string=DFHack&id=15&limit=1000 +.. _here: https://dethware.org/dfhack/download Installing DFHack ================= +If you are installing from Steam, this is handled for you automatically. The +instructions here are for manual installs. + When you `download DFHack `, you will end up with a release archive (a ``.zip`` file on Windows, or a ``.tar.bz2`` file on other platforms). Your operating system should have built-in utilities capable of extracting files from these archives. -The release archives contain several files and folders, including a ``hack`` -folder, a ``dfhack-config`` folder, and a ``dfhack.init-example`` file. To -install DFHack, copy all of the files from the DFHack archive into the root DF -folder, which should already include a ``data`` folder and a ``raw`` folder, -among other things. Some packs and other redistributions of Dwarf Fortress may -place DF in another folder, so ensure that the ``hack`` folder ends up next to -the ``data`` folder. - .. note:: - On Windows, installing DFHack will overwrite ``SDL.dll``. This is - intentional and necessary for DFHack to work, so be sure to choose to - overwrite ``SDL.dll`` if prompted. (If you are not prompted, you may be - installing DFHack in the wrong place.) - - -Uninstalling DFHack -=================== - -Uninstalling DFHack essentially involves reversing what you did to install -DFHack. On Windows, replace ``SDL.dll`` with ``SDLreal.dll`` first. Then, you -can remove any files that were part of the DFHack archive. DFHack does not -currently maintain a list of these files, so if you want to completely remove -them, you should consult the DFHack archive that you installed for a full list. -Generally, any files left behind should not negatively affect DF. + If you are on Windows, please remember to right click on the file after + downloading, open the file properties, and select the "Unblock" checkbox. + This will prevent issues with Windows antivirus programs. +The release archives contain a ``hack`` folder where DFHack binary and system +data is stored, a ``stonesense`` folder that contains data specific to the +`stonesense` 3d renderer, and various libraries and executable files. To +install DFHack, copy all of the files from the DFHack archive into the root DF +folder, which should already include a ``data`` folder and a ``save`` folder, +among other things. Some redistributions of Dwarf Fortress may place DF in +another folder, so ensure that the ``hack`` folder ends up next to the ``data`` +folder, and you'll be fine. -Upgrading DFHack -================ +Installing into a wineskin on Mac +--------------------------------- -The recommended approach to upgrade DFHack is to uninstall DFHack first, then -install the new version. This will ensure that any files that are only part -of the older DFHack installation do not affect the new DFHack installation -(although this is unlikely to occur). +Until DF (and DFHack) is natively available for Mac, you'll have to run the +Windows version under emulation. Here are the instructions for adding DFHack to +a wineskin that has DF installed in it: -It is also possible to overwrite an existing DFHack installation in-place. -To do this, follow the installation instructions above, but overwrite all files -that exist in the new DFHack archive (on Windows, this includes ``SDL.dll`` again). +#. Find the location of your existing Dwarf Fortress app (default is + ``/user/applications/Wineskin/``). Control + click and select "Show package + contents" from the menu. +#. Find the location of the ``Dwarf Fortress`` folder inside the package + contents (default is ``/drive_c/Program Files/``) +#. Copy the contents of the unzipped DFHack folder (Windows version) into the + ``Dwarf Fortress`` folder inside the package. -.. note:: +These instructions were last tested on Mac Sonoma 14.1.2. - You may wish to make a backup of your ``dfhack-config`` folder first if you - have made changes to it. Some archive managers (e.g. Archive Utility on macOS) - will overwrite the entire folder, removing any files that you have added. +Uninstalling DFHack +=================== +Just renaming or removing the ``dfhooks`` library files is enough to disable +DFHack. If you would like to remove all DFHack files, consult the DFHack install +archive to see the list of files and remove the corresponding files in the Dwarf +Fortress folder. Any DFHack files left behind will not negatively affect DF. -Pre-packaged DFHack installations -================================= +On Steam, uninstalling DFHack will cleanly remove everything that was installed +with DFHack, so there is nothing else for you to do. -There are :wiki:`several packs available ` that include -DF, DFHack, and other utilities. If you are new to Dwarf Fortress and DFHack, -these may be easier to set up. Note that these packs are not maintained by the -DFHack team and vary in their release schedules and contents. Some may make -significant configuration changes, and some may not include DFHack at all. +Note that Steam will leave behind the ``dfhack-config`` folder, which contains +all your personal DFHack-related settings and data. If you keep this folder, +all your settings will be restored when you reinstall DFHack later. -Linux packages -============== +Upgrading DFHack +================ -Third-party DFHack packages are available for some Linux distributions, -including in: +Again, if you have installed from Steam, your copy of DFHack will automatically +be kept up to date. This section is for manual installers. -* `AUR `__, for Arch and related - distributions -* `RPM Fusion `__, - for Fedora and related distributions +First, remove the ``hack`` and ``stonesense`` folders in their entirety. This +ensures that files that don't exist in the latest version are properly removed +and don't affect your new installation. -Note that these may lag behind DFHack releases. If you want to use a newer -version of DFHack, we generally recommended installing it in a clean copy of DF -in your home folder. Attempting to upgrade an installation of DFHack from a -package manager may break it. +Then, follow the instructions in the `Installing DFHack`_ section above, making +sure to choose to overwrite any remaining top-level files when extracting. diff --git a/docs/Introduction.rst b/docs/Introduction.rst index 27c887a8b8..8f3506dad5 100644 --- a/docs/Introduction.rst +++ b/docs/Introduction.rst @@ -1,34 +1,40 @@ .. _introduction: ######################### -Introduction and Overview +Introduction and overview ######################### DFHack is a Dwarf Fortress memory access library, distributed with a wide variety of useful scripts and plugins. -The project is currently hosted `on GitHub `_, -and can be downloaded from `the releases page `_ -- see `installing` for installation instructions. This is also where the -`DFHack bug tracker `_ is hosted. - -All new releases are announced in `the Bay12 forums thread `_, -which is also a good place for discussion and questions. +The project is hosted `on GitHub `__, +and can be downloaded from `the releases page `__ +-- see `installing` for installation instructions. This is also where the +`DFHack bug tracker `__ is hosted. If you would like +to download the DFHack documentation for offline viewing, you can do so by clicking +the expansion panel in the lower right corner of our +`online documentation `__ and selecting your desired format from +the "Downloads" section. + +New releases are announced in the +`DF subreddit `__, the +`DFHack Discord `__, and the +`Bay12 forums thread `__. Discussion and questions are also +welcome in each of these venues. For users, DFHack provides a significant suite of bugfixes and interface -enhancements by default, and more can be enabled. There are also many tools -(such as `workflow` or `autodump`) which can make life easier. -You can even add third-party scripts and plugins to do almost anything! +enhancements by default, and more features can be enabled as desired. There are +also many tools (such as `autofarm`) which automate aspects of gameplay many players +find toilsome. You can even add third-party scripts and plugins to do almost anything! -For modders, DFHack makes many things possible. Custom reactions, new -interactions, magic creature abilities, and more can be set through `scripts-modtools` -and custom raws. Non-standard DFHack scripts and inits can be stored in the -raw directory, making raws or saves fully self-contained for distribution - -or for coexistence in a single DF install, even with incompatible components. +For modders, DFHack makes many things possible. Custom reactions, new +interactions, magic creature abilities, and more can be set through `tools` +and custom raws. 3rd party DFHack scripts can be distributed `in mods ` +via the DF Steam Workshop or on the forums. For developers, DFHack unites the various ways tools access DF memory and -allows easier development of new tools. As an open-source project under -`various open-source licences `, contributions are welcome. +allows easier development of new tools. As an open-source project under +`various open-source licenses `, contributions are welcome. .. contents:: Contents @@ -37,29 +43,69 @@ allows easier development of new tools. As an open-source project under Getting started =============== -See `installing` for details on installing DFHack. + +See `installing` for details about installing DFHack. Once DFHack is installed, it extends DF with a console that can be used to run -commands. On Windows, this console will open automatically when DF is started. -On Linux and macOS, you will need to run the ``dfhack`` script from a terminal -(instead of the ``df`` script included with DF), and that terminal will be -used by the DFHack console. +commands. The in-game version of this console is called `gui/launcher`, and you +can bring it up at any time by hitting the backtick (\`) key (on most keyboards +this is the same as the tilde (~) key). There are also external consoles you can +open in a separate window. On Windows, you can show this console with the `show` +command. On Linux and macOS, you will need to run the ``dfhack`` script from a +terminal, and that terminal will be used as the DFHack console. + +Basic interaction with DFHack involves entering commands into the console. To +learn what commands are available, you can keep reading this documentation or +skip ahead and use the `ls` and `help` commands. The first command you should +run is likely `gui/control-panel` so you can set up which tools you would like +to enable now and which tools you want automatically started for new games. + +Another way to interact with DFHack is to set in-game `keybindings ` +to run commands in response to a hotkey. If you have specific commands that you +run frequently and that don't already have default keybindings, this can be a +better option than adding the command to the `gui/quickcmd` list. + +Commands can also run at startup via `init files `, or in batches +at other times with the `script` command. -* Basic interaction with DFHack involves entering commands into the console. To - learn what commands are available, you can keep reading this documentation or - skip ahead and use the `ls` and `help` commands. +Finally, some commands are persistent once enabled, and will sit in the +background managing or changing some aspect of the game if you `enable` them. -* Another way to interact with DFHack is to set in-game `keybindings ` - for certain commands. Many of the newer and user-friendly tools are designed - to be used this way. +.. note:: + In order to avoid user confusion, as a matter of policy all GUI tools + display the word :guilabel:`DFHack` on the screen somewhere while active. -* Commands can also run at startup via `init files `, - on in batches at other times with the `script` command. + When that is not appropriate because they merely add keybinding hints to + existing DF screens, they surround the added text or clickable buttons in red + square brackets. -* Finally, some commands are persistent once enabled, and will sit in the - background managing or changing some aspect of the game if you `enable` them. +For a more thorough introduction and guide through DFHack's capabilities, please see +the `quickstart`. +.. _support: Getting help ============ -There are several support channels available - see `support` for details. + +DFHack has several ways to get help online, including: + +- The `DFHack Discord server `__ +- GitHub: + - for bugs, use the :issue:`issue tracker <>` + - for more open-ended questions, use the `discussion board + `__. Note that this is a + relatively-new feature as of 2021, but maintainers should still be + notified of any discussions here. +- The `DFHack thread on the Bay 12 Forum `__ +- The `/r/dwarffortress `__ questions thread on Reddit + +When reaching out to any support channels regarding problems with DFHack, please +remember to provide enough details for others to identify the issue. For +instance, specific error messages (copied text or screenshots) are helpful, as +well as any steps you can follow to reproduce the problem. Log output from +``stderr.log`` in the DF folder can often help point to the cause of issues. + +Some common questions may also be answered in documentation, including: + +- This documentation (`online here `__; search functionality available `here `) +- :wiki:`The DF wiki <>` diff --git a/docs/Lua API.rst b/docs/Lua API.rst deleted file mode 100644 index 0b50695e53..0000000000 --- a/docs/Lua API.rst +++ /dev/null @@ -1,4642 +0,0 @@ -.. highlight:: lua - -.. _lua-api: - -############## -DFHack Lua API -############## - -DFHack has extensive support for -the Lua_ scripting language, providing access to: - -.. _Lua: https://www.lua.org - -1. Raw data structures used by the game. -2. Many C++ functions for high-level access to these - structures, and interaction with dfhack itself. -3. Some functions exported by C++ plugins. - -Lua code can be used both for writing scripts, which -are treated by DFHack command line prompt almost as -native C++ commands, and invoked by plugins written in C++. - -This document describes native API available to Lua in detail. -It does not describe all of the utility functions -implemented by Lua files located in :file:`hack/lua/*` -(:file:`library/lua/*` in the git repo). - - -.. contents:: Contents - :local: - :depth: 2 - - -========================= -DF data structure wrapper -========================= - -.. contents:: - :local: - -Data structures of the game are defined in XML files located in :file:`library/xml` -(and `online `_, and automatically exported -to lua code as a tree of objects and functions under the ``df`` global, which -also broadly maps to the ``df`` namespace in the headers generated for C++. - -.. warning:: - - The wrapper provides almost raw access to the memory of the game, so - mistakes in manipulating objects are as likely to crash the game as - equivalent plain C++ code would be - e.g. null pointer access is safely - detected, but dangling pointers aren't. - -Objects managed by the wrapper can be broadly classified into the following groups: - -1. Typed object pointers (references). - - References represent objects in DF memory with a known type. - - In addition to fields and methods defined by the wrapped type, - every reference has some built-in properties and methods. - -2. Untyped pointers - - Represented as lightuserdata. - - In assignment to a pointer NULL can be represented either as - ``nil``, or a NULL lightuserdata; reading a NULL pointer field - returns ``nil``. - -3. Named types - - Objects in the ``df`` tree that represent identity of struct, class, - enum and bitfield types. They host nested named types, static - methods, builtin properties & methods, and, for enums and bitfields, - the bi-directional mapping between key names and values. - -4. The ``global`` object - - ``df.global`` corresponds to the ``df::global`` namespace, and - behaves as a mix between a named type and a reference, containing - both nested types and fields corresponding to global symbols. - -In addition to the ``global`` object and top-level types the ``df`` -global also contains a few global builtin utility functions. - -Typed object references -======================= - -The underlying primitive lua object is userdata with a metatable. -Every structured field access produces a new userdata instance. - -All typed objects have the following built-in features: - -* ``ref1 == ref2``, ``tostring(ref)`` - - References implement equality by type & pointer value, and string conversion. - -* ``pairs(ref)`` - - Returns an iterator for the sequence of actual C++ field names - and values. Fields are enumerated in memory order. Methods and - lua wrapper properties are not included in the iteration. - - .. warning:: - a few of the data structures (like ui_look_list) - contain unions with pointers to different types with vtables. - Using pairs on such structs is an almost sure way to crash with - an access violation. - -* ``ref._kind`` - - Returns one of: ``primitive``, ``struct``, ``container``, - or ``bitfield``, as appropriate for the referenced object. - -* ``ref._type`` - - Returns the named type object or a string that represents - the referenced object type. - -* ``ref:sizeof()`` - - Returns *size, address* - -* ``ref:new()`` - - Allocates a new instance of the same type, and copies data - from the current object. - -* ``ref:delete()`` - - Destroys the object with the C++ ``delete`` operator. If the destructor is not - available, returns *false*. (This typically only occurs when trying to delete - an instance of a DF class with virtual methods whose vtable address has not - been found; it is impossible for ``delete()`` to determine the validity of - ``ref``.) - - .. warning:: - ``ref`` **must** be an object allocated with ``new``, like in C++. Calling - ``obj.field:delete()`` where ``obj`` was allocated with ``new`` will not - work. After ``delete()`` returns, ``ref`` remains as a dangling pointer, - like a raw C++ pointer would. Any accesses to ``ref`` after ``ref:delete()`` - has been called are undefined behavior. - -* ``ref:assign(object)`` - - Assigns data from object to ref. Object must either be another - ref of a compatible type, or a lua table; in the latter case - special recursive assignment rules are applied. - -* ``ref:_displace(index[,step])`` - - Returns a new reference with the pointer adjusted by index*step. - Step defaults to the natural object size. - -Primitive references --------------------- - -References of the *_kind* ``'primitive'`` are used for objects -that don't fit any of the other reference types. Such -references can only appear as a value of a pointer field, -or as a result of calling the ``_field()`` method. - -They behave as structs with a ``value`` field of the right type. If the -object's XML definition has a ``ref-target`` attribute, they will also have -a read-only ``ref_target`` field set to the corresponding type object. - -To make working with numeric buffers easier, they also allow -numeric indices. Note that other than excluding negative values -no bound checking is performed, since buffer length is not available. -Index 0 is equivalent to the ``value`` field. - - -Struct references ------------------ - -Struct references are used for class and struct objects. - -They implement the following features: - -* ``ref.field``, ``ref.field = value`` - - Valid fields of the structure may be accessed by subscript. - - Primitive typed fields, i.e. numbers & strings, are converted - to/from matching lua values. The value of a pointer is a reference - to the target, or ``nil``/NULL. Complex types are represented by - a reference to the field within the structure; unless recursive - lua table assignment is used, such fields can only be read. - - .. note:: - In case of inheritance, *superclass* fields have precedence - over the subclass, but fields shadowed in this way can still - be accessed as ``ref['subclasstype.field']``. - - This shadowing order is necessary because vtable-based classes - are automatically exposed in their exact type, and the reverse - rule would make access to superclass fields unreliable. - -* ``ref._field(field)`` - - Returns a reference to a valid field. That is, unlike regular - subscript, it returns a reference to the field within the structure - even for primitive typed fields and pointers. - -* ``ref:vmethod(args...)`` - - Named virtual methods are also exposed, subject to the same - shadowing rules. - -* ``pairs(ref)`` - - Enumerates all real fields (but not methods) in memory - order, which is the same as declaration order. - -Container references --------------------- - -Containers represent vectors and arrays, possibly resizable. - -A container field can associate an enum to the container -reference, which allows accessing elements using string keys -instead of numerical indices. - -Note that two-dimensional arrays in C++ (ie pointers to pointers) -are exposed to lua as one-dimensional. The best way to handle this -is probably ``array[x].value:_displace(y)``. - -Implemented features: - -* ``ref._enum`` - - If the container has an associated enum, returns the matching - named type object. - -* ``#ref`` - - Returns the *length* of the container. - -* ``ref[index]`` - - Accesses the container element, using either a *0-based* numerical - index, or, if an enum is associated, a valid enum key string. - - Accessing an invalid index is an error, but some container types - may return a default value, or auto-resize instead for convenience. - Currently this relaxed mode is implemented by df-flagarray aka BitArray. - -* ``ref._field(index)`` - - Like with structs, returns a pointer to the array element, if possible. - Flag and bit arrays cannot return such pointer, so it fails with an error. - -* ``pairs(ref)``, ``ipairs(ref)`` - - If the container has no associated enum, both behave identically, - iterating over numerical indices in order. Otherwise, ipairs still - uses numbers, while pairs tries to substitute enum keys whenever - possible. - -* ``ref:resize(new_size)`` - - Resizes the container if supported, or fails with an error. - -* ``ref:insert(index,item)`` - - Inserts a new item at the specified index. To add at the end, - use ``#ref``, or just ``'#'`` as index. - -* ``ref:erase(index)`` - - Removes the element at the given valid index. - -Bitfield references -------------------- - -Bitfields behave like special fixed-size containers. -Consider them to be something in between structs and -fixed-size vectors. - -The ``_enum`` property points to the bitfield type. -Numerical indices correspond to the shift value, -and if a subfield occupies multiple bits, the -``ipairs`` order would have a gap. - -Since currently there is no API to allocate a bitfield -object fully in GC-managed lua heap, consider using the -lua table assignment feature outlined below in order to -pass bitfield values to dfhack API functions that need -them, e.g. ``matinfo:matches{metal=true}``. - - -Named types -=========== - -Named types are exposed in the ``df`` tree with names identical -to the C++ version, except for the ``::`` vs ``.`` difference. - -All types and the global object have the following features: - -* ``type._kind`` - - Evaluates to one of ``struct-type``, ``class-type``, ``enum-type``, - ``bitfield-type`` or ``global``. - -* ``type._identity`` - - Contains a lightuserdata pointing to the underlying - ``DFHack::type_instance`` object. - -Types excluding the global object also support: - -* ``type:sizeof()`` - - Returns the size of an object of the type. - -* ``type:new()`` - - Creates a new instance of an object of the type. - -* ``type:is_instance(object)`` - - Returns true if object is same or subclass type, or a reference - to an object of same or subclass type. It is permissible to pass - ``nil``, NULL or non-wrapper value as object; in this case the - method returns ``nil``. - -In addition to this, enum and bitfield types contain a -bi-directional mapping between key strings and values, and -also map ``_first_item`` and ``_last_item`` to the min and -max values. - -Struct and class types with instance-vector attribute in the -xml have a ``type.find(key)`` function that wraps the find -method provided in C++. - -Global functions -================ - -The ``df`` table itself contains the following functions and values: - -* ``NULL``, ``df.NULL`` - - Contains the NULL lightuserdata. - -* ``df.isnull(obj)`` - - Evaluates to true if obj is nil or NULL; false otherwise. - -* ``df.isvalid(obj[,allow_null])`` - - For supported objects returns one of ``type``, ``voidptr``, ``ref``. - - If *allow_null* is true, and obj is nil or NULL, returns ``null``. - - Otherwise returns *nil*. - -* ``df.sizeof(obj)`` - - For types and refs identical to ``obj:sizeof()``. - For lightuserdata returns *nil, address* - -* ``df.new(obj)``, ``df.delete(obj)``, ``df.assign(obj, obj2)`` - - Equivalent to using the matching methods of obj. - -* ``df._displace(obj,index[,step])`` - - For refs equivalent to the method, but also works with - lightuserdata (step is mandatory then). - -* ``df.is_instance(type,obj)`` - - Equivalent to the method, but also allows a reference as proxy for its type. - -* ``df.new(ptype[,count])`` - - Allocate a new instance, or an array of built-in types. - The ``ptype`` argument is a string from the following list: - ``string``, ``int8_t``, ``uint8_t``, ``int16_t``, ``uint16_t``, - ``int32_t``, ``uint32_t``, ``int64_t``, ``uint64_t``, ``bool``, - ``float``, ``double``. All of these except ``string`` can be - used with the count argument to allocate an array. - -* ``df.reinterpret_cast(type,ptr)`` - - Converts ptr to a ref of specified type. The type may be anything - acceptable to ``df.is_instance``. Ptr may be *nil*, a ref, - a lightuserdata, or a number. - - Returns *nil* if NULL, or a ref. - -.. _lua-api-table-assignment: - -Recursive table assignment -========================== - -Recursive assignment is invoked when a lua table is assigned -to a C++ object or field, i.e. one of: - -* ``ref:assign{...}`` -* ``ref.field = {...}`` - -The general mode of operation is that all fields of the table -are assigned to the fields of the target structure, roughly -emulating the following code:: - - function rec_assign(ref,table) - for key,value in pairs(table) do - ref[key] = value - end - end - -Since assigning a table to a field using = invokes the same -process, it is recursive. - -There are however some variations to this process depending -on the type of the field being assigned to: - -1. If the table contains an ``assign`` field, it is - applied first, using the ``ref:assign(value)`` method. - It is never assigned as a usual field. - -2. When a table is assigned to a non-NULL pointer field - using the ``ref.field = {...}`` syntax, it is applied - to the target of the pointer instead. - - If the pointer is NULL, the table is checked for a ``new`` field: - - a. If it is *nil* or *false*, assignment fails with an error. - - b. If it is *true*, the pointer is initialized with a newly - allocated object of the declared target type of the pointer. - - c. Otherwise, ``table.new`` must be a named type, or an - object of a type compatible with the pointer. The pointer - is initialized with the result of calling ``table.new:new()``. - - After this auto-vivification process, assignment proceeds - as if the pointer wasn't NULL. - - Obviously, the ``new`` field inside the table is always skipped - during the actual per-field assignment processing. - -3. If the target of the assignment is a container, a separate - rule set is used: - - a. If the table contains neither ``assign`` nor ``resize`` - fields, it is interpreted as an ordinary *1-based* lua - array. The container is resized to the #-size of the - table, and elements are assigned in numeric order:: - - ref:resize(#table); - for i=1,#table do ref[i-1] = table[i] end - - b. Otherwise, ``resize`` must be *true*, *false*, or - an explicit number. If it is not false, the container - is resized. After that the usual struct-like 'pairs' - assignment is performed. - - In case ``resize`` is *true*, the size is computed - by scanning the table for the largest numeric key. - - This means that in order to reassign only one element of - a container using this system, it is necessary to use:: - - { resize=false, [idx]=value } - -Since ``nil`` inside a table is indistinguishable from missing key, -it is necessary to use ``df.NULL`` as a null pointer value. - -This system is intended as a way to define a nested object -tree using pure lua data structures, and then materialize it in -C++ memory in one go. Note that if pointer auto-vivification -is used, an error in the middle of the recursive walk would -not destroy any objects allocated in this way, so the user -should be prepared to catch the error and do the necessary -cleanup. - -========== -DFHack API -========== - -.. contents:: - :local: - -DFHack utility functions are placed in the ``dfhack`` global tree. - -Native utilities -================ - -Input & Output --------------- - -* ``dfhack.print(args...)`` - - Output tab-separated args as standard lua print would do, - but without a newline. - -* ``print(args...)``, ``dfhack.println(args...)`` - - A replacement of the standard library print function that - works with DFHack output infrastructure. - -* ``dfhack.printerr(args...)`` - - Same as println; intended for errors. Uses red color and logs to stderr.log. - -* ``dfhack.color([color])`` - - Sets the current output color. If color is *nil* or *-1*, resets to default. - Returns the previous color value. - -* ``dfhack.is_interactive()`` - - Checks if the thread can access the interactive console and returns *true* or *false*. - -* ``dfhack.lineedit([prompt[,history_filename]])`` - - If the thread owns the interactive console, shows a prompt - and returns the entered string. Otherwise returns *nil, error*. - - Depending on the context, this function may actually yield the - running coroutine and let the C++ code release the core suspend - lock. Using an explicit ``dfhack.with_suspend`` will prevent - this, forcing the function to block on input with lock held. - -* ``dfhack.interpreter([prompt[,history_filename[,env]]])`` - - Starts an interactive lua interpreter, using the specified prompt - string, global environment and command-line history file. - - If the interactive console is not accessible, returns *nil, error*. - - -Exception handling ------------------- - -* ``dfhack.error(msg[,level[,verbose]])`` - - Throws a dfhack exception object with location and stack trace. - The verbose parameter controls whether the trace is printed by default. - -* ``qerror(msg[,level])`` - - Calls ``dfhack.error()`` with ``verbose`` being *false*. Intended to - be used for user-caused errors in scripts, where stack traces are not - desirable. - -* ``dfhack.pcall(f[,args...])`` - - Invokes f via xpcall, using an error function that attaches - a stack trace to the error. The same function is used by SafeCall - in C++, and dfhack.safecall. - -* ``safecall(f[,args...])``, ``dfhack.safecall(f[,args...])`` - - Just like pcall, but also prints the error using printerr before - returning. Intended as a convenience function. - -* ``dfhack.saferesume(coroutine[,args...])`` - - Compares to coroutine.resume like dfhack.safecall vs pcall. - -* ``dfhack.exception`` - - Metatable of error objects used by dfhack. The objects have the - following properties: - - ``err.where`` - The location prefix string, or *nil*. - ``err.message`` - The base message string. - ``err.stacktrace`` - The stack trace string, or *nil*. - ``err.cause`` - A different exception object, or *nil*. - ``err.thread`` - The coroutine that has thrown the exception. - ``err.verbose`` - Boolean, or *nil*; specifies if where and stacktrace should be printed. - ``tostring(err)``, or ``err:tostring([verbose])`` - Converts the exception to string. - -* ``dfhack.exception.verbose`` - - The default value of the ``verbose`` argument of ``err:tostring()``. - - -Miscellaneous -------------- - -* ``dfhack.VERSION`` - - DFHack version string constant. - -* ``dfhack.curry(func,args...)``, or ``curry(func,args...)`` - - Returns a closure that invokes the function with args combined - both from the curry call and the closure call itself. I.e. - ``curry(func,a,b)(c,d)`` equals ``func(a,b,c,d)``. - - -Locking and finalization ------------------------- - -* ``dfhack.with_suspend(f[,args...])`` - - Calls ``f`` with arguments after grabbing the DF core suspend lock. - Suspending is necessary for accessing a consistent state of DF memory. - - Returned values and errors are propagated through after releasing - the lock. It is safe to nest suspends. - - Every thread is allowed only one suspend per DF frame, so it is best - to group operations together in one big critical section. A plugin - can choose to run all lua code inside a C++-side suspend lock. - -* ``dfhack.call_with_finalizer(num_cleanup_args,always,cleanup_fn[,cleanup_args...],fn[,args...])`` - - Invokes ``fn`` with ``args``, and after it returns or throws an - error calls ``cleanup_fn`` with ``cleanup_args``. Any return values from - ``fn`` are propagated, and errors are re-thrown. - - The ``num_cleanup_args`` integer specifies the number of ``cleanup_args``, - and the ``always`` boolean specifies if cleanup should be called in any case, - or only in case of an error. - -* ``dfhack.with_finalize(cleanup_fn,fn[,args...])`` - - Calls ``fn`` with arguments, then finalizes with ``cleanup_fn``. - Implemented using ``call_with_finalizer(0,true,...)``. - -* ``dfhack.with_onerror(cleanup_fn,fn[,args...])`` - - Calls ``fn`` with arguments, then finalizes with ``cleanup_fn`` on any thrown error. - Implemented using ``call_with_finalizer(0,false,...)``. - -* ``dfhack.with_temp_object(obj,fn[,args...])`` - - Calls ``fn(obj,args...)``, then finalizes with ``obj:delete()``. - - -Persistent configuration storage --------------------------------- - -This api is intended for storing configuration options in the world itself. -It probably should be restricted to data that is world-dependent. - -Entries are identified by a string ``key``, but it is also possible to manage -multiple entries with the same key; their identity is determined by ``entry_id``. -Every entry has a mutable string ``value``, and an array of 7 mutable ``ints``. - -* ``dfhack.persistent.get(key)``, ``entry:get()`` - - Retrieves a persistent config record with the given string key, - or refreshes an already retrieved entry. If there are multiple - entries with the same key, it is undefined which one is retrieved - by the first version of the call. - - Returns entry, or *nil* if not found. - -* ``dfhack.persistent.delete(key)``, ``entry:delete()`` - - Removes an existing entry. Returns *true* if succeeded. - -* ``dfhack.persistent.get_all(key[,match_prefix])`` - - Retrieves all entries with the same key, or starting with key..'/'. - Calling ``get_all('',true)`` will match all entries. - - If none found, returns nil; otherwise returns an array of entries. - -* ``dfhack.persistent.save({key=str1, ...}[,new])``, ``entry:save([new])`` - - Saves changes in an entry, or creates a new one. Passing true as - new forces creation of a new entry even if one already exists; - otherwise the existing one is simply updated. - Returns *entry, did_create_new* - -Since the data is hidden in data structures owned by the DF world, -and automatically stored in the save game, these save and retrieval -functions can just copy values in memory without doing any actual I/O. -However, currently every entry has a 180+-byte dead-weight overhead. - -It is also possible to associate one bit per map tile with an entry, -using these two methods: - -* ``entry:getTilemask(block[, create])`` - - Retrieves the tile bitmask associated with this entry in the given map - block. If ``create`` is *true*, an empty mask is created if none exists; - otherwise the function returns *nil*, which must be assumed to be the same - as an all-zero mask. - -* ``entry:deleteTilemask(block)`` - - Deletes the associated tile mask from the given map block. - -Note that these masks are only saved in fortress mode, and also that deleting -the persistent entry will **NOT** delete the associated masks. - - -Material info lookup --------------------- - -A material info record has fields: - -* ``type``, ``index``, ``material`` - - DF material code pair, and a reference to the material object. - -* ``mode`` - - One of ``'builtin'``, ``'inorganic'``, ``'plant'``, ``'creature'``. - -* ``inorganic``, ``plant``, ``creature`` - - If the material is of the matching type, contains a reference to the raw object. - -* ``figure`` - - For a specific creature material contains a ref to the historical figure. - -Functions: - -* ``dfhack.matinfo.decode(type,index)`` - - Looks up material info for the given number pair; if not found, returs *nil*. - -* ``....decode(matinfo)``, ``....decode(item)``, ``....decode(obj)`` - - Uses ``matinfo.type``/``matinfo.index``, item getter vmethods, - or ``obj.mat_type``/``obj.mat_index`` to get the code pair. - -* ``dfhack.matinfo.find(token[,token...])`` - - Looks up material by a token string, or a pre-split string token sequence. - -* ``dfhack.matinfo.getToken(...)``, ``info:getToken()`` - - Applies ``decode`` and constructs a string token. - -* ``info:toString([temperature[,named]])`` - - Returns the human-readable name at the given temperature. - -* ``info:getCraftClass()`` - - Returns the classification used for craft skills. - -* ``info:matches(obj)`` - - Checks if the material matches job_material_category or job_item. - Accept dfhack_material_category auto-assign table. - -.. _lua_api_random: - -Random number generation ------------------------- - -* ``dfhack.random.new([seed[,perturb_count]])`` - - Creates a new random number generator object. Without any - arguments, the object is initialized using current time. - Otherwise, the seed must be either a non-negative integer, - or a list of such integers. The second argument may specify - the number of additional randomization steps performed to - improve the initial state. - -* ``rng:init([seed[,perturb_count]])`` - - Re-initializes an already existing random number generator object. - -* ``rng:random([limit])`` - - Returns a random integer. If ``limit`` is specified, the value - is in the range [0, limit); otherwise it uses the whole 32-bit - unsigned integer range. - -* ``rng:drandom()`` - - Returns a random floating-point number in the range [0,1). - -* ``rng:drandom0()`` - - Returns a random floating-point number in the range (0,1). - -* ``rng:drandom1()`` - - Returns a random floating-point number in the range [0,1]. - -* ``rng:unitrandom()`` - - Returns a random floating-point number in the range [-1,1]. - -* ``rng:unitvector([size])`` - - Returns multiple values that form a random vector of length 1, - uniformly distributed over the corresponding sphere surface. - The default size is 3. - -* ``fn = rng:perlin([dim]); fn(x[,y[,z]])`` - - Returns a closure that computes a classical Perlin noise function - of dimension *dim*, initialized from this random generator. - Dimension may be 1, 2 or 3 (default). - - -.. _lua-cpp-func-wrappers: - -C++ function wrappers -===================== - -.. contents:: - :local: - -Thin wrappers around C++ functions, similar to the ones for virtual methods. -One notable difference is that these explicit wrappers allow argument count -adjustment according to the usual lua rules, so trailing false/nil arguments -can be omitted. - -* ``dfhack.getOSType()`` - - Returns the OS type string from ``symbols.xml``. - -* ``dfhack.getDFVersion()`` - - Returns the DF version string from ``symbols.xml``. - -* ``dfhack.getDFHackVersion()`` -* ``dfhack.getDFHackRelease()`` -* ``dfhack.getDFHackBuildID()`` -* ``dfhack.getCompiledDFVersion()`` -* ``dfhack.getGitDescription()`` -* ``dfhack.getGitCommit()`` -* ``dfhack.getGitXmlCommit()`` -* ``dfhack.getGitXmlExpectedCommit()`` -* ``dfhack.gitXmlMatch()`` -* ``dfhack.isRelease()`` - - Return information about the DFHack build in use. - - .. note:: - ``getCompiledDFVersion()`` returns the DF version specified at compile time, - while ``getDFVersion()`` returns the version and typically the OS as well. - These do not necessarily match - for example, DFHack 0.34.11-r5 worked with - DF 0.34.10 and 0.34.11, so the former function would always return ``0.34.11`` - while the latter would return ``v0.34.10 `` or ``v0.34.11 ``. - -* ``dfhack.getDFPath()`` - - Returns the DF directory path. - -* ``dfhack.getHackPath()`` - - Returns the dfhack directory path, i.e. ``".../df/hack/"``. - -* ``dfhack.getSavePath()`` - - Returns the path to the current save directory, or *nil* if no save loaded. - -* ``dfhack.getTickCount()`` - - Returns the tick count in ms, exactly as DF ui uses. - -* ``dfhack.isWorldLoaded()`` - - Checks if the world is loaded. - -* ``dfhack.isMapLoaded()`` - - Checks if the world and map are loaded. - -* ``dfhack.TranslateName(name[,in_english,only_last_name])`` - - Convert a language_name or only the last name part to string. - -* ``dfhack.df2utf(string)`` - - Convert a string from DF's CP437 encoding to UTF-8. - -* ``dfhack.df2console()`` - - Convert a string from DF's CP437 encoding to the correct encoding for the - DFHack console. - -.. warning:: - - When printing CP437-encoded text to the console (for example, names returned - from ``dfhack.TranslateName()``), use ``print(dfhack.df2console(text))`` to - ensure proper display on all platforms. - - -* ``dfhack.utf2df(string)`` - - Convert a string from UTF-8 to DF's CP437 encoding. - -* ``dfhack.toSearchNormalized(string)`` - - Replace non-ASCII alphabetic characters in a CP437-encoded string with their - nearest ASCII equivalents, if possible, and returns a CP437-encoded string. - Note that the returned string may be longer than the input string. For - example, ``ä`` is replaced with ``a``, and ``æ`` is replaced with ``ae``. - -* ``dfhack.run_command(command[, ...])`` - - Run an arbitrary DFHack command, with the core suspended, and send output to - the DFHack console. The command can be passed as a table, multiple string - arguments, or a single string argument (not recommended - in this case, the - usual DFHack console tokenization is used). - - A ``command_result`` constant starting with ``CR_`` is returned, where ``CR_OK`` - indicates success. - - The following examples are equivalent:: - - dfhack.run_command({'ls', '-a'}) - dfhack.run_command('ls', '-a') - dfhack.run_command('ls -a') -- not recommended - -* ``dfhack.run_command_silent(command[, ...])`` - - Similar to ``run_command()``, but instead of printing to the console, - returns an ``output, command_result`` pair. ``output`` is a single string - - see ``dfhack.internal.runCommand()`` to obtain colors as well. - -Gui module ----------- - -Screens -~~~~~~~ - -* ``dfhack.gui.getCurViewscreen([skip_dismissed])`` - - Returns the topmost viewscreen. If ``skip_dismissed`` is *true*, - ignores screens already marked to be removed. - -* ``dfhack.gui.getFocusString(viewscreen)`` - - Returns a string representation of the current focus position - in the ui. The string has a "screen/foo/bar/baz..." format. - -* ``dfhack.gui.getCurFocus([skip_dismissed])`` - - Returns the focus string of the current viewscreen. - -* ``dfhack.gui.getViewscreenByType(type [, depth])`` - - Returns the topmost viewscreen out of the top ``depth`` viewscreens with - the specified type (e.g. ``df.viewscreen_titlest``), or ``nil`` if none match. - If ``depth`` is not specified or is less than 1, all viewscreens are checked. - -General-purpose selections -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -* ``dfhack.gui.getSelectedWorkshopJob([silent])`` - - When a job is selected in :kbd:`q` mode, returns the job, else - prints error unless silent and returns *nil*. - -* ``dfhack.gui.getSelectedJob([silent])`` - - Returns the job selected in a workshop or unit/jobs screen. - -* ``dfhack.gui.getSelectedUnit([silent])`` - - Returns the unit selected via :kbd:`v`, :kbd:`k`, unit/jobs, or - a full-screen item view of a cage or suchlike. - -* ``dfhack.gui.getSelectedItem([silent])`` - - Returns the item selected via :kbd:`v` ->inventory, :kbd:`k`, :kbd:`t`, or - a full-screen item view of a container. Note that in the - last case, the highlighted *contained item* is returned, not - the container itself. - -* ``dfhack.gui.getSelectedBuilding([silent])`` - - Returns the building selected via :kbd:`q`, :kbd:`t`, :kbd:`k` or :kbd:`i`. - -* ``dfhack.gui.getSelectedPlant([silent])`` - - Returns the plant selected via :kbd:`k`. - -* ``dfhack.gui.getAnyUnit(screen)`` -* ``dfhack.gui.getAnyItem(screen)`` -* ``dfhack.gui.getAnyBuilding(screen)`` -* ``dfhack.gui.getAnyPlant(screen)`` - - Similar to the corresponding ``getSelected`` functions, but operate on the - screen given instead of the current screen and always return ``nil`` silently - on failure. - -Fortress mode -~~~~~~~~~~~~~ - -* ``dfhack.gui.getDwarfmodeViewDims()`` - - Returns dimensions of the main fortress mode screen. See ``getPanelLayout()`` - in the ``gui.dwarfmode`` module for a more Lua-friendly version. - -* ``dfhack.gui.resetDwarfmodeView([pause])`` - - Resets the fortress mode sidebar menus and cursors to their default state. If - ``pause`` is true, also pauses the game. - -* ``dfhack.gui.revealInDwarfmodeMap(pos)`` - - Centers the view on the given position, which can be a ``df.coord`` instance - or a table assignable to a ``df.coord`` (see `lua-api-table-assignment`), - e.g.:: - - {x = 5, y = 7, z = 11} - getSelectedUnit().pos - copyall(df.global.cursor) - - Returns false if unsuccessful. - -* ``dfhack.gui.refreshSidebar()`` - - Refreshes the fortress mode sidebar. This can be useful when making changes to - the map, for example, because DF only updates the sidebar when the cursor - position changes. - -* ``dfhack.gui.inRenameBuilding()`` - - Returns ``true`` if a building is being renamed. - -Announcements -~~~~~~~~~~~~~ - -* ``dfhack.gui.writeToGamelog(text)`` - - Writes a string to :file:`gamelog.txt` without doing an announcement. - -* ``dfhack.gui.makeAnnouncement(type,flags,pos,text,color[,is_bright])`` - - Adds an announcement with given announcement_type, text, color, and brightness. - The is_bright boolean actually seems to invert the brightness. - - The announcement is written to :file:`gamelog.txt`. The announcement_flags - argument provides a custom set of :file:`announcements.txt` options, - which specify if the message should actually be displayed in the - announcement list, and whether to recenter or show a popup. - - Returns the index of the new announcement in ``df.global.world.status.reports``, or -1. - -* ``dfhack.gui.addCombatReport(unit,slot,report_index)`` - - Adds the report with the given index (returned by makeAnnouncement) - to the specified group of the given unit. Returns *true* on success. - -* ``dfhack.gui.addCombatReportAuto(unit,flags,report_index)`` - - Adds the report with the given index to the appropriate group(s) - of the given unit, as requested by the flags. - -* ``dfhack.gui.showAnnouncement(text,color[,is_bright])`` - - Adds a regular announcement with given text, color, and brightness. - The is_bright boolean actually seems to invert the brightness. - -* ``dfhack.gui.showZoomAnnouncement(type,pos,text,color[,is_bright])`` - - Like above, but also specifies a position you can zoom to from the announcement menu. - -* ``dfhack.gui.showPopupAnnouncement(text,color[,is_bright])`` - - Pops up a titan-style modal announcement window. - -* ``dfhack.gui.showAutoAnnouncement(type,pos,text,color[,is_bright,unit1,unit2])`` - - Uses the type to look up options from announcements.txt, and calls the above - operations accordingly. The units are used to call ``addCombatReportAuto``. - -Other -~~~~~ - -* ``dfhack.gui.getDepthAt(x, y)`` - - Returns the distance from the z-level of the tile at map coordinates (x, y) to - the closest ground z-level below. Defaults to 0, unless overriden by plugins. - -Job module ----------- - -* ``dfhack.job.cloneJobStruct(job)`` - - Creates a deep copy of the given job. - -* ``dfhack.job.printJobDetails(job)`` - - Prints info about the job. - -* ``dfhack.job.printItemDetails(jobitem,idx)`` - - Prints info about the job item. - -* ``dfhack.job.getGeneralRef(job, type)`` - - Searches for a general_ref with the given type. - -* ``dfhack.job.getSpecificRef(job, type)`` - - Searches for a specific_ref with the given type. - -* ``dfhack.job.getHolder(job)`` - - Returns the building holding the job. - -* ``dfhack.job.getWorker(job)`` - - Returns the unit performing the job. - -* ``dfhack.job.setJobCooldown(building,worker,cooldown)`` - - Prevent the worker from taking jobs at the specified workshop for the - specified cooldown period (in ticks). This doesn't decrease the cooldown - period in any circumstances. - -* ``dfhack.job.removeWorker(job,cooldown)`` - - Removes the worker from the specified workshop job, and sets the cooldown - period (using the same logic as ``setJobCooldown``). Returns *true* on - success. - -* ``dfhack.job.checkBuildingsNow()`` - - Instructs the game to check buildings for jobs next frame and assign workers. - -* ``dfhack.job.checkDesignationsNow()`` - - Instructs the game to check designations for jobs next frame and assign workers. - -* ``dfhack.job.is_equal(job1,job2)`` - - Compares important fields in the job and nested item structures. - -* ``dfhack.job.is_item_equal(job_item1,job_item2)`` - - Compares important fields in the job item structures. - -* ``dfhack.job.linkIntoWorld(job,new_id)`` - - Adds job into ``df.global.job_list``, and if new_id - is true, then also sets its id and increases - ``df.global.job_next_id`` - -* ``dfhack.job.listNewlyCreated(first_id)`` - - Returns the current value of ``df.global.job_next_id``, and - if there are any jobs with ``first_id <= id < job_next_id``, - a lua list containing them. - -* ``dfhack.job.isSuitableItem(job_item, item_type, item_subtype)`` - - Does basic sanity checks to verify if the suggested item type matches - the flags in the job item. - -* ``dfhack.job.isSuitableMaterial(job_item, mat_type, mat_index, item_type)`` - - Likewise, if replacing material. - -* ``dfhack.job.getName(job)`` - - Returns the job's description, as seen in the Units and Jobs screens. - -Units module ------------- - -* ``dfhack.units.getPosition(unit)`` - - Returns true *x,y,z* of the unit, or *nil* if invalid; may be not equal to unit.pos if caged. - -* ``dfhack.units.getUnitsInBox(x1,y1,z1,x2,y2,z2[,filter])`` - - Returns a table of all units within the specified coordinates. If the ``filter`` - argument is given, only units where ``filter(unit)`` returns true will be included. - Note that ``pos2xyz()`` cannot currently be used to convert coordinate objects to - the arguments required by this function. - -* ``dfhack.units.teleport(unit, pos)`` - - Moves the specified unit and any riders to the target coordinates, setting - tile occupancy flags appropriately. Returns true if successful. - -* ``dfhack.units.getGeneralRef(unit, type)`` - - Searches for a general_ref with the given type. - -* ``dfhack.units.getSpecificRef(unit, type)`` - - Searches for a specific_ref with the given type. - -* ``dfhack.units.getContainer(unit)`` - - Returns the container (cage) item or *nil*. - -* ``dfhack.units.setNickname(unit,nick)`` - - Sets the unit's nickname properly. - -* ``dfhack.units.getVisibleName(unit)`` - - Returns the language_name object visible in game, accounting for false identities. - -* ``dfhack.units.getIdentity(unit)`` - - Returns the false identity of the unit if it has one, or *nil*. - -* ``dfhack.units.getNemesis(unit)`` - - Returns the nemesis record of the unit if it has one, or *nil*. - -* ``dfhack.units.isHidingCurse(unit)`` - - Checks if the unit hides improved attributes from its curse. - -* ``dfhack.units.getPhysicalAttrValue(unit, attr_type)`` -* ``dfhack.units.getMentalAttrValue(unit, attr_type)`` - - Computes the effective attribute value, including curse effect. - -* ``dfhack.units.isCrazed(unit)`` -* ``dfhack.units.isOpposedToLife(unit)`` -* ``dfhack.units.hasExtravision(unit)`` -* ``dfhack.units.isBloodsucker(unit)`` - - Simple checks of caste attributes that can be modified by curses. - -* ``dfhack.units.getMiscTrait(unit, type[, create])`` - - Finds (or creates if requested) a misc trait object with the given id. - -* ``dfhack.units.isActive(unit)`` - - The unit is active (alive and on the map). - -* ``dfhack.units.isAlive(unit)`` - - The unit isn't dead or undead. - -* ``dfhack.units.isDead(unit)`` - - The unit is completely dead and passive, or a ghost. Equivalent to - ``dfhack.units.isKilled(unit) or dfhack.units.isGhost(unit)``. - -* ``dfhack.units.isKilled(unit)`` - - The unit has been killed. - -* ``dfhack.units.isGhost(unit)`` - - The unit is a ghost. - -* ``dfhack.units.isSane(unit)`` - - The unit is capable of rational action, i.e. not dead, insane, zombie, or active werewolf. - -* ``dfhack.units.isDwarf(unit)`` - - The unit is of the correct race of the fortress. - -* ``dfhack.units.isCitizen(unit)`` - - The unit is an alive sane citizen of the fortress; wraps the - same checks the game uses to decide game-over by extinction. - -* ``dfhack.units.isVisible(unit)`` - - The unit is visible on the map. - -* ``dfhack.units.getAge(unit[,true_age])`` - - Returns the age of the unit in years as a floating-point value. - If ``true_age`` is true, ignores false identities. - -* ``dfhack.units.isValidLabor(unit, unit_labor)`` - - Returns whether the indicated labor is settable for the given unit. - -* ``dfhack.units.setLaborValidity(unit_labor, isValid)`` - - Sets the given labor to the given (boolean) validity for all units that are - part of your fortress civilization. Valid labors are allowed to be toggled - in the in-game labor management screens (including DFHack's `labor manipulator - screen `). - -* ``dfhack.units.getNominalSkill(unit, skill[, use_rust])`` - - Retrieves the nominal skill level for the given unit. If ``use_rust`` - is *true*, subtracts the rust penalty. - -* ``dfhack.units.getEffectiveSkill(unit, skill)`` - - Computes the effective rating for the given skill, taking into account exhaustion, pain etc. - -* ``dfhack.units.getExperience(unit, skill[, total])`` - - Returns the experience value for the given skill. If ``total`` is true, adds experience implied by the current rating. - -* ``dfhack.units.computeMovementSpeed(unit)`` - - Computes number of frames * 100 it takes the unit to move in its current state of mind and body. - -* ``dfhack.units.computeSlowdownFactor(unit)`` - - Meandering and floundering in liquid introduces additional slowdown. It is - random, but the function computes and returns the expected mean factor as a float. - -* ``dfhack.units.getNoblePositions(unit)`` - - Returns a list of tables describing noble position assignments, or *nil*. - Every table has fields ``entity``, ``assignment`` and ``position``. - -* ``dfhack.units.getProfessionName(unit[,ignore_noble,plural])`` - - Retrieves the profession name using custom profession, noble assignments - or raws. The ``ignore_noble`` boolean disables the use of noble positions. - -* ``dfhack.units.getCasteProfessionName(race,caste,prof_id[,plural])`` - - Retrieves the profession name for the given race/caste using raws. - -* ``dfhack.units.getProfessionColor(unit[,ignore_noble])`` - - Retrieves the color associated with the profession, using noble assignments - or raws. The ``ignore_noble`` boolean disables the use of noble positions. - -* ``dfhack.units.getCasteProfessionColor(race,caste,prof_id)`` - - Retrieves the profession color for the given race/caste using raws. - -* ``dfhack.units.getGoalType(unit[,goalIndex])`` - - Retrieves the goal type of the dream that the given unit has. - By default the goal of the first dream is returned. - The goalIndex parameter may be used to retrieve additional dream goals. - Currently only one dream per unit is supported by Dwarf Fortress. - Support for multiple dreams may be added in future versions of Dwarf Fortress. - -* ``dfhack.units.getGoalName(unit[,goalIndex])`` - - Retrieves the short name describing the goal of the dream that the given unit has. - By default the goal of the first dream is returned. - The goalIndex parameter may be used to retrieve additional dream goals. - Currently only one dream per unit is supported by Dwarf Fortress. - Support for multiple dreams may be added in future versions of Dwarf Fortress. - -* ``dfhack.units.isGoalAchieved(unit[,goalIndex])`` - - Checks if given unit has achieved the goal of the dream. - By default the status of the goal of the first dream is returned. - The goalIndex parameter may be used to check additional dream goals. - Currently only one dream per unit is supported by Dwarf Fortress. - Support for multiple dreams may be added in future versions of Dwarf Fortress. - -* ``dfhack.units.getStressCategory(unit)`` - - Returns a number from 0-6 indicating stress. 0 is most stressed; 6 is least. - Note that 0 is guaranteed to remain the most stressed but 6 could change in the future. - -* ``dfhack.units.getStressCategoryRaw(stress_level)`` - - Identical to ``getStressCategory`` but takes a raw stress level instead of a unit. - -* ``dfhack.units.getStressCutoffs()`` - - Returns a table of the cutoffs used by the above stress level functions. - -Items module ------------- - -* ``dfhack.items.getPosition(item)`` - - Returns true *x,y,z* of the item, or *nil* if invalid; may be not equal to item.pos if in inventory. - -* ``dfhack.items.getBookTitle(item)`` - - Returns the title of the "book" item, or an empty string if the item isn't a "book" or it doesn't - have a title. A "book" is a codex or a tool item that has page or writings improvements, such as - scrolls and quires. - -* ``dfhack.items.getDescription(item, type[, decorate])`` - - Returns the string description of the item, as produced by the ``getItemDescription`` - method. If decorate is true, also adds markings for quality and improvements. - -* ``dfhack.items.getGeneralRef(item, type)`` - - Searches for a general_ref with the given type. - -* ``dfhack.items.getSpecificRef(item, type)`` - - Searches for a specific_ref with the given type. - -* ``dfhack.items.getOwner(item)`` - - Returns the owner unit or *nil*. - -* ``dfhack.items.setOwner(item,unit)`` - - Replaces the owner of the item. If unit is *nil*, removes ownership. - Returns *false* in case of error. - -* ``dfhack.items.getContainer(item)`` - - Returns the container item or *nil*. - -* ``dfhack.items.getContainedItems(item)`` - - Returns a list of items contained in this one. - -* ``dfhack.items.getHolderBuilding(item)`` - - Returns the holder building or *nil*. - -* ``dfhack.items.getHolderUnit(item)`` - - Returns the holder unit or *nil*. - -* ``dfhack.items.moveToGround(item,pos)`` - - Move the item to the ground at position. Returns *false* if impossible. - -* ``dfhack.items.moveToContainer(item,container)`` - - Move the item to the container. Returns *false* if impossible. - -* ``dfhack.items.moveToBuilding(item,building[,use_mode[,force_in_building])`` - - Move the item to the building. Returns *false* if impossible. - - ``use_mode`` defaults to 0. If set to 2, the item will be treated as part of the building. - - If ``force_in_building`` is true, the item will be considered to be stored by the building - (used for items temporarily used in traps in vanilla DF) - -* ``dfhack.items.moveToInventory(item,unit,use_mode,body_part)`` - - Move the item to the unit inventory. Returns *false* if impossible. - -* ``dfhack.items.remove(item[, no_uncat])`` - - Removes the item, and marks it for garbage collection unless ``no_uncat`` is true. - -* ``dfhack.items.makeProjectile(item)`` - - Turns the item into a projectile, and returns the new object, or *nil* if impossible. - -* ``dfhack.items.isCasteMaterial(item_type)`` - - Returns *true* if this item type uses a creature/caste pair as its material. - -* ``dfhack.items.getSubtypeCount(item_type)`` - - Returns the number of raw-defined subtypes of the given item type, or *-1* if not applicable. - -* ``dfhack.items.getSubtypeDef(item_type, subtype)`` - - Returns the raw definition for the given item type and subtype, or *nil* if invalid. - -* ``dfhack.items.getItemBaseValue(item_type, subtype, material, mat_index)`` - - Calculates the base value for an item of the specified type and material. - -* ``dfhack.items.getValue(item)`` - - Calculates the Basic Value of an item, as seen in the View Item screen. - -* ``dfhack.items.createItem(item_type, item_subtype, mat_type, mat_index, unit)`` - - Creates an item, similar to the `createitem` plugin. - -* ``dfhack.items.checkMandates(item)`` - - Returns true if the item is free from mandates, or false if mandates prevent trading the item. - -* ``dfhack.items.canTrade(item)`` - - Checks whether the item can be traded. - -* ``dfhack.items.canTradeWithContents(item)`` - - Checks whether the item and all items it contains, if any, can be traded. - -* ``dfhack.items.isRouteVehicle(item)`` - - Checks whether the item is an assigned hauling vehicle. - -* ``dfhack.items.isSquadEquipment(item)`` - - Checks whether the item is assigned to a squad. - -.. _lua-maps: - -Maps module ------------ - -* ``dfhack.maps.getSize()`` - - Returns map size in blocks: *x, y, z* - -* ``dfhack.maps.getTileSize()`` - - Returns map size in tiles: *x, y, z* - -* ``dfhack.maps.getBlock(x,y,z)`` - - Returns a map block object for given x,y,z in local block coordinates. - -* ``dfhack.maps.isValidTilePos(coords)``, or ``isValidTilePos(x,y,z)`` - - Checks if the given df::coord or x,y,z in local tile coordinates are valid. - -* ``dfhack.maps.isTileVisible(coords)``, or ``isTileVisible(x,y,z)`` - - Checks if the given df::coord or x,y,z in local tile coordinates is visible. - -* ``dfhack.maps.getTileBlock(coords)``, or ``getTileBlock(x,y,z)`` - - Returns a map block object for given df::coord or x,y,z in local tile coordinates. - -* ``dfhack.maps.ensureTileBlock(coords)``, or ``ensureTileBlock(x,y,z)`` - - Like ``getTileBlock``, but if the block is not allocated, try creating it. - -* ``dfhack.maps.getTileType(coords)``, or ``getTileType(x,y,z)`` - - Returns the tile type at the given coordinates, or *nil* if invalid. - -* ``dfhack.maps.getTileFlags(coords)``, or ``getTileFlags(x,y,z)`` - - Returns designation and occupancy references for the given coordinates, or *nil, nil* if invalid. - -* ``dfhack.maps.getRegionBiome(region_coord2d)``, or ``getRegionBiome(x,y)`` - - Returns the biome info struct for the given global map region. - -* ``dfhack.maps.enableBlockUpdates(block[,flow,temperature])`` - - Enables updates for liquid flow or temperature, unless already active. - -* ``dfhack.maps.spawnFlow(pos,type,mat_type,mat_index,dimension)`` - - Spawns a new flow (i.e. steam/mist/dust/etc) at the given pos, and with - the given parameters. Returns it, or *nil* if unsuccessful. - -* ``dfhack.maps.getGlobalInitFeature(index)`` - - Returns the global feature object with the given index. - -* ``dfhack.maps.getLocalInitFeature(region_coord2d,index)`` - - Returns the local feature object with the given region coords and index. - -* ``dfhack.maps.getTileBiomeRgn(coords)``, or ``getTileBiomeRgn(x,y,z)`` - - Returns *x, y* for use with ``getRegionBiome``. - -* ``dfhack.maps.getPlantAtTile(pos)``, or ``getPlantAtTile(x,y,z)`` - - Returns the plant struct that owns the tile at the specified position. - -* ``dfhack.maps.canWalkBetween(pos1, pos2)`` - - Checks if a dwarf may be able to walk between the two tiles, - using a pathfinding cache maintained by the game. - - .. note:: - This cache is only updated when the game is unpaused, and thus - can get out of date if doors are forbidden or unforbidden, or - tools like `liquids` or `tiletypes` are used. It also cannot possibly - take into account anything that depends on the actual units, like - burrows, or the presence of invaders. - -* ``dfhack.maps.hasTileAssignment(tilemask)`` - - Checks if the tile_bitmask object is not *nil* and contains any set bits; returns *true* or *false*. - -* ``dfhack.maps.getTileAssignment(tilemask,x,y)`` - - Checks if the tile_bitmask object is not *nil* and has the relevant bit set; returns *true* or *false*. - -* ``dfhack.maps.setTileAssignment(tilemask,x,y,enable)`` - - Sets the relevant bit in the tile_bitmask object to the *enable* argument. - -* ``dfhack.maps.resetTileAssignment(tilemask[,enable])`` - - Sets all bits in the mask to the *enable* argument. - - -Burrows module --------------- - -* ``dfhack.burrows.findByName(name)`` - - Returns the burrow pointer or *nil*. - -* ``dfhack.burrows.clearUnits(burrow)`` - - Removes all units from the burrow. - -* ``dfhack.burrows.isAssignedUnit(burrow,unit)`` - - Checks if the unit is in the burrow. - -* ``dfhack.burrows.setAssignedUnit(burrow,unit,enable)`` - - Adds or removes the unit from the burrow. - -* ``dfhack.burrows.clearTiles(burrow)`` - - Removes all tiles from the burrow. - -* ``dfhack.burrows.listBlocks(burrow)`` - - Returns a table of map block pointers. - -* ``dfhack.burrows.isAssignedTile(burrow,tile_coord)`` - - Checks if the tile is in burrow. - -* ``dfhack.burrows.setAssignedTile(burrow,tile_coord,enable)`` - - Adds or removes the tile from the burrow. Returns *false* if invalid coords. - -* ``dfhack.burrows.isAssignedBlockTile(burrow,block,x,y)`` - - Checks if the tile within the block is in burrow. - -* ``dfhack.burrows.setAssignedBlockTile(burrow,block,x,y,enable)`` - - Adds or removes the tile from the burrow. Returns *false* if invalid coords. - - -Buildings module ----------------- - -General -~~~~~~~ - -* ``dfhack.buildings.getGeneralRef(building, type)`` - - Searches for a general_ref with the given type. - -* ``dfhack.buildings.getSpecificRef(building, type)`` - - Searches for a specific_ref with the given type. - -* ``dfhack.buildings.setOwner(item,unit)`` - - Replaces the owner of the building. If unit is *nil*, removes ownership. - Returns *false* in case of error. - -* ``dfhack.buildings.getSize(building)`` - - Returns *width, height, centerx, centery*. - -* ``dfhack.buildings.findAtTile(pos)``, or ``findAtTile(x,y,z)`` - - Scans the buildings for the one located at the given tile. - Does not work on civzones. Warning: linear scan if the map - tile indicates there are buildings at it. - -* ``dfhack.buildings.findCivzonesAt(pos)``, or ``findCivzonesAt(x,y,z)`` - - Scans civzones, and returns a lua sequence of those that touch - the given tile, or *nil* if none. - -* ``dfhack.buildings.getCorrectSize(width, height, type, subtype, custom, direction)`` - - Computes correct dimensions for the specified building type and orientation, - using width and height for flexible dimensions. - Returns *is_flexible, width, height, center_x, center_y*. - -* ``dfhack.buildings.checkFreeTiles(pos,size[,extents,change_extents,allow_occupied,allow_wall])`` - - Checks if the rectangle defined by ``pos`` and ``size``, and possibly extents, - can be used for placing a building. If ``change_extents`` is true, bad tiles - are removed from extents. If ``allow_occupied``, the occupancy test is skipped. - Set ``allow_wall`` to true if the building is unhindered by walls (such as an - activity zone). - -* ``dfhack.buildings.countExtentTiles(extents,defval)`` - - Returns the number of tiles included by extents, or defval. - -* ``dfhack.buildings.containsTile(building, x, y[, room])`` - - Checks if the building contains the specified tile, either directly, or as room. - -* ``dfhack.buildings.hasSupport(pos,size)`` - - Checks if a bridge constructed at specified position would have - support from terrain, and thus won't collapse if retracted. - -* ``dfhack.buildings.getStockpileContents(stockpile)`` - - Returns a list of items stored on the given stockpile. - Ignores empty bins, barrels, and wheelbarrows assigned as storage and transport for that stockpile. - -* ``dfhack.buildings.getCageOccupants(cage)`` - - Returns a list of units in the given built cage. Note that this is different - from the list of units assigned to the cage, which can be accessed with - ``cage.assigned_units``. - -Low-level -~~~~~~~~~ -Low-level building creation functions: - -* ``dfhack.buildings.allocInstance(pos, type, subtype, custom)`` - - Creates a new building instance of given type, subtype and custom type, - at specified position. Returns the object, or *nil* in case of an error. - -* ``dfhack.buildings.setSize(building, width, height, direction)`` - - Configures an object returned by ``allocInstance``, using specified - parameters wherever appropriate. If the building has fixed size along - any dimension, the corresponding input parameter will be ignored. - Returns *false* if the building cannot be placed, or *true, width, - height, rect_area, true_area*. Returned width and height are the - final values used by the building; true_area is less than rect_area - if any tiles were removed from designation. You can specify a non-rectangular - designation for building types that support extents by setting the - ``room.extents`` bitmap before calling this function. The extents will be - reset, however, if the size returned by this function doesn't match the - input size parameter. - -* ``dfhack.buildings.constructAbstract(building)`` - - Links a fully configured object created by ``allocInstance`` into the - world. The object must be an abstract building, i.e. a stockpile or civzone. - Returns *true*, or *false* if impossible. - -* ``dfhack.buildings.constructWithItems(building, items)`` - - Links a fully configured object created by ``allocInstance`` into the - world for construction, using a list of specific items as material. - Returns *true*, or *false* if impossible. - -* ``dfhack.buildings.constructWithFilters(building, job_items)`` - - Links a fully configured object created by ``allocInstance`` into the - world for construction, using a list of job_item filters as inputs. - Returns *true*, or *false* if impossible. Filter objects are claimed - and possibly destroyed in any case. - Use a negative ``quantity`` field value to auto-compute the amount - from the size of the building. - -* ``dfhack.buildings.deconstruct(building)`` - - Destroys the building, or queues a deconstruction job. - Returns *true* if the building was destroyed and deallocated immediately. - -* ``dfhack.buildings.markedForRemoval(building)`` - - Returns *true* if the building is marked for removal (with :kbd:`x`), *false* - otherwise. - -* ``dfhack.buildings.getRoomDescription(building[, unit])`` - - If the building is a room, returns a description including quality modifiers, e.g. "Royal Bedroom". - Otherwise, returns an empty string. - - The unit argument is passed through to DF and may modify the room's value depending on the unit given. - -High-level -~~~~~~~~~~ -More high-level functions are implemented in lua and can be loaded by -``require('dfhack.buildings')``. See ``hack/lua/dfhack/buildings.lua``. - -Among them are: - -* ``dfhack.buildings.getFiltersByType(argtable,type,subtype,custom)`` - - Returns a sequence of lua structures, describing input item filters - suitable for the specified building type, or *nil* if unknown or invalid. - The returned sequence is suitable for use as the ``job_items`` argument - of ``constructWithFilters``. - Uses tables defined in ``buildings.lua``. - - Argtable members ``material`` (the default name), ``bucket``, ``barrel``, - ``chain``, ``mechanism``, ``screw``, ``pipe``, ``anvil``, ``weapon`` are used to - augment the basic attributes with more detailed information if the - building has input items with the matching name (see the tables for naming details). - Note that it is impossible to *override* any properties this way, only supply those that - are not mentioned otherwise; one exception is that flags2.non_economic - is automatically cleared if an explicit material is specified. - -* ``dfhack.buildings.constructBuilding{...}`` - - Creates a building in one call, using options contained - in the argument table. Returns the building, or *nil, error*. - - .. note:: - Despite the name, unless the building is abstract, - the function creates it in an 'unconstructed' stage, with - a queued in-game job that will actually construct it. I.e. - the function replicates programmatically what can be done - through the construct building menu in the game ui, except - that it does less environment constraint checking. - - The following options can be used: - - - ``pos = coordinates``, or ``x = ..., y = ..., z = ...`` - - Mandatory. Specifies the left upper corner of the building. - - - ``type = df.building_type.FOO, subtype = ..., custom = ...`` - - Mandatory. Specifies the type of the building. Obviously, subtype - and custom are only expected if the type requires them. - - - ``fields = { ... }`` - - Initializes fields of the building object after creation with - ``df.assign``. If ``room.extents`` is assigned this way and this function - returns with error, the memory allocated for the extents is freed. - - - ``width = ..., height = ..., direction = ...`` - - Sets size and orientation of the building. If it is - fixed-size, specified dimensions are ignored. - - - ``full_rectangle = true`` - - For buildings like stockpiles or farm plots that can normally - accomodate individual tile exclusion, forces an error if any - tiles within the specified width*height are obstructed. - - - ``items = { item, item ... }``, or ``filters = { {...}, {...}... }`` - - Specifies explicit items or item filters to use in construction. - It is the job of the user to ensure they are correct for the building type. - - - ``abstract = true`` - - Specifies that the building is abstract and does not require construction. - Required for stockpiles and civzones; an error otherwise. - - - ``material = {...}, mechanism = {...}, ...`` - - If none of ``items``, ``filter``, or ``abstract`` is used, - the function uses ``getFiltersByType`` to compute the input - item filters, and passes the argument table through. If no filters - can be determined this way, ``constructBuilding`` throws an error. - - -Constructions module --------------------- - -* ``dfhack.constructions.designateNew(pos,type,item_type,mat_index)`` - - Designates a new construction at given position. If there already is - a planned but not completed construction there, changes its type. - Returns *true*, or *false* if obstructed. - Note that designated constructions are technically buildings. - -* ``dfhack.constructions.designateRemove(pos)``, or ``designateRemove(x,y,z)`` - - If there is a construction or a planned construction at the specified - coordinates, designates it for removal, or instantly cancels the planned one. - Returns *true, was_only_planned* if removed; or *false* if none found. - - -Kitchen module --------------- - -* ``dfhack.kitchen.findExclusion(type, item_type, item_subtype, mat_type, mat_index)`` - - Finds a kitchen exclusion in the vectors in ``df.global.ui.kitchen``. Returns - -1 if not found. - - * ``type`` is a ``df.kitchen_exc_type``, i.e. ``df.kitchen_exc_type.Cook`` or - ``df.kitchen_exc_type.Brew``. - * ``item_type`` is a ``df.item_type`` - * ``item_subtype``, ``mat_type``, and ``mat_index`` are all numeric - -* ``dfhack.kitchen.addExclusion(type, item_type, item_subtype, mat_type, mat_index)`` -* ``dfhack.kitchen.removeExclusion(type, item_type, item_subtype, mat_type, mat_index)`` - - Adds or removes a kitchen exclusion, using the same parameters as - ``findExclusion``. Both return ``true`` on success and ``false`` on failure, - e.g. when adding an exclusion that already exists or removing one that does - not. - -Screen API ----------- - -The screen module implements support for drawing to the tiled screen of the game. -Note that drawing only has any effect when done from callbacks, so it can only -be feasibly used in the `core context `. - -.. contents:: - :local: - -Basic painting functions -~~~~~~~~~~~~~~~~~~~~~~~~ - -Common parameters to these functions include: - -* ``x``, ``y``: screen coordinates in tiles; the upper left corner of the screen - is ``x = 0, y = 0`` -* ``pen``: a `pen object ` -* ``map``: a boolean indicating whether to draw to a separate map buffer - (defaults to false, which is suitable for off-map text or a screen that hides - the map entirely). Note that only third-party plugins like TWBT currently - implement a separate map buffer. If no such plugins are enabled, passing - ``true`` has no effect. However, this parameter should still be used to ensure - that scripts work properly with such plugins. - -Functions: - -* ``dfhack.screen.getWindowSize()`` - - Returns *width, height* of the screen. - -* ``dfhack.screen.getMousePos()`` - - Returns *x,y* of the tile the mouse is over. - -* ``dfhack.screen.inGraphicsMode()`` - - Checks if [GRAPHICS:YES] was specified in init. - -* ``dfhack.screen.paintTile(pen,x,y[,char,tile,map])`` - - Paints a tile using given parameters. `See below ` for a description of ``pen``. - - Returns *false* on error, e.g. if coordinates are out of bounds - -* ``dfhack.screen.readTile(x,y[,map])`` - - Retrieves the contents of the specified tile from the screen buffers. - Returns a `pen object `, or *nil* if invalid or TrueType. - -* ``dfhack.screen.paintString(pen,x,y,text[,map])`` - - Paints the string starting at *x,y*. Uses the string characters - in sequence to override the ``ch`` field of `pen `. - - Returns *true* if painting at least one character succeeded. - -* ``dfhack.screen.fillRect(pen,x1,y1,x2,y2[,map])`` - - Fills the rectangle specified by the coordinates with the given `pen `. - Returns *true* if painting at least one character succeeded. - -* ``dfhack.screen.findGraphicsTile(pagename,x,y)`` - - Finds a tile from a graphics set (i.e. the raws used for creatures), - if in graphics mode and loaded. - - Returns: *tile, tile_grayscale*, or *nil* if not found. - The values can then be used for the *tile* field of *pen* structures. - -* ``dfhack.screen.clear()`` - - Fills the screen with blank background. - -* ``dfhack.screen.invalidate()`` - - Requests repaint of the screen by setting a flag. Unlike other - functions in this section, this may be used at any time. - -* ``dfhack.screen.getKeyDisplay(key)`` - - Returns the string that should be used to represent the given - logical keybinding on the screen in texts like "press Key to ...". - -* ``dfhack.screen.keyToChar(key)`` - - Returns the integer character code of the string input - character represented by the given logical keybinding, - or *nil* if not a string input key. - -* ``dfhack.screen.charToKey(charcode)`` - - Returns the keybinding representing the given string input - character, or *nil* if impossible. - -.. _lua-screen-pen: - -Pen API -~~~~~~~ - -The ``pen`` argument used by ``dfhack.screen`` functions may be represented by -a table with the following possible fields: - - ``ch`` - Provides the ordinary tile character, as either a 1-character string or a number. - Can be overridden with the ``char`` function parameter. - ``fg`` - Foreground color for the ordinary tile. Defaults to COLOR_GREY (7). - ``bg`` - Background color for the ordinary tile. Defaults to COLOR_BLACK (0). - ``bold`` - Bright/bold text flag. If *nil*, computed based on (fg & 8); fg is masked to 3 bits. - Otherwise should be *true/false*. - ``tile`` - Graphical tile id. Ignored unless [GRAPHICS:YES] was in init.txt. - ``tile_color = true`` - Specifies that the tile should be shaded with *fg/bg*. - ``tile_fg, tile_bg`` - If specified, overrides *tile_color* and supplies shading colors directly. - -Alternatively, it may be a pre-parsed native object with the following API: - -* ``dfhack.pen.make(base[,pen_or_fg,bg,bold])`` - - Creates a new pre-parsed pen by combining its arguments according to the - following rules: - - 1. The ``base`` argument may be a pen object, a pen table as specified above, - or a single color value. In the single value case, it is split into - ``fg`` and ``bold`` properties, and others are initialized to 0. - This argument will be converted to a pre-parsed object and returned - if there are no other arguments. - - 2. If the ``pen_or_fg`` argument is specified as a table or object, it - completely replaces the base, and is returned instead of it. - - 3. Otherwise, the non-nil subset of the optional arguments is used - to update the ``fg``, ``bg`` and ``bold`` properties of the base. - If the ``bold`` flag is *nil*, but *pen_or_fg* is a number, ``bold`` - is deduced from it like in the simple base case. - - This function always returns a new pre-parsed pen, or *nil*. - -* ``dfhack.pen.parse(base[,pen_or_fg,bg,bold])`` - - Exactly like the above function, but returns ``base`` or ``pen_or_fg`` - directly if they are already a pre-parsed native object. - -* ``pen.property``, ``pen.property = value``, ``pairs(pen)`` - - Pre-parsed pens support reading and setting their properties, - but don't behave exactly like a simple table would; for instance, - assigning to ``pen.tile_color`` also resets ``pen.tile_fg`` and - ``pen.tile_bg`` to *nil*. - -Screen management -~~~~~~~~~~~~~~~~~ - -In order to actually be able to paint to the screen, it is necessary -to create and register a viewscreen (basically a modal dialog) with -the game. - -.. warning:: - As a matter of policy, in order to avoid user confusion, all - interface screens added by dfhack should bear the "DFHack" signature. - -Screens are managed with the following functions: - -* ``dfhack.screen.show(screen[,below])`` - - Displays the given screen, possibly placing it below a different one. - The screen must not be already shown. Returns *true* if success. - -* ``dfhack.screen.dismiss(screen[,to_first])`` - - Marks the screen to be removed when the game enters its event loop. - If ``to_first`` is *true*, all screens up to the first one will be deleted. - -* ``dfhack.screen.isDismissed(screen)`` - - Checks if the screen is already marked for removal. - -Apart from a native viewscreen object, these functions accept a table -as a screen. In this case, ``show`` creates a new native viewscreen -that delegates all processing to methods stored in that table. - -.. note:: - - * The `gui.Screen class ` provides stubs for all of the - functions listed below, and its use is recommended - * Lua-implemented screens are only supported in the `core context `. - -Supported callbacks and fields are: - -* ``screen._native`` - - Initialized by ``show`` with a reference to the backing viewscreen - object, and removed again when the object is deleted. - -* ``function screen:onShow()`` - - Called by ``dfhack.screen.show`` if successful. - -* ``function screen:onDismiss()`` - - Called by ``dfhack.screen.dismiss`` if successful. - -* ``function screen:onDestroy()`` - - Called from the destructor when the viewscreen is deleted. - -* ``function screen:onResize(w, h)`` - - Called before ``onRender`` or ``onIdle`` when the window size has changed. - -* ``function screen:onRender()`` - - Called when the viewscreen should paint itself. This is the only context - where the above painting functions work correctly. - - If omitted, the screen is cleared; otherwise it should do that itself. - In order to make a see-through dialog, call ``self._native.parent:render()``. - -* ``function screen:onIdle()`` - - Called every frame when the screen is on top of the stack. - -* ``function screen:onHelp()`` - - Called when the help keybinding is activated (usually '?'). - -* ``function screen:onInput(keys)`` - - Called when keyboard or mouse events are available. - If any keys are pressed, the keys argument is a table mapping them to *true*. - Note that this refers to logical keybingings computed from real keys via - options; if multiple interpretations exist, the table will contain multiple keys. - - The table also may contain special keys: - - ``_STRING`` - Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code for convenience. - - ``_MOUSE_L, _MOUSE_R`` - If the left or right mouse button is being pressed. - - ``_MOUSE_L_DOWN, _MOUSE_R_DOWN`` - If the left or right mouse button was just pressed. - - If this method is omitted, the screen is dismissed on receival of the ``LEAVESCREEN`` key. - -* ``function screen:onGetSelectedUnit()`` -* ``function screen:onGetSelectedItem()`` -* ``function screen:onGetSelectedJob()`` -* ``function screen:onGetSelectedBuilding()`` - - Implement these to provide a return value for the matching - ``dfhack.gui.getSelected...`` function. - - -PenArray class --------------- - -Screens that require significant computation in their onRender() method can use -a ``dfhack.penarray`` instance to cache their output. - -* ``dfhack.penarray.new(w, h)`` - - Creates a new penarray instance with an internal buffer of ``w * h`` tiles. - These dimensions currently cannot be changed after a penarray is instantiated. - -* ``penarray:clear()`` - - Clears the internal buffer, similar to ``dfhack.screen.clear()``. - -* ``penarray:get_dims()`` - - Returns the x and y dimensions of the internal buffer. - -* ``penarray:get_tile(x, y)`` - - Returns a pen corresponding to the tile at (``x``, ``y``) in the internal buffer. - Note that indices are 0-based. - -* ``penarray:set_tile(x, y, pen)`` - - Sets the tile at (``x``, ``y``) in the internal buffer to the pen given. - -* ``penarray:draw(x, y, w, h, bufferx, buffery)`` - - Draws the contents of the internal buffer, beginning at - (``bufferx``, ``buffery``) and spanning ``w`` columns and ``h`` rows, to the - screen starting at (``x``, ``y``). Any invalid screen and buffer coordinates - are skipped. - - ``bufferx`` and ``buffery`` default to 0. - -Filesystem module ------------------ - -Most of these functions return ``true`` on success and ``false`` on failure, -unless otherwise noted. - -* ``dfhack.filesystem.exists(path)`` - - Returns ``true`` if ``path`` exists. - -* ``dfhack.filesystem.isfile(path)`` - - Returns ``true`` if ``path`` exists and is a file. - -* ``dfhack.filesystem.isdir(path)`` - - Returns ``true`` if ``path`` exists and is a directory. - -* ``dfhack.filesystem.getcwd()`` - - Returns the current working directory. To retrieve the DF path, use ``dfhack.getDFPath()`` instead. - -* ``dfhack.filesystem.chdir(path)`` - - Changes the current directory to ``path``. Use with caution. - -* ``dfhack.filesystem.restore_cwd()`` - - Restores the current working directory to what it was when DF started. - -* ``dfhack.filesystem.get_initial_cwd()`` - - Returns the value of the working directory when DF was started. - -* ``dfhack.filesystem.mkdir(path)`` - - Creates a new directory. Returns ``false`` if unsuccessful, including if ``path`` already exists. - -* ``dfhack.filesystem.mkdir_recursive(path)`` - - Creates a new directory, including any intermediate directories that don't exist yet. - Returns ``true`` if the folder was created or already existed, or ``false`` if unsuccessful. - -* ``dfhack.filesystem.rmdir(path)`` - - Removes a directory. Only works if the directory is already empty. - -* ``dfhack.filesystem.mtime(path)`` - - Returns the modification time (in seconds) of the file or directory specified by ``path``, - or -1 if ``path`` does not exist. This depends on the system clock and should only be used locally. - -* ``dfhack.filesystem.atime(path)`` -* ``dfhack.filesystem.ctime(path)`` - - Return values vary across operating systems - return the ``st_atime`` and ``st_ctime`` - fields of a C++ stat struct, respectively. - -* ``dfhack.filesystem.listdir(path)`` - - Lists files/directories in a directory. Returns ``{}`` if ``path`` does not exist. - Set include_prefix to false if you don't want the ``path`` string prepended to the - returned filenames. - -* ``dfhack.filesystem.listdir_recursive(path [, depth = 10[, include_prefix = true]])`` - - Lists all files/directories in a directory and its subdirectories. All directories - are listed before their contents. Returns a table with subtables of the format:: - - {path: 'path to file', isdir: true|false} - - Note that ``listdir()`` returns only the base name of each directory entry, while - ``listdir_recursive()`` returns the initial path and all components following it - for each entry. - -Console API ------------ - -* ``dfhack.console.clear()`` - - Clears the console; equivalent to the ``cls`` built-in command. - -* ``dfhack.console.flush()`` - - Flushes all output to the console. This can be useful when printing text that - does not end in a newline but should still be displayed. - -.. _lua-api-internal: - -Internal API ------------- - -These functions are intended for the use by dfhack developers, -and are only documented here for completeness: - -* ``dfhack.internal.getPE()`` - - Returns the PE timestamp of the DF executable (only on Windows) - -* ``dfhack.internal.getMD5()`` - - Returns the MD5 of the DF executable (only on OS X and Linux) - -* ``dfhack.internal.getAddress(name)`` - - Returns the global address ``name``, or *nil*. - -* ``dfhack.internal.setAddress(name, value)`` - - Sets the global address ``name``. Returns the value of ``getAddress`` before the change. - -* ``dfhack.internal.getVTable(name)`` - - Returns the pre-extracted vtable address ``name``, or *nil*. - -* ``dfhack.internal.getImageBase()`` - - Returns the mmap base of the executable. - -* ``dfhack.internal.getRebaseDelta()`` - - Returns the ASLR rebase offset of the DF executable. - -* ``dfhack.internal.adjustOffset(offset[,to_file])`` - - Returns the re-aligned offset, or *nil* if invalid. - If ``to_file`` is true, the offset is adjusted from memory to file. - This function returns the original value everywhere except windows. - -* ``dfhack.internal.getMemRanges()`` - - Returns a sequence of tables describing virtual memory ranges of the process. - -* ``dfhack.internal.patchMemory(dest,src,count)`` - - Like memmove below, but works even if dest is read-only memory, e.g. code. - If destination overlaps a completely invalid memory region, or another error - occurs, returns false. - -* ``dfhack.internal.patchBytes(write_table[, verify_table])`` - - The first argument must be a lua table, which is interpreted as a mapping from - memory addresses to byte values that should be stored there. The second argument - may be a similar table of values that need to be checked before writing anything. - - The function takes care to either apply all of ``write_table``, or none of it. - An empty ``write_table`` with a nonempty ``verify_table`` can be used to reasonably - safely check if the memory contains certain values. - - Returns *true* if successful, or *nil, error_msg, address* if not. - -* ``dfhack.internal.memmove(dest,src,count)`` - - Wraps the standard memmove function. Accepts both numbers and refs as pointers. - -* ``dfhack.internal.memcmp(ptr1,ptr2,count)`` - - Wraps the standard memcmp function. - -* ``dfhack.internal.memscan(haystack,count,step,needle,nsize)`` - - Searches for ``needle`` of ``nsize`` bytes in ``haystack``, - using ``count`` steps of ``step`` bytes. - Returns: *step_idx, sum_idx, found_ptr*, or *nil* if not found. - -* ``dfhack.internal.diffscan(old_data, new_data, start_idx, end_idx, eltsize[, oldval, newval, delta])`` - - Searches for differences between buffers at ptr1 and ptr2, as integers of size eltsize. - The oldval, newval or delta arguments may be used to specify additional constraints. - Returns: *found_index*, or *nil* if end reached. - -* ``dfhack.internal.getDir(path)`` - - Lists files/directories in a directory. - Returns: *file_names* or empty table if not found. Identical to ``dfhack.filesystem.listdir(path)``. - -* ``dfhack.internal.strerror(errno)`` - - Wraps strerror() - returns a string describing a platform-specific error code - -* ``dfhack.internal.addScriptPath(path, search_before)`` - - Registers ``path`` as a `script path `. - If ``search_before`` is passed and ``true``, the path will be searched before - the default paths (e.g. ``raw/scripts``, ``hack/scripts``); otherwise, it will - be searched after. - - Returns ``true`` if successful or ``false`` otherwise (e.g. if the path does - not exist or has already been registered). - -* ``dfhack.internal.removeScriptPath(path)`` - - Removes ``path`` from the list of `script paths ` and returns - ``true`` if successful. - -* ``dfhack.internal.getScriptPaths()`` - - Returns the list of `script paths ` in the order they are - searched, including defaults. (This can change if a world is loaded.) - -* ``dfhack.internal.findScript(name)`` - - Searches `script paths ` for the script ``name`` and returns the - path of the first file found, or ``nil`` on failure. - - .. note:: - This requires an extension to be specified (``.lua`` or ``.rb``) - use - ``dfhack.findScript()`` to include the ``.lua`` extension automatically. - -* ``dfhack.internal.runCommand(command[, use_console])`` - - Runs a DFHack command with the core suspended. Used internally by the - ``dfhack.run_command()`` family of functions. - - - ``command``: either a table of strings or a single string which is parsed by - the default console tokenization strategy (not recommended) - - ``use_console``: if true, output is sent directly to the DFHack console - - Returns a table with a ``status`` key set to a ``command_result`` constant - (``status = CR_OK`` indicates success). Additionally, if ``use_console`` is - not true, enumerated table entries of the form ``{color, text}`` are included, - e.g. ``result[1][0]`` is the color of the first piece of text printed (a - ``COLOR_`` constant). These entries can be iterated over with ``ipairs()``. - -* ``dfhack.internal.md5(string)`` - - Returns the MD5 hash of the given string. - -* ``dfhack.internal.md5File(filename[,first_kb])`` - - Computes the MD5 hash of the given file. Returns ``hash, length`` on success - (where ``length`` is the number of bytes read from the file), or ``nil, - error`` on failure. - - If the parameter ``first_kb`` is specified and evaluates to ``true``, and the - hash was computed successfully, a table containing the first 1024 bytes of the - file is returned as the third return value. - -* ``dfhack.internal.threadid()`` - - Returns a numeric identifier of the current thread. - -.. _lua-core-context: - -Core interpreter context -======================== - -While plugins can create any number of interpreter instances, -there is one special context managed by the DFHack core. It is the -only context that can receive events from DF and plugins. - -Core context specific functions: - -* ``dfhack.is_core_context`` - - Boolean value; *true* in the core context. - -* ``dfhack.timeout(time,mode,callback)`` - - Arranges for the callback to be called once the specified - period of time passes. The ``mode`` argument specifies the - unit of time used, and may be one of ``'frames'`` (raw FPS), - ``'ticks'`` (unpaused FPS), ``'days'``, ``'months'``, - ``'years'`` (in-game time). All timers other than - ``'frames'`` are cancelled when the world is unloaded, - and cannot be queued until it is loaded again. - Returns the timer id, or *nil* if unsuccessful due to - world being unloaded. - -* ``dfhack.timeout_active(id[,new_callback])`` - - Returns the active callback with the given id, or *nil* - if inactive or nil id. If called with 2 arguments, replaces - the current callback with the given value, if still active. - Using ``timeout_active(id,nil)`` cancels the timer. - -* ``dfhack.onStateChange.foo = function(code)`` - - Creates a handler for state change events. Receives the same - `SC_ codes ` as ``plugin_onstatechange()`` in C++. - - -Event type ----------- - -An event is a native object transparently wrapping a lua table, -and implementing a __call metamethod. When it is invoked, it loops -through the table with next and calls all contained values. -This is intended as an extensible way to add listeners. - -This type itself is available in any context, but only the -`core context ` has the actual events defined by C++ code. - -Features: - -* ``dfhack.event.new()`` - - Creates a new instance of an event. - -* ``event[key] = function`` - - Sets the function as one of the listeners. Assign *nil* to remove it. - - .. note:: - The ``df.NULL`` key is reserved for the use by - the C++ owner of the event; it is an error to try setting it. - -* ``#event`` - - Returns the number of non-nil listeners. - -* ``pairs(event)`` - - Iterates over all listeners in the table. - -* ``event(args...)`` - - Invokes all listeners contained in the event in an arbitrary - order using ``dfhack.safecall``. - - -=========== -Lua Modules -=========== - -.. contents:: - :local: - -DFHack sets up the lua interpreter so that the built-in ``require`` -function can be used to load shared lua code from :file:`hack/lua/`. -The ``dfhack`` namespace reference itself may be obtained via -``require('dfhack')``, although it is initially created as a -global by C++ bootstrap code. - -The following module management functions are provided: - -* ``mkmodule(name)`` - - Creates an environment table for the module. Intended to be used as:: - - local _ENV = mkmodule('foo') - ... - return _ENV - - If called the second time, returns the same table; thus providing reload support. - -* ``reload(name)`` - - Reloads a previously ``require``-d module *"name"* from the file. - Intended as a help for module development. - -* ``dfhack.BASE_G`` - - This variable contains the root global environment table, which is - used as a base for all module and script environments. Its contents - should be kept limited to the standard Lua library and API described - in this document. - -.. _lua-globals: - -Global environment -================== - -A number of variables and functions are provided in the base global -environment by the mandatory init file dfhack.lua: - -* Color constants - - These are applicable both for ``dfhack.color()`` and color fields - in DF functions or structures:: - - COLOR_RESET, COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, - COLOR_RED, COLOR_MAGENTA, COLOR_BROWN, COLOR_GREY, COLOR_DARKGREY, - COLOR_LIGHTBLUE, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN, COLOR_LIGHTRED, - COLOR_LIGHTMAGENTA, COLOR_YELLOW, COLOR_WHITE - -* State change event codes, used by ``dfhack.onStateChange`` - - Available only in the `core context `, as is the event itself: - - SC_WORLD_LOADED, SC_WORLD_UNLOADED, SC_MAP_LOADED, - SC_MAP_UNLOADED, SC_VIEWSCREEN_CHANGED, SC_CORE_INITIALIZED - -* Command result constants (equivalent to ``command_result`` in C++), used by - ``dfhack.run_command()`` and related functions: - - CR_OK, CR_LINK_FAILURE, CR_NEEDS_CONSOLE, CR_NOT_IMPLEMENTED, CR_FAILURE, - CR_WRONG_USAGE, CR_NOT_FOUND - -* Functions already described above - - safecall, qerror, mkmodule, reload - -* Miscellaneous constants - - ``NEWLINE``, ``COMMA``, ``PERIOD`` - evaluate to the relevant character strings. - ``DEFAULT_NIL`` - is an unspecified unique token used by the class module below. - -* ``printall(obj)`` - - If the argument is a lua table or DF object reference, prints all fields. - -* ``printall_recurse(obj)`` - - If the argument is a lua table or DF object reference, prints all fields recursively. - -* ``copyall(obj)`` - - Returns a shallow copy of the table or reference as a lua table. - -* ``pos2xyz(obj)`` - - The object must have fields x, y and z. Returns them as 3 values. - If obj is *nil*, or x is -30000 (the usual marker for undefined - coordinates), returns *nil*. - -* ``xyz2pos(x,y,z)`` - - Returns a table with x, y and z as fields. - -* ``same_xyz(a,b)`` - - Checks if ``a`` and ``b`` have the same x, y and z fields. - -* ``get_path_xyz(path,i)`` - - Returns ``path.x[i], path.y[i], path.z[i]``. - -* ``pos2xy(obj)``, ``xy2pos(x,y)``, ``same_xy(a,b)``, ``get_path_xy(a,b)`` - - Same as above, but for 2D coordinates. - -* ``safe_index(obj,index...)`` - - Walks a sequence of dereferences, which may be represented by numbers or strings. - Returns *nil* if any of obj or indices is *nil*, or a numeric index is out of array bounds. - -utils -===== - -* ``utils.compare(a,b)`` - - Comparator function; returns *-1* if ab, *0* otherwise. - -* ``utils.compare_name(a,b)`` - - Comparator for names; compares empty string last. - -* ``utils.is_container(obj)`` - - Checks if obj is a container ref. - -* ``utils.make_index_sequence(start,end)`` - - Returns a lua sequence of numbers in start..end. - -* ``utils.make_sort_order(data, ordering)`` - - Computes a sorted permutation of objects in data, as a table of integer - indices into the data sequence. Uses ``data.n`` as input length - if present. - - The ordering argument is a sequence of ordering specs, represented - as lua tables with following possible fields: - - ord.key = *function(value)* - Computes comparison key from input data value. Not called on nil. - If omitted, the comparison key is the value itself. - ord.key_table = *function(data)* - Computes a key table from the data table in one go. - ord.compare = *function(a,b)* - Comparison function. Defaults to ``utils.compare`` above. - Called on non-nil keys; nil sorts last. - ord.nil_first = *true/false* - If true, nil keys are sorted first instead of last. - ord.reverse = *true/false* - If true, sort non-nil keys in descending order. - - For every comparison during sorting the specs are applied in - order until an unambiguous decision is reached. Sorting is stable. - - Example of sorting a sequence by field foo:: - - local spec = { key = function(v) return v.foo end } - local order = utils.make_sort_order(data, { spec }) - local output = {} - for i = 1,#order do output[i] = data[order[i]] end - - Separating the actual reordering of the sequence in this - way enables applying the same permutation to multiple arrays. - This function is used by the sort plugin. - -* ``for link,item in utils.listpairs(list)`` - - Iterates a df-list structure, for example ``df.global.world.job_list``. - -* ``utils.assign(tgt, src)`` - - Does a recursive assignment of src into tgt. - Uses ``df.assign`` if tgt is a native object ref; otherwise - recurses into lua tables. - -* ``utils.clone(obj, deep)`` - - Performs a shallow, or semi-deep copy of the object as a lua table tree. - The deep mode recurses into lua tables and subobjects, except pointers - to other heap objects. - Null pointers are represented as ``df.NULL``. Zero-based native containers - are converted to 1-based lua sequences. - -* ``utils.clone_with_default(obj, default, force)`` - - Copies the object, using the ``default`` lua table tree - as a guide to which values should be skipped as uninteresting. - The ``force`` argument makes it always return a non-*nil* value. - -* ``utils.parse_bitfield_int(value, type_ref)`` - - Given an int ``value``, and a bitfield type in the ``df`` tree, - it returns a lua table mapping the enabled bit keys to *true*, - unless value is 0, in which case it returns *nil*. - -* ``utils.list_bitfield_flags(bitfield[, list])`` - - Adds all enabled bitfield keys to ``list`` or a newly-allocated - empty sequence, and returns it. The ``bitfield`` argument may - be *nil*. - -* ``utils.sort_vector(vector,field,cmpfun)`` - - Sorts a native vector or lua sequence using the comparator function. - If ``field`` is not *nil*, applies the comparator to the field instead - of the whole object. - -* ``utils.linear_index(vector,key[,field])`` - - Searches for ``key`` in the vector, and returns *index, found_value*, - or *nil* if none found. - -* ``utils.binsearch(vector,key,field,cmpfun,min,max)`` - - Does a binary search in a native vector or lua sequence for - ``key``, using ``cmpfun`` and ``field`` like sort_vector. - If ``min`` and ``max`` are specified, they are used as the - search subrange bounds. - - If found, returns *item, true, idx*. Otherwise returns - *nil, false, insert_idx*, where *insert_idx* is the correct - insertion point. - -* ``utils.insert_sorted(vector,item,field,cmpfun)`` - - Does a binary search, and inserts item if not found. - Returns *did_insert, vector[idx], idx*. - -* ``utils.insert_or_update(vector,item,field,cmpfun)`` - - Like ``insert_sorted``, but also assigns the item into - the vector cell if insertion didn't happen. - - As an example, you can use this to set skill values:: - - utils.insert_or_update(soul.skills, {new=true, id=..., rating=...}, 'id') - - (For an explanation of ``new=true``, see `lua-api-table-assignment`) - -* ``utils.erase_sorted_key(vector,key,field,cmpfun)`` - - Removes the item with the given key from the list. Returns: *did_erase, vector[idx], idx*. - -* ``utils.erase_sorted(vector,item,field,cmpfun)`` - - Exactly like ``erase_sorted_key``, but if field is specified, takes the key from ``item[field]``. - -* ``utils.call_with_string(obj,methodname,...)`` - - Allocates a temporary string object, calls ``obj:method(tmp,...)``, and - returns the value written into the temporary after deleting it. - -* ``utils.getBuildingName(building)`` - - Returns the string description of the given building. - -* ``utils.getBuildingCenter(building)`` - - Returns an x/y/z table pointing at the building center. - -* ``utils.split_string(string, delimiter)`` - - Splits the string by the given delimiter, and returns a sequence of results. - -* ``utils.prompt_yes_no(prompt, default)`` - - Presents a yes/no prompt to the user. If ``default`` is not *nil*, - allows just pressing Enter to submit the default choice. - If the user enters ``'abort'``, throws an error. - -* ``utils.prompt_input(prompt, checkfun, quit_str)`` - - Presents a prompt to input data, until a valid string is entered. - Once ``checkfun(input)`` returns *true, ...*, passes the values - through. If the user enters the quit_str (defaults to ``'~~~'``), - throws an error. - -* ``utils.check_number(text)`` - - A ``prompt_input`` ``checkfun`` that verifies a number input. - -dumper -====== - -A third-party lua table dumper module from -http://lua-users.org/wiki/DataDumper. Defines one -function: - -* ``dumper.DataDumper(value, varname, fastmode, ident, indent_step)`` - - Returns ``value`` converted to a string. The ``indent_step`` - argument specifies the indentation step size in spaces. For - the other arguments see the original documentation link above. - -profiler -======== - -A third-party lua profiler module from -http://lua-users.org/wiki/PepperfishProfiler. Module defines one function to -create profiler objects which can be used to profile and generate report. - -* ``profiler.newProfiler([variant[, sampling_frequency]])`` - - Returns an profile object with ``variant`` either ``'time'`` or ``'call'``. - ``'time'`` variant takes optional ``sampling_frequency`` parameter to select - lua instruction counts between samples. Default is ``'time'`` variant with - ``10*1000`` frequency. - - ``'call'`` variant has much higher runtime cost which will increase the - runtime of profiled code by factor of ten. For the extreme costs it provides - accurate function call counts that can help locate code which takes much time - in native calls. - -* ``obj:start()`` - - Resets collected statistics. Then it starts collecting new statistics. - -* ``obj:stop()`` - - Stops profile collection. - -* ``obj:report(outfile[, sort_by_total_time])`` - - Write a report from previous statistics collection to ``outfile``. - ``outfile`` should be writeable io file object (``io.open`` or - ``io.stdout``). Passing ``true`` as second parameter ``sort_by_total_time`` - switches sorting order to use total time instead of default self time order. - -* ``obj:prevent(function)`` - - Adds an ignore filter for a ``function``. It will ignore the pointed function - and all of it children. - -Examples --------- - -:: - - local prof = profiler.newProfiler() - prof:start() - - profiledCode() - - prof:stop() - - local out = io.open( "lua-profile.txt", "w+") - prof:report(out) - out:close() - -class -===== - -Implements a trivial single-inheritance class system. - -* ``Foo = defclass(Foo[, ParentClass])`` - - Defines or updates class Foo. The ``Foo = defclass(Foo)`` syntax - is needed so that when the module or script is reloaded, the - class identity will be preserved through the preservation of - global variable values. - - The ``defclass`` function is defined as a stub in the global - namespace, and using it will auto-load the class module. - -* ``Class.super`` - - This class field is set by defclass to the parent class, and - allows a readable ``Class.super.method(self, ...)`` syntax for - calling superclass methods. - -* ``Class.ATTRS { foo = xxx, bar = yyy }`` - - Declares certain instance fields to be attributes, i.e. auto-initialized - from fields in the table used as the constructor argument. If omitted, - they are initialized with the default values specified in this declaration. - - If the default value should be *nil*, use ``ATTRS { foo = DEFAULT_NIL }``. - - Declaring an attribute is mostly the same as defining your ``init`` method like this:: - - function Class.init(args) - self.attr1 = args.attr1 or default1 - self.attr2 = args.attr2 or default2 - ... - end - - The main difference is that attributes are processed as a separate - initialization step, before any ``init`` methods are called. They - also make the directy relation between instance fields and constructor - arguments more explicit. - -* ``new_obj = Class{ foo = arg, bar = arg, ... }`` - - Calling the class as a function creates and initializes a new instance. - Initialization happens in this order: - - 1. An empty instance table is created, and its metatable set. - 2. The ``preinit`` methods are called via ``invoke_before`` (see below) - with the table used as argument to the class. These methods are intended - for validating and tweaking that argument table. - 3. Declared ATTRS are initialized from the argument table or their default values. - 4. The ``init`` methods are called via ``invoke_after`` with the argument table. - This is the main constructor method. - 5. The ``postinit`` methods are called via ``invoke_after`` with the argument table. - Place code that should be called after the object is fully constructed here. - -Predefined instance methods: - -* ``instance:assign{ foo = xxx }`` - - Assigns all values in the input table to the matching instance fields. - -* ``instance:callback(method_name, [args...])`` - - Returns a closure that invokes the specified method of the class, - properly passing in self, and optionally a number of initial arguments too. - The arguments given to the closure are appended to these. - -* ``instance:cb_getfield(field_name)`` - - Returns a closure that returns the specified field of the object when called. - -* ``instance:cb_setfield(field_name)`` - - Returns a closure that sets the specified field to its argument when called. - -* ``instance:invoke_before(method_name, args...)`` - - Navigates the inheritance chain of the instance starting from the most specific - class, and invokes the specified method with the arguments if it is defined in - that specific class. Equivalent to the following definition in every class:: - - function Class:invoke_before(method, ...) - if rawget(Class, method) then - rawget(Class, method)(self, ...) - end - Class.super.invoke_before(method, ...) - end - -* ``instance:invoke_after(method_name, args...)`` - - Like invoke_before, only the method is called after the recursive call to super, - i.e. invocations happen in the parent to child order. - - These two methods are inspired by the Common Lisp before and after methods, and - are intended for implementing similar protocols for certain things. The class - library itself uses them for constructors. - -To avoid confusion, these methods cannot be redefined. - -================== -In-game UI Library -================== - -.. contents:: - :local: - -A number of lua modules with names starting with ``gui`` are dedicated -to wrapping the natives of the ``dfhack.screen`` module in a way that -is easy to use. This allows relatively easily and naturally creating -dialogs that integrate in the main game UI window. - -These modules make extensive use of the ``class`` module, and define -things ranging from the basic ``Painter``, ``View`` and ``Screen`` -classes, to fully functional predefined dialogs. - -gui -=== - -This module defines the most important classes and functions for -implementing interfaces. This documents those of them that are -considered stable. - - -Misc ----- - -* ``USE_GRAPHICS`` - - Contains the value of ``dfhack.screen.inGraphicsMode()``, which cannot be - changed without restarting the game and thus is constant during the session. - -* ``CLEAR_PEN`` - - The black pen used to clear the screen. - -* ``simulateInput(screen, keys...)`` - - This function wraps an undocumented native function that passes a set of - keycodes to a screen, and is the official way to do that. - - Every argument after the initial screen may be *nil*, a numeric keycode, - a string keycode, a sequence of numeric or string keycodes, or a mapping - of keycodes to *true* or *false*. For instance, it is possible to use the - table passed as argument to ``onInput``. - -* ``mkdims_xy(x1,y1,x2,y2)`` - - Returns a table containing the arguments as fields, and also ``width`` and - ``height`` that contains the rectangle dimensions. - -* ``mkdims_wh(x1,y1,width,height)`` - - Returns the same kind of table as ``mkdims_xy``, only this time it computes - ``x2`` and ``y2``. - -* ``is_in_rect(rect,x,y)`` - - Checks if the given point is within a rectangle, represented by a table produced - by one of the ``mkdims`` functions. - -* ``blink_visible(delay)`` - - Returns *true* or *false*, with the value switching to the opposite every ``delay`` - msec. This is intended for rendering blinking interface objects. - -* ``getKeyDisplay(keycode)`` - - Wraps ``dfhack.screen.getKeyDisplay`` in order to allow using strings for the keycode argument. - - -ViewRect class --------------- - -This class represents an on-screen rectangle with an associated independent -clip area rectangle. It is the base of the ``Painter`` class, and is used by -``Views`` to track their client area. - -* ``ViewRect{ rect = ..., clip_rect = ..., view_rect = ..., clip_view = ... }`` - - The constructor has the following arguments: - - :rect: The ``mkdims`` rectangle in screen coordinates of the logical viewport. - Defaults to the whole screen. - :clip_rect: The clip rectangle in screen coordinates. Defaults to ``rect``. - :view_rect: A ViewRect object to copy from; overrides both ``rect`` and ``clip_rect``. - :clip_view: A ViewRect object to intersect the specified clip area with. - -* ``rect:isDefunct()`` - - Returns *true* if the clip area is empty, i.e. no painting is possible. - -* ``rect:inClipGlobalXY(x,y)`` - - Checks if these global coordinates are within the clip rectangle. - -* ``rect:inClipLocalXY(x,y)`` - - Checks if these coordinates (specified relative to ``x1,y1``) are within the clip rectangle. - -* ``rect:localXY(x,y)`` - - Converts a pair of global coordinates to local; returns *x_local,y_local*. - -* ``rect:globalXY(x,y)`` - - Converts a pair of local coordinates to global; returns *x_global,y_global*. - -* ``rect:viewport(x,y,w,h)`` or ``rect:viewport(subrect)`` - - Returns a ViewRect representing a sub-rectangle of the current one. - The arguments are specified in local coordinates; the ``subrect`` - argument must be a ``mkdims`` table. The returned object consists of - the exact specified rectangle, and a clip area produced by intersecting - it with the clip area of the original object. - - -Painter class -------------- - -The painting natives in ``dfhack.screen`` apply to the whole screen, are -completely stateless and don't implement clipping. - -The Painter class inherits from ViewRect to provide clipping and local -coordinates, and tracks current cursor position and current pen. It also -supports drawing to a separate map buffer if applicable (see ``map()`` below -for details). - -* ``Painter{ ..., pen = ..., key_pen = ... }`` - - In addition to ViewRect arguments, Painter accepts a suggestion of - the initial value for the main pen, and the keybinding pen. They - default to COLOR_GREY and COLOR_LIGHTGREEN otherwise. - - There are also some convenience functions that wrap this constructor: - - - ``Painter.new(rect,pen)`` - - ``Painter.new_view(view_rect,pen)`` - - ``Painter.new_xy(x1,y1,x2,y2,pen)`` - - ``Painter.new_wh(x1,y1,width,height,pen)`` - -* ``painter:isValidPos()`` - - Checks if the current cursor position is within the clip area. - -* ``painter:viewport(x,y,w,h)`` - - Like the superclass method, but returns a Painter object. - -* ``painter:cursor()`` - - Returns the current cursor *x,y* in screen coordinates. - -* ``painter:cursorX()`` - - Returns just the current *x* cursor coordinate - -* ``painter:cursorY()`` - - Returns just the current *y* cursor coordinate - -* ``painter:seek(x,y)`` - - Sets the current cursor position, and returns *self*. - Either of the arguments may be *nil* to keep the current value. - -* ``painter:advance(dx,dy)`` - - Adds the given offsets to the cursor position, and returns *self*. - Either of the arguments may be *nil* to keep the current value. - -* ``painter:newline([dx])`` - - Advances the cursor to the start of the next line plus the given x offset, and returns *self*. - -* ``painter:pen(...)`` - - Sets the current pen to ``dfhack.pen.parse(old_pen,...)``, and returns *self*. - -* ``painter:color(fg[,bold[,bg]])`` - - Sets the specified colors of the current pen and returns *self*. - -* ``painter:key_pen(...)`` - - Sets the current keybinding pen to ``dfhack.pen.parse(old_pen,...)``, and returns *self*. - -* ``painter:map(to_map)`` - - Enables or disables drawing to a separate map buffer. ``to_map`` is a boolean - that will be passed as the ``map`` parameter to any ``dfhack.screen`` functions - that accept it. Note that only third-party plugins like TWBT currently implement - a separate map buffer; if none are enabled, this function has no effect (but - should still be used to ensure proper support for such plugins). Returns *self*. - -* ``painter:clear()`` - - Fills the whole clip rectangle with ``CLEAR_PEN``, and returns *self*. - -* ``painter:fill(x1,y1,x2,y2[,...])`` or ``painter:fill(rect[,...])`` - - Fills the specified local coordinate rectangle with ``dfhack.pen.parse(cur_pen,...)``, - and returns *self*. - -* ``painter:char([char[, ...]])`` - - Paints one character using ``char`` and ``dfhack.pen.parse(cur_pen,...)``; returns *self*. - The ``char`` argument, if not nil, is used to override the ``ch`` property of the pen. - -* ``painter:tile([char, tile[, ...]])`` - - Like ``char()`` above, but also allows overriding the ``tile`` property on ad-hoc basis. - -* ``painter:string(text[, ...])`` - - Paints the string with ``dfhack.pen.parse(cur_pen,...)``; returns *self*. - -* ``painter:key(keycode[, ...])`` - - Paints the description of the keycode using ``dfhack.pen.parse(cur_key_pen,...)``; returns *self*. - -* ``painter:key_string(keycode, text, ...)`` - - A convenience wrapper around both ``key()`` and ``string()`` that prints both - the specified keycode description and text, separated by ``:``. Any extra - arguments are passed directly to ``string()``. Returns *self*. - -Unless specified otherwise above, all Painter methods return *self*, in order to allow chaining them like this:: - - painter:pen(foo):seek(x,y):char(1):advance(1):string('bar')... - - -View class ----------- - -This class is the common abstract base of both the stand-alone screens -and common widgets to be used inside them. It defines the basic layout, -rendering and event handling framework. - -The class defines the following attributes: - -:visible: Specifies that the view should be painted. -:active: Specifies that the view should receive events, if also visible. -:view_id: Specifies an identifier to easily identify the view among subviews. - This is reserved for implementation of top-level views, and should - not be used by widgets for their internal subviews. - -It also always has the following fields: - -:subviews: Contains a table of all subviews. The sequence part of the - table is used for iteration. In addition, subviews are also - indexed under their *view_id*, if any; see ``addviews()`` below. - -These fields are computed by the layout process: - -:frame_parent_rect: The ViewRect represeting the client area of the parent view. -:frame_rect: The ``mkdims`` rect of the outer frame in parent-local coordinates. -:frame_body: The ViewRect representing the body part of the View's own frame. - -The class has the following methods: - -* ``view:addviews(list)`` - - Adds the views in the list to the ``subviews`` sequence. If any of the views - in the list have ``view_id`` attributes that don't conflict with existing keys - in ``subviews``, also stores them under the string keys. Finally, copies any - non-conflicting string keys from the ``subviews`` tables of the listed views. - - Thus, doing something like this:: - - self:addviews{ - Panel{ - view_id = 'panel', - subviews = { - Label{ view_id = 'label' } - } - } - } - - Would make the label accessible as both ``self.subviews.label`` and - ``self.subviews.panel.subviews.label``. - -* ``view:getWindowSize()`` - - Returns the dimensions of the ``frame_body`` rectangle. - -* ``view:getMousePos()`` - - Returns the mouse *x,y* in coordinates local to the ``frame_body`` - rectangle if it is within its clip area, or nothing otherwise. - -* ``view:updateLayout([parent_rect])`` - - Recomputes layout of the view and its subviews. If no argument is - given, re-uses the previous parent rect. The process goes as follows: - - 1. Calls ``preUpdateLayout(parent_rect)`` via ``invoke_before``. - 2. Uses ``computeFrame(parent_rect)`` to compute the desired frame. - 3. Calls ``postComputeFrame(frame_body)`` via ``invoke_after``. - 4. Calls ``updateSubviewLayout(frame_body)`` to update children. - 5. Calls ``postUpdateLayout(frame_body)`` via ``invoke_after``. - -* ``view:computeFrame(parent_rect)`` *(for overriding)* - - Called by ``updateLayout`` in order to compute the frame rectangle(s). - Should return the ``mkdims`` rectangle for the outer frame, and optionally - also for the body frame. If only one rectangle is returned, it is used - for both frames, and the margin becomes zero. - -* ``view:updateSubviewLayout(frame_body)`` - - Calls ``updateLayout`` on all children. - -* ``view:render(painter)`` - - Given the parent's painter, renders the view via the following process: - - 1. Calls ``onRenderFrame(painter, frame_rect)`` to paint the outer frame. - 2. Creates a new painter using the ``frame_body`` rect. - 3. Calls ``onRenderBody(new_painter)`` to paint the client area. - 4. Calls ``renderSubviews(new_painter)`` to paint visible children. - -* ``view:renderSubviews(painter)`` - - Calls ``render`` on all ``visible`` subviews in the order they - appear in the ``subviews`` sequence. - -* ``view:onRenderFrame(painter, rect)`` *(for overriding)* - - Called by ``render`` to paint the outer frame; by default does nothing. - -* ``view:onRenderBody(painter)`` *(for overriding)* - - Called by ``render`` to paint the client area; by default does nothing. - -* ``view:onInput(keys)`` *(for overriding)* - - Override this to handle events. By default directly calls ``inputToSubviews``. - Return a true value from this method to signal that the event has been handled - and should not be passed on to more views. - -* ``view:inputToSubviews(keys)`` - - Calls ``onInput`` on all visible active subviews, iterating the ``subviews`` - sequence in *reverse order*, so that topmost subviews get events first. - Returns *true* if any of the subviews handled the event. - - -.. _lua-gui-screen: - -Screen class ------------- - -This is a View subclass intended for use as a stand-alone dialog or screen. -It adds the following methods: - -* ``screen:isShown()`` - - Returns *true* if the screen is currently in the game engine's display stack. - -* ``screen:isDismissed()`` - - Returns *true* if the screen is dismissed. - -* ``screen:isActive()`` - - Returns *true* if the screen is shown and not dismissed. - -* ``screen:invalidate()`` - - Requests a repaint. Note that currently using it is not necessary, because - repaints are constantly requested automatically, due to issues with native - screens happening otherwise. - -* ``screen:renderParent()`` - - Asks the parent native screen to render itself, or clears the screen if impossible. - -* ``screen:sendInputToParent(...)`` - - Uses ``simulateInput`` to send keypresses to the native parent screen. - -* ``screen:show([parent])`` - - Adds the screen to the display stack with the given screen as the parent; - if parent is not specified, places this one one topmost. Before calling - ``dfhack.screen.show``, calls ``self:onAboutToShow(parent)``. - -* ``screen:onAboutToShow(parent)`` *(for overriding)* - - Called when ``dfhack.screen.show`` is about to be called. - -* ``screen:onShow()`` - - Called by ``dfhack.screen.show`` once the screen is successfully shown. - -* ``screen:dismiss()`` - - Dismisses the screen. A dismissed screen does not receive any more - events or paint requests, but may remain in the display stack for - a short time until the game removes it. - -* ``screen:onDismiss()`` *(for overriding)* - - Called by ``dfhack.screen.dismiss()``. - -* ``screen:onDestroy()`` *(for overriding)* - - Called by the native code when the screen is fully destroyed and removed - from the display stack. Place code that absolutely must be called whenever - the screen is removed by any means here. - -* ``screen:onResize``, ``screen:onRender`` - - Defined as callbacks for native code. - - -FramedScreen class ------------------- - -A Screen subclass that paints a visible frame around its body. -Most dialogs should inherit from this class. - -A framed screen has the following attributes: - -:frame_style: A table that defines a set of pens to draw various parts of the frame. -:frame_title: A string to display in the middle of the top of the frame. -:frame_width: Desired width of the client area. If *nil*, the screen will occupy the whole width. -:frame_height: Likewise, for height. -:frame_inset: The gap between the frame and the client area. Defaults to 0. -:frame_background: The pen to fill in the frame with. Defaults to CLEAR_PEN. - -There are the following predefined frame style tables: - -* ``GREY_FRAME`` - - A plain grey-colored frame. - -* ``BOUNDARY_FRAME`` - - The same frame as used by the usual full-screen DF views, like dwarfmode. - -* ``GREY_LINE_FRAME`` - - A frame consisting of grey lines, similar to the one used by titan announcements. - - -gui.widgets -=========== - -This module implements some basic widgets based on the View infrastructure. - -Widget class ------------- - -Base of all the widgets. Inherits from View and has the following attributes: - -* ``frame = {...}`` - - Specifies the constraints on the outer frame of the widget. - If omitted, the widget will occupy the whole parent rectangle. - - The frame is specified as a table with the following possible fields: - - :l: gap between the left edges of the frame and the parent. - :t: gap between the top edges of the frame and the parent. - :r: gap between the right edges of the frame and the parent. - :b: gap between the bottom edges of the frame and the parent. - :w: maximum width of the frame. - :h: maximum heigth of the frame. - :xalign: X alignment of the frame. - :yalign: Y alignment of the frame. - - First the ``l,t,r,b`` fields restrict the available area for - placing the frame. If ``w`` and ``h`` are not specified or - larger then the computed area, it becomes the frame. Otherwise - the smaller frame is placed within the are based on the - ``xalign/yalign`` fields. If the align hints are omitted, they - are assumed to be 0, 1, or 0.5 based on which of the ``l/r/t/b`` - fields are set. - -* ``frame_inset = {...}`` - - Specifies the gap between the outer frame, and the client area. - The attribute may be a simple integer value to specify a uniform - inset, or a table with the following fields: - - :l: left margin. - :t: top margin. - :r: right margin. - :b: bottom margin. - :x: left/right margin, if ``l`` and/or ``r`` are omitted. - :y: top/bottom margin, if ``t`` and/or ``b`` are omitted. - -* ``frame_background = pen`` - - The pen to fill the outer frame with. Defaults to no fill. - -Panel class ------------ - -Inherits from Widget, and intended for grouping a number of subviews. - -Has attributes: - -* ``subviews = {}`` - - Used to initialize the subview list in the constructor. - -* ``on_render = function(painter)`` - - Called from ``onRenderBody``. - -Pages class ------------ - -Subclass of Panel; keeps exactly one child visible. - -* ``Pages{ ..., selected = ... }`` - - Specifies which child to select initially; defaults to the first one. - -* ``pages:getSelected()`` - - Returns the selected *index, child*. - -* ``pages:setSelected(index)`` - - Selects the specified child, hiding the previous selected one. - It is permitted to use the subview object, or its ``view_id`` as index. - -EditField class ---------------- - -Subclass of Widget; implements a simple edit field. - -Attributes: - -:text: The current contents of the field. -:text_pen: The pen to draw the text with. -:on_char: Input validation callback; used as ``on_char(new_char,text)``. - If it returns false, the character is ignored. -:on_change: Change notification callback; used as ``on_change(new_text,old_text)``. -:on_submit: Enter key callback; if set the field will handle the key and call ``on_submit(text)``. -:key: If specified, the field is disabled until this key is pressed. Must be given as a string. - -Label class ------------ - -This Widget subclass implements flowing semi-static text. - -It has the following attributes: - -:text_pen: Specifies the pen for active text. -:text_dpen: Specifies the pen for disabled text. -:text_hpen: Specifies the pen for text hovered over by the mouse, if a click handler is registered. -:disabled: Boolean or a callback; if true, the label is disabled. -:enabled: Boolean or a callback; if false, the label is disabled. -:auto_height: Sets self.frame.h from the text height. -:auto_width: Sets self.frame.w from the text width. -:on_click: A callback called when the label is clicked (optional) -:on_rclick: A callback called when the label is right-clicked (optional) - -The text itself is represented as a complex structure, and passed -to the object via the ``text`` argument of the constructor, or via -the ``setText`` method, as one of: - -* A simple string, possibly containing newlines. -* A sequence of tokens. - -Every token in the sequence in turn may be either a string, possibly -containing newlines, or a table with the following possible fields: - -* ``token.text = ...`` - - Specifies the main text content of a token, and may be a string, or - a callback returning a string. - -* ``token.gap = ...`` - - Specifies the number of character positions to advance on the line - before rendering the token. - -* ``token.tile = pen`` - - Specifies a pen to paint as one tile before the main part of the token. - -* ``token.width = ...`` - - If specified either as a value or a callback, the text field is padded - or truncated to the specified number. - -* ``token.pad_char = '?'`` - - If specified together with ``width``, the padding area is filled with - this character instead of just being skipped over. - -* ``token.key = '...'`` - - Specifies the keycode associated with the token. The string description - of the key binding is added to the text content of the token. - -* ``token.key_sep = '...'`` - - Specifies the separator to place between the keybinding label produced - by ``token.key``, and the main text of the token. If the separator is - '()', the token is formatted as ``text..' ('..binding..')'``. Otherwise - it is simply ``binding..sep..text``. - -* ``token.enabled``, ``token.disabled`` - - Same as the attributes of the label itself, but applies only to the token. - -* ``token.pen``, ``token.dpen`` - - Specify the pen and disabled pen to be used for the token's text. - The field may be either the pen itself, or a callback that returns it. - -* ``token.on_activate`` - - If this field is not nil, and ``token.key`` is set, the token will actually - respond to that key binding unless disabled, and call this callback. Eventually - this may be extended with mouse click support. - -* ``token.id`` - - Specifies a unique identifier for the token. - -* ``token.line``, ``token.x1``, ``token.x2`` - - Reserved for internal use. - -The Label widget implements the following methods: - -* ``label:setText(new_text)`` - - Replaces the text currently contained in the widget. - -* ``label:itemById(id)`` - - Finds a token by its ``id`` field. - -* ``label:getTextHeight()`` - - Computes the height of the text. - -* ``label:getTextWidth()`` - - Computes the width of the text. - -List class ----------- - -The List widget implements a simple list with paging. - -It has the following attributes: - -:text_pen: Specifies the pen for deselected list entries. -:cursor_pen: Specifies the pen for the selected entry. -:inactive_pen: If specified, used for the cursor when the widget is not active. -:icon_pen: Default pen for icons. -:on_select: Selection change callback; called as ``on_select(index,choice)``. - This is also called with *nil* arguments if ``setChoices`` is called - with an empty list. -:on_submit: Enter key callback; if specified, the list reacts to the key - and calls it as ``on_submit(index,choice)``. -:on_submit2: Shift-Enter key callback; if specified, the list reacts to the key - and calls it as ``on_submit2(index,choice)``. -:row_height: Height of every row in text lines. -:icon_width: If not *nil*, the specified number of character columns - are reserved to the left of the list item for the icons. -:scroll_keys: Specifies which keys the list should react to as a table. - -Every list item may be specified either as a string, or as a lua table -with the following fields: - -:text: Specifies the label text in the same format as the Label text. -:caption, [1]: Deprecated legacy aliases for **text**. -:text_*: Reserved for internal use. -:key: Specifies a keybinding that acts as a shortcut for the specified item. -:icon: Specifies an icon string, or a pen to paint a single character. May be a callback. -:icon_pen: When the icon is a string, used to paint it. - -The list supports the following methods: - -* ``List{ ..., choices = ..., selected = ... }`` - - Same as calling ``setChoices`` after construction. - -* ``list:setChoices(choices[, selected])`` - - Replaces the list of choices, possibly also setting the currently selected index. - -* ``list:setSelected(selected)`` - - Sets the currently selected index. Returns the index after validation. - -* ``list:getChoices()`` - - Returns the list of choices. - -* ``list:getSelected()`` - - Returns the selected *index, choice*, or nothing if the list is empty. - -* ``list:getContentWidth()`` - - Returns the minimal width to draw all choices without clipping. - -* ``list:getContentHeight()`` - - Returns the minimal width to draw all choices without scrolling. - -* ``list:submit()`` - - Call the ``on_submit`` callback, as if the Enter key was handled. - -* ``list:submit2()`` - - Call the ``on_submit2`` callback, as if the Shift-Enter key was handled. - -FilteredList class ------------------- - -This widget combines List, EditField and Label into a combo-box like -construction that allows filtering the list by subwords of its items. - -In addition to passing through all attributes supported by List, it -supports: - -:edit_pen: If specified, used instead of ``cursor_pen`` for the edit field. -:edit_below: If true, the edit field is placed below the list instead of above. -:edit_key: If specified, the edit field is disabled until this key is pressed. -:not_found_label: Specifies the text of the label shown when no items match the filter. - -The list choices may include the following attributes: - -:search_key: If specified, used instead of **text** to match against the filter. - This is required for any entries where **text** is not a string. - -The widget implements: - -* ``list:setChoices(choices[, selected])`` - - Resets the filter, and passes through to the inner list. - -* ``list:getChoices()`` - - Returns the list of *all* choices. - -* ``list:getVisibleChoices()`` - - Returns the *filtered* list of choices. - -* ``list:getFilter()`` - - Returns the current filter string, and the *filtered* list of choices. - -* ``list:setFilter(filter[,pos])`` - - Sets the new filter string, filters the list, and selects the item at - index ``pos`` in the *unfiltered* list if possible. - -* ``list:canSubmit()`` - - Checks if there are currently any choices in the filtered list. - -* ``list:getSelected()``, ``list:getContentWidth()``, ``list:getContentHeight()``, ``list:submit()`` - - Same as with an ordinary list. - - -.. _lua-plugins: - -======= -Plugins -======= - -.. contents:: - :local: - -DFHack plugins may export native functions and events to Lua contexts. These are -exposed as ``plugins.`` modules, which can be imported with -``require('plugins.')``. The plugins listed in this section expose -functions and/or data to Lua in this way. - -In addition to any native functions documented here, plugins that can be -enabled (that is, plugins that support the `enable/disable API `) will -have the following functions defined: - -* ``isEnabled()`` returns whether the plugin is enabled. -* ``setEnabled(boolean)`` sets whether the plugin is enabled. - -For plugin developers, note that a Lua file in ``plugins/lua`` is required for -``require()`` to work, even if it contains no pure-Lua functions. This file must -contain ``mkmodule('plugins.')`` to import any native functions defined in -the plugin. See existing files in ``plugins/lua`` for examples. - -blueprint -========= - -Lua functions provided by the `blueprint` plugin to programmatically generate -blueprint files: - -* ``dig(start, end, name)`` -* ``build(start, end, name)`` -* ``place(start, end, name)`` -* ``query(start, end, name)`` - - ``start`` and ``end`` are tables containing positions (see ``xyz2pos``). - ``name`` is used as the basis for the generated filenames. - -The names of the functions are also available as the keys of the -``valid_phases`` table. - -.. _building-hacks: - -building-hacks -============== - -This plugin overwrites some methods in workshop df class so that mechanical workshops are possible. Although -plugin export a function it's recommended to use lua decorated function. - -.. contents:: - :local: - -Functions ---------- - -``registerBuilding(table)`` where table must contain name, as a workshop raw name, the rest are optional: - - :name: - custom workshop id e.g. ``SOAPMAKER`` - - .. note:: this is the only mandatory field. - - :fix_impassible: - if true make impassible tiles impassible to liquids too - :consume: - how much machine power is needed to work. - Disables reactions if not supplied enough and ``needs_power==1`` - :produce: - how much machine power is produced. - :needs_power: - if produced in network < consumed stop working, default true - :gears: - a table or ``{x=?,y=?}`` of connection points for machines. - :action: - a table of number (how much ticks to skip) and a function which - gets called on shop update - :animate: - a table of frames which can be a table of: - - a. tables of 4 numbers ``{tile,fore,back,bright}`` OR - b. empty table (tile not modified) OR - c. ``{x= y= + 4 numbers like in first case}``, - this generates full frame useful for animations that change little (1-2 tiles) - - :canBeRoomSubset: - a flag if this building can be counted in room. 1 means it can, 0 means it can't and -1 default building behaviour - :auto_gears: - a flag that automatically fills up gears and animate. It looks over building definition for gear icons and maps them. - - Animate table also might contain: - - :frameLength: - how many ticks does one frame take OR - :isMechanical: - a bool that says to try to match to mechanical system (i.e. how gears are turning) - -``getPower(building)`` returns two number - produced and consumed power if building can be modified and returns nothing otherwise - -``setPower(building,produced,consumed)`` sets current productiona and consumption for a building. - -Examples --------- - -Simple mechanical workshop:: - - require('plugins.building-hacks').registerBuilding{name="BONE_GRINDER", - consume=15, - gears={x=0,y=0}, --connection point - animate={ - isMechanical=true, --animate the same conn. point as vanilla gear - frames={ - {{x=0,y=0,42,7,0,0}}, --first frame, 1 changed tile - {{x=0,y=0,15,7,0,0}} -- second frame, same - } - } - -Or with auto_gears:: - - require('plugins.building-hacks').registerBuilding{name="BONE_GRINDER", - consume=15, - auto_gears=true - } - -buildingplan -============ - -Native functions provided by the `buildingplan` plugin: - -* ``bool isPlannableBuilding(df::building_type type, int16_t subtype, int32_t custom)`` returns whether the building type is handled by buildingplan. -* ``bool isPlanModeEnabled(df::building_type type, int16_t subtype, int32_t custom)`` returns whether the buildingplan UI is enabled for the specified building type. -* ``bool isPlannedBuilding(df::building *bld)`` returns whether the given building is managed by buildingplan. -* ``void addPlannedBuilding(df::building *bld)`` suspends the building jobs and adds the building to the monitor list. -* ``void doCycle()`` runs a check for whether buildlings in the monitor list can be assigned items and unsuspended. This method runs automatically twice a game day, so you only need to call it directly if you want buildingplan to do a check right now. -* ``void scheduleCycle()`` schedules a cycle to be run during the next non-paused game frame. Can be called multiple times while the game is paused and only one cycle will be scheduled. - -burrows -======= - -The `burrows` plugin implements extended burrow manipulations. - -Events: - -* ``onBurrowRename.foo = function(burrow)`` - - Emitted when a burrow might have been renamed either through - the game UI, or ``renameBurrow()``. - -* ``onDigComplete.foo = function(job_type,pos,old_tiletype,new_tiletype,worker)`` - - Emitted when a tile might have been dug out. Only tracked if the - auto-growing burrows feature is enabled. - -Native functions: - -* ``renameBurrow(burrow,name)`` - - Renames the burrow, emitting ``onBurrowRename`` and updating auto-grow state properly. - -* ``findByName(burrow,name)`` - - Finds a burrow by name, using the same rules as the plugin command line interface. - Namely, trailing ``'+'`` characters marking auto-grow burrows are ignored. - -* ``copyUnits(target,source,enable)`` - - Applies units from ``source`` burrow to ``target``. The ``enable`` - parameter specifies if they are to be added or removed. - -* ``copyTiles(target,source,enable)`` - - Applies tiles from ``source`` burrow to ``target``. The ``enable`` - parameter specifies if they are to be added or removed. - -* ``setTilesByKeyword(target,keyword,enable)`` - - Adds or removes tiles matching a predefined keyword. The keyword - set is the same as used by the command line. - -The lua module file also re-exports functions from ``dfhack.burrows``. - -.. _cxxrandom: - -cxxrandom -========= - -Exposes some features of the C++11 random number library to Lua. - -.. contents:: - :local: - -Native functions (exported to Lua) ----------------------------------- - -- ``GenerateEngine(seed)`` - - returns engine id - -- ``DestroyEngine(rngID)`` - - destroys corresponding engine - -- ``NewSeed(rngID, seed)`` - - re-seeds engine - -- ``rollInt(rngID, min, max)`` - - generates random integer - -- ``rollDouble(rngID, min, max)`` - - generates random double - -- ``rollNormal(rngID, avg, stddev)`` - - generates random normal[gaus.] - -- ``rollBool(rngID, chance)`` - - generates random boolean - -- ``MakeNumSequence(start, end)`` - - returns sequence id - -- ``AddToSequence(seqID, num)`` - - adds a number to the sequence - -- ``ShuffleSequence(rngID, seqID)`` - - shuffles the number sequence - -- ``NextInSequence(seqID)`` - - returns the next number in sequence - - -Lua plugin functions --------------------- - -- ``MakeNewEngine(seed)`` - - returns engine id - -Lua plugin classes ------------------- - -``crng`` -~~~~~~~~ - -- ``init(id, df, dist)``: constructor - - - ``id``: Reference ID of engine to use in RNGenerations - - ``df`` (optional): bool indicating whether to destroy the Engine when the crng object is garbage collected - - ``dist`` (optional): lua number distribution to use - -- ``changeSeed(seed)``: alters engine's seed value -- ``setNumDistrib(distrib)``: sets the number distribution crng object should use - - - ``distrib``: number distribution object to use in RNGenerations - -- ``next()``: returns the next number in the distribution -- ``shuffle()``: effectively shuffles the number distribution - -``normal_distribution`` -~~~~~~~~~~~~~~~~~~~~~~~ - -- ``init(avg, stddev)``: constructor -- ``next(id)``: returns next number in the distribution - - - ``id``: engine ID to pass to native function - -``real_distribution`` -~~~~~~~~~~~~~~~~~~~~~ - -- ``init(min, max)``: constructor -- ``next(id)``: returns next number in the distribution - - - ``id``: engine ID to pass to native function - -``int_distribution`` -~~~~~~~~~~~~~~~~~~~~ - -- ``init(min, max)``: constructor -- ``next(id)``: returns next number in the distribution - - - ``id``: engine ID to pass to native function - -``bool_distribution`` -~~~~~~~~~~~~~~~~~~~~~ - -- ``init(min, max)``: constructor -- ``next(id)``: returns next boolean in the distribution - - - ``id``: engine ID to pass to native function - -``num_sequence`` -~~~~~~~~~~~~~~~~ - -- ``init(a, b)``: constructor -- ``add(num)``: adds num to the end of the number sequence -- ``shuffle()``: shuffles the sequence of numbers -- ``next()``: returns next number in the sequence - -dig-now -======= - -The dig-now plugin exposes the following functions to Lua: - -* ``dig_now_tile(pos)`` or ``dig_now_tile(x,y,z)``: Runs dig-now for the - specified tile coordinate. Default options apply, as if you were running the - command ``dig-now ``. See the `dig-now` documentation for details - on default settings. - -.. _eventful: - -eventful -======== - -This plugin exports some events to lua thus allowing to run lua functions -on DF world events. - -.. contents:: - :local: - -List of events --------------- - -1. ``onReactionComplete(reaction,reaction_product,unit,input_items,input_reagents,output_items,call_native)`` - - Auto activates if detects reactions starting with ``LUA_HOOK_``. Is called when reaction finishes. - -2. ``onItemContaminateWound(item,unit,wound,number1,number2)`` - - Is called when item tries to contaminate wound (e.g. stuck in). - -3. ``onProjItemCheckMovement(projectile)`` - - Is called when projectile moves. - -4. ``onProjItemCheckImpact(projectile,somebool)`` - - Is called when projectile hits something. - -5. ``onProjUnitCheckMovement(projectile)`` - - Is called when projectile moves. - -6. ``onProjUnitCheckImpact(projectile,somebool)`` - - Is called when projectile hits something. - -7. ``onWorkshopFillSidebarMenu(workshop,callnative)`` - - Is called when viewing a workshop in 'q' mode, to populate reactions, useful for custom viewscreens for shops. - -8. ``postWorkshopFillSidebarMenu(workshop)`` - - Is called after calling (or not) native fillSidebarMenu(). Useful for job button - tweaking (e.g. adding custom reactions) - -.. _EventManager: - -Events from EventManager ------------------------- -These events are straight from EventManager module. Each of them first needs to be enabled. See functions for more info. If you register a listener before the game is loaded, be aware that no events will be triggered immediately after loading, so you might need to add another event listener for when the game first loads in some cases. - -1. ``onBuildingCreatedDestroyed(building_id)`` - - Gets called when building is created or destroyed. - -2. ``onConstructionCreatedDestroyed(building_id)`` - - Gets called when construction is created or destroyed. - -3. ``onJobInitiated(job)`` - - Gets called when job is issued. - -4. ``onJobCompleted(job)`` - - Gets called when job is finished. The job that is passed to this function is a copy. Requires a frequency of 0 in order to distinguish between workshop jobs that were cancelled by the user and workshop jobs that completed successfully. - -5. ``onUnitDeath(unit_id)`` - - Gets called on unit death. - -6. ``onItemCreated(item_id)`` - - Gets called when item is created (except due to traders, migrants, invaders and spider webs). - -7. ``onSyndrome(unit_id,syndrome_index)`` - - Gets called when new syndrome appears on a unit. - -8. ``onInvasion(invasion_id)`` - - Gets called when new invasion happens. - -9. ``onInventoryChange(unit_id,item_id,old_equip,new_equip)`` - - Gets called when someone picks up an item, puts one down, or changes the way they are holding it. If an item is picked up, old_equip will be null. If an item is dropped, new_equip will be null. If an item is re-equipped in a new way, then neither will be null. You absolutely must NOT alter either old_equip or new_equip or you might break other plugins. - -10. ``onReport(reportId)`` - - Gets called when a report happens. This happens more often than you probably think, even if it doesn't show up in the announcements. - -11. ``onUnitAttack(attackerId, defenderId, woundId)`` - - Called when a unit wounds another with a weapon. Is NOT called if blocked, dodged, deflected, or parried. - -12. ``onUnload()`` - - A convenience event in case you don't want to register for every onStateChange event. - -13. ``onInteraction(attackVerb, defendVerb, attackerId, defenderId, attackReportId, defendReportId)`` - - Called when a unit uses an interaction on another. - -Functions ---------- - -1. ``registerReaction(reaction_name,callback)`` - - Simplified way of using onReactionComplete; the callback is function (same params as event). - -2. ``removeNative(shop_name)`` - - Removes native choice list from the building. - -3. ``addReactionToShop(reaction_name,shop_name)`` - - Add a custom reaction to the building. - -4. ``enableEvent(evType,frequency)`` - - Enable event checking for EventManager events. For event types use ``eventType`` table. Note that different types of events require different frequencies to be effective. The frequency is how many ticks EventManager will wait before checking if that type of event has happened. If multiple scripts or plugins use the same event type, the smallest frequency is the one that is used, so you might get events triggered more often than the frequency you use here. - -5. ``registerSidebar(shop_name,callback)`` - - Enable callback when sidebar for ``shop_name`` is drawn. Usefull for custom workshop views e.g. using gui.dwarfmode lib. Also accepts a ``class`` instead of function - as callback. Best used with ``gui.dwarfmode`` class ``WorkshopOverlay``. - -Examples --------- -Spawn dragon breath on each item attempt to contaminate wound:: - - b=require "plugins.eventful" - b.onItemContaminateWound.one=function(item,unit,un_wound,x,y) - local flw=dfhack.maps.spawnFlow(unit.pos,6,0,0,50000) - end - -Reaction complete example:: - - b=require "plugins.eventful" - - b.registerReaction("LUA_HOOK_LAY_BOMB",function(reaction,unit,in_items,in_reag,out_items,call_native) - local pos=copyall(unit.pos) - -- spawn dragonbreath after 100 ticks - dfhack.timeout(100,"ticks",function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end) - --do not call real item creation code - call_native.value=false - end) - -Grenade example:: - - b=require "plugins.eventful" - b.onProjItemCheckImpact.one=function(projectile) - -- you can check if projectile.item e.g. has correct material - dfhack.maps.spawnFlow(projectile.cur_pos,6,0,0,50000) - end - -Integrated tannery:: - - b=require "plugins.eventful" - b.addReactionToShop("TAN_A_HIDE","LEATHERWORKS") - -.. _luasocket: - -luasocket -========= - -A way to access csocket from lua. The usage is made similar to luasocket in vanilla lua distributions. Currently -only subset of functions exist and only tcp mode is implemented. - -.. contents:: - :local: - -Socket class ------------- - -This is a base class for ``client`` and ``server`` sockets. You can not create it - it's like a virtual -base class in c++. - - -* ``socket:close()`` - - Closes the connection. - -* ``socket:setTimeout(sec,msec)`` - - Sets the operation timeout for this socket. It's possible to set timeout to 0. Then it performs like - a non-blocking socket. - -Client class ------------- - -Client is a connection socket to a server. You can get this object either from ``tcp:connect(address,port)`` or -from ``server:accept()``. It's a subclass of ``socket``. - -* ``client:receive(pattern)`` - - Receives data. Pattern is one of: - - :``*l``: read one line (default, if pattern is *nil*) - :: read specified number of bytes - :``*a``: read all available data - -* ``client:send(data)`` - - Sends data. Data is a string. - - -Server class ------------- - -Server is a socket that is waiting for clients. -You can get this object from ``tcp:bind(address,port)``. - -* ``server:accept()`` - - Accepts an incoming connection if it exists. - Returns a ``client`` object representing that socket. - -Tcp class ---------- - -A class with all the tcp functionality. - -* ``tcp:bind(address,port)`` - - Starts listening on that port for incoming connections. Returns ``server`` object. - -* ``tcp:connect(address,port)`` - - Tries connecting to that address and port. Returns ``client`` object. - - -.. _map-render: - -map-render -========== - -A way to ask DF to render a section of the fortress mode map. This uses a native -DF rendering function so it's highly dependent on DF settings (e.g. tileset, -colors, etc.) - -Functions ---------- - -- ``render_map_rect(x,y,z,w,h)`` - - returns a table with w*h*4 entries of rendered tiles. The format is same as ``df.global.gps.screen`` (tile,foreground,bright,background). - -.. _pathable: - -pathable -======== - -This plugin implements the back end of the `gui/pathable` script. It exports a -single Lua function, in ``hack/lua/plugins/pathable.lua``: - -* ``paintScreen(cursor[,skip_unrevealed])``: Paint each visible of the screen - green or red, depending on whether it can be pathed to from the tile at - ``cursor``. If ``skip_unrevealed`` is specified and true, do not draw - unrevealed tiles. - -reveal -====== - -Native functions provided by the `reveal` plugin: - -* ``void unhideFlood(pos)``: Unhides map tiles according to visibility rules, - starting from the given coordinates. This algorithm only processes adjacent - hidden tiles, so it must start on a hidden tile in order to have any effect. - It will not reveal hidden sections separated by already-unhidden tiles. - -Example of revealing a cavern that happens to have an open tile at the specified -coordinate:: - - unhideFlood({x=25, y=38, z=140}) - -sort -==== - -The `sort ` plugin does not export any native functions as of now. -Instead, it calls Lua code to perform the actual ordering of list items. - -.. _xlsxreader: - -xlsxreader -========== - -Utility functions to facilitate reading .xlsx spreadsheets. It provides the -following low-level API methods: - -- ``open_xlsx_file(filename)`` returns a file_handle or nil on error -- ``close_xlsx_file(file_handle)`` closes the specified file_handle -- ``list_sheets(file_handle)`` returns a list of strings representing sheet - names -- ``open_sheet(file_handle, sheet_name)`` returns a sheet_handle. This call - always succeeds, even if the sheet doesn't exist. Non-existent sheets will - have no data, though. -- ``close_sheet(sheet_handle)`` closes the specified sheet_handle -- ``get_row(sheet_handle, max_tokens)`` returns a list of strings representing - the contents of the cells in the next row. The ``max_tokens`` parameter is - optional. If set to a number > 0, it limits the number of cells read and - returned for the row. - -The plugin also provides Lua class wrappers for ease of use: - -- ``XlsxioReader`` provides access to .xlsx files -- ``XlsxioSheetReader`` provides access to sheets within .xlsx files -- ``open(filepath)`` initializes and returns an ``XlsxioReader`` object - -The ``XlsxioReader`` class has the following methods: - -- ``XlsxioReader:close()`` closes the file. Be sure to close any open child - sheet handles first! -- ``XlsxioReader:list_sheets()`` returns a list of strings representing sheet - names -- ``XlsxioReader:open_sheet(sheet_name)`` returns an initialized - ``XlsxioSheetReader`` object - -The ``XlsxioSheetReader`` class has the following methods: - -- ``XlsxioSheetReader:close()`` closes the sheet -- ``XlsxioSheetReader:get_row(max_tokens)`` reads the next row from the sheet. - If ``max_tokens`` is specified and is a positive integer, only the first - ``max_tokens`` elements of the row are returned. - -Here is an end-to-end example:: - - local xlsxreader = require('plugins.xlsxreader') - - local function dump_sheet(reader, sheet_name) - print('reading sheet: ' .. sheet_name) - local sheet_reader = reader:open_sheet(sheet_name) - dfhack.with_finalize( - function() sheet_reader:close() end, - function() - local row_cells = sheet_reader:get_row() - while row_cells do - printall(row_cells) - row_cells = sheet_reader:get_row() - end - end - ) - end - - local filepath = 'path/to/some_file.xlsx' - local reader = xlsxreader.open(filepath) - dfhack.with_finalize( - function() reader:close() end, - function() - for _,sheet_name in ipairs(reader:list_sheets()) do - dump_sheet(reader, sheet_name) - end - end - ) - -======= -Scripts -======= - -.. contents:: - :local: - -Any files with the ``.lua`` extension placed into the :file:`hack/scripts` folder -are automatically made avaiable as DFHack commands. The command corresponding to -a script is simply the script's filename, relative to the scripts folder, with -the extension omitted. For example: - -* :file:`hack/scripts/add-thought.lua` is invoked as ``add-thought`` -* :file:`hack/scripts/gui/teleport.lua` is invoked as ``gui/teleport`` - -.. note:: - Scripts placed in subdirectories can be run as described above, but are not - listed by the `ls` command unless ``-a`` is specified. In general, scripts - should be placed in subfolders in the following situations: - - * ``devel``: scripts that are intended exclusively for DFHack development, - including examples, or scripts that are experimental and unstable - * ``fix``: fixes for specific DF issues - * ``gui``: GUI front-ends for existing tools (for example, see the - relationship between `teleport` and `gui/teleport`) - * ``modtools``: scripts that are intended to be run exclusively as part of - mods, not directly by end-users (as a rule of thumb: if someone other than - a mod developer would want to run a script from the console, it should - not be placed in this folder) - -Scripts can also be placed in other folders - by default, these include -:file:`raw/scripts` and :file:`data/save/{region}/raw/scripts`, but additional -folders can be added (for example, a copy of the -:source-scripts:`scripts repository <>` for local development). See -`script-paths` for more information on how to configure this behavior. - -If the first line of the script is a one-line comment (starting with ``--``), -the content of the comment is used by the built-in ``ls`` and ``help`` commands. -Such a comment is required for every script in the official DFHack repository. - -Scripts are read from disk when run for the first time, or if they have changed -since the last time they were run. - -Each script has an isolated environment where global variables set by the script -are stored. Values of globals persist across script runs in the same DF session. -See `devel/lua-example` for an example of this behavior. Note that local -variables do *not* persist. - -Arguments are passed in to the scripts via the ``...`` built-in quasi-variable; -when the script is called by the DFHack core, they are all guaranteed to be -non-nil strings. - -Additional data about how a script is invoked is passed to the script as a -special ``dfhack_flags`` global, which is unique to each script. This table -is guaranteed to exist, but individual entries may be present or absent -depending on how the script was invoked. Flags that are present are described -in the subsections below. - -DFHack invokes the scripts in the `core context `; however it -is possible to call them from any lua code (including from other scripts) in any -context with ``dfhack.run_script()`` below. - -General script API -================== - -* ``dfhack.run_script(name[,args...])`` - - Run a Lua script in hack/scripts/, as if it were started from the DFHack - command-line. The ``name`` argument should be the name of the script without - its extension, as it would be used on the command line. - - Example: - - In DFHack prompt:: - - repeat -time 14 -timeUnits days -command [ workorder ShearCreature ] -name autoShearCreature - - In Lua script:: - - dfhack.run_script("repeat", "-time", "14", "-timeUnits", "days", "-command", "[", "workorder", "ShearCreature", "]", "-name", "autoShearCreature") - - Note that the ``dfhack.run_script()`` function allows Lua errors to propagate to the caller. - - To run other types of commands (such as built-in commands, plugin commands, or - Ruby scripts), see ``dfhack.run_command()``. Note that this is slightly slower - than ``dfhack.run_script()`` for Lua scripts. - -* ``dfhack.script_help([name, [extension]])`` - - Returns the contents of the embedded documentation of the specified script. - ``extension`` defaults to "lua", and ``name`` defaults to the name of the - script where this function was called. For example, the following can be used - to print the current script's help text:: - - local args = {...} - if args[1] == 'help' then - print(script_help()) - return - end - - -Importing scripts -================= - -* ``dfhack.reqscript(name)`` or ``reqscript(name)`` - - Loads a Lua script and returns its environment (i.e. a table of all global - functions and variables). This is similar to the built-in ``require()``, but - searches all script paths for the first matching ``name.lua`` file instead - of searching the Lua library paths (like ``hack/lua``). - - Most scripts can be made to support ``reqscript()`` without significant - changes (in contrast, ``require()`` requires the use of ``mkmodule()`` and - some additional boilerplate). However, because scripts can have side effects - when they are loaded (such as printing messages or modifying the game state), - scripts that intend to support being imported must satisfy some criteria to - ensure that they can be imported safely: - - 1. Include the following line - ``reqscript()`` will fail if this line is - not present:: - - --@ module = true - - 2. Include a check for ``dfhack_flags.module``, and avoid running any code - that has side-effects if this flag is true. For instance:: - - -- (function definitions) - if dfhack_flags.module then - return - end - -- (main script code with side-effects) - - or:: - - -- (function definitions) - function main() - -- (main script code with side-effects) - end - if not dfhack_flags.module then - main() - end - - Example usage:: - - local addThought = reqscript('add-thought') - addThought.addEmotionToUnit(unit, ...) - - Circular dependencies between scripts are supported, as long as the scripts - have no side-effects at load time (which should already be the case per - the above criteria). - - .. warning:: - - Avoid caching the table returned by ``reqscript()`` beyond storing it in - a local or global variable as in the example above. ``reqscript()`` is fast - for scripts that have previously been loaded and haven't changed. If you - retain a reference to a table returned by an old ``reqscript()`` call, this - may lead to unintended behavior if the location of the script changes - (e.g. if a save is loaded or unloaded, or if a `script path ` - is added in some other way). - - .. admonition:: Tip - - Mods that include custom Lua modules can write these modules to support - ``reqscript()`` and distribute them as scripts in ``raw/scripts``. Since the - entire ``raw`` folder is copied into new saves, this will allow saves to be - successfully transferred to other users who do not have the mod installed - (as long as they have DFHack installed). - - .. admonition:: Backwards compatibility notes - - For backwards compatibility, ``moduleMode`` is also defined if - ``dfhack_flags.module`` is defined, and is set to the same value. - Support for this may be removed in a future version. - -* ``dfhack.script_environment(name)`` - - Similar to ``reqscript()`` but does not enforce the check for module support. - This can be used to import scripts that support being used as a module but do - not declare support as described above, although it is preferred to update - such scripts so that ``reqscript()`` can be used instead. - -Enabling and disabling scripts -============================== - -Scripts can choose to recognize the built-in ``enable`` and ``disable`` commands -by including the following line anywhere in their file:: - - --@ enable = true - -When the ``enable`` and ``disable`` commands are invoked, the ``dfhack_flags`` -table passed to the script will have the following fields set: - -* ``enable``: Always ``true`` if the script is being enabled *or* disabled -* ``enable_state``: ``true`` if the script is being enabled, ``false`` otherwise - -Example usage:: - - --@ enable = true - -- (function definitions...) - if dfhack_flags.enable then - if dfhack_flags.enable_state then - start() - else - stop() - end - end - -Save init script -================ - -If a save directory contains a file called ``raw/init.lua``, it is -automatically loaded and executed every time the save is loaded. -The same applies to any files called ``raw/init.d/*.lua``. Every -such script can define the following functions to be called by dfhack: - -* ``function onStateChange(op) ... end`` - - Automatically called from the regular onStateChange event as long - as the save is still loaded. This avoids the need to install a hook - into the global ``dfhack.onStateChange`` table, with associated - cleanup concerns. - -* ``function onUnload() ... end`` - - Called when the save containing the script is unloaded. This function - should clean up any global hooks installed by the script. Note that - when this is called, the world is already completely unloaded. - -Within the init script, the path to the save directory is available as ``SAVE_PATH``. diff --git a/docs/NEWS-dev.rst b/docs/NEWS-dev.rst index f0c47fe963..f77b1b4f51 100644 --- a/docs/NEWS-dev.rst +++ b/docs/NEWS-dev.rst @@ -5,7 +5,7 @@ .. _dev-changelog: ##################### -Development Changelog +Development changelog ##################### This file contains changes grouped by the release (stable or development) in @@ -17,4 +17,4 @@ See `changelog` for a list of changes grouped by stable releases. :local: :depth: 1 -.. include:: /docs/_auto/news-dev.rst +.. include:: /docs/changelogs/news-dev.rst diff --git a/docs/NEWS.rst b/docs/NEWS.rst index 1283b079af..41e64b339b 100644 --- a/docs/NEWS.rst +++ b/docs/NEWS.rst @@ -17,11 +17,11 @@ See `dev-changelog` for a list of changes grouped by development releases. :local: :depth: 1 -.. include:: /docs/_auto/news.rst +.. include:: /docs/changelogs/news.rst Older Changelogs ================ -Are kept in a seperate file: `History` +Are kept in a separate file: `History` -.. that's ``docs/History.rst``, if you're reading the raw text. +.. that's ``docs/about/History.rst``, if you're reading the raw text. diff --git a/docs/Plugins.rst b/docs/Plugins.rst deleted file mode 100644 index 6db9af3229..0000000000 --- a/docs/Plugins.rst +++ /dev/null @@ -1,3229 +0,0 @@ -.. _plugins-index: - -############## -DFHack Plugins -############## - -DFHack plugins are the commands, that are compiled with a specific version. -They can provide anything from a small keybinding, to a complete overhaul of -game subsystems or the entire renderer. - -Most commands offered by plugins are listed here, -hopefully organised in a way you will find useful. - -.. contents:: Contents - :local: - :depth: 2 - -=============================== -Data inspection and visualizers -=============================== - -.. contents:: - :local: - -.. _plugin-stonesense: - -stonesense -========== -An isometric visualizer that runs in a second window. Usage: - -:stonesense: Open the visualiser in a new window. Alias ``ssense``. -:ssense overlay: Overlay DF window, replacing the map area. - -For more information, see `the full Stonesense README `. - -.. _blueprint: - -blueprint -========= -The ``blueprint`` command exports the structure of a portion of your fortress in -a blueprint file that you (or anyone else) can later play back with `quickfort`. - -Blueprints are ``.csv`` or ``.xlsx`` files created in the ``blueprints`` -subdirectory of your DF folder. The map area to turn into a blueprint is either -selected interactively with the ``blueprint gui`` command or, if the GUI is not -used, starts at the active cursor location and extends right and down for the -requested width and height. - -**Usage:** - - ``blueprint [] [ []] []`` - - ``blueprint gui [ []] []`` - -**Examples:** - -``blueprint gui`` - Runs `gui/blueprint`, the interactive frontend, where all configuration for - a ``blueprint`` command can be set visually and interactively. - -``blueprint 30 40 bedrooms`` - Generates blueprints for an area 30 tiles wide by 40 tiles tall, starting - from the active cursor on the current z-level. Output is written to files - with names matching the pattern ``bedrooms-PHASE.csv`` in the ``blueprints`` - directory. - -``blueprint 30 40 bedrooms dig --cursor 108,100,150`` - Generates only the ``bedrooms-dig.csv`` file from the previous example, and - the blueprint start coordinate is set to a specific value instead of using - the in-game cursor position. - -**Positional Parameters:** - -:``width``: Width of the area (in tiles) to translate. -:``height``: Height of the area (in tiles) to translate. -:``depth``: Number of z-levels to translate. Positive numbers go *up* from the - cursor and negative numbers go *down*. Defaults to 1 if not specified, - indicating that the blueprint should only include the current z-level. -:``name``: Base name for blueprint files created in the ``blueprints`` - directory. If no name is specified, "blueprint" is used by default. The - string must contain some characters other than numbers so the name won't be - confused with the optional ``depth`` parameter. - -**Phases:** - -If you want to generate blueprints only for specific phases, add their names to -the commandline, anywhere after the blueprint base name. You can list multiple -phases; just separate them with a space. - -:``dig``: Generate quickfort ``#dig`` blueprints. -:``build``: Generate quickfort ``#build`` blueprints for constructions and - buildings. -:``place``: Generate quickfort ``#place`` blueprints for placing stockpiles. -:``query``: Generate quickfort ``#query`` blueprints for configuring rooms. - -If no phases are specified, all blueprints are created. - -**Options:** - -``-c``, ``--cursor ,,``: - Use the specified map coordinates instead of the current cursor position for - the upper left corner of the blueprint range. If this option is specified, - then an active game map cursor is not necessary. -``-f``, ``--format ``: - Select the output format of the generated files. See the ``Output formats`` - section below for options. If not specified, the output format defaults to - "minimal", which will produce a small, fast ``.csv`` file. -``-h``, ``--help``: - Show command help text. -``-s``, ``--playback-start ,,``: - Specify the column and row offsets (relative to the upper-left corner of the - blueprint, which is ``1,1``) where the player should put the cursor when the - blueprint is played back with `quickfort`, in - `quickfort start marker ` format, for example: - ``10,10,central stairs``. If there is a space in the comment, you will need - to surround the parameter string in double quotes: ``"-s10,10,central stairs"`` or - ``--playback-start "10,10,central stairs"`` or - ``"--playback-start=10,10,central stairs"``. -``-t``, ``--splitby ``: - Split blueprints into multiple files. See the ``Splitting output into - multiple files`` section below for details. If not specified, defaults to - "none", which will create a standard quickfort - `multi-blueprint ` file. - -**Output formats:** - -Here are the values that can be passed to the ``--format`` flag: - -:``minimal``: - Creates ``.csv`` files with minimal file size that are fast to read and - write. This is the default. -:``pretty``: - Makes the blueprints in the ``.csv`` files easier to read and edit with a text - editor by adding extra spacing and alignment markers. - -**Splitting output into multiple files:** - -The ``--splitby`` flag can take any of the following values: - -:``none``: - Writes all blueprints into a single file. This is the standard format for - quickfort fortress blueprint bundles and is the default. -:``phase``: - Creates a separate file for each phase. - -.. _remotefortressreader: - -remotefortressreader -==================== -An in-development plugin for realtime fortress visualisation. -See :forums:`Armok Vision <146473>`. - -.. _isoworldremote: - -isoworldremote -============== -A plugin that implements a `remote API ` used by Isoworld. - -.. _cursecheck: - -cursecheck -========== -Checks a single map tile or the whole map/world for cursed creatures (ghosts, -vampires, necromancers, werebeasts, zombies). - -With an active in-game cursor only the selected tile will be observed. -Without a cursor the whole map will be checked. - -By default cursed creatures will be only counted in case you just want to find -out if you have any of them running around in your fort. Dead and passive -creatures (ghosts who were put to rest, killed vampires, ...) are ignored. -Undead skeletons, corpses, bodyparts and the like are all thrown into the curse -category "zombie". Anonymous zombies and resurrected body parts will show -as "unnamed creature". - -Options: - -:detail: Print full name, date of birth, date of curse and some status - info (some vampires might use fake identities in-game, though). -:nick: Set the type of curse as nickname (does not always show up - in-game, some vamps don't like nicknames). -:all: Include dead and passive cursed creatures (can result in a quite - long list after having FUN with necromancers). -:verbose: Print all curse tags (if you really want to know it all). - -Examples: - -``cursecheck detail all`` - Give detailed info about all cursed creatures including deceased ones (no - in-game cursor). -``cursecheck nick`` - Give a nickname all living/active cursed creatures on the map(no in-game - cursor). - -.. note:: - - If you do a full search (with the option "all") former ghosts will show up - with the cursetype "unknown" because their ghostly flag is not set. - - Please report any living/active creatures with cursetype "unknown" - - this is most likely with mods which introduce new types of curses. - -.. _flows: - -flows -===== -A tool for checking how many tiles contain flowing liquids. If you suspect that -your magma sea leaks into HFS, you can use this tool to be sure without -revealing the map. - -.. _probe: - -probe -===== - -This plugin provides multiple commands that print low-level properties of the -selected objects. - -* ``probe``: prints some properties of the tile selected with :kbd:`k`. Some of - these properties can be passed into `tiletypes`. -* ``cprobe``: prints some properties of the unit selected with :kbd:`v`, as well - as the IDs of any worn items. `gui/gm-unit` and `gui/gm-editor` are more - complete in-game alternatives. -* ``bprobe``: prints some properties of the building selected with :kbd:`q` or - :kbd:`t`. `gui/gm-editor` is a more complete in-game alternative. - -.. _prospect: -.. _prospector: - -prospect -======== -Prints a big list of all the present minerals and plants. By default, only -the visible part of the map is scanned. - -Options: - -:all: Scan the whole map, as if it were revealed. -:value: Show material value in the output. Most useful for gems. -:hell: Show the Z range of HFS tubes. Implies 'all'. - -If prospect is called during the embark selection screen, it displays an estimate of -layer stone availability. - -.. note:: - - The results of pre-embark prospect are an *estimate*, and can at best be expected - to be somewhere within +/- 30% of the true amount; sometimes it does a lot worse. - Especially, it is not clear how to precisely compute how many soil layers there - will be in a given embark tile, so it can report a whole extra layer, or omit one - that is actually present. - -Options: - -:all: Also estimate vein mineral amounts. - -.. _reveal: -.. _unreveal: -.. _revtoggle: -.. _revflood: -.. _revforget: - -reveal -====== -This reveals the map. By default, HFS will remain hidden so that the demons -don't spawn. You can use ``reveal hell`` to reveal everything. With hell revealed, -you won't be able to unpause until you hide the map again. If you really want -to unpause with hell revealed, use ``reveal demons``. - -Reveal also works in adventure mode, but any of its effects are negated once -you move. When you use it this way, you don't need to run ``unreveal``. - -Usage and related commands: - -:reveal: Reveal the whole map, except for HFS to avoid demons spawning -:reveal hell: Also show hell, but requires ``unreveal`` before unpausing -:reveal demon: Reveals everything and allows unpausing - good luck! -:unreveal: Reverts the effects of ``reveal`` -:revtoggle: Switches between ``reveal`` and ``unreveal`` -:revflood: Hide everything, then reveal tiles with a path to the cursor. - Note that tiles behind constructed walls are also revealed as a - workaround for :bug:`1871`. -:revforget: Discard info about what was visible before revealing the map. - Only useful where (e.g.) you abandoned with the fort revealed - and no longer want the data. - -.. _showmood: - -showmood -======== -Shows all items needed for the currently active strange mood. - - -======== -Bugfixes -======== - -.. contents:: - :local: - -.. _fix-unit-occupancy: - -fix-unit-occupancy -================== -This plugin fixes issues with unit occupancy, notably phantom -"unit blocking tile" messages (:bug:`3499`). It can be run manually, or -periodically when enabled with the built-in enable/disable commands: - -:(no argument): Run the plugin once immediately, for the whole map. -:-h, here, cursor: Run immediately, only operate on the tile at the cursor -:-n, dry, dry-run: Run immediately, do not write changes to map -:interval : Run the plugin every ``X`` ticks (when enabled). - The default is 1200 ticks, or 1 day. - Ticks are only counted when the game is unpaused. - -.. _fixveins: - -fixveins -======== -Removes invalid references to mineral inclusions and restores missing ones. -Use this if you broke your embark with tools like `tiletypes`, or if you -accidentally placed a construction on top of a valuable mineral floor. - -.. _petcapRemover: - -petcapRemover -============= -Allows you to remove or raise the pet population cap. In vanilla -DF, pets will not reproduce unless the population is below 50 and the number of -children of that species is below a certain percentage. This plugin allows -removing the second restriction and removing or raising the first. Pets still -require PET or PET_EXOTIC tags in order to reproduce. Type ``help petcapRemover`` -for exact usage. In order to make population more stable and avoid sudden -population booms as you go below the raised population cap, this plugin counts -pregnancies toward the new population cap. It can still go over, but only in the -case of multiple births. - -Usage: - -:petcapRemover: cause pregnancies now and schedule the next check -:petcapRemover every n: set how often in ticks the plugin checks for possible pregnancies -:petcapRemover cap n: set the new cap to n. if n = 0, no cap -:petcapRemover pregtime n: sets the pregnancy duration to n ticks. natural pregnancies are - 300000 ticks for the current race and 200000 for everyone else - -.. _tweak: - -tweak -===== -Contains various tweaks for minor bugs. - -One-shot subcommands: - -:clear-missing: Remove the missing status from the selected unit. - This allows engraving slabs for ghostly, but not yet - found, creatures. -:clear-ghostly: Remove the ghostly status from the selected unit and mark - it as dead. This allows getting rid of bugged ghosts - which do not show up in the engraving slab menu at all, - even after using clear-missing. It works, but is - potentially very dangerous - so use with care. Probably - (almost certainly) it does not have the same effects like - a proper burial. You've been warned. -:fixmigrant: Remove the resident/merchant flag from the selected unit. - Intended to fix bugged migrants/traders who stay at the - map edge and don't enter your fort. Only works for - dwarves (or generally the player's race in modded games). - Do NOT abuse this for 'real' caravan merchants (if you - really want to kidnap them, use 'tweak makeown' instead, - otherwise they will have their clothes set to forbidden etc). -:makeown: Force selected unit to become a member of your fort. - Can be abused to grab caravan merchants and escorts, even if - they don't belong to the player's race. Foreign sentients - (humans, elves) can be put to work, but you can't assign rooms - to them and they don't show up in DwarfTherapist because the - game treats them like pets. Grabbing draft animals from - a caravan can result in weirdness (animals go insane or berserk - and are not flagged as tame), but you are allowed to mark them - for slaughter. Grabbing wagons results in some funny spam, then - they are scuttled. - -Subcommands that persist until disabled or DF quits: - -.. comment: sort these alphabetically - -:adamantine-cloth-wear: Prevents adamantine clothing from wearing out while being worn (:bug:`6481`). -:advmode-contained: Works around :bug:`6202`, custom reactions with container inputs - in advmode. The issue is that the screen tries to force you to select - the contents separately from the container. This forcefully skips child - reagents. -:block-labors: Prevents labors that can't be used from being toggled -:burrow-name-cancel: Implements the "back" option when renaming a burrow, - which currently does nothing (:bug:`1518`) -:cage-butcher: Adds an option to butcher units when viewing cages with :kbd:`q` -:civ-view-agreement: Fixes overlapping text on the "view agreement" screen -:condition-material: Fixes a crash in the work order contition material list (:bug:`9905`). -:craft-age-wear: Fixes the behavior of crafted items wearing out over time (:bug:`6003`). - With this tweak, items made from cloth and leather will gain a level of - wear every 20 years. -:do-job-now: Adds a job priority toggle to the jobs list -:embark-profile-name: Allows the use of lowercase letters when saving embark profiles -:eggs-fertile: Displays a fertility indicator on nestboxes -:farm-plot-select: Adds "Select all" and "Deselect all" options to farm plot menus -:fast-heat: Further improves temperature update performance by ensuring that 1 degree - of item temperature is crossed in no more than specified number of frames - when updating from the environment temperature. This reduces the time it - takes for stable-temp to stop updates again when equilibrium is disturbed. -:fast-trade: Makes Shift-Down in the Move Goods to Depot and Trade screens select - the current item (fully, in case of a stack), and scroll down one line. -:fps-min: Fixes the in-game minimum FPS setting -:hide-priority: Adds an option to hide designation priority indicators -:hotkey-clear: Adds an option to clear currently-bound hotkeys (in the :kbd:`H` menu) -:import-priority-category: - Allows changing the priority of all goods in a - category when discussing an import agreement with the liaison -:kitchen-prefs-all: Adds an option to toggle cook/brew for all visible items in kitchen preferences -:kitchen-prefs-color: Changes color of enabled items to green in kitchen preferences -:kitchen-prefs-empty: Fixes a layout issue with empty kitchen tabs (:bug:`9000`) -:max-wheelbarrow: Allows assigning more than 3 wheelbarrows to a stockpile -:military-color-assigned: - Color squad candidates already assigned to other squads in yellow/green - to make them stand out more in the list. - - .. image:: images/tweak-mil-color.png - -:military-stable-assign: - Preserve list order and cursor position when assigning to squad, - i.e. stop the rightmost list of the Positions page of the military - screen from constantly resetting to the top. -:nestbox-color: Fixes the color of built nestboxes -:reaction-gloves: Fixes reactions to produce gloves in sets with correct handedness (:bug:`6273`) -:shift-8-scroll: Gives Shift-8 (or :kbd:`*`) priority when scrolling menus, instead of scrolling the map -:stable-cursor: Saves the exact cursor position between t/q/k/d/b/etc menus of fortress mode. -:stone-status-all: Adds an option to toggle the economic status of all stones -:title-start-rename: Adds a safe rename option to the title screen "Start Playing" menu -:tradereq-pet-gender: Displays pet genders on the trade request screen - -.. comment: sort these alphabetically - -.. _fix-armory: - -fix-armory -========== -`This plugin requires a binpatch `, which has not -been available since DF 0.34.11 - - -=========== -UI Upgrades -=========== - -.. note:: - In order to avoid user confusion, as a matter of policy all GUI tools - display the word :guilabel:`DFHack` on the screen somewhere while active. - - When that is not appropriate because they merely add keybinding hints to - existing DF screens, they deliberately use red instead of green for the key. - -.. contents:: - :local: - - -.. _automelt: - -automelt -======== -When automelt is enabled for a stockpile, any meltable items placed -in it will be designated to be melted. -This plugin adds an option to the :kbd:`q` menu when `enabled `. - -.. _autotrade: - -autotrade -========= -When autotrade is enabled for a stockpile, any items placed in it will be -designated to be taken to the Trade Depot whenever merchants are on the map. -This plugin adds an option to the :kbd:`q` menu when `enabled `. - -.. _command-prompt: - -command-prompt -============== -An in-game DFHack terminal, where you can enter other commands. - -:dfhack-keybind:`command-prompt` - -Usage: ``command-prompt [entry]`` - -If called with an entry, it starts with that text filled in. -Most useful for developers, who can set a keybinding to open -a laungage interpreter for lua or Ruby by starting with the -`:lua ` or `:rb ` commands. - -Otherwise somewhat similar to `gui/quickcmd`. - -.. image:: images/command-prompt.png - - -.. _debug: - -debug -===== -Manager for DFHack runtime debug prints. Debug prints are grouped by plugin name, -category name and print level. Levels are ``trace``, ``debug``, ``info``, -``warning`` and ``error``. - -The runtime message printing is controlled using filters. Filters set the -visible messages of all matching categories. Matching uses regular expression syntax, -which allows listing multiple alternative matches or partial name matches. -This syntax is a C++ version of the ECMA-262 grammar (Javascript regular expressions). -Details of differences can be found at -https://en.cppreference.com/w/cpp/regex/ecmascript - -Persistent filters are stored in ``dfhack-config/runtime-debug.json``. -Oldest filters are applied first. That means a newer filter can override the -older printing level selection. - -Usage: ``debugfilter [subcommand] [parameters...]`` - -The following subcommands are supported: - -help ----- -Give overall help or a detailed help for a subcommand. - -Usage: ``debugfilter help [subcommand]`` - -category --------- -List available debug plugin and category names. - -Usage: ``debugfilter category [plugin regex] [category regex]`` - -The list can be filtered using optional regex parameters. If filters aren't -given then the it uses ``"."`` regex which matches any character. The regex -parameters are good way to test regex before passing them to ``set``. - -filter ------- -List active and passive debug print level changes. - -Usage: ``debugfilter filter [id]`` - -Optional ``id`` parameter is the id listed as first column in the filter list. -If id is given then the command shows information for the given filter only in -multi line format that is better format if filter has long regex. - -set ---- -Creates a new debug filter to set category printing levels. - -Usage: ``debugfilter set [level] [plugin regex] [category regex]`` - -Adds a filter that will be deleted when DF process exists or plugin is unloaded. - -Usage: ``debugfilter set persistent [level] [plugin regex] [category regex]`` - -Stores the filter in the configuration file to until ``unset`` is used to remove -it. - -Level is the minimum debug printing level to show in log. - -* ``trace``: Possibly very noisy messages which can be printed many times per second - -* ``debug``: Messages that happen often but they should happen only a couple of times per second - -* ``info``: Important state changes that happen rarely during normal execution - -* ``warning``: Enabled by default. Shows warnings about unexpected events which code managed to handle correctly. - -* ``error``: Enabled by default. Shows errors which code can't handle without user intervention. - -unset ------ -Delete a space separated list of filters - -Usage: ``debugfilter unset [id...]`` - -disable -------- -Disable a space separated list of filters but keep it in the filter list - -Usage: ``debugfilter disable [id...]`` - -enable ------- -Enable a space sperate list of filters - -Usage: ``debugfilter enable [id...]`` - -.. _hotkeys: - -hotkeys -======= -Opens an in-game screen showing which DFHack keybindings are -active in the current context. See also `hotkey-notes`. - -.. image:: images/hotkeys.png - -:dfhack-keybind:`hotkeys` - -.. _rb: -.. _ruby: - -ruby -==== -Ruby language plugin, which evaluates the following arguments as a ruby string. -Best used as ``:rb [string]``, for the special parsing mode. Alias ``rb_eval``. - -.. _manipulator: - -manipulator -=========== -An in-game equivalent to the popular program Dwarf Therapist. - -To activate, open the unit screen and press :kbd:`l`. - -.. image:: images/manipulator.png - -The far left column displays the unit's Happiness (color-coded based on its -value), Name, Profession/Squad, and the right half of the screen displays each -dwarf's labor settings and skill levels (0-9 for Dabbling through Professional, -A-E for Great through Grand Master, and U-Z for Legendary through Legendary+5). - -Cells with teal backgrounds denote skills not controlled by labors, e.g. -military and social skills. - -.. image:: images/manipulator2.png - -Press :kbd:`t` to toggle between Profession, Squad, and Job views. - -.. image:: images/manipulator3.png - -Use the arrow keys or number pad to move the cursor around, holding :kbd:`Shift` to -move 10 tiles at a time. - -Press the Z-Up (:kbd:`<`) and Z-Down (:kbd:`>`) keys to move quickly between labor/skill -categories. The numpad Z-Up and Z-Down keys seek to the first or last unit -in the list. :kbd:`Backspace` seeks to the top left corner. - -Press Enter to toggle the selected labor for the selected unit, or Shift+Enter -to toggle all labors within the selected category. - -Press the :kbd:`+`:kbd:`-` keys to sort the unit list according to the currently selected -skill/labor, and press the :kbd:`*`:kbd:`/` keys to sort the unit list by Name, Profession/Squad, -Happiness, or Arrival order (using :kbd:`Tab` to select which sort method to use here). - -With a unit selected, you can press the :kbd:`v` key to view its properties (and -possibly set a custom nickname or profession) or the :kbd:`c` key to exit -Manipulator and zoom to its position within your fortress. - -The following mouse shortcuts are also available: - -* Click on a column header to sort the unit list. Left-click to sort it in one - direction (descending for happiness or labors/skills, ascending for name, - profession or squad) and right-click to sort it in the opposite direction. -* Left-click on a labor cell to toggle that labor. Right-click to move the - cursor onto that cell instead of toggling it. -* Left-click on a unit's name, profession or squad to view its properties. -* Right-click on a unit's name, profession or squad to zoom to it. - -Pressing :kbd:`Esc` normally returns to the unit screen, but :kbd:`Shift`:kbd:`Esc` would exit -directly to the main dwarf mode screen. - -Professions ------------ - -The manipulator plugin supports saving professions: a named set of labors that can be -quickly applied to one or multiple dwarves. - -To save a profession, highlight a dwarf and press :kbd:`P`. The profession will be saved using -the custom profession name of the dwarf, or the default for that dwarf if no custom profession -name has been set. - -To apply a profession, either highlight a single dwarf or select multiple with -:kbd:`x`, and press :kbd:`p` to select the profession to apply. All labors for -the selected dwarves will be reset to the labors of the chosen profession. - -Professions are saved as human-readable text files in the "professions" folder -within the DF folder, and can be edited or deleted there. - -.. comment - the link target "search" is reserved for the Sphinx search page -.. _search-plugin: - -search -====== -The search plugin adds search to the Stocks, Animals, Trading, Stockpile, -Noble (assignment candidates), Military (position candidates), Burrows -(unit list), Rooms, Announcements, Job List and Unit List screens. - -.. image:: images/search.png - -Searching works the same way as the search option in :guilabel:`Move to Depot`. -You will see the Search option displayed on screen with a hotkey (usually :kbd:`s`). -Pressing it lets you start typing a query and the relevant list will start -filtering automatically. - -Pressing :kbd:`Enter`, :kbd:`Esc` or the arrow keys will return you to browsing the now -filtered list, which still functions as normal. You can clear the filter -by either going back into search mode and backspacing to delete it, or -pressing the "shifted" version of the search hotkey while browsing the -list (e.g. if the hotkey is :kbd:`s`, then hitting :kbd:`Shift`:kbd:`s` will clear any -filter). - -Leaving any screen automatically clears the filter. - -In the Trade screen, the actual trade will always only act on items that -are actually visible in the list; the same effect applies to the Trade -Value numbers displayed by the screen. Because of this, the :kbd:`t` key is -blocked while search is active, so you have to reset the filters first. -Pressing :kbd:`Alt`:kbd:`C` will clear both search strings. - -In the stockpile screen the option only appears if the cursor is in the -rightmost list: - -.. image:: images/search-stockpile.png - -Note that the 'Permit XXX'/'Forbid XXX' keys conveniently operate only -on items actually shown in the rightmost list, so it is possible to select -only fat or tallow by forbidding fats, then searching for fat/tallow, and -using Permit Fats again while the list is filtered. - - -.. _nopause: - -nopause -======= -Disables pausing (both manual and automatic) with the exception of pause forced -by `reveal` ``hell``. This is nice for digging under rivers. - -.. _embark-assistant: - -embark-assistant -================ - -This plugin provides embark site selection help. It has to be run with the -``embark-assistant`` command while the pre-embark screen is displayed and shows -extended (and correct(?)) resource information for the embark rectangle as well -as normally undisplayed sites in the current embark region. It also has a site -selection tool with more options than DF's vanilla search tool. For detailed -help invoke the in game info screen. - -.. _embark-tools: - -embark-tools -============ -A collection of embark-related tools. Usage and available tools:: - - embark-tools enable/disable tool [tool]... - -:anywhere: Allows embarking anywhere (including sites, mountain-only biomes, - and oceans). Use with caution. -:mouse: Implements mouse controls (currently in the local embark region only) -:sand: Displays an indicator when sand is present in the currently-selected - area, similar to the default clay/stone indicators. -:sticky: Maintains the selected local area while navigating the world map - -.. _automaterial: - -automaterial -============ -This makes building constructions (walls, floors, fortifications, etc) a little bit -easier by saving you from having to trawl through long lists of materials each time -you place one. - -Firstly, it moves the last used material for a given construction type to the top of -the list, if there are any left. So if you build a wall with chalk blocks, the next -time you place a wall the chalk blocks will be at the top of the list, regardless of -distance (it only does this in "grouped" mode, as individual item lists could be huge). -This should mean you can place most constructions without having to search for your -preferred material type. - -.. image:: images/automaterial-mat.png - -Pressing :kbd:`a` while highlighting any material will enable that material for "auto select" -for this construction type. You can enable multiple materials as autoselect. Now the next -time you place this type of construction, the plugin will automatically choose materials -for you from the kinds you enabled. If there is enough to satisfy the whole placement, -you won't be prompted with the material screen - the construction will be placed and you -will be back in the construction menu as if you did it manually. - -When choosing the construction placement, you will see a couple of options: - -.. image:: images/automaterial-pos.png - -Use :kbd:`a` here to temporarily disable the material autoselection, e.g. if you need -to go to the material selection screen so you can toggle some materials on or off. - -The other option (auto type selection, off by default) can be toggled on with :kbd:`t`. If you -toggle this option on, instead of returning you to the main construction menu after selecting -materials, it returns you back to this screen. If you use this along with several autoselect -enabled materials, you should be able to place complex constructions more conveniently. - -.. _buildingplan: - -buildingplan -============ -When active (via ``enable buildingplan``), this plugin adds a planning mode for -building placement. You can then place furniture, constructions, and other buildings -before the required materials are available, and they will be created in a suspended -state. Buildingplan will periodically scan for appropriate items, and the jobs will -be unsuspended when the items are available. - -This is very useful when combined with `workflow` - you can set a constraint -to always have one or two doors/beds/tables/chairs/etc available, and place -as many as you like. The plugins then take over and fulfill the orders, -with minimal space dedicated to stockpiles. - -.. _buildingplan-filters: - -Item filtering --------------- - -While placing a building, you can set filters for what materials you want the building made -out of, what quality you want the component items to be, and whether you want the items to -be decorated. - -If a building type takes more than one item to construct, use :kbd:`Ctrl`:kbd:`Left` and -:kbd:`Ctrl`:kbd:`Right` to select the item that you want to set filters for. Any filters that -you set will be used for all buildings of the selected type placed from that point onward -(until you set a new filter or clear the current one). Buildings placed before the filters -were changed will keep the filter values that were set when the building was placed. - -For example, you can be sure that all your constructed walls are the same color by setting -a filter to accept only certain types of stone. - -Quickfort mode --------------- - -If you use the external Python Quickfort to apply building blueprints instead of the native -DFHack `quickfort` script, you must enable Quickfort mode. This temporarily enables -buildingplan for all building types and adds an extra blank screen after every building -placement. This "dummy" screen is needed for Python Quickfort to interact successfully with -Dwarf Fortress. - -Note that Quickfort mode is only for compatibility with the legacy Python Quickfort. The -DFHack `quickfort` script does not need Quickfort mode to be enabled. The `quickfort` script -will successfully integrate with buildingplan as long as the buildingplan plugin is enabled. - -.. _buildingplan-settings: - -Global settings ---------------- - -The buildingplan plugin has several global settings that can be set from the UI (:kbd:`G` -from any building placement screen, for example: :kbd:`b`:kbd:`a`:kbd:`G`). These settings -can also be set from the ``DFHack#`` prompt once a map is loaded (or from your -``onMapLoad.init`` file) with the syntax:: - - buildingplan set - -and displayed with:: - - buildingplan set - -The available settings are: - -+----------------+---------+-----------+---------------------------------------+ -| Setting | Default | Persisted | Description | -+================+=========+===========+=======================================+ -| all_enabled | false | no | Enable planning mode for all building | -| | | | types. | -+----------------+---------+-----------+---------------------------------------+ -| blocks | true | yes | Allow blocks, boulders, logs, or bars | -+----------------+---------+ | to be matched for generic "building | -| boulders | true | | material" items | -+----------------+---------+ | | -| logs | true | | | -+----------------+---------+ | | -| bars | false | | | -+----------------+---------+-----------+---------------------------------------+ -| quickfort_mode | false | no | Enable compatibility mode for the | -| | | | legacy Python Quickfort (not required | -| | | | for DFHack quickfort) | -+----------------+---------+-----------+---------------------------------------+ - -For example, to ensure you only use blocks when a "building material" item is required, you -could add this to your ``onMapLoad.init`` file:: - - on-new-fortress buildingplan set boulders false; buildingplan set logs false - -Persisted settings (i.e. ``blocks``, ``boulders``, ``logs``, and ``bars``) are saved with -your game, so you only need to set them to the values you want once. - -.. _confirm: - -confirm -======= -Implements several confirmation dialogs for potentially destructive actions -(for example, seizing goods from traders or deleting hauling routes). - -Usage: - -:enable confirm: Enable all confirmations; alias ``confirm enable all``. - Replace with ``disable`` to disable. -:confirm help: List available confirmation dialogues. -:confirm enable option1 [option2...]: - Enable (or disable) specific confirmation dialogues. - -.. _follow: - -follow -====== -Makes the game view follow the currently highlighted unit after you exit from the -current menu or cursor mode. Handy for watching dwarves running around. Deactivated -by moving the view manually. - -.. _mousequery: - -mousequery -========== -Adds mouse controls to the DF interface, e.g. click-and-drag designations. - -Options: - -:plugin: enable/disable the entire plugin -:rbutton: enable/disable right mouse button -:track: enable/disable moving cursor in build and designation mode -:edge: enable/disable active edge scrolling (when on, will also enable tracking) -:live: enable/disable query view when unpaused -:delay: Set delay when edge scrolling in tracking mode. Omit amount to display current setting. - -Usage:: - - mousequery [plugin] [rbutton] [track] [edge] [live] [enable|disable] - -.. _resume: - -resume -====== -Allows automatic resumption of suspended constructions, along with colored -UI hints for construction status. - -.. _title-folder: - -title-folder -============= -Displays the DF folder name in the window title bar when enabled. - -.. _title-version: - -title-version -============= -Displays the DFHack version on DF's title screen when enabled. - -.. _trackstop: - -trackstop -========= -Adds a :kbd:`q` menu for track stops, which is completely blank by default. -This allows you to view and/or change the track stop's friction and dump -direction settings, using the keybindings from the track stop building interface. - -.. _sort: -.. _sort-items: - -sort-items -========== -Sort the visible item list:: - - sort-items order [order...] - -Sort the item list using the given sequence of comparisons. -The ``<`` prefix for an order makes undefined values sort first. -The ``>`` prefix reverses the sort order for defined values. - -Item order examples:: - - description material wear type quality - -The orderings are defined in ``hack/lua/plugins/sort/*.lua`` - -.. _sort-units: - -sort-units -========== -Sort the visible unit list:: - - sort-units order [order...] - -Sort the unit list using the given sequence of comparisons. -The ``<`` prefix for an order makes undefined values sort first. -The ``>`` prefix reverses the sort order for defined values. - -Unit order examples:: - - name age arrival squad squad_position profession - -The orderings are defined in ``hack/lua/plugins/sort/*.lua`` - -:dfhack-keybind:`sort-units` - -.. _stocks: - -stocks -====== -Replaces the DF stocks screen with an improved version. - -:dfhack-keybind:`stocks` - -.. _stocksettings: -.. _stockpiles: - -stockpiles -========== -Offers the following commands to save and load stockpile settings. -See `gui/stockpiles` for an in-game interface. - -:copystock: Copies the parameters of the currently highlighted stockpile to the custom - stockpile settings and switches to custom stockpile placement mode, effectively - allowing you to copy/paste stockpiles easily. - :dfhack-keybind:`copystock` - -:savestock: Saves the currently highlighted stockpile's settings to a file in your Dwarf - Fortress folder. This file can be used to copy settings between game saves or - players. e.g.: ``savestock food_settings.dfstock`` - -:loadstock: Loads a saved stockpile settings file and applies it to the currently selected - stockpile. e.g.: ``loadstock food_settings.dfstock`` - -To use savestock and loadstock, use the :kbd:`q` command to highlight a stockpile. -Then run savestock giving it a descriptive filename. Then, in a different (or -the same!) gameworld, you can highlight any stockpile with :kbd:`q` then execute the -``loadstock`` command passing it the name of that file. The settings will be -applied to that stockpile. - -Note that files are relative to the DF folder, so put your files there or in a -subfolder for easy access. Filenames should not have spaces. Generated materials, -divine metals, etc are not saved as they are different in every world. - -.. _rename: - -rename -====== -Allows renaming various things. Use `gui/rename` for an in-game interface. - -Options: - -``rename squad "name"`` - Rename squad by index to 'name'. -``rename hotkey \"name\"`` - Rename hotkey by index. This allows assigning - longer commands to the DF hotkeys. -``rename unit "nickname"`` - Rename a unit/creature highlighted in the DF user interface. -``rename unit-profession "custom profession"`` - Change proffession name of the highlighted unit/creature. -``rename building "name"`` - Set a custom name for the selected building. - The building must be one of stockpile, workshop, furnace, trap, - siege engine or an activity zone. - -.. _rendermax: - -rendermax -========= -A collection of renderer replacing/enhancing filters. For better effect try changing the -black color in palette to non totally black. See :forums:`128487` for more info. - -Options: - -:trippy: Randomizes the color of each tiles. Used for fun, or testing. -:light: Enable lighting engine. -:light reload: Reload the settings file. -:light sun |cycle: Set time to (in hours) or set it to df time cycle. -:occlusionON, occlusionOFF: Show debug occlusion info. -:disable: Disable any filter that is enabled. - -An image showing lava and dragon breath. Not pictured here: sunlight, shining items/plants, -materials that color the light etc... - -.. image:: images/rendermax.png - - -=========================== -Job and Fortress management -=========================== - -.. contents:: - :local: - -.. _autolabor: - -autolabor -========= -Automatically manage dwarf labors to efficiently complete jobs. -Autolabor tries to keep as many dwarves as possible busy but -also tries to have dwarves specialize in specific skills. - -The key is that, for almost all labors, once a dwarf begins a job it will finish that -job even if the associated labor is removed. Autolabor therefore frequently checks -which dwarf or dwarves should take new jobs for that labor, and sets labors accordingly. -Labors with equiptment (mining, hunting, and woodcutting), which are abandoned -if labors change mid-job, are handled slightly differently to minimise churn. - -.. warning:: - - *autolabor will override any manual changes you make to labors while - it is enabled, including through other tools such as Dwarf Therapist* - -Simple usage: - -:enable autolabor: Enables the plugin with default settings. (Persistent per fortress) -:disable autolabor: Disables the plugin. - -Anything beyond this is optional - autolabor works well on the default settings. - -By default, each labor is assigned to between 1 and 200 dwarves (2-200 for mining). -By default 33% of the workforce become haulers, who handle all hauling jobs as well -as cleaning, pulling levers, recovering wounded, removing constructions, and filling ponds. -Other jobs are automatically assigned as described above. Each of these settings can be adjusted. - -Jobs are rarely assigned to nobles with responsibilities for meeting diplomats or merchants, -never to the chief medical dwarf, and less often to the bookeeper and manager. - -Hunting is never assigned without a butchery, and fishing is never assigned without a fishery. - -For each labor a preference order is calculated based on skill, biased against masters of other -trades and excluding those who can't do the job. The labor is then added to the best -dwarves for that labor. We assign at least the minimum number of dwarfs, in order of preference, -and then assign additional dwarfs that meet any of these conditions: - -* The dwarf is idle and there are no idle dwarves assigned to this labor -* The dwarf has non-zero skill associated with the labor -* The labor is mining, hunting, or woodcutting and the dwarf currently has it enabled. - -We stop assigning dwarfs when we reach the maximum allowed. - -Advanced usage: - -:autolabor []: - Set number of dwarves assigned to a labor. -:autolabor haulers: Set a labor to be handled by hauler dwarves. -:autolabor disable: Turn off autolabor for a specific labor. -:autolabor reset: Return a labor to the default handling. -:autolabor reset-all: Return all labors to the default handling. -:autolabor list: List current status of all labors. -:autolabor status: Show basic status information. - -See `autolabor-artisans` for a differently-tuned setup. - -Examples: - -``autolabor MINE`` - Keep at least 5 dwarves with mining enabled. -``autolabor CUT_GEM 1 1`` - Keep exactly 1 dwarf with gemcutting enabled. -``autolabor COOK 1 1 3`` - Keep 1 dwarf with cooking enabled, selected only from the top 3. -``autolabor FEED_WATER_CIVILIANS haulers`` - Have haulers feed and water wounded dwarves. -``autolabor CUTWOOD disable`` - Turn off autolabor for wood cutting. - -.. _labormanager: - -labormanager -============ -Automatically manage dwarf labors to efficiently complete jobs. -Labormanager is derived from autolabor (above) but uses a completely -different approach to assigning jobs to dwarves. While autolabor tries -to keep as many dwarves busy as possible, labormanager instead strives -to get jobs done as quickly as possible. - -Labormanager frequently scans the current job list, current list of -dwarfs, and the map to determine how many dwarves need to be assigned to -what labors in order to meet all current labor needs without starving -any particular type of job. - -.. warning:: - - *As with autolabor, labormanager will override any manual changes you - make to labors while it is enabled, including through other tools such - as Dwarf Therapist* - -Simple usage: - -:enable labormanager: Enables the plugin with default settings. - (Persistent per fortress) - -:disable labormanager: Disables the plugin. - -Anything beyond this is optional - labormanager works fairly well on the -default settings. - -The default priorities for each labor vary (some labors are higher -priority by default than others). The way the plugin works is that, once -it determines how many of each labor is needed, it then sorts them by -adjusted priority. (Labors other than hauling have a bias added to them -based on how long it's been since they were last used, to prevent job -starvation.) The labor with the highest priority is selected, the "best -fit" dwarf for that labor is assigned to that labor, and then its -priority is *halved*. This process is repeated until either dwarfs or -labors run out. - -Because there is no easy way to detect how many haulers are actually -needed at any moment, the plugin always ensures that at least one dwarf -is assigned to each of the hauling labors, even if no hauling jobs are -detected. At least one dwarf is always assigned to construction removing -and cleaning because these jobs also cannot be easily detected. Lever -pulling is always assigned to everyone. Any dwarfs for which there are -no jobs will be assigned hauling, lever pulling, and cleaning labors. If -you use animal trainers, note that labormanager will misbehave if you -assign specific trainers to specific animals; results are only guaranteed -if you use "any trainer", and animal trainers will probably be -overallocated in any case. - -Labormanager also sometimes assigns extra labors to currently busy -dwarfs so that when they finish their current job, they will go off and -do something useful instead of standing around waiting for a job. - -There is special handling to ensure that at least one dwarf is assigned -to haul food whenever food is detected left in a place where it will rot -if not stored. This will cause a dwarf to go idle if you have no -storepiles to haul food to. - -Dwarfs who are unable to work (child, in the military, wounded, -handless, asleep, in a meeting) are entirely excluded from labor -assignment. Any dwarf explicitly assigned to a burrow will also be -completely ignored by labormanager. - -The fitness algorithm for assigning jobs to dwarfs generally attempts to -favor dwarfs who are more skilled over those who are less skilled. It -also tries to avoid assigning female dwarfs with children to jobs that -are "outside", favors assigning "outside" jobs to dwarfs who are -carrying a tool that could be used as a weapon, and tries to minimize -how often dwarfs have to reequip. - -Labormanager automatically determines medical needs and reserves health -care providers as needed. Note that this may cause idling if you have -injured dwarfs but no or inadequate hospital facilities. - -Hunting is never assigned without a butchery, and fishing is never -assigned without a fishery, and neither of these labors is assigned -unless specifically enabled. - -The method by which labormanager determines what labor is needed for a -particular job is complicated and, in places, incomplete. In some -situations, labormanager will detect that it cannot determine what labor -is required. It will, by default, pause and print an error message on -the dfhack console, followed by the message "LABORMANAGER: Game paused -so you can investigate the above message.". If this happens, please open -an issue on github, reporting the lines that immediately preceded this -message. You can tell labormanager to ignore this error and carry on by -typing ``labormanager pause-on-error no``, but be warned that some job may go -undone in this situation. - -Advanced usage: - -:labormanager enable: Turn plugin on. -:labormanager disable: Turn plugin off. -:labormanager priority : Set the priority value (see above) for labor to . -:labormanager reset : Reset the priority value of labor to its default. -:labormanager reset-all: Reset all priority values to their defaults. -:labormanager allow-fishing: Allow dwarfs to fish. *Warning* This tends to result in most of the fort going fishing. -:labormanager forbid-fishing: Forbid dwarfs from fishing. Default behavior. -:labormanager allow-hunting: Allow dwarfs to hunt. *Warning* This tends to result in as many dwarfs going hunting as you have crossbows. -:labormanager forbid-hunting: Forbid dwarfs from hunting. Default behavior. -:labormanager list: Show current priorities and current allocation stats. -:labormanager pause-on-error yes: Make labormanager pause if the labor inference engine fails. See above. -:labormanager pause-on-error no: Allow labormanager to continue past a labor inference engine failure. - - -.. _autohauler: - -autohauler -========== -Autohauler is an autolabor fork. - -Rather than the all-of-the-above means of autolabor, autohauler will instead -only manage hauling labors and leave skilled labors entirely to the user, who -will probably use Dwarf Therapist to do so. - -Idle dwarves will be assigned the hauling labors; everyone else (including -those currently hauling) will have the hauling labors removed. This is to -encourage every dwarf to do their assigned skilled labors whenever possible, -but resort to hauling when those jobs are not available. This also implies -that the user will have a very tight skill assignment, with most skilled -labors only being assigned to just one dwarf, no dwarf having more than two -active skilled labors, and almost every non-military dwarf having at least -one skilled labor assigned. - -Autohauler allows skills to be flagged as to prevent hauling labors from -being assigned when the skill is present. By default this is the unused -ALCHEMIST labor but can be changed by the user. - - -.. _job: - -job -=== -Command for general job query and manipulation. - -Options: - -*no extra options* - Print details of the current job. The job can be selected - in a workshop, or the unit/jobs screen. -**list** - Print details of all jobs in the selected workshop. -**item-material ** - Replace the exact material id in the job item. -**item-type ** - Replace the exact item type id in the job item. - -.. _job-material: - -job-material -============ -Alter the material of the selected job. Similar to ``job item-material ...`` - -Invoked as:: - - job-material - -:dfhack-keybind:`job-material` - -* In :kbd:`q` mode, when a job is highlighted within a workshop or furnace, - changes the material of the job. Only inorganic materials can be used - in this mode. -* In :kbd:`b` mode, during selection of building components positions the cursor - over the first available choice with the matching material. - -.. _job-duplicate: - -job-duplicate -============= -In :kbd:`q` mode, when a job is highlighted within a workshop or furnace -building, calling ``job-duplicate`` instantly duplicates the job. - -:dfhack-keybind:`job-duplicate` - -.. _autogems: - -autogems -======== -Creates a new Workshop Order setting, automatically cutting rough gems -when `enabled `. - -See `gui/autogems` for a configuration UI. If necessary, the ``autogems-reload`` -command reloads the configuration file produced by that script. - -.. _stockflow: - -stockflow -========= -Allows the fortress bookkeeper to queue jobs through the manager, -based on space or items available in stockpiles. - -Inspired by `workflow`. - -Usage: - -``stockflow enable`` - Enable the plugin. -``stockflow disable`` - Disable the plugin. -``stockflow fast`` - Enable the plugin in fast mode. -``stockflow list`` - List any work order settings for your stockpiles. -``stockflow status`` - Display whether the plugin is enabled. - -While enabled, the :kbd:`q` menu of each stockpile will have two new options: - -* :kbd:`j`: Select a job to order, from an interface like the manager's screen. -* :kbd:`J`: Cycle between several options for how many such jobs to order. - -Whenever the bookkeeper updates stockpile records, new work orders will -be placed on the manager's queue for each such selection, reduced by the -number of identical orders already in the queue. - -In fast mode, new work orders will be enqueued once per day, instead of -waiting for the bookkeeper. - -.. _workflow: - -workflow -======== -Manage control of repeat jobs. `gui/workflow` provides a simple -front-end integrated in the game UI. - -Usage: - -``workflow enable [option...], workflow disable [option...]`` - If no options are specified, enables or disables the plugin. - Otherwise, enables or disables any of the following options: - - - drybuckets: Automatically empty abandoned water buckets. - - auto-melt: Resume melt jobs when there are objects to melt. -``workflow jobs`` - List workflow-controlled jobs (if in a workshop, filtered by it). -``workflow list`` - List active constraints, and their job counts. -``workflow list-commands`` - List active constraints as workflow commands that re-create them; - this list can be copied to a file, and then reloaded using the - ``script`` built-in command. -``workflow count [cnt-gap]`` - Set a constraint, counting every stack as 1 item. -``workflow amount [cnt-gap]`` - Set a constraint, counting all items within stacks. -``workflow unlimit `` - Delete a constraint. -``workflow unlimit-all`` - Delete all constraints. - -Function --------- -When the plugin is enabled, it protects all repeat jobs from removal. -If they do disappear due to any cause, they are immediately re-added to their -workshop and suspended. - -In addition, when any constraints on item amounts are set, repeat jobs that -produce that kind of item are automatically suspended and resumed as the item -amount goes above or below the limit. The gap specifies how much below the limit -the amount has to drop before jobs are resumed; this is intended to reduce -the frequency of jobs being toggled. - -Constraint format ------------------ -The constraint spec consists of 4 parts, separated with ``/`` characters:: - - ITEM[:SUBTYPE]/[GENERIC_MAT,...]/[SPECIFIC_MAT:...]/[LOCAL,] - -The first part is mandatory and specifies the item type and subtype, -using the raw tokens for items (the same syntax used custom reaction inputs). -For more information, see :wiki:`this wiki page `. - -The subsequent parts are optional: - -- A generic material spec constrains the item material to one of - the hard-coded generic classes, which currently include:: - - PLANT WOOD CLOTH SILK LEATHER BONE SHELL SOAP TOOTH HORN PEARL YARN - METAL STONE SAND GLASS CLAY MILK - -- A specific material spec chooses the material exactly, using the - raw syntax for reaction input materials, e.g. ``INORGANIC:IRON``, - although for convenience it also allows just ``IRON``, or ``ACACIA:WOOD`` etc. - See the link above for more details on the unabbreviated raw syntax. - -- A comma-separated list of miscellaneous flags, which currently can - be used to ignore imported items or items below a certain quality. - -Constraint examples -------------------- -Keep metal bolts within 900-1000, and wood/bone within 150-200:: - - workflow amount AMMO:ITEM_AMMO_BOLTS/METAL 1000 100 - workflow amount AMMO:ITEM_AMMO_BOLTS/WOOD,BONE 200 50 - -Keep the number of prepared food & drink stacks between 90 and 120:: - - workflow count FOOD 120 30 - workflow count DRINK 120 30 - -Make sure there are always 25-30 empty bins/barrels/bags:: - - workflow count BIN 30 - workflow count BARREL 30 - workflow count BOX/CLOTH,SILK,YARN 30 - -Make sure there are always 15-20 coal and 25-30 copper bars:: - - workflow count BAR//COAL 20 - workflow count BAR//COPPER 30 - -Produce 15-20 gold crafts:: - - workflow count CRAFTS//GOLD 20 - -Collect 15-20 sand bags and clay boulders:: - - workflow count POWDER_MISC/SAND 20 - workflow count BOULDER/CLAY 20 - -Make sure there are always 80-100 units of dimple dye:: - - workflow amount POWDER_MISC//MUSHROOM_CUP_DIMPLE:MILL 100 20 - -.. note:: - - In order for this to work, you have to set the material of the PLANT input - on the Mill Plants job to MUSHROOM_CUP_DIMPLE using the `job item-material ` - command. Otherwise the plugin won't be able to deduce the output material. - -Maintain 10-100 locally-made crafts of exceptional quality:: - - workflow count CRAFTS///LOCAL,EXCEPTIONAL 100 90 - -.. _fix-job-postings: - -fix-job-postings ----------------- -This command fixes crashes caused by previous versions of workflow, mostly in -DFHack 0.40.24-r4, and should be run automatically when loading a world (but can -also be run manually if desired). - -.. _clean: - -clean -===== -Cleans all the splatter that get scattered all over the map, items and -creatures. In an old fortress, this can significantly reduce FPS lag. It can -also spoil your !!FUN!!, so think before you use it. - -Options: - -:map: Clean the map tiles. By default, it leaves mud and snow alone. -:units: Clean the creatures. Will also clean hostiles. -:items: Clean all the items. Even a poisoned blade. - -Extra options for ``map``: - -:mud: Remove mud in addition to the normal stuff. -:snow: Also remove snow coverings. - -.. _spotclean: - -spotclean -========= -Works like ``clean map snow mud``, but only for the tile under the cursor. Ideal -if you want to keep that bloody entrance ``clean map`` would clean up. - -:dfhack-keybind:`spotclean` - -.. _autodump: - -autodump -======== -This plugin adds an option to the :kbd:`q` menu for stckpiles when `enabled `. -When autodump is enabled for a stockpile, any items placed in the stockpile will -automatically be designated to be dumped. - -Alternatively, you can use it to quickly move all items designated to be dumped. -Items are instantly moved to the cursor position, the dump flag is unset, -and the forbid flag is set, as if it had been dumped normally. -Be aware that any active dump item tasks still point at the item. - -Cursor must be placed on a floor tile so the items can be dumped there. - -Options: - -:destroy: Destroy instead of dumping. Doesn't require a cursor. - If called again before the game is resumed, cancels destroy. -:destroy-here: As ``destroy``, but only the selected item in the :kbd:`k` list, - or inside a container. - Alias ``autodump-destroy-here``, for keybindings. - :dfhack-keybind:`autodump-destroy-here` -:visible: Only process items that are not hidden. -:hidden: Only process hidden items. -:forbidden: Only process forbidden items (default: only unforbidden). - -``autodump-destroy-item`` destroys the selected item, which may be selected -in the :kbd:`k` list, or inside a container. If called again before the game -is resumed, cancels destruction of the item. -:dfhack-keybind:`autodump-destroy-item` - -.. _cleanowned: - -cleanowned -========== -Confiscates items owned by dwarfs. By default, owned food on the floor -and rotten items are confistacted and dumped. - -Options: - -:all: confiscate all owned items -:scattered: confiscated and dump all items scattered on the floor -:x: confiscate/dump items with wear level 'x' and more -:X: confiscate/dump items with wear level 'X' and more -:dryrun: a dry run. combine with other options to see what will happen - without it actually happening. - -Example: - -``cleanowned scattered X`` - This will confiscate rotten and dropped food, garbage on the floors and any - worn items with 'X' damage and above. - -.. _dwarfmonitor: - -dwarfmonitor -============ -Records dwarf activity to measure fort efficiency. - -Options: - -:enable : Start monitoring ``mode``. ``mode`` can be "work", "misery", - "weather", or "all". This will enable all corresponding widgets, - if applicable. -:disable : Stop monitoring ``mode``, and disable corresponding widgets, if applicable. -:stats: Show statistics summary -:prefs: Show dwarf preferences summary -:reload: Reload configuration file (``dfhack-config/dwarfmonitor.json``) - -:dfhack-keybind:`dwarfmonitor` - -Widget configuration: - -The following types of widgets (defined in :file:`hack/lua/plugins/dwarfmonitor.lua`) -can be displayed on the main fortress mode screen: - -:date: Show the in-game date -:misery: Show overall happiness levels of all dwarves -:weather: Show current weather (rain/snow) -:cursor: Show the current mouse cursor position - -The file :file:`dfhack-config/dwarfmonitor.json` can be edited to control the -positions and settings of all widgets displayed. This file should contain a -JSON object with the key ``widgets`` containing an array of objects - see the -included file in the ``dfhack-config`` folder for an example: - -.. code-block:: lua - - { - "widgets": [ - { - "type": "widget type (weather, misery, etc.)", - "x": X coordinate, - "y": Y coordinate - <...additional options...> - } - ] - } - -X and Y coordinates begin at zero (in the upper left corner of the screen). -Negative coordinates will be treated as distances from the lower right corner, -beginning at 1 - e.g. an x coordinate of 0 is the leftmost column, while an x -coordinate of 1 is the rightmost column. - -By default, the x and y coordinates given correspond to the leftmost tile of -the widget. Including an ``anchor`` option set to ``right`` will cause the -rightmost tile of the widget to be located at this position instead. - -Some widgets support additional options: - -* ``date`` widget: - - * ``format``: specifies the format of the date. The following characters - are replaced (all others, such as punctuation, are not modified) - - * ``Y`` or ``y``: The current year - * ``M``: The current month, zero-padded if necessary - * ``m``: The current month, *not* zero-padded - * ``D``: The current day, zero-padded if necessary - * ``d``: The current day, *not* zero-padded - - The default date format is ``Y-M-D``, per the ISO8601_ standard. - - .. _ISO8601: https://en.wikipedia.org/wiki/ISO_8601 - -* ``cursor`` widget: - - * ``format``: Specifies the format. ``X``, ``x``, ``Y``, and ``y`` are - replaced with the corresponding cursor cordinates, while all other - characters are unmodified. - * ``show_invalid``: If set to ``true``, the mouse coordinates will both be - displayed as ``-1`` when the cursor is outside of the DF window; otherwise, - nothing will be displayed. - -.. _dwarfvet: - -dwarfvet -======== -Enables Animal Caretaker functionality - -Always annoyed your dragons become useless after a minor injury? Well, with -dwarfvet, your animals become first rate members of your fort. It can also -be used to train medical skills. - -Animals need to be treated in an animal hospital, which is simply a hospital -that is also an animal training zone. The console will print out a list on game -load, and whenever one is added or removed. Dwarfs must have the Animal Caretaker -labor to treat animals. Normal medical skills are used (and no experience is given -to the Animal Caretaker skill). - -Options: - -:enable: Enables Animal Caretakers to treat and manage animals -:disable: Turns off the plguin -:report: Reports all zones that the game considers animal hospitals - -.. _workNow: - -workNow -======= -Don't allow dwarves to idle if any jobs are available. - -When workNow is active, every time the game pauses, DF will make dwarves -perform any appropriate available jobs. This includes when you one step -through the game using the pause menu. Usage: - -:workNow: print workNow status -:workNow 0: deactivate workNow -:workNow 1: activate workNow (look for jobs on pause, and only then) -:workNow 2: make dwarves look for jobs whenever a job completes - -.. _seedwatch: - -seedwatch -========= -Watches the numbers of seeds available and enables/disables seed and plant cooking. - -Each plant type can be assigned a limit. If their number falls below that limit, -the plants and seeds of that type will be excluded from cookery. -If the number rises above the limit + 20, then cooking will be allowed. - -The plugin needs a fortress to be loaded and will deactivate automatically otherwise. -You have to reactivate with 'seedwatch start' after you load the game. - -Options: - -:all: Adds all plants from the abbreviation list to the watch list. -:start: Start watching. -:stop: Stop watching. -:info: Display whether seedwatch is watching, and the watch list. -:clear: Clears the watch list. - -Examples: - -``seedwatch MUSHROOM_HELMET_PLUMP 30`` - add ``MUSHROOM_HELMET_PLUMP`` to the watch list, limit = 30 -``seedwatch MUSHROOM_HELMET_PLUMP`` - removes ``MUSHROOM_HELMET_PLUMP`` from the watch list. -``seedwatch all 30`` - adds all plants from the abbreviation list to the watch list, the limit being 30. - -.. _zone: - -zone -==== -Helps a bit with managing activity zones (pens, pastures and pits) and cages. - -:dfhack-keybind:`zone` - -Options: - -:set: Set zone or cage under cursor as default for future assigns. -:assign: Assign unit(s) to the pen or pit marked with the 'set' command. - If no filters are set a unit must be selected in the in-game ui. - Can also be followed by a valid zone id which will be set - instead. -:unassign: Unassign selected creature from it's zone. -:nick: Mass-assign nicknames, must be followed by the name you want - to set. -:remnick: Mass-remove nicknames. -:enumnick: Assign enumerated nicknames (e.g. "Hen 1", "Hen 2"...). Must be - followed by the prefix to use in nicknames. -:tocages: Assign unit(s) to cages inside a pasture. -:uinfo: Print info about unit(s). If no filters are set a unit must - be selected in the in-game ui. -:zinfo: Print info about zone(s). If no filters are set zones under - the cursor are listed. -:verbose: Print some more info. -:filters: Print list of valid filter options. -:examples: Print some usage examples. -:not: Negates the next filter keyword. - -Filters: - -:all: Process all units (to be used with additional filters). -:count: Must be followed by a number. Process only n units (to be used - with additional filters). -:unassigned: Not assigned to zone, chain or built cage. -:minage: Minimum age. Must be followed by number. -:maxage: Maximum age. Must be followed by number. -:race: Must be followed by a race RAW ID (e.g. BIRD_TURKEY, ALPACA, - etc). Negatable. -:caged: In a built cage. Negatable. -:own: From own civilization. Negatable. -:merchant: Is a merchant / belongs to a merchant. Should only be used for - pitting, not for stealing animals (slaughter should work). -:war: Trained war creature. Negatable. -:hunting: Trained hunting creature. Negatable. -:tamed: Creature is tame. Negatable. -:trained: Creature is trained. Finds war/hunting creatures as well as - creatures who have a training level greater than 'domesticated'. - If you want to specifically search for war/hunting creatures use - 'war' or 'hunting' Negatable. -:trainablewar: Creature can be trained for war (and is not already trained for - war/hunt). Negatable. -:trainablehunt: Creature can be trained for hunting (and is not already trained - for war/hunt). Negatable. -:male: Creature is male. Negatable. -:female: Creature is female. Negatable. -:egglayer: Race lays eggs. Negatable. -:grazer: Race is a grazer. Negatable. -:milkable: Race is milkable. Negatable. - -Usage with single units ------------------------ -One convenient way to use the zone tool is to bind the command 'zone assign' to -a hotkey, maybe also the command 'zone set'. Place the in-game cursor over -a pen/pasture or pit, use 'zone set' to mark it. Then you can select units -on the map (in 'v' or 'k' mode), in the unit list or from inside cages -and use 'zone assign' to assign them to their new home. Allows pitting your -own dwarves, by the way. - -Usage with filters ------------------- -All filters can be used together with the 'assign' command. - -Restrictions: It's not possible to assign units who are inside built cages -or chained because in most cases that won't be desirable anyways. -It's not possible to cage owned pets because in that case the owner -uncages them after a while which results in infinite hauling back and forth. - -Usually you should always use the filter 'own' (which implies tame) unless you -want to use the zone tool for pitting hostiles. 'own' ignores own dwarves unless -you specify 'race DWARF' (so it's safe to use 'assign all own' to one big -pasture if you want to have all your animals at the same place). 'egglayer' and -'milkable' should be used together with 'female' unless you have a mod with -egg-laying male elves who give milk or whatever. Merchants and their animals are -ignored unless you specify 'merchant' (pitting them should be no problem, -but stealing and pasturing their animals is not a good idea since currently they -are not properly added to your own stocks; slaughtering them should work). - -Most filters can be negated (e.g. 'not grazer' -> race is not a grazer). - -Mass-renaming -------------- -Using the 'nick' command you can set the same nickname for multiple units. -If used without 'assign', 'all' or 'count' it will rename all units in the -current default target zone. Combined with 'assign', 'all' or 'count' (and -further optional filters) it will rename units matching the filter conditions. - -Cage zones ----------- -Using the 'tocages' command you can assign units to a set of cages, for example -a room next to your butcher shop(s). They will be spread evenly among available -cages to optimize hauling to and butchering from them. For this to work you need -to build cages and then place one pen/pasture activity zone above them, covering -all cages you want to use. Then use 'zone set' (like with 'assign') and use -'zone tocages filter1 filter2 ...'. 'tocages' overwrites 'assign' because it -would make no sense, but can be used together with 'nick' or 'remnick' and all -the usual filters. - -Examples --------- -``zone assign all own ALPACA minage 3 maxage 10`` - Assign all own alpacas who are between 3 and 10 years old to the selected - pasture. -``zone assign all own caged grazer nick ineedgrass`` - Assign all own grazers who are sitting in cages on stockpiles (e.g. after - buying them from merchants) to the selected pasture and give them - the nickname 'ineedgrass'. -``zone assign all own not grazer not race CAT`` - Assign all own animals who are not grazers, excluding cats. -``zone assign count 5 own female milkable`` - Assign up to 5 own female milkable creatures to the selected pasture. -``zone assign all own race DWARF maxage 2`` - Throw all useless kids into a pit :) -``zone nick donttouchme`` - Nicknames all units in the current default zone or cage to 'donttouchme'. - Mostly intended to be used for special pastures or cages which are not marked - as rooms you want to protect from autobutcher. -``zone tocages count 50 own tame male not grazer`` - Stuff up to 50 owned tame male animals who are not grazers into cages built - on the current default zone. - -.. _autonestbox: - -autonestbox -=========== -Assigns unpastured female egg-layers to nestbox zones. Requires that you create -pen/pasture zones above nestboxes. If the pen is bigger than 1x1 the nestbox -must be in the top left corner. Only 1 unit will be assigned per pen, regardless -of the size. The age of the units is currently not checked, most birds grow up -quite fast. Egglayers who are also grazers will be ignored, since confining them -to a 1x1 pasture is not a good idea. Only tame and domesticated own units are -processed since pasturing half-trained wild egglayers could destroy your neat -nestbox zones when they revert to wild. When called without options autonestbox -will instantly run once. - -Options: - -:start: Start running every X frames (df simulation ticks). - Default: X=6000, which would be every 60 seconds at 100fps. -:stop: Stop running automatically. -:sleep: Must be followed by number X. Changes the timer to sleep X - frames between runs. - -.. _autobutcher: - -autobutcher -=========== -Assigns lifestock for slaughter once it reaches a specific count. Requires that -you add the target race(s) to a watch list. Only tame units will be processed. - -Units will be ignored if they are: - -* Nicknamed (for custom protection; you can use the `rename` ``unit`` tool - individually, or `zone` ``nick`` for groups) -* Caged, if and only if the cage is defined as a room (to protect zoos) -* Trained for war or hunting - -Creatures who will not reproduce (because they're not interested in the -opposite sex or have been gelded) will be butchered before those who will. -Older adults and younger children will be butchered first if the population -is above the target (default 1 male, 5 female kids and adults). Note that -you may need to set a target above 1 to have a reliable breeding population -due to asexuality etc. See `fix-ster` if this is a problem. - -Options: - -:example: Print some usage examples. -:start: Start running every X frames (df simulation ticks). - Default: X=6000, which would be every 60 seconds at 100fps. -:stop: Stop running automatically. -:sleep : Changes the timer to sleep X frames between runs. -:watch R: Start watching a race. R can be a valid race RAW id (ALPACA, - BIRD_TURKEY, etc) or a list of ids seperated by spaces or - the keyword 'all' which affects all races on your current - watchlist. -:unwatch R: Stop watching race(s). The current target settings will be - remembered. R can be a list of ids or the keyword 'all'. -:forget R: Stop watching race(s) and forget it's/their target settings. - R can be a list of ids or the keyword 'all'. -:autowatch: Automatically adds all new races (animals you buy from merchants, - tame yourself or get from migrants) to the watch list using - default target count. -:noautowatch: Stop auto-adding new races to the watchlist. -:list: Print the current status and watchlist. -:list_export: Print the commands needed to set up status and watchlist, - which can be used to import them to another save (see notes). -:target : - Set target count for specified race(s). The first four arguments - are the number of female and male kids, and female and male adults. - R can be a list of spceies ids, or the keyword ``all`` or ``new``. - ``R = 'all'``: change target count for all races on watchlist - and set the new default for the future. ``R = 'new'``: don't touch - current settings on the watchlist, only set the new default - for future entries. -:list_export: Print the commands required to rebuild your current settings. - -.. note:: - - Settings and watchlist are stored in the savegame, so that you can have - different settings for each save. If you want to copy your watchlist to - another savegame you must export the commands required to recreate your settings. - - To export, open an external terminal in the DF directory, and run - ``dfhack-run autobutcher list_export > filename.txt``. To import, load your - new save and run ``script filename.txt`` in the DFHack terminal. - - -Examples: - -You want to keep max 7 kids (4 female, 3 male) and max 3 adults (2 female, -1 male) of the race alpaca. Once the kids grow up the oldest adults will get -slaughtered. Excess kids will get slaughtered starting with the youngest -to allow that the older ones grow into adults. Any unnamed cats will -be slaughtered as soon as possible. :: - - autobutcher target 4 3 2 1 ALPACA BIRD_TURKEY - autobutcher target 0 0 0 0 CAT - autobutcher watch ALPACA BIRD_TURKEY CAT - autobutcher start - -Automatically put all new races onto the watchlist and mark unnamed tame units -for slaughter as soon as they arrive in your fort. Settings already made -for specific races will be left untouched. :: - - autobutcher target 0 0 0 0 new - autobutcher autowatch - autobutcher start - -Stop watching the races alpaca and cat, but remember the target count -settings so that you can use 'unwatch' without the need to enter the -values again. Note: 'autobutcher unwatch all' works, but only makes sense -if you want to keep the plugin running with the 'autowatch' feature or manually -add some new races with 'watch'. If you simply want to stop it completely use -'autobutcher stop' instead. :: - - autobutcher unwatch ALPACA CAT - -.. _autochop: - -autochop -======== -Automatically manage tree cutting designation to keep available logs withing given -quotas. - -Open the dashboard by running:: - - enable autochop - -The plugin must be activated (with :kbd:`d`-:kbd:`t`-:kbd:`c`-:kbd:`a`) before -it can be used. You can then set logging quotas and restrict designations to -specific burrows (with 'Enter') if desired. The plugin's activity cycle runs -once every in game day. - -If you add ``enable autochop`` to your dfhack.init there will be a hotkey to -open the dashboard from the chop designation menu. - -.. _orders: - -orders -====== - -A plugin for manipulating manager orders. - -Subcommands: - -:export NAME: Exports the current list of manager orders to a file named ``dfhack-config/orders/NAME.json``. -:import NAME: Imports manager orders from a file named ``dfhack-config/orders/NAME.json``. -:clear: Deletes all manager orders in the current embark. -:sort: Sorts current manager orders by repeat frequency so daily orders don't - prevent other orders from ever being completed: one-time orders first, then - yearly, seasonally, monthly, then finally daily. - -You can keep your orders automatically sorted by adding the following command to -your ``onMapLoad.init`` file:: - - repeat -name orders-sort -time 1 -timeUnits days -command [ orders sort ] - -.. _nestboxes: - -nestboxes -========= - -Automatically scan for and forbid fertile eggs incubating in a nestbox. -Toggle status with `enable` or `disable `. - -.. _tailor: - -tailor -====== - -Whenever the bookkeeper updates stockpile records, this plugin will scan every unit in the fort, -count up the number that are worn, and then order enough more made to replace all worn items. -If there are enough replacement items in inventory to replace all worn items, the units wearing them -will have the worn items confiscated (in the same manner as the `cleanowned` plugin) so that they'll -reeequip with replacement items. - -Use the `enable` and `disable ` commands to toggle this plugin's status, or run -``tailor status`` to check its current status. - -.. _autoclothing: - -autoclothing -============ - -Automatically manage clothing work orders, allowing the user to set how many of -each clothing type every citizen should have. Usage:: - - autoclothing [number] - -Examples: - -* ``autoclothing cloth "short skirt" 10``: - Sets the desired number of cloth short skirts available per citizen to 10. -* ``autoclothing cloth dress``: - Displays the currently set number of cloth dresses chosen per citizen. - -.. _autofarm: - -autofarm -======== - -Automatically handles crop selection in farm plots based on current plant -stocks, and selects crops for planting if current stock is below a threshold. -Selected crops are dispatched on all farmplots. (Note that this plugin replaces -an older Ruby script of the same name.) - -Use the `enable` or `disable ` commands to change whether this plugin is -enabled. - -Usage: - -* ``autofarm runonce``: - Updates all farm plots once, without enabling the plugin -* ``autofarm status``: - Prints status information, including any applied limits -* ``autofarm default 30``: - Sets the default threshold -* ``autofarm threshold 150 helmet_plump tail_pig``: - Sets thresholds of individual plants - - -================ -Map modification -================ - -.. contents:: - :local: - -.. _3dveins: - -3dveins -======= -Removes all existing veins from the map and generates new ones using -3D Perlin noise, in order to produce a layout that smoothly flows between -Z levels. The vein distribution is based on the world seed, so running -the command for the second time should produce no change. It is best to -run it just once immediately after embark. - -This command is intended as only a cosmetic change, so it takes -care to exactly preserve the mineral counts reported by `prospect` ``all``. -The amounts of different layer stones may slightly change in some cases -if vein mass shifts between Z layers. - -The only undo option is to restore your save from backup. - -.. _alltraffic: - -alltraffic -========== -Set traffic designations for every single tile of the map - useful for resetting -traffic designations. See also `filltraffic`, `restrictice`, and `restrictliquids`. - -Options: - -:H: High Traffic -:N: Normal Traffic -:L: Low Traffic -:R: Restricted Traffic - -.. _burrows: - -burrows -======= -Miscellaneous burrow control. Allows manipulating burrows and automated burrow -expansion while digging. - -Options: - -:enable feature ...: - Enable features of the plugin. -:disable feature ...: - Disable features of the plugin. -:clear-unit burrow burrow ...: - Remove all units from the burrows. -:clear-tiles burrow burrow ...: - Remove all tiles from the burrows. -:set-units target-burrow src-burrow ...: - Clear target, and adds units from source burrows. -:add-units target-burrow src-burrow ...: - Add units from the source burrows to the target. -:remove-units target-burrow src-burrow ...: - Remove units in source burrows from the target. -:set-tiles target-burrow src-burrow ...: - Clear target and adds tiles from the source burrows. -:add-tiles target-burrow src-burrow ...: - Add tiles from the source burrows to the target. -:remove-tiles target-burrow src-burrow ...: - Remove tiles in source burrows from the target. - - For these three options, in place of a source burrow it is - possible to use one of the following keywords: ABOVE_GROUND, - SUBTERRANEAN, INSIDE, OUTSIDE, LIGHT, DARK, HIDDEN, REVEALED - -Features: - -:auto-grow: When a wall inside a burrow with a name ending in '+' is dug - out, the burrow is extended to newly-revealed adjacent walls. - This final '+' may be omitted in burrow name args of commands above. - Digging 1-wide corridors with the miner inside the burrow is SLOW. - - -.. _changelayer: - -changelayer -=========== -Changes material of the geology layer under cursor to the specified inorganic -RAW material. Can have impact on all surrounding regions, not only your embark! -By default changing stone to soil and vice versa is not allowed. By default -changes only the layer at the cursor position. Note that one layer can stretch -across lots of z levels. By default changes only the geology which is linked -to the biome under the cursor. That geology might be linked to other biomes -as well, though. Mineral veins and gem clusters will stay on the map. Use -`changevein` for them. - -tl;dr: You will end up with changing quite big areas in one go, especially if -you use it in lower z levels. Use with care. - -Options: - -:all_biomes: Change selected layer for all biomes on your map. - Result may be undesirable since the same layer can AND WILL - be on different z-levels for different biomes. Use the tool - 'probe' to get an idea how layers and biomes are distributed - on your map. -:all_layers: Change all layers on your map (only for the selected biome - unless 'all_biomes' is added). - Candy mountain, anyone? Will make your map quite boring, - but tidy. -:force: Allow changing stone to soil and vice versa. !!THIS CAN HAVE - WEIRD EFFECTS, USE WITH CARE!! - Note that soil will not be magically replaced with stone. - You will, however, get a stone floor after digging so it - will allow the floor to be engraved. - Note that stone will not be magically replaced with soil. - You will, however, get a soil floor after digging so it - could be helpful for creating farm plots on maps with no - soil. -:verbose: Give some details about what is being changed. -:trouble: Give some advice about known problems. - -Examples: - -``changelayer GRANITE`` - Convert layer at cursor position into granite. -``changelayer SILTY_CLAY force`` - Convert layer at cursor position into clay even if it's stone. -``changelayer MARBLE all_biomes all_layers`` - Convert all layers of all biomes which are not soil into marble. - -.. note:: - - * If you use changelayer and nothing happens, try to pause/unpause the game - for a while and try to move the cursor to another tile. Then try again. - If that doesn't help try temporarily changing some other layer, undo your - changes and try again for the layer you want to change. Saving - and reloading your map might also help. - * You should be fine if you only change single layers without the use - of 'force'. Still it's advisable to save your game before messing with - the map. - * When you force changelayer to convert soil to stone you might experience - weird stuff (flashing tiles, tiles changed all over place etc). - Try reverting the changes manually or even better use an older savegame. - You did save your game, right? - -.. _changevein: - -changevein -========== -Changes material of the vein under cursor to the specified inorganic RAW -material. Only affects tiles within the current 16x16 block - for veins and -large clusters, you will need to use this command multiple times. - -Example: - -``changevein NATIVE_PLATINUM`` - Convert vein at cursor position into platinum ore. - -.. _changeitem: - -changeitem -========== -Allows changing item material and base quality. By default the item currently -selected in the UI will be changed (you can select items in the 'k' list -or inside containers/inventory). By default change is only allowed if materials -is of the same subtype (for example wood<->wood, stone<->stone etc). But since -some transformations work pretty well and may be desired you can override this -with 'force'. Note that some attributes will not be touched, possibly resulting -in weirdness. To get an idea how the RAW id should look like, check some items -with 'info'. Using 'force' might create items which are not touched by -crafters/haulers. - -Options: - -:info: Don't change anything, print some info instead. -:here: Change all items at the cursor position. Requires in-game cursor. -:material, m: Change material. Must be followed by valid material RAW id. -:quality, q: Change base quality. Must be followed by number (0-5). -:force: Ignore subtypes, force change to new material. - -Examples: - -``changeitem m INORGANIC:GRANITE here`` - Change material of all items under the cursor to granite. -``changeitem q 5`` - Change currently selected item to masterpiece quality. - -.. _cleanconst: - -cleanconst -========== -Cleans up construction materials. - -This utility alters all constructions on the map so that they spawn their -building component when they are disassembled, allowing their actual -build items to be safely deleted. This can improve FPS in extreme situations. - -.. _deramp: - -deramp -====== -Removes all ramps designated for removal from the map. This is useful for -replicating the old channel digging designation. It also removes any and -all 'down ramps' that can remain after a cave-in (you don't have to designate -anything for that to happen). - -.. _dig: -.. _digv: -.. _digvx: -.. _digl: -.. _diglx: - -dig -=== -This plugin makes many automated or complicated dig patterns easy. - -Basic commands: - -:digv: Designate all of the selected vein for digging. -:digvx: Also cross z-levels, digging stairs as needed. Alias for ``digv x``. -:digl: Like ``digv``, for layer stone. Also supports an ``undo`` option - to remove designations, for if you accidentally set 50 levels at once. -:diglx: Also cross z-levels, digging stairs as needed. Alias for ``digl x``. - -:dfhack-keybind:`digv` - -.. note:: - - All commands implemented by the `dig` plugin (listed by ``ls dig``) support - specifying the designation priority with ``-p#``, ``-p #``, or ``p=#``, - where ``#`` is a number from 1 to 7. If a priority is not specified, the - priority selected in-game is used as the default. - -.. _digexp: - -digexp -====== -This command is for :wiki:`exploratory mining `. - -There are two variables that can be set: pattern and filter. - -Patterns: - -:diag5: diagonals separated by 5 tiles -:diag5r: diag5 rotated 90 degrees -:ladder: A 'ladder' pattern -:ladderr: ladder rotated 90 degrees -:clear: Just remove all dig designations -:cross: A cross, exactly in the middle of the map. - -Filters: - -:all: designate whole z-level -:hidden: designate only hidden tiles of z-level (default) -:designated: Take current designation and apply pattern to it. - -After you have a pattern set, you can use ``expdig`` to apply it again. - -Examples: - -``expdig diag5 hidden`` - Designate the diagonal 5 patter over all hidden tiles -``expdig`` - Apply last used pattern and filter -``expdig ladder designated`` - Take current designations and replace them with the ladder pattern - -.. _digcircle: - -digcircle -========= -A command for easy designation of filled and hollow circles. -It has several types of options. - -Shape: - -:hollow: Set the circle to hollow (default) -:filled: Set the circle to filled -:#: Diameter in tiles (default = 0, does nothing) - -Action: - -:set: Set designation (default) -:unset: Unset current designation -:invert: Invert designations already present - -Designation types: - -:dig: Normal digging designation (default) -:ramp: Ramp digging -:ustair: Staircase up -:dstair: Staircase down -:xstair: Staircase up/down -:chan: Dig channel - -After you have set the options, the command called with no options -repeats with the last selected parameters. - -Examples: - -``digcircle filled 3`` - Dig a filled circle with diameter = 3. -``digcircle`` - Do it again. - -.. _digtype: - -digtype -======= -For every tile on the map of the same vein type as the selected tile, -this command designates it to have the same designation as the -selected tile. If the selected tile has no designation, they will be -dig designated. -If an argument is given, the designation of the selected tile is -ignored, and all appropriate tiles are set to the specified -designation. - -Options: - -:dig: -:channel: -:ramp: -:updown: up/down stairs -:up: up stairs -:down: down stairs -:clear: clear designation - -.. _digFlood: - -digFlood -======== -Automatically digs out specified veins as they are discovered. It runs once -every time a dwarf finishes a dig job. It will only dig out appropriate tiles -that are adjacent to the finished dig job. To add a vein type, use ``digFlood 1 [type]``. -This will also enable the plugin. To remove a vein type, use ``digFlood 0 [type] 1`` -to disable, then remove, then re-enable. - -Usage: - -:help digflood: detailed help message -:digFlood 0: disable the plugin -:digFlood 1: enable the plugin -:digFlood 0 MICROCLINE COAL_BITUMINOUS 1: - disable plugin, remove microcline and bituminous coal from monitoring, then re-enable the plugin -:digFlood CLEAR: remove all inorganics from monitoring -:digFlood digAll1: ignore the monitor list and dig any vein -:digFlood digAll0: disable digAll mode - -.. _filltraffic: - -filltraffic -=========== -Set traffic designations using flood-fill starting at the cursor. -See also `alltraffic`, `restrictice`, and `restrictliquids`. Options: - -:H: High Traffic -:N: Normal Traffic -:L: Low Traffic -:R: Restricted Traffic -:X: Fill across z-levels. -:B: Include buildings and stockpiles. -:P: Include empty space. - -Example: - -``filltraffic H`` - When used in a room with doors, it will set traffic to HIGH in just that room. - -.. _fortplan: - -fortplan -======== -Usage: ``fortplan [filename]`` - -**Fortplan is deprecated.** Please use DFHack's more powerful `quickfort` -command instead. You can use your existing .csv files. Just move them to the -``blueprints`` folder in your DF installation, and instead of ``fortplan file.csv`` run ``quickfort run file.csv``. - -Designates furniture for building according to a ``.csv`` file with -quickfort-style syntax. - -The first line of the file must contain the following:: - - #build start(X; Y; ) - -...where X and Y are the offset from the top-left corner of the file's area -where the in-game cursor should be located, and ```` -is an optional description of where that is. You may also leave a description -of the contents of the file itself following the closing parenthesis on the -same line. - -The syntax of the file itself is similar to `digfort` or :forums:`quickfort <35931>`. -At present, only buildings constructed of an item with the same name as the building -are supported. All other characters are ignored. For example:: - - `,`,d,`,` - `,f,`,t,` - `,s,b,c,` - -This section of a file would designate for construction a door and some -furniture inside a bedroom: specifically, clockwise from top left, a cabinet, -a table, a chair, a bed, and a statue. - -All of the building designation uses `buildingplan`, so you do not need to -have the items available to construct all the buildings when you run -fortplan with the .csv file. - -.. _getplants: - -getplants -========= -This tool allows plant gathering and tree cutting by RAW ID. Specify the types -of trees to cut down and/or shrubs to gather by their plant names, separated -by spaces. - -Options: - -:``-t``: Tree: Select trees only (exclude shrubs) -:``-s``: Shrub: Select shrubs only (exclude trees) -:``-f``: Farming: Designate only shrubs that yield seeds for farming. Implies -s -:``-c``: Clear: Clear designations instead of setting them -:``-x``: eXcept: Apply selected action to all plants except those specified (invert - selection) -:``-a``: All: Select every type of plant (obeys ``-t``/``-s``/``-f``) -:``-v``: Verbose: Lists the number of (un)designations per plant -:``-n *``: Number: Designate up to * (an integer number) plants of each species - -Specifying both ``-t`` and ``-s`` or ``-f`` will have no effect. If no plant IDs are -specified, all valid plant IDs will be listed, with ``-t``, ``-s``, and ``-f`` -restricting the list to trees, shrubs, and farmable shrubs, respectively. - -.. note:: - - DF is capable of determining that a shrub has already been picked, leaving - an unusable structure part behind. This plugin does not perform such a check - (as the location of the required information has not yet been identified). - This leads to some shrubs being designated when they shouldn't be, causing a - plant gatherer to walk there and do nothing (except clearing the - designation). See :issue:`1479` for details. - - The implementation another known deficiency: it's incapable of detecting that - raw definitions that specify a seed extraction reaction for the structural part - but has no other use for it cannot actually yield any seeds, as the part is - never used (parts of :bug:`6940`, e.g. Red Spinach), even though DF - collects it, unless there's a workshop reaction to do it (which there isn't - in vanilla). - -.. _infiniteSky: - -infiniteSky -=========== -Automatically allocates new z-levels of sky at the top of the map as you build up, -or on request allocates many levels all at once. - -Usage: - -``infiniteSky n`` - Raise the sky by n z-levels. -``infiniteSky enable/disable`` - Enables/disables monitoring of constructions. If you build anything in the second to highest z-level, it will allocate one more sky level. This is so you can continue to build stairs upward. - -.. warning:: - - :issue:`Sometimes <254>` new z-levels disappear and cause cave-ins. - Saving and loading after creating new z-levels should fix the problem. - -.. _liquids: - -liquids -======= -Allows adding magma, water and obsidian to the game. It replaces the normal -dfhack command line and can't be used from a hotkey. Settings will be remembered -as long as dfhack runs. Intended for use in combination with the command -``liquids-here`` (which can be bound to a hotkey). See also :issue:`80`. - -.. warning:: - - Spawning and deleting liquids can mess up pathing data and - temperatures (creating heat traps). You've been warned. - -.. note:: - - `gui/liquids` is an in-game UI for this script. - -Settings will be remembered until you quit DF. You can call `liquids-here` to execute -the last configured action, which is useful in combination with keybindings. - -Usage: point the DF cursor at a tile you want to modify and use the commands. - -If you only want to add or remove water or magma from one tile, -`source` may be easier to use. - -Commands --------- -Misc commands: - -:q: quit -:help, ?: print this list of commands -:: put liquid - -Modes: - -:m: switch to magma -:w: switch to water -:o: make obsidian wall instead -:of: make obsidian floors -:rs: make a river source -:f: flow bits only -:wclean: remove salt and stagnant flags from tiles - -Set-Modes and flow properties (only for magma/water): - -:s+: only add mode -:s.: set mode -:s-: only remove mode -:f+: make the spawned liquid flow -:f.: don't change flow state (read state in flow mode) -:f-: make the spawned liquid static - -Permaflow (only for water): - -:pf.: don't change permaflow state -:pf-: make the spawned liquid static -:pf[NS][EW]: make the spawned liquid permanently flow -:0-7: set liquid amount - -Brush size and shape: - -:p, point: Single tile -:r, range: Block with cursor at bottom north-west (any place, any size) -:block: DF map block with cursor in it (regular spaced 16x16x1 blocks) -:column: Column from cursor, up through free space -:flood: Flood-fill water tiles from cursor (only makes sense with wclean) - -.. _liquids-here: - -liquids-here ------------- -Run the liquid spawner with the current/last settings made in liquids (if no -settings in liquids were made it paints a point of 7/7 magma by default). - -Intended to be used as keybinding. Requires an active in-game cursor. - -.. _plant: - -plant -===== -A tool for creating shrubs, growing, or getting rid of them. - -Subcommands: - -:create: Creates a new sapling under the cursor. Takes a raw ID as argument - (e.g. TOWER_CAP). The cursor must be located on a dirt or grass floor tile. -:grow: Turns saplings into trees; under the cursor if a sapling is selected, - or every sapling on the map if the cursor is hidden. - -For mass effects, use one of the additional options: - -:shrubs: affect all shrubs on the map -:trees: affect all trees on the map -:all: affect every plant! - -.. _regrass: - -regrass -======= -Regrows all the grass. Not much to it ;) - -.. _restrictice: - -restrictice -=========== -Restrict traffic on all tiles on top of visible ice. -See also `alltraffic`, `filltraffic`, and `restrictliquids`. - -.. _restrictliquids: - -restrictliquids -=============== -Restrict traffic on all visible tiles with liquid. -See also `alltraffic`, `filltraffic`, and `restrictice`. - -.. _tiletypes: - -tiletypes -========= -Can be used for painting map tiles and is an interactive command, much like -`liquids`. Some properties of existing tiles can be looked up with `probe`. If -something goes wrong, `fixveins` may help. - -The tool works with two set of options and a brush. The brush determines which -tiles will be processed. First set of options is the filter, which can exclude -some of the tiles from the brush by looking at the tile properties. The second -set of options is the paint - this determines how the selected tiles are -changed. - -Both paint and filter can have many different properties including things like -general shape (WALL, FLOOR, etc.), general material (SOIL, STONE, MINERAL, -etc.), state of 'designated', 'hidden' and 'light' flags. - -The properties of filter and paint can be partially defined. This means that -you can for example turn all stone fortifications into floors, preserving the -material:: - - filter material STONE - filter shape FORTIFICATION - paint shape FLOOR - -Or turn mineral vein floors back into walls:: - - filter shape FLOOR - filter material MINERAL - paint shape WALL - -The tool also allows tweaking some tile flags:: - - paint hidden 1 - paint hidden 0 - -This will hide previously revealed tiles (or show hidden with the 0 option). - -More recently, the tool supports changing the base material of the tile to -an arbitrary stone from the raws, by creating new veins as required. Note -that this mode paints under ice and constructions, instead of overwriting -them. To enable, use:: - - paint stone MICROCLINE - -This mode is incompatible with the regular ``material`` setting, so changing -it cancels the specific stone selection:: - - paint material ANY - -Since different vein types have different drop rates, it is possible to choose -which one to use in painting:: - - paint veintype CLUSTER_SMALL - -When the chosen type is ``CLUSTER`` (the default), the tool may automatically -choose to use layer stone or lava stone instead of veins if its material matches -the desired one. - -Any paint or filter option (or the entire paint or filter) can be disabled entirely by using the ANY keyword:: - - paint hidden ANY - paint shape ANY - filter material any - filter shape any - filter any - -You can use several different brushes for painting tiles: - -:point: a single tile -:range: a rectangular range -:column: a column ranging from current cursor to the first solid tile above -:block: a DF map block - 16x16 tiles, in a regular grid - -Example:: - - range 10 10 1 - -This will change the brush to a rectangle spanning 10x10 tiles on one z-level. -The range starts at the position of the cursor and goes to the east, south and -up. - -For more details, use ``tiletypes help``. - -.. _tiletypes-command: - -tiletypes-command ------------------ -Runs tiletypes commands, separated by ``;``. This makes it possible to change -tiletypes modes from a hotkey or via dfhack-run. - -Example:: - - tiletypes-command p any ; p s wall ; p sp normal - -This resets the paint filter to unsmoothed walls. - -.. _tiletypes-here: - -tiletypes-here --------------- -Apply the current tiletypes options at the in-game cursor position, including -the brush. Can be used from a hotkey. - -Options: - -:``-c``, ``--cursor ,,``: - Use the specified map coordinates instead of the current cursor position. If - this option is specified, then an active game map cursor is not necessary. -:``-h``, ``--help``: - Show command help text. -:``-q``, ``--quiet``: - Suppress non-error status output. - -.. _tiletypes-here-point: - -tiletypes-here-point --------------------- -Apply the current tiletypes options at the in-game cursor position to a single -tile. Can be used from a hotkey. - -This command supports the same options as `tiletypes-here` above. - -.. _tubefill: - -tubefill -======== -Fills all the adamantine veins again. Veins that were hollow will be left -alone. - -Options: - -:hollow: fill in naturally hollow veins too - -Beware that filling in hollow veins will trigger a demon invasion on top of -your miner when you dig into the region that used to be hollow. - - - -================= -Mods and Cheating -================= - -.. contents:: - :local: - -.. _add-spatter: - -add-spatter -=========== -This plugin makes reactions with names starting with ``SPATTER_ADD_`` -produce contaminants on the items instead of improvements. The plugin is -intended to give some use to all those poisons that can be bought from caravans, -so they're immune to being washed away by water or destroyed by `clean`. - -.. _adv-bodyswap: - -adv-bodyswap -============ -This allows taking control over your followers and other creatures in adventure -mode. For example, you can make them pick up new arms and armor and equip them -properly. - -Usage: - -* When viewing unit details, body-swaps into that unit. -* In the main adventure mode screen, reverts transient swap. - -:dfhack-keybind:`adv-bodyswap` - -.. _createitem: - -createitem -========== -Allows creating new items of arbitrary types and made of arbitrary materials. A -unit must be selected in-game to use this command. By default, items created are -spawned at the feet of the selected unit. - -Specify the item and material information as you would indicate them in -custom reaction raws, with the following differences: - -* Separate the item and material with a space rather than a colon -* If the item has no subtype, the ``:NONE`` can be omitted -* If the item is ``REMAINS``, ``FISH``, ``FISH_RAW``, ``VERMIN``, ``PET``, or ``EGG``, - specify a ``CREATURE:CASTE`` pair instead of a material token. -* If the item is a ``PLANT_GROWTH``, specify a ``PLANT_ID:GROWTH_ID`` pair - instead of a material token. - -Corpses, body parts, and prepared meals cannot be created using this tool. - -To obtain the item and material tokens of an existing item, run -``createitem inspect``. Its output can be passed directly as arguments to -``createitem`` to create new matching items, as long as the item type is -supported. - -Examples: - -* Create 2 pairs of steel gauntlets:: - - createitem GLOVES:ITEM_GLOVES_GAUNTLETS INORGANIC:STEEL 2 - -* Create tower-cap logs:: - - createitem WOOD PLANT_MAT:TOWER_CAP:WOOD - -* Create bilberries:: - - createitem PLANT_GROWTH BILBERRY:FRUIT - -For more examples, :wiki:`see this wiki page `. - -To change where new items are placed, first run the command with a -destination type while an appropriate destination is selected. - -Options: - -:floor: Subsequent items will be placed on the floor beneath the selected unit's feet. -:item: Subsequent items will be stored inside the currently selected item. -:building: Subsequent items will become part of the currently selected building. - Good for loading traps; do not use with workshops (or deconstruct to use the item). - -.. _dig-now: - -dig-now -======= - -Instantly completes non-marker dig designations, modifying tile shapes and -creating boulders, ores, and gems as if a miner were doing the mining or -engraving. By default, the entire map is processed and boulder generation -follows standard game rules, but the behavior is configurable. - -Note that no units will get mining or engraving experience for the dug/engraved -tiles. - -Trees and roots are not currently handled by this plugin and will be skipped. -Requests for engravings are also skipped since they would depend on the skill -and creative choices of individual engravers. Other types of engraving (i.e. -smoothing and track carving) are handled. - -Usage:: - - dig-now [ []] [] - -Where the optional ```` pair can be used to specify the coordinate bounds -within which ``dig-now`` will operate. If they are not specified, ``dig-now`` -will scan the entire map. If only one ```` is specified, only the tile at -that coordinate is processed. - -Any ```` parameters can either be an ``,,`` triple (e.g. -``35,12,150``) or the string ``here``, which means the position of the active -game cursor should be used. - -Examples: - -``dig-now`` - Dig designated tiles according to standard game rules. - -``dig-now --clean`` - Dig designated tiles, but don't generate any boulders, ores, or gems. - -``dig-now --dump here`` - Dig tiles and dump all generated boulders, ores, and gems at the tile under - the game cursor. - -Options: - -:``-c``, ``--clean``: - Don't generate any boulders, ores, or gems. Equivalent to - ``--percentages 0,0,0,0``. -:``-d``, ``--dump ``: - Dump any generated items at the specified coordinates. If the tile at those - coordinates is open space or is a wall, items will be generated on the - closest walkable tile below. -:``-e``, ``--everywhere``: - Generate a boulder, ore, or gem for every tile that can produce one. - Equivalent to ``--percentages 100,100,100,100``. -:``-h``, ``--help``: - Show quick usage help text. -:``-p``, ``--percentages ,,,``: - Set item generation percentages for each of the tile categories. The - ``vein`` category includes both the large oval clusters and the long stringy - mineral veins. Default is ``25,33,100,100``. -:``-z``, ``--cur-zlevel``: - Restricts the bounds to the currently visible z-level. - -.. _diggingInvaders: - -diggingInvaders -=============== -Makes invaders dig or destroy constructions to get to your dwarves. - -To enable/disable the pluging, use: ``diggingInvaders (1|enable)|(0|disable)`` - -Basic usage: - -:add GOBLIN: registers the race GOBLIN as a digging invader. Case-sensitive. -:remove GOBLIN: unregisters the race GOBLIN as a digging invader. Case-sensitive. -:now: makes invaders try to dig now, if plugin is enabled -:clear: clears all digging invader races -:edgesPerTick n: makes the pathfinding algorithm work on at most n edges per tick. - Set to 0 or lower to make it unlimited. - -You can also use ``diggingInvaders setCost (race) (action) n`` to set the -pathing cost of particular action, or ``setDelay`` to set how long it takes. -Costs and delays are per-tile, and the table shows default values. - -============================== ======= ====== ================================= -Action Cost Delay Notes -============================== ======= ====== ================================= -``walk`` 1 0 base cost in the path algorithm -``destroyBuilding`` 2 1,000 delay adds to the job_completion_timer of destroy building jobs that are assigned to invaders -``dig`` 10,000 1,000 digging soil or natural stone -``destroyRoughConstruction`` 1,000 1,000 constructions made from boulders -``destroySmoothConstruction`` 100 100 constructions made from blocks or bars -============================== ======= ====== ================================= - - -.. _fastdwarf: - -fastdwarf -========= -Controls speedydwarf and teledwarf. Speedydwarf makes dwarves move quickly -and perform tasks quickly. Teledwarf makes dwarves move instantaneously, -but do jobs at the same speed. - -:fastdwarf 0: disables both (also ``0 0``) -:fastdwarf 1: enables speedydwarf and disables teledwarf (also ``1 0``) -:fastdwarf 2: sets a native debug flag in the game memory that implements an - even more aggressive version of speedydwarf. -:fastdwarf 0 1: disables speedydwarf and enables teledwarf -:fastdwarf 1 1: enables both - -See `superdwarf` for a per-creature version. - -.. _forceequip: - -forceequip -========== -Forceequip moves local items into a unit's inventory. It is typically used to -equip specific clothing/armor items onto a dwarf, but can also be used to put -armor onto a war animal or to add unusual items (such as crowns) to any unit. - -For more information run ``forceequip help``. See also `modtools/equip-item`. - -.. _generated-creature-renamer: - -generated-creature-renamer -========================== -Automatically renames generated creatures, such as forgotten beasts, titans, -etc, to have raw token names that match the description given in-game. - -The ``list-generated`` command can be used to list the token names of all -generated creatures in a given save, with an optional ``detailed`` argument -to show the accompanying description. - -The ``save-generated-raws`` command will save a sample creature graphics file in -the Dwarf Fortress root directory, to use as a start for making a graphics set -for generated creatures using the new names that they get with this plugin. - -The new names are saved with the save, and the plugin, when enabled, only runs once -per save, unless there's an update. - -.. _lair: - -lair -==== -This command allows you to mark the map as a monster lair, preventing item -scatter on abandon. When invoked as ``lair reset``, it does the opposite. - -Unlike `reveal`, this command doesn't save the information about tiles - you -won't be able to restore state of real monster lairs using ``lair reset``. - -Options: - -:lair: Mark the map as monster lair -:lair reset: Mark the map as ordinary (not lair) - -.. _misery: - -misery -====== -When enabled, fake bad thoughts will be added to all dwarves. - -Usage: - -:misery enable n: enable misery with optional magnitude n. If specified, n must - be positive. -:misery n: same as "misery enable n" -:misery enable: same as "misery enable 1" -:misery disable: stop adding new negative thoughts. This will not remove - existing negative thoughts. Equivalent to "misery 0". -:misery clear: remove fake thoughts, even after saving and reloading. Does - not change factor. - -.. _mode: - -mode -==== -This command lets you see and change the game mode directly. - -.. warning:: - - Only use ``mode`` after making a backup of your save! - - Not all combinations are good for every situation and most of them will - produce undesirable results. There are a few good ones though. - -Examples: - - * You are in fort game mode, managing your fortress and paused. - * You switch to the arena game mode, *assume control of a creature* and then - * switch to adventure game mode(1). - You just lost a fortress and gained an adventurer. Alternatively: - - * You are in fort game mode, managing your fortress and paused at the esc menu. - * You switch to the adventure game mode, assume control of a creature, then save or retire. - * You just created a returnable mountain home and gained an adventurer. - -.. _strangemood: - -strangemood -=========== -Creates a strange mood job the same way the game itself normally does it. - -Options: - -:-force: Ignore normal strange mood preconditions (no recent mood, minimum - moodable population, artifact limit not reached). -:-unit: Make the strange mood strike the selected unit instead of picking - one randomly. Unit eligibility is still enforced. -:-type : Force the mood to be of a particular type instead of choosing randomly based on happiness. - Valid values for T are "fey", "secretive", "possessed", "fell", and "macabre". -:-skill S: Force the mood to use a specific skill instead of choosing the highest moodable skill. - Valid values are "miner", "carpenter", "engraver", "mason", "tanner", "weaver", - "clothier", "weaponsmith", "armorsmith", "metalsmith", "gemcutter", "gemsetter", - "woodcrafter", "stonecrafter", "metalcrafter", "glassmaker", "leatherworker", - "bonecarver", "bowyer", and "mechanic". - -Known limitations: if the selected unit is currently performing a job, the mood will not be started. - - -.. _siege-engine: - -siege-engine -============ -Siege engines in DF haven't been updated since the game was 2D, and can -only aim in four directions. To make them useful above-ground, -this plugin allows you to: - -* link siege engines to stockpiles -* restrict operator skill levels (like workshops) -* load any object into a catapult, not just stones -* aim at a rectangular area in any direction, and across Z-levels - -The front-end is implemented by `gui/siege-engine`. - -.. _power-meter: - -power-meter -=========== -The power-meter plugin implements a modified pressure plate that detects power being -supplied to gear boxes built in the four adjacent N/S/W/E tiles. - -The configuration front-end is implemented by `gui/power-meter`. - -.. _steam-engine: - -steam-engine -============ -The steam-engine plugin detects custom workshops with STEAM_ENGINE in -their token, and turns them into real steam engines. - -The vanilla game contains only water wheels and windmills as sources of -power, but windmills give relatively little power, and water wheels require -flowing water, which must either be a real river and thus immovable and -limited in supply, or actually flowing and thus laggy. - -Compared to the :wiki:`water reactor ` -exploit, steam engines make a lot of sense! - -Construction ------------- -The workshop needs water as its input, which it takes via a -passable floor tile below it, like usual magma workshops do. -The magma version also needs magma. - -Due to DFHack limits, the workshop will collapse over true open space. -However down stairs are passable but support machines, so you can use them. - -After constructing the building itself, machines can be connected -to the edge tiles that look like gear boxes. Their exact position -is extracted from the workshop raws. - -Like with collapse above, due to DFHack limits the workshop -can only immediately connect to machine components built AFTER it. -This also means that engines cannot be chained without intermediate -axles built after both engines. - -Operation ---------- -In order to operate the engine, queue the Stoke Boiler job (optionally -on repeat). A furnace operator will come, possibly bringing a bar of fuel, -and perform it. As a result, a "boiling water" item will appear -in the :kbd:`t` view of the workshop. - -.. note:: - - The completion of the job will actually consume one unit - of the appropriate liquids from below the workshop. This means - that you cannot just raise 7 units of magma with a piston and - have infinite power. However, liquid consumption should be slow - enough that water can be supplied by a pond zone bucket chain. - -Every such item gives 100 power, up to a limit of 300 for coal, -and 500 for a magma engine. The building can host twice that -amount of items to provide longer autonomous running. When the -boiler gets filled to capacity, all queued jobs are suspended; -once it drops back to 3+1 or 5+1 items, they are re-enabled. - -While the engine is providing power, steam is being consumed. -The consumption speed includes a fixed 10% waste rate, and -the remaining 90% are applied proportionally to the actual -load in the machine. With the engine at nominal 300 power with -150 load in the system, it will consume steam for actual -300*(10% + 90%*150/300) = 165 power. - -Masterpiece mechanism and chain will decrease the mechanical -power drawn by the engine itself from 10 to 5. Masterpiece -barrel decreases waste rate by 4%. Masterpiece piston and pipe -decrease it by further 4%, and also decrease the whole steam -use rate by 10%. - -Explosions ----------- -The engine must be constructed using barrel, pipe and piston -from fire-safe, or in the magma version magma-safe metals. - -During operation weak parts get gradually worn out, and -eventually the engine explodes. It should also explode if -toppled during operation by a building destroyer, or a -tantruming dwarf. - -Save files ----------- -It should be safe to load and view engine-using fortresses -from a DF version without DFHack installed, except that in such -case the engines won't work. However actually making modifications -to them, or machines they connect to (including by pulling levers), -can easily result in inconsistent state once this plugin is -available again. The effects may be as weird as negative power -being generated. - -======= -Lua API -======= - -Some plugins consist solely of native libraries exposed to Lua. They are listed -in the `lua-api` file under `lua-plugins`: - -* `building-hacks` -* `cxxrandom` -* `eventful` -* `luasocket` -* `map-render` -* `pathable` -* `xlsxreader` diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst new file mode 100644 index 0000000000..10d64e0bef --- /dev/null +++ b/docs/Quickstart.rst @@ -0,0 +1,239 @@ +.. _quickstart: + +Quickstart guide +================ + +Welcome to DFHack! This guide will help get you oriented with the DFHack system +and teach you how to find and use the tools productively. If you're reading this +in the in-game `quickstart-guide` reader, hit the right arrow key or click on +the hotkey hint in the lower right corner of the window to go to the next page. + +What is DFHack? +--------------- + +DFHack is an add-on for Dwarf Fortress that enables mods and tools to +significantly extend the game. The default DFHack distribution contains a wide +variety of these mods and tools, including bugfixes, interface improvements, +automation agents, design blueprints, modding building blocks, and more. +Third-party tools (e.g. mods downloaded from Steam Workshop or the forums) can +also seamlessly integrate with the DFHack framework and extend the game far +beyond what can be done by just modding the raws. + +DFHack's mission is to provide tools and interfaces for players and modders to: + +- expand the bounds of what is possible in Dwarf Fortress +- reduce the impact of game bugs +- give the player more agency and control over the game +- provide alternatives to toilsome or frustrating aspects of gameplay +- **make the game more fun** + +What can I do with DFHack tools? +-------------------------------- + +DFHack has been around for a long time -- almost as long as Dwarf Fortress +itself. Many of the game's rough edges have been smoothed with DFHack tools. +Here are some common tasks people use DFHack tools to accomplish: + +- Automatically chop trees when log stocks are low +- Mark all damaged items for trade in a single click +- Copy and paste fort layouts +- Import and export lists of manager orders +- Clean contaminants from map squares that dwarves can't reach +- Automatically butcher excess livestock so you don't become overrun with + animals +- Promote time-sensitive job types (e.g. food hauling) so they are done + expediently +- Quickly scan the map for visible ores of specific types so you can focus + your mining efforts + +Some tools are one-shot commands. For example, you can run +`unforbid all ` to claim all (reachable) items on the map after a +messy siege. + +Other tools must be `enabled ` once and then they will run in the +background. For example, once enabled, `seedwatch` will start monitoring your +stocks of seeds and prevent your chefs from cooking seeds that you need for +planting. Tools that are enabled in the context of a fort will save their state +with that fort, and they will remember that they are enabled the next time you +load your save. You can see which tools you have enabled and toggle their states +in `gui/control-panel`. + +A third class of tools adds information to the screen or provides new integrated +functionality via the DFHack `overlay` framework. For example, the `sort` tool +adds widgets to the squad member selection screen that allow you to sort and +filter the list of military candidates. You don't have to run any command to get +the benefits of the tool, it appears automatically when you're on the relevant +screen. + +How can I figure out which commands to run? +------------------------------------------- + +There are several ways to scan DFHack tools and find the ones you need right +now. + +The first place to check is the DFHack logo menu. It's in the upper left corner +of the screen by default, though you can move it anywhere you want with the +`gui/overlay` configuration UI. + +When you click on the logo (or hit the Ctrl-Shift-C keyboard shortcut), a short +list of popular, relevant DFHack tools comes up. These are the tools that have +been assigned hotkeys that are active in the current context. For example, when +you're looking at a fort map, the list will contain fortress design tools like +`gui/quickfort` and `gui/design`. You can click on the tools in the list, or +note the hotkeys listed next to them and maybe use them to launch the tool next +time without even opening the logo menu. + +The second place to check is the DFHack control panel: `gui/control-panel`. It +will give you an overview of which tools are currently enabled, and will allow +you to toggle tools on or off, see help text for them, or launch their +dedicated configuration UIs. You can open the control panel from anywhere with +the Ctrl-Shift-E hotkey or by selecting it from the logo menu list. + +In the control panel, you can also select which tools you'd like to be +automatically enabled and popular commands you'd like to run when you start a +new fort. On the "Preferences" tab, there are settings you can change, like +"mortal mode" (you'll learn more about this in the next section) or whether you +want DFHack windows to pause the game when they come up. + +Finally, you can explore the full extent of the DFHack catalog in +`gui/launcher`, which is always listed first in the DFHack logo menu list. You +can bring up the launcher by tapping the backtick key (\`) or hitting +Ctrl-Shift-D. In the launcher, you can quickly autocomplete any command name by +selecting it in the list on the right side of the window. You can filter the list +by command tag, for example, you can see only productivity tools by setting the +"productivity" tag to "include" in the filter panel. Commands are ordered by how +often you run them, so your favorite commands will always be on top. You can +also pull full commandlines out of your history with Alt-S or by clicking on the +"history search" button. + +Once you have typed (or autocompleted, or searched for) a command, other +commands related to the one you have selected will appear in the right-hand +panel. Scanning through that list is a great way to learn about new tools that +you might find useful. + +The bottom panel will show the full help text for the command you are running, +allowing you to refer to the usage documentation and examples when you are +typing your command. After you run a command, the bottom panel switches to +command output mode, but you can get back to the help text by hitting Ctrl-T or +clicking on the ``Help`` tab. + +What if I don't want to be tempted by god-mode tools? +----------------------------------------------------- + +DFHack can give you god-like powers over the game. Sometimes, this is necessary +to recover from game-breaking bugs. Sometimes, this is desirable so players can +create specific role playing environments and situations. Sometimes, this is just +fun : ) + +But sometimes the knowledge that you can just "Armok" your way out of trouble +detracts from the game experience. If this is the way you feel, you can hide +DFHack's god-mode tools -- they all have the tag "armok" -- from the game. Open +`gui/control-panel` and go to the "Preferences" tab. Enable "Mortal mode" to +hide all "armok" tools. You can still access them in `gui/launcher` if you type +their names in full, but they won't show up in autocomplete lists, in the output +of `ls`, or anywhere else. Any global hotkeys that run "armok" tools will be +disabled. + +How do DFHack in-game windows work? +----------------------------------- + +Many DFHack tools have graphical interfaces that appear in-game. You can tell +which windows belong to DFHack tools because they will have the word "DFHack" +printed across their bottom frame edge. DFHack provides an advanced windowing +system that gives the player a lot of control over where the windows appear and +whether they capture keyboard and mouse input. + +The DFHack windowing system allows multiple overlapping windows to be active at +once. The one with the highlighted title bar has focus and will receive anything +you type at the keyboard. Hit Esc or right click to close the window or cancel +the current action. You can click anywhere on the screen that is not a DFHack +window to unfocus the window and let it just sit in the background. It won't +respond to key presses or mouse clicks until you click on it again to give it +focus. If no DFHack windows are focused, you can right click directly on a +window to close it without left clicking to focus it first. + +DFHack windows are draggable from the title bar or from anywhere on the window +that doesn't have a mouse-clickable widget on it. Many are resizable as well +(if the tool window has components that can reasonably be resized). + +You can generally use DFHack tools without interrupting the game. That is, if +the game is unpaused, it can continue to run while a DFHack window is open. If +configured to do so in `gui/control-panel`, tools will initially pause the game +to let you focus on the task at hand, but you can unpause like normal if you +want. You can also interact with the map, scrolling it with the keyboard or +mouse and selecting units, buildings, and items. Some tools, like +`gui/blueprint`, will intercept all mouse clicks to allow you to select regions +of the map. When these tools have focus, you will not be able to use the mouse +to interact with map elements or pause/unpause the game. Therefore, these tools +will pause the game when they open, regardless of your settings in +`gui/control-panel`. You can still unpause with the keyboard (spacebar by +default), though. + +Where do I go next? +------------------- + +To recap: + +You can get to popular, relevant tools for the current context by clicking on +the DFHack logo or by hitting Ctrl-Shift-C. + +You can enable DFHack tools and configure settings with `gui/control-panel`, +which you can open from the DFHack logo or access directly with the +Ctrl-Shift-E hotkey. + +You can get to the launcher and its integrated autocomplete, history search, +and help text by hitting backtick (\`) or Ctrl-Shift-D, or, of course, by +running it from the logo menu list. + +With those three interfaces, you have the complete DFHack tool suite at your +fingertips. So what to run first? Here are a few examples to get you started. + +First, let's import some useful manager orders to keep your fort stocked with +basic necessities. Run ``orders import library/basic``. If you go to your +manager orders screen, you can see all the orders that have been created for +you. Note that you could have imported the orders directly from this screen as +well, using the DFHack `overlay` widget at the bottom of the manager orders +panel. + +Next, try setting up `autochop` to automatically designate trees for chopping +when you get low on usable logs. Run `gui/control-panel` and enable +``autochop`` in the ``Automation`` -> ``Enabled`` tab. Click on the button to +the left of the name or hit Enter to enable it. You can then click on the +configure button (the gear icon) to launch `gui/autochop` if you'd like to +customize its settings (the defaults are usually fine). If you have the extra +screen space, you can go ahead and set the `gui/autochop` window to minimal +mode (click on the button near the upper right corner of the window or hit +Alt-M) and click on the map so the window loses keyboard focus. As you play +the game, you can glance at the live status panel to check on your stocks of +wood. + +Finally, let's do some fort design copy-pasting. Go to some bedrooms that you +have set up in your fort. Run `gui/blueprint`, set a name for your blueprint by +clicking on the name field (or hitting the 'n' hotkey). Type "rooms" (or +whatever) and hit Enter to set. Then draw a box around the target area by +clicking with the mouse. When you select the second corner, the blueprint will +be saved to your ``dfhack-config/blueprints`` subfolder. + +Now open up `gui/quickfort` (the hotkey is Ctrl-Shift-Q). You can search for the +blueprint you just created by typing its name, but it should be up near the top +already. If you copied a dug-out area with furniture in it, you will see two +blueprints with the labels "/dig" and "/build". Click on the "/dig" blueprint or +select it with the keyboard arrow keys and hit Enter. You can rotate or flip the +blueprint around if you need to with the transform hotkeys. You'll see a preview +of where the blueprint will be applied as you move the mouse cursor around the +map. Red outlines mean that the blueprint may fail to fully apply at that +location, so be sure to choose a spot where all the preview tiles are shown with +green diamonds. Click the mouse or hit Enter to apply the blueprint and +designate the tiles for digging. Your dwarves will come and dig it out as if you +had designated the tiles yourself. + +Once the area is dug out, run `gui/quickfort` again and select the "/build" +blueprint this time. Hit ``o`` to generate manager orders for the required +furniture. Click to apply the blueprint in the dug-out area, and your furniture +will be designated. It's just that easy! Note that `quickfort` uses +`buildingplan` to place buildings, so you don't even need to have the relevant +furniture or building materials in stock yet. The planned furniture/buildings +will get built whenever you are able to produce the building materials. + +There are many, many more tools to explore. Poke around or ask other player for +advice. Have fun, and dig deep! diff --git a/docs/Removed.rst b/docs/Removed.rst deleted file mode 100644 index f98915bddf..0000000000 --- a/docs/Removed.rst +++ /dev/null @@ -1,17 +0,0 @@ -############# -Removed tools -############# - -This page lists tools (plugins or scripts) that were previously included in -DFHack but have been removed. It exists primarily so that internal links still -work (e.g. links from the `changelog`). - -.. contents:: Contents - :local: - :depth: 1 - -.. _warn-stuck-trees: - -warn-stuck-trees -================ -The corresponding DF bug, :bug:`9252` was fixed in DF 0.44.01. diff --git a/docs/Scripts.rst b/docs/Scripts.rst deleted file mode 100644 index 4193855828..0000000000 --- a/docs/Scripts.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _scripts-index: - -############## -DFHack Scripts -############## - -Lua or ruby scripts placed in the :file:`hack/scripts/` directory -are considered for execution as if they were native DFHack commands. - -The following pages document all the scripts in the DFHack standard library. - -.. toctree:: - :maxdepth: 2 - - /docs/_auto/base - /docs/_auto/devel - /docs/_auto/fix - /docs/_auto/gui - /docs/_auto/modtools diff --git a/docs/Support.rst b/docs/Support.rst deleted file mode 100644 index 00e055baa2..0000000000 --- a/docs/Support.rst +++ /dev/null @@ -1,34 +0,0 @@ -.. _support: - -=============== -Getting Support -=============== - -DFHack has several ways to get help online, including: - -- The `DFHack Discord server `__ -- The ``#dfhack`` IRC channel on `Libera `__ -- GitHub: - - for bugs, use the :issue:`issue tracker <>` - - for more open-ended questions, use the `discussion board - `__. Note that this is a - relatively-new feature as of 2021, but maintainers should still be - notified of any discussions here. -- The `DFHack thread on the Bay 12 Forum `__ - -Some additional, but less DFHack-specific, places where questions may be answered include: - -- The `/r/dwarffortress `_ questions thread on Reddit -- If you are using a starter pack, the relevant thread on the `Bay 12 Forum `__ - - see the :wiki:`DF Wiki ` for a list of these threads - -When reaching out to any support channels regarding problems with DFHack, please -remember to provide enough details for others to identify the issue. For -instance, specific error messages (copied text or screenshots) are helpful, as -well as any steps you can follow to reproduce the problem. Sometimes, log output -from ``stderr.log`` in the DF folder can point to the cause of issues as well. - -Some common questions may also be answered in documentation, including: - -- This documentation (`online here `__; search functionality available `here `) -- :wiki:`The DF wiki <>` diff --git a/docs/Tags.rst b/docs/Tags.rst new file mode 100644 index 0000000000..55bfde977b --- /dev/null +++ b/docs/Tags.rst @@ -0,0 +1,52 @@ +:orphan: + +.. _tag-list: + +DFHack tool tags +================ + +A tool often has at least one tag per group, encompassing when you use the tool, +why you might want to use it, and what kind of thing you're trying to affect. + +See https://docs.google.com/spreadsheets/d/1hiDlo8M_bB_1jE-5HRs2RrrA_VZ4cRu9VXaTctX_nwk/edit#gid=1774645373 +for the tag assignment spreadsheet. + +"when" tags +----------- +- `adventure `: Tools that are useful while in adventure mode. +- `dfhack `: Tools that you use to run DFHack commands or interact with the DFHack or DF system. +- `embark `: Tools that are useful while on the fort embark screen or while creating an adventurer. +- `fort `: Tools that are useful while in fort mode. +- `legends `: Tools that are useful while in legends mode. + +"why" tags +---------- +- `armok `: Tools which give the player god-like powers or the ability to access information the game intentionally keeps hidden. Players that do not wish to see these tools can hide them in the ``Preferences`` tab of `gui/control-panel`. +- `auto `: Tools that run in the background and automatically manage routine, toilsome aspects of your fortress. +- `bugfix `: Tools that fix specific bugs, either permanently or on-demand. +- `design `: Tools that help you with fort layout. +- `dev `: Tools that are useful when debugging or developing mods. +- `fps `: Tools that help you prevent impact to your FPS. +- `gameplay `: Tools that introduce new gameplay elements. +- `inspection `: Tools that let you view information that is otherwise difficult to find. +- `productivity `: Tools that help you perform common tasks quickly and easily. + +"what" tags +----------- +- `animals `: Tools that interact with animals. +- `buildings `: Tools that interact with buildings and furniture. +- `graphics `: Tools that interact with game graphics. +- `interface `: Tools that interact with or extend the DF user interface. +- `items `: Tools that interact with in-game items. +- `jobs `: Tools that interact with jobs. +- `labors `: Tools that deal with labor assignment. +- `map `: Tools that interact with the game map. +- `military `: Tools that interact with the military. +- `plants `: Tools that interact with grass, trees, shrubs, and crops. +- `stockpiles `: Tools that interact with stockpiles. +- `units `: Tools that interact with units. +- `workorders `: Tools that interact with workorders. + +"misc" tags +----------- +- `unavailable `: Tools that are not yet available for the current release. diff --git a/docs/Tools.rst b/docs/Tools.rst new file mode 100644 index 0000000000..67d7edc54b --- /dev/null +++ b/docs/Tools.rst @@ -0,0 +1,69 @@ +.. _tools: + +DFHack tools +============ + +DFHack comes with **a lot** of tools. This page attempts to make it clearer +what they are, how they work, and how to find the ones you want. + +.. contents:: Contents + :local: + +What tools are and how they work +-------------------------------- + +DFHack is a Dwarf Fortress memory access and modification framework, so DFHack +tools normally access Dwarf Fortress internals and make some specific changes. + +Some tools just make a targeted change when you run them, like `unforbid`, which +scans through all your items and removes the ``forbidden`` flag from each of +them. + +Some tools need to be enabled, and then they run in the background and make +changes to the game on your behalf, like `autobutcher`, which monitors your +livestock population and automatically marks excess animals for butchering. + +And some tools just exist to give you information that is otherwise hard to +come by, like `gui/petitions`, which shows you the active petitions for +guildhalls and temples that you have agreed to. + +Finding the tool you need +------------------------- + +DFHack tools are tagged with categories to make them easier to find. These +categories are listed in the next few sections. Note that a tool can belong to +more than one category. If you already know what you're looking for, try the +`search` or Ctrl-F on this page. If you'd like to see the full list of tools in +one flat list, please refer to the `annotated index `. + +Some tools are part of our back catalog and haven't been updated yet for v50 of +Dwarf Fortress. These tools are tagged as +`unavailable `. They will still appear in the +alphabetical list at the bottom of this page, but unavailable tools will not +listed in any of the indices. + +DFHack tools by game mode +------------------------- + +.. include:: tags/bywhen.rst + +DFHack tools by theme +--------------------- + +.. include:: tags/bywhy.rst + +DFHack tools by what they affect +-------------------------------- + +.. include:: tags/bywhat.rst + +All DFHack tools alphabetically +------------------------------- + +.. toctree:: + :glob: + :maxdepth: 1 + :titlesonly: + + tools/* + tools/*/* diff --git a/docs/_auto/.gitignore b/docs/_auto/.gitignore deleted file mode 100644 index 30d85567b5..0000000000 --- a/docs/_auto/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.rst diff --git a/docs/_changelogs/.gitignore b/docs/_changelogs/.gitignore deleted file mode 100644 index 2211df63dd..0000000000 --- a/docs/_changelogs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.txt diff --git a/docs/Authors.rst b/docs/about/Authors.rst similarity index 68% rename from docs/Authors.rst rename to docs/about/Authors.rst index b749840d21..a154d314b6 100644 --- a/docs/Authors.rst +++ b/docs/about/Authors.rst @@ -1,9 +1,9 @@ -List of Authors +List of authors =============== The following is a list of people who have contributed to DFHack, in alphabetical order. -If you should be here and aren't, please get in touch on IRC or the forums, +If you should be here and aren't, please get in touch on Discord or the forums, or make a pull request! ======================= ======================= =========================== @@ -12,16 +12,23 @@ Name Github Other 8Z 8Z Abel abstern acwatkins acwatkins +Aleksandr Glotov glotov4 +Alex Blamey Cubittus +Alexander Collins gearsix Alexander Gavrilov angavrilov ag +Amber Brown hawkowl Amostubal Amostubal Andrea Cattaneo acattaneo88 AndreasPK AndreasPK +Andriel Chaoti AndrielChaoti Angus Mezick amezick Antalia tamarakorr Anuradha Dissanayake falconne +Ariphaos Ariphaos arzyu arzyu Atkana Atkana AtomicChicken AtomicChicken +Batt Mush hobotron-df Bearskie Bearskie belal jimhester Ben Lubar BenLubar @@ -32,10 +39,15 @@ billw2012 billw2012 BrickViking brickviking brndd brndd burneddi Caldfir caldfir +Cameron Ewell Ozzatron Carter Bray Qartar Chris Dombroski cdombroski +Chris Parsons chrismdp +Christian Doczkal chdoc +cjhammel cjhammel Clayton Hughes Clément Vuchener cvuchener +Corey CoreyJ87 daedsidog daedsidog Dan Amlund danamlund Daniel Brooks db48x @@ -43,11 +55,21 @@ David Nilsolm David Corbett dscorbett David Seguin dseguin David Timm dtimm +Dean Golden LightHardt Deon +dhthwy dhthwy +dikbutdagrate Tjudge1 +Dmitrii Kurkin Kurkin DoctorVanGogh DoctorVanGogh Donald Ruegsegger hashaash doomchild doomchild +Droseran Droseran +dvantwisk dvantwisk +DwarvenM DwarvenM +Eamon Bode eamondo2 Baron Von Munchhausen +EarthPulseAcademy EarthPulseAcademy ElMendukol ElMendukol +ElsaTheHobo ElsaTheHobo Elsa enjia2000 Eric Wald eswald Erik Youngren Artanis @@ -56,16 +78,22 @@ expwnent expwnent Feng figment figment Gabe Rau gaberau +Gaelmare Gaelmare gchristopher gchristopher George Murray GitOnUp grubsteak grubsteak +Guilherme Abraham GuilhermeAbraham Harlan Playford playfordh Hayati Ayguen hayguen Herwig Hochleitner bendlas +Hevlikn Hevlikn Ian S kremlin- IndigoFenix +Jacek Konieczny Jajcus +James 20k James Gilles kazimuth James Logsdon jlogsdon +Janeene Beeforth dawnmist Jared Adams Jeremy Apthorp nornagon Jim Lisi stonetoad @@ -74,16 +102,23 @@ jimcarreer jimcarreer jj jjyg jj\`\` Joel Meador janxious John Beisley huin +John Cosker johncosker John Shade gsvslto +Johnny Fisher jfisher446 JohnnyWing Jonas Ask +Jonathan Clark AridTag Josh Cooper cppcooper coope +jowario jowario kane-t kane-t Kelly Kinkade ab9rf +Kelvie Wong kelvie +Kib Arekatír arekatir KlonZK KlonZK Kris Parker kaypy Kristjan Moore kristjanmoore Kromtec Kromtec Kurik Amudnil +Kévin Boissonneault KABoissonneault Lethosor lethosor LordGolias LordGolias Mark Nielson pseudodragon @@ -93,6 +128,7 @@ Matthew Cline Matthew Lindner mlindner Matthew Taylor ymber yutna Max maxthyme Max^TM +Maxim Verkhov nibirubingus McArcady McArcady melkor217 melkor217 Meneth32 @@ -102,32 +138,52 @@ Michael Crouch creidieki Michon van Dooren MaienM miffedmap miffedmap Mike Stewart thewonderidiot +Mikhail Panov Halifay Mikko Juola Noeda Adeon Milo Christiansen milochristiansen MithrilTuxedo MithrilTuxedo mizipzor mizipzor moversti moversti +mrrho mrrho +Murad Beybalaev Erquint Myk Taylor myk002 +Najeeb Al-Shabibi master-spike napagokc napagokc Neil Little nmlittle +Nicholas McDaniel NicksWorld Nick Rart nickrart comestible Nicolas Ayala nicolasayala +Nik Nyby nikolas Nikolay Amiantov abbradar nocico nocico +NotRexButCaesar NotRexButCaesar +Nuno Fernandes UnknowableCoder +nuvu vallode Omniclasm +Ong Ying Gao ong-yinggao98 +oorzkws oorzkws OwnageIsMagic OwnageIsMagic +pajawojciech pajawojciech palenerd dlmarquis PassionateAngler PassionateAngler Patrik Lundell PatrikLundell Paul Fenwick pjf PeridexisErrant PeridexisErrant +Peter Hansen previsualconsent Petr Mrázek peterix Pfhreak Pfhreak +Pierre Lulé plule Pierre-David Bélanger pierredavidbelanger +PopnROFL PopnROFL potato +ppaawwll ppaawwll ðŸ‡ðŸ‡ðŸ‡ðŸ‡ Priit Laes plaes +PrzemysÅ‚aw Skrobot frogi16 +psychowico wiktor-obrebski Putnam Putnam3145 +quarque2 quarque2 Quietust quietust _Q +RafaÅ‚ Karczmarczyk CarabusX Raidau Raidau Ralph Bisschops ralpha Ramblurr Ramblurr @@ -138,6 +194,8 @@ reverb Rich Rauenzahn rrauenza Rinin Rinin rndmvar rndmvar +Rob Bailey actionninja +Rob Goodberry robob27 Robert Heinrich rh73 Robert Janetzko robertjanetzko Rocco Moretti roccomoretti @@ -148,18 +206,27 @@ Rose RosaryMala Roses Pheosics Ross M RossM rout +Roxy TealSeer gallowsCalibrator rubybrowncoat rubybrowncoat Rumrusher rumrusher RusAnon RusAnon Ryan Bennitt ryanbennitt +Ryan Dwyer ToxicBananaParty Jimdude2435 Ryan Williams Bumber64 Bumber sami scamtank scamtank +Scott Ellis StormCrow42 Sebastian Wolfertz Enkrod +SeerSkye SeerSkye seishuuu seishuuu Seth Woodworth sethwoodworth +shevernitskiy shevernitskiy +Shim Panze Shim-Panze +Silver silverflyone simon Simon Jackson sizeak +Simon Lees simotek +Squid Coder realSquidCoder stolencatkarma Stoyan Gaydarov sgayda2 Su Moth-Tolias @@ -167,14 +234,19 @@ suokko suokko shrieker sv-esk sv-esk Tachytaenius wolfboyft Tacomagic +tatoyoda600 tatoyoda600 +TaxiService TaxiService +terribleperson terribleperson thefriendlyhacker thefriendlyhacker TheHologram TheHologram Theo Kalfas teolandon therahedwig therahedwig ThiagoLira ThiagoLira thurin thurin +Tim Siegel softmoth Tim Walberg twalberg Timothy Collett danaris +Timothy Torres timothymtorres Timur Kelman TymurGubayev Tom Jobbins TheBloke Tom Prince @@ -184,13 +256,19 @@ Travis Hoppe thoppe orthographic-pedant txtsd txtsd U-glouglou\\simon Valentin Ochs Cat-Ion +Varnavskii Aleksandr Crystalwarrior Vitaly Pronkin pronvit mifki ViTuRaS ViTuRaS Vjek vjek +Vladimir Florov foxxelias Warmist warmist Wes Malone wesQ3 +Will H TSM-EVO Will Rogers wjrogers +WoosterUK WoosterUK +XianMaeve XianMaeve ZechyW ZechyW Zhentar Zhentar zilpin zilpin +Zishi Wu zishiwu123 ======================= ======================= =========================== diff --git a/docs/about/History.rst b/docs/about/History.rst new file mode 100644 index 0000000000..4bd4ec6429 --- /dev/null +++ b/docs/about/History.rst @@ -0,0 +1,3979 @@ +:orphan: + +.. _History: + +##################### +Historical changelogs +##################### + +This file is where old changelogs live, so the `current changelog ` +doesn't get too long. Some of these changelogs are also formatted differently +from current changelogs and would be difficult for the current `changelog +generation system ` to handle. + +.. contents:: Contents + :local: + :depth: 1 + +DFHack 0.47.05-r8 +================= + +New Plugins +----------- +- `channel-safely`: auto-manage channel designations to keep dwarves safe +- `overlay`: plugin is transformed from a single line of text that runs `gui/launcher` on click to a fully-featured overlay injection framework. It now houses a popup menu for keybindings relevant to the current DF screen, all the widgets previously provided by `dwarfmonitor` (e.g. the current date and number of happy/unhappy dwarves), the overlay that highlights suspended buildings when you pause, and others. See `overlay-dev-guide` for details. + +New Scripts +----------- +- `gui/overlay`: configuration interface for the DFHack overlays and overlay widgets. includes a click-and-drag interface for repositioning widgets! + +Fixes +----- +- Core: ensure ``foo.init`` always runs before ``foo.*.init`` (e.g. ``dfhack.init`` should always run before ``dfhack.something.init``) +- `autofarm`: flush output so status text is visible immediately after running the command +- `autolabor`, `autohauler`: properly handle jobs 241, 242, and 243 +- `automaterial`: + - fix the cursor jumping up a z level when clicking quickly after box select + - fix rendering errors with box boundary markers +- `buildingplan`: fix crash when canceling out of placement mode for a building with planning mode enabled and subsequently attempting to place a building that does not have planning mode enabled and that has no pertinent materials available +- `dwarf-op`: fixed error when matching dwarves by name +- `gui/create-item`: prevent materials list filter from intercepting sublist hotkeys +- `gui/gm-unit`: fixed behavior of ``+`` and ``-`` to adjust skill values instead of populating the search field +- `hotkeys`: correctly detect hotkeys bound to number keys, F11, and F12 +- `labormanager`: associate quern construction with the correct labor +- `mousequery`: fix the cursor jumping up z levels sometimes when using TWBT +- `tiletypes`: no longer resets dig priority to the default when updating other properties of a tile +- `warn-stealers`: + - register callback with correct event name so that units entering the map are detected + - announce thieving creatures that spawn already revealed + - cache unit IDs instead of unit objects to avoid referencing stale pointers +- `workorder`: fix interpretation of json-specified orders that set the ``item_type`` field +- ``EventManager``: + - fix a segmentation fault with the ``REPORT`` event + - fix the ``JOB_STARTED`` event only sending events to the first handler listed instead of all registered handlers + +Misc Improvements +----------------- +- UX: + - List widgets now have mouse-interactive scrollbars + - You can now hold down the mouse button on a scrollbar to make it scroll multiple times. + - You can now drag the scrollbar up and down to scroll to a specific spot +- `autolabor`, `autohauler`: refactored to use DFHack's messaging system for info/debug/trace messages +- `blueprint`: + - new ``--smooth`` option for recording all smoothed floors and walls instead of just the ones that require smoothing for later carving + - record built constructions in blueprints + - record stockpile/building/zone names in blueprints + - record room sizes in blueprints + - generate meta blueprints to reduce the number of blueprints you have to apply + - support splitting the output file into phases grouped by when they can be applied + - when splitting output files, number them so they sort into the order you should apply them in +- `digtype`: new ``-z`` option for digtype to restrict designations to the current z-level and down +- `dwarfmonitor`: widgets have been ported to the overlay framework and can be enabled and configured via the `gui/overlay` UI +- `gui/blueprint`: support new blueprint phases and options +- `gui/cp437-table`: new global keybinding for the clickable on-screen keyboard for players with keyboard layouts that prevent them from using certain keys: Ctrl-Shift-K +- `gui/create-item`: restrict materials to those normally allowed by the game by default, introduce new ``--unrestricted`` option for full freedom in choosing materials +- `gui/launcher`: show help for commands that start with ':' (like ``:lua``) +- `gui/quantum`: add option to allow corpses and refuse in your quantum stockpile +- `hotkeys`: + - hotkey screen has been transformed into an interactive `overlay` widget that you can bring up by moving the mouse cursor over the hotspot (in the upper left corner of the screen by default). Enable/disable/reposition the hotspot in the `gui/overlay` UI. Even if the hotspot is disabled, the menu can be brought up at any time with the Ctrl-Shift-C hotkey. + - now supports printing active hotkeys to the console with ``hotkeys list`` +- `ls`: + - indent tag listings and wrap them in the rightmost column for better readability + - new ``--exclude`` option for hiding matched scripts from the output. this can be especially useful for modders who don't want their mod scripts to be included in ``ls`` output. +- `modtools/create-unit`: better unit naming, more argument checks, assign nemesis save data for units without civilization so they can be properly saved when offloaded +- `orders`: replace shell craft orders in the standard orders list you get with ``orders import library/basic`` with orders for shell leggings. They have a slightly higher trade price. Also, "shleggings" is just hilarious. +- `quickfort-library-guide`: improved layout of marksdwarf barracks in the example Dreamfort blueprints +- `spectate`: + - new ``auto-unpause`` option for auto-dismissal of announcement pause events (e.g. sieges). + - new ``auto-disengage`` option for auto-disengagement of plugin through player interaction whilst unpaused. + - new ``tick-threshold`` option for specifying the maximum time to follow the same dwarf + - new ``animals`` option for sometimes following animals + - new ``hostiles`` option for sometimes following hostiles + - new ``visiting`` option for sometimes following visiting merchants, diplomats or plain visitors + - added persistent configuration of the plugin settings +- `unsuspend`: new `overlay` for displaying status of suspended buildings (functionality migrated from removed `resume` plugin) + +Documentation +------------- +- `overlay-dev-guide`: documentation and guide for injecting functionality into DF viewscreens from Lua scripts and creating interactive overlay widgets +- ``dfhack.gui.revealInDwarfmodeMap``: document ``center`` bool for Lua API + +Removed +------- +- `gui/create-item`: removed ``--restricted`` option. it is now the default behavior +- `resume`: functionality (including suspended building overlay) has moved to `unsuspend` + +API +--- +- Constructions module: added ``insert()`` to insert constructions into the game's sorted list. +- MiscUtils: added the following string transformation functions (refactored from ``uicommon.h``): ``int_to_string``, ``ltrim``, ``rtrim``, and ``trim``; added ``string_to_int`` +- Units module: + - added new predicates for: + - ``isUnitInBox()`` + - ``isAnimal()`` + - ``isVisiting()`` any visiting unit (diplomat, merchant, visitor) + - ``isVisitor()`` ie. not merchants or diplomats + - ``isInvader()`` + - ``isDemon()`` returns true for unique/regular demons + - ``isTitan()`` + - ``isMegabeast()`` + - ``isGreatDanger()`` returns true if unit is a demon, titan, or megabeast + - ``isSemiMegabeast()`` + - ``isNightCreature()`` + - ``isDanger()`` returns true if is a 'GreatDanger', semi-megabeast, night creature, undead, or invader + - modified predicates: + - ``isUndead()`` now optionally ignores vampires instead of always ignoring vampires + - ``isCitizen()`` now optionally ignores insane citizens instead of always ignoring insane citizens + - new action timer API for speeding up of slowing down units +- ``Gui::anywhere_hotkey``: for plugin commands bound to keybindings that can be invoked on any screen +- ``Gui::autoDFAnnouncement``, ``Gui::pauseRecenter``: added functionality reverse-engineered from announcement code +- ``Gui::revealInDwarfmodeMap``: Now enforce valid view bounds when pos invalid, add variant accepting x, y, z +- ``Lua::Push()``: now handles maps with otherwise supported keys and values +- ``Lua::PushInterfaceKeys()``: transforms viewscreen ``feed()`` keys into something that can be interpreted by lua-based widgets + +Internals +--------- +- Constructions module: ``findAtTile`` now uses a binary search instead of a linear search +- MSVC warning level upped to /W3, and /WX added to make warnings cause compilations to fail. + +Lua +--- +- Lua mouse events now conform to documented behavior in `lua-api` -- ``_MOUSE_L_DOWN`` will be sent exactly once per mouse click and ``_MOUSE_L`` will be sent repeatedly as long as the button is held down. Similarly for right mouse button events. +- ``dfhack.constructions.findAtTile()``: exposed preexisting function to Lua. +- ``dfhack.constructions.insert()``: exposed new function to Lua. +- ``gui.Screen.show()``: now returns ``self`` as a convenience +- ``gui.View.getMousePos()`` now takes an optional ``ViewRect`` parameter in case the caller wants to get the mouse pos relative to a rect that is not the frame_body (such as the frame_rect that includes the frame itself) +- ``widgets.EditField``: now allows other widgets to process characters that the ``on_char`` callback rejects. +- ``widgets.FilteredList``: now provides a useful default search key for list items made up of text tokens instead of plain text +- ``widgets.HotkeyLabel``: now ignores mouse clicks when ``on_activate`` is not defined +- ``widgets.List``: + - new ``getIdxUnderMouse()`` function for detecting the list index under the active mouse cursor. this allows for "selection follows mouse" behavior + - shift-clicking now triggers the ``submit2`` attribute function if it is defined +- ``widgets.Panel``: new ``frame_style`` and ``frame_title`` attributes for drawing frames around groups of widgets +- ``widgets.ResizingPanel``: now accounts for frame inset when calculating frame size +- ``widgets.Scrollbar``: new scrollbar widget that can be paired with an associated scrollable widget. Integrated with ``widgets.Label`` and ``widgets.List``. + +Structures +---------- +- ``general_refst``: type virtual union member for ``ITEM_GENERAL`` +- ``historical_figure_info.T_reputation.unk_2c``: identify ``year`` + ``year_ticks`` +- ``itemst``: identify two vmethods related to adding thread improvements to items made of cloth, and label several previously unknown return types +- ``proj_magicst``: correct structure fields (to match 40d) +- ``unit_action_type_group``: added enum and tagged ``unit_action_type`` entries with its groups for DFHack's new action timer API. +- ``world``: identify type of a vector (still not known what it's for, but it's definitely an item vector) + + +DFHack 0.47.05-r7 +================= + +New Plugins +----------- +- `autobutcher`: split off from `zone` into its own plugin. Note that to enable, the command has changed from ``autobutcher start`` to ``enable autobutcher``. +- `autonestbox`: split off from `zone` into its own plugin. Note that to enable, the command has changed from ``autonestbox start`` to ``enable autonestbox``. +- `overlay`: display a "DFHack" button in the lower left corner that you can click to start the new GUI command launcher. The `dwarfmonitor` weather display had to be moved to make room for the button. If you are seeing the weather indicator rendered over the overlay button, please remove the ``dfhack-config/dwarfmonitor.json`` file to fix the weather indicator display offset. + +New Scripts +----------- +- `gui/kitchen-info`: adds more info to the Kitchen screen +- `gui/launcher`: in-game command launcher with autocomplete, history, and context-sensitive help +- `gui/workorder-details`: adjusts work orders' input item, material, traits +- `max-wave`: dynamically limit the next immigration wave, can be set to repeat +- `pop-control`: persistent per fortress population cap, `hermit`, and `max-wave` management +- `warn-stealers`: warn when creatures that may steal your food, drinks, or items become visible + +New Internal Commands +--------------------- +- `tags`: new built-in command to list the tool category tags and their definitions. tags associated with each tool are visible in the tool help and in the output of `ls`. + +Fixes +----- +- `autochop`: designate largest trees for chopping first, instead of the smallest +- `devel/query`: fixed error when --tile is specified +- `dig-now`: Fix direction of smoothed walls when adjacent to a door or floodgate +- `dwarf-op`: fixed error when applying the Miner job to dwarves +- `emigration`: fix emigrant logic so unhappy dwarves leave as designed +- `gui/gm-unit`: allow ``+`` and ``-`` to adjust skill values as intended instead of letting the filter intercept the characters +- `gui/unit-info-viewer`: fix logic for displaying undead creature names +- `gui/workflow`: restore functionality to the add/remove/order hotkeys on the workflow status screen +- `modtools/moddable-gods`: fixed an error when assigning spheres +- `quickfort`: `Dreamfort ` blueprint set: declare the hospital zone before building the coffer; otherwise DF fails to stock the hospital with materials +- `view-item-info`: fixed a couple errors when viewing items without materials +- ``dfhack.buildings.findCivzonesAt``: no longer return duplicate civzones after loading a save with existing civzones +- ``dfhack.run_script``: ensure the arguments passed to scripts are always strings. This allows other scripts to call ``run_script`` with numeric args and it won't break parameter parsing. +- ``job.removeJob()``: ensure jobs are removed from the world list when they are canceled + +Misc Improvements +----------------- +- History files: ``dfhack.history``, ``tiletypes.history``, ``lua.history``, and ``liquids.history`` have moved to the ``dfhack-config`` directory. If you'd like to keep the contents of your current history files, please move them to ``dfhack-config``. +- Init scripts: ``dfhack.init`` and other init scripts have moved to ``dfhack-config/init/``. If you have customized your ``dfhack.init`` file and want to keep your changes, please move the part that you have customized to the new location at ``dfhack-config/init/dfhack.init``. If you do not have changes that you want to keep, do not copy anything, and the new defaults will be used automatically. +- UX: + - You can now move the cursor around in DFHack text fields in ``gui/`` scripts (e.g. `gui/blueprint`, `gui/quickfort`, or `gui/gm-editor`). You can move the cursor by clicking where you want it to go with the mouse or using the Left/Right arrow keys. Ctrl+Left/Right will move one word at a time, and Alt+Left/Right will move to the beginning/end of the text. + - You can now click on the hotkey hint text in many ``gui/`` script windows to activate the hotkey, like a button. Not all scripts have been updated to use the clickable widget yet, but you can try it in `gui/blueprint` or `gui/quickfort`. + - Label widget scroll icons are replaced with scrollbars that represent the percentage of text on the screen and move with the position of the visible text, just like web browser scrollbars. +- `devel/query`: + - inform the user when a query has been truncated due to ``--maxlength`` being hit. + - increased default maxlength value from 257 to 2048 +- `do-job-now`: new global keybinding for boosting the priority of the jobs associated with the selected building/work order/unit/item etc.: Alt-N +- `dwarf-op`: replaces [ a b c ] option lists with a,b,c option lists +- `gui/gm-unit`: don't clear the list filter when you adjust a skill value +- `gui/quickfort`: + - better formatting for the generated manager orders report + - you can now click on the map to move the blueprint anchor point to that tile instead of having to use the cursor movement keys + - display an error message when the blueprints directory cannot be found +- `gui/workorder-details`: new keybinding on the workorder details screen: ``D`` +- `keybinding`: support backquote (\`) as a hotkey (and assign the hotkey to the new `gui/launcher` interface) +- `ls`: can now filter tools by substring or tag. note that dev scripts are hidden by default. pass the ``--dev`` option to show them. +- `manipulator`: + - add a library of useful default professions + - move professions configuration from ``professions/`` to ``dfhack-config/professions/`` to keep it together with other dfhack configuration. If you have saved professions that you would like to keep, please manually move them to the new folder. +- `orders`: added useful library of manager orders. see them with ``orders list`` and import them with, for example, ``orders import library/basic`` +- `prioritize`: new ``defaults`` keyword to prioritize the list of jobs that the community agrees should generally be prioritized. Run ``prioritize -a defaults`` to try it out in your fort! +- `prospect`: add new ``--show`` option to give the player control over which report sections are shown. e.g. ``prospect all --show ores`` will just show information on ores. +- `quickfort`: + - `Dreamfort ` blueprint set improvements: set traffic designations to encourage dwarves to eat cooked food instead of raw ingredients + - library blueprints are now included by default in ``quickfort list`` output. Use the new ``--useronly`` (or just ``-u``) option to filter out library blueprints. + - better error message when the blueprints directory cannot be found +- `seedwatch`: ``seedwatch all`` now adds all plants with seeds to the watchlist, not just the "basic" crops. +- ``materials.ItemTraitsDialog``: added a default ``on_select``-handler which toggles the traits. + +Documentation +------------- +- Added `modding-guide` +- Group DFHack tools by `tag ` so similar tools are grouped and easy to find +- Update all DFHack tool documentation (300+ pages) with standard syntax formatting, usage examples, and overall clarified text. + +Removed +------- +- `fix/build-location`: The corresponding DF bug (5991) was fixed in DF 0.40.05 +- `fix/diplomats`: DF bug 3295 fixed in 0.40.05 +- `fix/fat-dwarves`: DF bug 5971 fixed in 0.40.05 +- `fix/feeding-timers`: DF bug 2606 is fixed in 0.40.12 +- `fix/merchants`: DF bug that prevents humans from making trade agreements has been fixed +- `gui/assign-rack`: No longer useful in current DF versions +- `gui/hack-wish`: Replaced by `gui/create-item` +- `gui/no-dfhack-init`: No longer useful since players don't have to create their own ``dfhack.init`` files anymore + +API +--- +- Removed "egg" ("eggy") hook support (Linux only). The only remaining method of hooking into DF is by interposing SDL calls, which has been the method used by all binary releases of DFHack. +- Removed ``Engravings`` module (C++-only). Access ``world.engravings`` directly instead. +- Removed ``Notes`` module (C++-only). Access ``ui.waypoints.points`` directly instead. +- Removed ``Windows`` module (C++-only) - unused. +- ``Constructions`` module (C++-only): removed ``t_construction``, ``isValid()``, ``getCount()``, ``getConstruction()``, and ``copyConstruction()``. Access ``world.constructions`` directly instead. +- ``Gui::getSelectedItem()``, ``Gui::getAnyItem()``: added support for the artifacts screen +- ``Units::teleport()``: now sets ``unit.idle_area`` to discourage units from walking back to their original location (or teleporting back, if using `fastdwarf`) + +Lua +--- +- Added ``dfhack.screen.hideGuard()``: exposes the C++ ``Screen::Hide`` to Lua +- History: added ``dfhack.getCommandHistory(history_id, history_filename)`` and ``dfhack.addCommandToHistory(history_id, history_filename, command)`` so gui scripts can access a commandline history without requiring a terminal. +- ``helpdb``: database and query interface for DFHack tool help text +- ``tile-material``: fix the order of declarations. The ``GetTileMat`` function now returns the material as intended (always returned nil before). Also changed the license info, with permission of the original author. +- ``utils.df_expr_to_ref()``: fixed some errors that could occur when navigating tables +- ``widgets.CycleHotkeyLabel``: clicking on the widget will now cycle the options and trigger ``on_change()``. This also applies to the ``ToggleHotkeyLabel`` subclass. +- ``widgets.EditField``: + - new ``onsubmit2`` callback attribute is called when the user hits Shift-Enter. + - new function: ``setCursor(position)`` sets the input cursor. + - new attribute: ``ignore_keys`` lets you ignore specified characters if you want to use them as hotkeys +- ``widgets.FilteredList``: new attribute: ``edit_ignore_keys`` gets passed to the filter EditField as ``ignore_keys`` +- ``widgets.HotkeyLabel``: clicking on the widget will now call ``on_activate()``. +- ``widgets.Label``: ``scroll`` function now interprets the keywords ``+page``, ``-page``, ``+halfpage``, and ``-halfpage`` in addition to simple positive and negative numbers. + +Structures +---------- +- Eliminate all "anon_X" names from structure fields +- ``army``: change ``squads`` vector type to ``world_site_inhabitant``, identify ``min_smell_trigger``+``max_odor_level``+``max_low_light_vision``+``sense_creature_classes`` +- ``cave_column_rectangle``: identify coordinates +- ``cave_column``: identify Z coordinates +- ``embark_profile``: identify reclaim fields, add missing pet_count vector +- ``entity_population``: identify ``layer_id`` +- ``feature``: identify "shiftCoords" vmethod, ``irritation_level`` and ``irritation_attacks`` fields +- ``flow_guide``: identify "shiftCoords" vmethod +- ``general_refst``: name parameters on ``getLocation`` and ``setLocation`` vmethods +- ``general_ref_locationst``: name member fields +- ``historical_entity``: confirm ``hostility_level`` and ``siege_tier`` +- ``item``: identify method ``notifyCreatedMasterwork`` that is called when a masterwork is created. +- ``language_name_type``: identify ``ElfTree`` and ``SymbolArtifice`` thru ``SymbolFood`` +- ``misc_trait_type``: update auto-decrement markers, remove obsolete references +- ``timed_event``: identify ``layer_id`` +- ``ui_advmode``: identify several fields as containing coordinates +- ``ui_build_selector``: identify ``cur_walk_tag`` and ``min_weight_races``+``max_weight_races`` +- ``ui``: identify actual contents of ``unk5b88`` field, identify infiltrator references +- ``unitst``: identify ``histeventcol_id`` field inside status2 +- ``viewscreen_barterst``: name member fields +- ``viewscreen_tradegoodsst``: rename trade_reply ``OffendedAnimal``+``OffendedAnimalAlt`` to ``OffendedBoth``+``OffendedAnimal`` +- ``world_site_inhabitant``: rename ``outcast_id`` and ``founder_outcast_entity_id``, identify ``interaction_id`` and ``interaction_effect_idx`` + + +DFHack 0.47.05-r6 +================= + +New Scripts +----------- +- `assign-minecarts`: automatically assign minecarts to hauling routes that don't have one +- `deteriorate`: combines, replaces, and extends previous `deteriorateclothes`, `deterioratecorpses`, and `deterioratefood` scripts. +- `gui/petitions`: shows petitions. now you can see which guildhall/temple you agreed to build! +- `gui/quantum`: point-and-click tool for creating quantum stockpiles +- `gui/quickfort`: shows blueprint previews on the live map so you can apply them interactively +- `modtools/fire-rate`: allows modders to adjust the rate of fire for ranged attacks + +Fixes +----- +- `build-now`: walls built above other walls can now be deconstructed like regularly-built walls +- `eventful`: + - fix ``eventful.registerReaction`` to correctly pass ``call_native`` argument thus allowing canceling vanilla item creation. Updated related documentation. + - renamed NEW_UNIT_ACTIVE event to UNIT_NEW_ACTIVE to match the ``EventManager`` event name + - fixed UNIT_NEW_ACTIVE event firing too often +- `gui/dfstatus`: no longer count items owned by traders +- `gui/unit-info-viewer`: fix calculation/labeling of unit size +- ``job.removeJob()``: fixes regression in DFHack 0.47.05-r5 where items/buildings associated with the job were not getting disassociated when the job is removed. Now `build-now` can build buildings and `gui/mass-remove` can cancel building deconstruction again +- ``widgets.CycleHotkeyLabel``: allow initial option values to be specified as an index instead of an option value + +Misc Improvements +----------------- +- `build-now`: buildings that were just designated with `buildingplan` are now built immediately (as long as there are items available to build the buildings with) instead of being skipped until buildingplan gets around to doing its regular scan +- `caravan`: new ``unload`` command, fixes endless unloading at the depot by reconnecting merchant pack animals that were disconnected from their owners +- `confirm`: + - added a confirmation dialog for removing manager orders + - allow players to pause the confirmation dialog until they exit the current screen +- `deteriorate`: new ``now`` command immediately deteriorates items of the specified types +- `dfhack-examples-guide`: + - refine food preparation orders so meal types are chosen intelligently according to the amount of meals that exist and the number of available items to cook with + - reduce required stock of dye for "Dye cloth" orders + - fix material conditions for making jugs and pots + - make wooden jugs by default to differentiate them from other stone tools. this allows players to more easily select jugs out with a properly-configured stockpile (i.e. the new ``woodentools`` alias) +- `list-agreements`: now displays translated guild names, worshipped deities, petition age, and race-appropriate professions (e.g. "Craftsdwarf" instead of "Craftsman") +- `quickfort-alias-guide`: + - new aliases: ``forbidsearch``, ``permitsearch``, and ``togglesearch`` use the `search-plugin` plugin to alter the settings for a filtered list of item types when configuring stockpiles + - new aliases: ``stonetools`` and ``woodentools``. the ``jugs`` alias is deprecated. please use ``stonetools`` instead, which is the same as the old ``jugs`` alias. + - new aliases: ``usablehair``, ``permitusablehair``, and ``forbidusablehair`` alter settings for the types of hair/wool that can be made into cloth: sheep, llama, alpaca, and troll. The ``craftrefuse`` aliases have been altered to use this alias as well. + - new aliases: ``forbidthread``, ``permitthread``, ``forbidadamantinethread``, ``permitadamantinethread``, ``forbidcloth``, ``permitcloth``, ``forbidadamantinecloth``, and ``permitadamantinecloth`` give you more control how adamantine-derived items are stored +- `quickfort`: + - `Dreamfort ` blueprint set improvements: automatically create tavern, library, and temple locations (restricted to residents only by default), automatically associate the rented rooms with the tavern + - `Dreamfort ` blueprint set improvements: new design for the services level, including were-bitten hospital recovery rooms and an appropriately-themed interrogation room next to the jail! Also fits better in a 1x1 embark for minimalist players. +- `workorder`: a manager is no longer required for orders to be created (matching behavior in the game itself) + +Removed +------- +- `deteriorateclothes`: please use ``deteriorate --types=clothes`` instead +- `deterioratecorpses`: please use ``deteriorate --types=corpses`` instead +- `deterioratefood`: please use ``deteriorate --types=food`` instead +- `devel/unforbidall`: please use `unforbid` instead. You can silence the output with ``unforbid all --quiet`` + +API +--- +- ``word_wrap``: argument ``bool collapse_whitespace`` converted to enum ``word_wrap_whitespace_mode mode``, with valid modes ``WSMODE_KEEP_ALL``, ``WSMODE_COLLAPSE_ALL``, and ``WSMODE_TRIM_LEADING``. + +Lua +--- +- ``gui.View``: all ``View`` subclasses (including all ``Widgets``) can now acquire keyboard focus with the new ``View:setFocus()`` function. See docs for details. +- ``materials.ItemTraitsDialog``: new dialog to edit item traits (where "item" is part of a job or work order or similar). The list of traits is the same as in vanilla work order conditions "``t`` change traits". +- ``widgets.EditField``: + - the ``key_sep`` string is now configurable + - can now display an optional string label in addition to the activation key + - views that have an ``EditField`` subview no longer need to manually manage the ``EditField`` activation state and input routing. This is now handled automatically by the new ``gui.View`` keyboard focus subsystem. +- ``widgets.HotkeyLabel``: the ``key_sep`` string is now configurable + +Structures +---------- +- ``art_image_elementst``: identify vmethod ``markDiscovered`` and second parameter for ``getName2`` +- ``art_image_propertyst``: identify parameters for ``getName`` +- ``building_handler``: fix vmethod ``get_machine_hookup_list`` parameters +- ``vermin``: identify ``category`` field as new enum +- ``world.unk_26a9a8``: rename to ``allow_announcements`` + + +DFHack 0.47.05-r5 +================= + +New Plugins +----------- +- `spectate`: "spectator mode" -- automatically follows dwarves doing things in your fort + +New Scripts +----------- +- `devel/eventful-client`: useful for testing eventful events + +New Tweaks +---------- +- `tweak`: ``partial-items`` displays percentage remaining for partially-consumed items such as hospital cloth + +Fixes +----- +- `autofarm`: removed restriction on only planting "discovered" plants +- `cxxrandom`: fixed exception when calling ``bool_distribution`` +- `devel/query`: + - fixed a problem printing parents when the starting path had lua pattern special characters in it + - fixed a crash when trying to iterate over linked lists +- `gui/advfort`: encrust and stud jobs no longer consume reagents without actually improving the target item +- `luasocket`: return correct status code when closing socket connections so clients can know when to retry +- `quickfort`: constructions and bridges are now properly placed over natural ramps +- `setfps`: keep internal ratio of processing FPS to graphics FPS in sync when updating FPS + +Misc Improvements +----------------- +- `autochop`: + - only designate the amount of trees required to reach ``max_logs`` + - preferably designate larger trees over smaller ones +- `autonick`: + - now displays help instead of modifying dwarf nicknames when run without parameters. use ``autonick all`` to rename all dwarves. + - added ``--quiet`` and ``--help`` options +- `blueprint`: + - ``track`` phase renamed to ``carve`` + - carved fortifications and (optionally) engravings are now captured in generated blueprints +- `cursecheck`: new option, ``--ids`` prints creature and race IDs of the cursed creature +- `debug`: + - DFHack log messages now have configurable headers (e.g. timestamp, origin plugin name, etc.) via the ``debugfilter`` command of the `debug` plugin + - script execution log messages (e.g. "Loading script: dfhack_extras.init" can now be controlled with the ``debugfilter`` command. To hide the messages, add this line to your ``dfhack.init`` file: ``debugfilter set Warning core script`` +- `dfhack-examples-guide`: + - add mugs to ``basic`` manager orders + - ``onMapLoad_dreamfort.init`` remove "cheaty" commands and new tweaks that are now in the default ``dfhack.init-example`` file +- `dig-now`: handle fortification carving +- `EventManager`: + - add new event type ``JOB_STARTED``, triggered when a job first gains a worker + - add new event type ``UNIT_NEW_ACTIVE``, triggered when a new unit appears on the active list +- `gui/blueprint`: support new `blueprint` options and phases +- `gui/create-item`: Added "(chain)" annotation text for armours with the [CHAIN_METAL_TEXT] flag set +- `manipulator`: tweak colors to make the cursor easier to locate +- `quickfort`: + - support transformations for blueprints that use expansion syntax + - adjust direction affinity when transforming buildings (e.g. bridges that open to the north now open to the south when rotated 180 degrees) + - automatically adjust cursor movements on the map screen in ``#query`` and ``#config`` modes when the blueprint is transformed. e.g. ``{Up}`` will be played back as ``{Right}`` when the blueprint is rotated clockwise and the direction key would move the map cursor + - new blueprint mode: ``#config``; for playing back key sequences that don't involve the map cursor (like configuring hotkeys, changing standing orders, or modifying military uniforms) + - API function ``apply_blueprint`` can now take ``data`` parameters that are simple strings instead of coordinate maps. This allows easier application of blueprints that are just one cell. +- `stocks`: allow search terms to match the full item label, even when the label is truncated for length +- `tweak`: ``stable-cursor`` now keeps the cursor stable even when the viewport moves a small amount +- ``dfhack.init-example``: recently-added tweaks added to example ``dfhack.init`` file + +Documentation +------------- +- add more examples to the plugin example skeleton files so they are more informative for a newbie +- update download link and installation instructions for Visual C++ 2015 build tools on Windows +- update information regarding obtaining a compatible Windows build environment +- `confirm`: correct the command name in the plugin help text +- `cxxrandom`: added usage examples +- `lua-string`: document DFHack string extensions (``startswith()``, ``endswith()``, ``split()``, ``trim()``, ``wrap()``, and ``escape_pattern()``) +- `quickfort-blueprint-guide`: added screenshots to the Dreamfort case study and overall clarified text +- `remote-client-libs`: add new Rust client library +- ``Lua API.rst``: added ``isHidden(unit)``, ``isFortControlled(unit)``, ``getOuterContainerRef(unit)``, ``getOuterContainerRef(item)`` + +API +--- +- add functions reverse-engineered from ambushing unit code: ``Units::isHidden()``, ``Units::isFortControlled()``, ``Units::getOuterContainerRef()``, ``Items::getOuterContainerRef()`` +- ``Job::removeJob()``: use the job cancel vmethod graciously provided by The Toady One in place of a synthetic method derived from reverse engineering + +Lua +--- +- `custom-raw-tokens`: library for accessing tokens added to raws by mods +- ``dfhack.units``: Lua wrappers for functions reverse-engineered from ambushing unit code: ``isHidden(unit)``, ``isFortControlled(unit)``, ``getOuterContainerRef(unit)``, ``getOuterContainerRef(item)`` +- ``dialogs``: ``show*`` functions now return a reference to the created dialog +- ``dwarfmode.enterSidebarMode()``: passing ``df.ui_sidebar_mode.DesignateMine`` now always results in you entering ``DesignateMine`` mode and not ``DesignateChopTrees``, even when you looking at the surface (where the default designation mode is ``DesignateChopTrees``) +- ``dwarfmode.MenuOverlay``: + - if ``sidebar_mode`` attribute is set, automatically manage entering a specific sidebar mode on show and restoring the previous sidebar mode on dismiss + - new class function ``renderMapOverlay`` to assist with painting tiles over the visible map +- ``ensure_key``: new global function for retrieving or dynamically creating Lua table mappings +- ``safe_index``: now properly handles lua sparse tables that are indexed by numbers +- ``string``: new function ``escape_pattern()`` escapes regex special characters within a string +- ``widgets``: + - unset values in ``frame_inset`` table default to ``0`` + - ``FilteredList`` class now allows all punctuation to be typed into the filter and can match search keys that start with punctuation + - minimum height of ``ListBox`` dialog is now calculated correctly when there are no items in the list (e.g. when a filter doesn't match anything) + - if ``autoarrange_subviews`` is set, ``Panel``\s will now automatically lay out widgets vertically according to their current height. This allows you to have widgets dynamically change height or become visible/hidden and you don't have to worry about recalculating frame layouts + - new class ``ResizingPanel`` (subclass of ``Panel``) automatically recalculates its own frame height based on the size, position, and visibility of its subviews + - new class ``HotkeyLabel`` (subclass of ``Label``) that displays and reacts to hotkeys + - new class ``CycleHotkeyLabel`` (subclass of ``Label``) allows users to cycle through a list of options by pressing a hotkey + - new class ``ToggleHotkeyLabel`` (subclass of ``CycleHotkeyLabel``) toggles between ``On`` and ``Off`` states + - new class ``WrappedLabel`` (subclass of ``Label``) provides autowrapping of text + - new class ``TooltipLabel`` (subclass of ``WrappedLabel``) provides tooltip-like behavior + +Structures +---------- +- ``adventure_optionst``: add missing ``getUnitContainer`` vmethod +- ``historical_figure.T_skills``: add ``account_balance`` field +- ``job``: add ``improvement`` field (union with ``hist_figure_id`` and ``race``) +- ``report_init.flags``: rename ``sparring`` flag to ``hostile_combat`` +- ``viewscreen_loadgamest``: add missing ``LoadingImageSets`` and ``LoadingDivinationSets`` enum values to ``cur_step`` field + + +DFHack 0.47.05-r4 +================= + +Fixes +----- +- `blueprint`: + - fixed passing incorrect parameters to `gui/blueprint` when you run ``blueprint gui`` with optional params + - key sequences for constructed walls and down stairs are now correct +- `exportlegends`: fix issue where birth year was outputted as birth seconds +- `quickfort`: + - produce a useful error message instead of a code error when a bad query blueprint key sequence leaves the game in a mode that does not have an active cursor + - restore functionality to the ``--verbose`` commandline flag + - don't designate tiles for digging if they are within the bounds of a planned or constructed building + - allow grates, bars, and hatches to be built on flat floor (like DF itself allows) + - allow tracks to be built on hard, natural rock ramps + - allow dig priority to be properly set for track designations + - fix incorrect directions for tracks that extend south or east from a track segment pair specified with expansion syntax (e.g. T(4x4)) + - fix parsing of multi-part extended zone configs (e.g. when you set custom supply limits for hospital zones AND set custom flags for a pond) + - fix error when attempting to set a custom limit for plaster powder in a hospital zone +- `tailor`: fixed some inconsistencies (and possible crashes) when parsing certain subcommands, e.g. ``tailor help`` +- `tiletypes-here`, `tiletypes-here-point`: fix crash when running from an unsuspended core context + +Misc Improvements +----------------- +- Core: DFHack now prints the name of the init script it is running to the console and stderr +- `automaterial`: ensure construction tiles are laid down in order when using `buildingplan` to plan the constructions +- `blueprint`: + - all blueprint phases are now written to a single file, using `quickfort` multi-blueprint file syntax. to get the old behavior of each phase in its own file, pass the ``--splitby=phase`` parameter to ``blueprint`` + - you can now specify the position where the cursor should be when the blueprint is played back with `quickfort` by passing the ``--playback-start`` parameter + - generated blueprints now have labels so `quickfort` can address them by name + - all building types are now supported + - multi-type stockpiles are now supported + - non-rectangular stockpiles and buildings are now supported + - blueprints are no longer generated for phases that have nothing to do (unless those phases are explicitly enabled on the commandline or gui) + - new "track" phase that discovers and records carved tracks + - new "zone" phase that discovers and records activity zones, including custom configuration for ponds, gathering, and hospitals +- `dig-now`: no longer leaves behind a designated tile when a tile was designated beneath a tile designated for channeling +- `gui/blueprint`: + - support the new ``--splitby`` and ``--format`` options for `blueprint` + - hide help text when the screen is too short to display it +- `orders`: added ``list`` subcommand to show existing exported orders +- `quickfort-library-guide`: added light aquifer tap and pump stack blueprints (with step-by-step usage guides) to the quickfort blueprint library +- `quickfort`: + - Dreamfort blueprint set improvements: added iron and flux stock level indicators on the industry level and a prisoner processing quantum stockpile in the surface barracks. also added help text for how to manage sieges and how to manage prisoners after a siege. + - add ``quickfort.apply_blueprint()`` API function that can be called directly by other scripts + - by default, don't designate tiles for digging that have masterwork engravings on them. quality level to preserve is configurable with the new ``--preserve-engravings`` param + - implement single-tile track aliases so engraved tracks can be specified tile-by-tile just like constructed tracks + - allow blueprints to jump up or down multiple z-levels with a single command (e.g. ``#>5`` goes down 5 levels) + - blueprints can now be repeated up and down a specified number of z-levels via ``repeat`` markers in meta blueprints or the ``--repeat`` commandline option + - blueprints can now be rotated, flipped, and shifted via ``transform`` and ``shift`` markers in meta blueprints or the corresponding commandline options +- `quickfort`, `dfhack-examples-guide`: Dreamfort blueprint set improvements based on playtesting and feedback. includes updated profession definitions. + +Removed +------- +- `digfort`: please use `quickfort` instead +- `fortplan`: please use `quickfort` instead + +API +--- +- ``Buildings::findCivzonesAt()``: lookups now complete in constant time instead of linearly scanning through all civzones in the game + +Lua +--- +- ``argparse.processArgsGetopt()``: you can now have long form parameters that are not an alias for a short form parameter. For example, you can now have a parameter like ``--longparam`` without needing to have an equivalent one-letter ``-l`` param. +- ``dwarfmode.enterSidebarMode()``: ``df.ui_sidebar_mode.DesignateMine`` is now a supported target sidebar mode + +Structures +---------- +- ``historical_figure_info.spheres``: give spheres vector a usable name +- ``unit.enemy``: fix definition of ``enemy_status_slot`` and add ``combat_side_id`` + + +DFHack 0.47.05-r3 +================= + +New Plugins +----------- +- `dig-now`: instantly completes dig designations (including smoothing and carving tracks) + +New Scripts +----------- +- `autonick`: gives dwarves unique nicknames +- `build-now`: instantly completes planned building constructions +- `do-job-now`: makes a job involving current selection high priority +- `prioritize`: automatically boosts the priority of current and/or future jobs of specified types, such as hauling food, tanning hides, or pulling levers +- `reveal-adv-map`: exposes/hides all world map tiles in adventure mode + +Fixes +----- +- Core: ``alt`` keydown state is now cleared when DF loses and regains focus, ensuring the ``alt`` modifier state is not stuck on for systems that don't send standard keyup events in response to ``alt-tab`` window manager events +- Lua: ``memscan.field_offset()``: fixed an issue causing `devel/export-dt-ini` to crash sometimes, especially on Windows +- `autofarm`: autofarm will now count plant growths as well as plants toward its thresholds +- `autogems`: no longer assigns gem cutting jobs to workshops with gem cutting prohibited in the workshop profile +- `devel/export-dt-ini`: fixed incorrect vtable address on Windows +- `quickfort`: + - allow machines (e.g. screw pumps) to be built on ramps just like DF allows + - fix error message when the requested label is not found in the blueprint file + +Misc Improvements +----------------- +- `assign-beliefs`, `assign-facets`: now update needs of units that were changed +- `buildingplan`: now displays which items are attached and which items are still missing for planned buildings +- `devel/query`: + - updated script to v3.2 (i.e. major rewrite for maintainability/readability) + - merged options ``-query`` and ``-querykeys`` into ``-search`` + - merged options ``-depth`` and ``-keydepth`` into ``-maxdepth`` + - replaced option ``-safer`` with ``-excludetypes`` and ``-excludekinds`` + - improved how tile data is dealt with identification, iteration, and searching + - added option ``-findvalue`` + - added option ``-showpaths`` to print full data paths instead of nested fields + - added option ``-nopointers`` to disable printing values with memory addresses + - added option ``-alignto`` to set the value column's alignment + - added options ``-oneline`` and alias ``-1`` to avoid using two lines for fields with metadata + - added support for matching multiple patterns + - added support for selecting the highlighted job, plant, building, and map block data + - added support for selecting a Lua script (e.g. `dorf_tables`) + - added support for selecting a Json file (e.g. dwarf_profiles.json) + - removed options ``-listall``, ``-listfields``, and ``-listkeys`` - these are now simply default behaviour + - ``-table`` now accepts the same abbreviations (global names, ``unit``, ``screen``, etc.) as `lua` and `gui/gm-editor` +- `dorf_tables`: integrated `devel/query` to show the table definitions when requested with ``-list`` +- `geld`: fixed ``-help`` option +- `gui/gm-editor`: made search case-insensitive +- `orders`: + - support importing and exporting reaction-specific item conditions, like "lye-containing" for soap production orders + - new ``sort`` command. sorts orders according to their repeat frequency. this prevents daily orders from blocking other orders for similar items from ever getting completed. +- `quickfort`: + - Dreamfort blueprint set improvements: extensive revision based on playtesting and feedback. includes updated ``onMapLoad_dreamfort.init`` settings file, enhanced automation orders, and premade profession definitions. see full changelog at https://github.com/DFHack/dfhack/pull/1921 and https://github.com/DFHack/dfhack/pull/1925 + - accept multiple commands, list numbers, and/or blueprint labels on a single commandline +- `tailor`: allow user to specify which materials to be used, and in what order +- `tiletypes-here`, `tiletypes-here-point`: add ``--cursor`` and ``--quiet`` options to support non-interactive use cases +- `unretire-anyone`: replaced the 'undead' descriptor with 'reanimated' to make it more mod-friendly +- `warn-starving`: added an option to only check sane dwarves + +Documentation +------------- +- `dfhack-examples-guide`: documentation for all of `dreamfort`'s supporting files (useful for all forts, not just Dreamfort!) +- `quickfort-library-guide`: updated dreamfort documentation and added screenshots + +API +--- +- The ``Items`` module ``moveTo*`` and ``remove`` functions now handle projectiles + +Internals +--------- +- Install tests in the scripts repo into hack/scripts/test/scripts when the CMake variable BUILD_TESTS is defined + +Lua +--- +- new global function: ``safe_pairs(iterable[, iterator_fn])`` will iterate over the ``iterable`` (a table or iterable userdata) with the ``iterator_fn`` (``pairs`` if not otherwise specified) if iteration is possible. If iteration is not possible or would throw an error, for example if ``nil`` is passed as the ``iterable``, the iteration is just silently skipped. + +Structures +---------- +- ``cursed_tomb``: new struct type +- ``job_item``: identified several fields +- ``ocean_wave_maker``: new struct type +- ``worldgen_parms``: moved to new struct type + + +DFHack 0.47.05-r2 +================= + +New Scripts +----------- +- `clear-webs`: removes all webs on the map and/or frees any webbed creatures +- `devel/block-borders`: overlay that displays map block borders +- `devel/luacov`: generate code test coverage reports for script development. Define the ``DFHACK_ENABLE_LUACOV=1`` environment variable to start gathering coverage metrics. +- `fix/drop-webs`: causes floating webs to fall to the ground +- `gui/blueprint`: interactive frontend for the `blueprint` plugin (with mouse support!) +- `gui/mass-remove`: mass removal/suspension tool for buildings and constructions +- `reveal-hidden-sites`: exposes all undiscovered sites +- `set-timeskip-duration`: changes the duration of the "Updating World" process preceding the start of a new game, enabling you to jump in earlier or later than usual + +Fixes +----- +- Fixed an issue preventing some external scripts from creating zones and other abstract buildings (see note about room definitions under "Internals") +- Fixed an issue where scrollable text in Lua-based screens could prevent other widgets from scrolling +- `bodyswap`: + - stopped prior party members from tagging along after bodyswapping and reloading the map + - made companions of bodyswapping targets get added to the adventurer party - they can now be viewed using the in-game party system +- `buildingplan`: + - fixed an issue where planned constructions designated with DF's sizing keys (``umkh``) would sometimes be larger than requested + - fixed an issue preventing other plugins like `automaterial` from planning constructions if the "enable all" buildingplan setting was turned on + - made navigation keys work properly in the materials selection screen when alternate keybindings are used +- `color-schemes`: fixed an error in the ``register`` subcommand when the DF path contains certain punctuation characters +- `command-prompt`: fixed issues where overlays created by running certain commands (e.g. `gui/liquids`, `gui/teleport`) would not update the parent screen correctly +- `dwarfvet`: fixed a crash that could occur with hospitals overlapping with other buildings in certain ways +- `embark-assistant`: fixed faulty early exit in first search attempt when searching for waterfalls +- `gui/advfort`: fixed an issue where starting a workshop job while not standing at the center of the workshop required advancing time manually +- `gui/unit-info-viewer`: fixed size description displaying unrelated values instead of size +- `orders`: fixed crash when importing orders with malformed IDs +- `quickfort`: + - comments in blueprint cells no longer prevent the rest of the row from being read. A cell with a single '#' marker in it, though, will still stop the parser from reading further in the row. + - fixed an off-by-one line number accounting in blueprints with implicit ``#dig`` modelines + - changed to properly detect and report an error on sub-alias params with no values instead of just failing to apply the alias later (if you really want an empty value, use ``{Empty}`` instead) + - improved handling of non-rectangular and non-solid extent-based structures (like fancy-shaped stockpiles and farm plots) + - fixed conversion of numbers to DF keycodes in ``#query`` blueprints + - fixed various errors with cropping across the map edge + - properly reset config to default values in ``quickfort reset`` even if if the ``dfhack-config/quickfort/quickfort.txt`` config file doesn't mention all config vars. Also now works even if the config file doesn't exist. +- `stonesense`: fixed a crash that could occur when ctrl+scrolling or closing the Stonesense window +- ``quickfortress.csv`` blueprint: fixed refuse stockpile config and prevented stockpiles from covering stairways + +Misc Improvements +----------------- +- Added adjectives to item selection dialogs, used in tools like `gui/create-item` - this makes it possible to differentiate between different types of high/low boots, shields, etc. (some of which are procedurally generated) +- `blueprint`: + - made ``depth`` and ``name`` parameters optional. ``depth`` now defaults to ``1`` (current level only) and ``name`` defaults to "blueprint" + - ``depth`` can now be negative, which will result in the blueprints being written from the highest z-level to the lowest. Before, blueprints were always written from the lowest z-level to the highest. + - added the ``--cursor`` option to set the starting coordinate for the generated blueprints. A game cursor is no longer necessary if this option is used. +- `devel/annc-monitor`: added ``report enable|disable`` subcommand to filter combat reports +- `embark-assistant`: slightly improved performance of surveying and improved code a little +- `gui/advfort`: added workshop name to workshop UI +- `quickfort`: + - the Dreamfort blueprint set can now be comfortably built in a 1x1 embark + - added the ``--cursor`` option for running a blueprint at specific coordinates instead of starting at the game cursor position + - added more helpful error messages for invalid modeline markers + - added support for extra space characters in blueprints + - added a warning when an invalid alias is encountered instead of silently ignoring it + - made more quiet when the ``--quiet`` parameter is specified +- `setfps`: improved error handling +- `stonesense`: sped up startup time +- `tweak` hide-priority: changed so that priorities stay hidden (or visible) when exiting and re-entering the designations menu +- `unretire-anyone`: the historical figure selection list now includes the ``SYN_NAME`` (necromancer, vampire, etc) of figures where applicable + +Documentation +------------- +- Added more client library implementations to the `remote interface docs ` + +API +--- +- Added ``dfhack.maps.getPlantAtTile(x, y, z)`` and ``dfhack.maps.getPlantAtTile(pos)``, and updated ``dfhack.gui.getSelectedPlant()`` to use it +- Added ``dfhack.units.teleport(unit, pos)`` + +Internals +--------- +- Room definitions and extents are now created for abstract buildings so callers don't have to initialize the room structure themselves +- The DFHack test harness is now much easier to use for iterative development. Configuration can now be specified on the commandline, there are more test filter options, and the test harness can now easily rerun tests that have been run before. +- The ``test/main`` command to invoke the test harness has been renamed to just ``test`` +- Unit tests can now use ``delay_until(predicate_fn, timeout_frames)`` to delay until a condition is met +- Unit tests must now match any output expected to be printed via ``dfhack.printerr()`` +- Unit tests now support fortress mode (allowing tests that require a fortress map to be loaded) - note that these tests are skipped by continuous integration for now, pending a suitable test fortress + +Lua +--- +- new library: ``argparse`` is a collection of commandline argument processing functions +- new string utility functions: + - ``string:wrap(width)`` wraps a string at space-separated word boundaries + - ``string:trim()`` removes whitespace characters from the beginning and end of the string + - ``string:split(delimiter, plain)`` splits a string with the given delimiter and returns a table of substrings. if ``plain`` is specified and set to ``true``, ``delimiter`` is interpreted as a literal string instead of as a pattern (the default) +- new utility function: ``utils.normalizePath()``: normalizes directory slashes across platforms to ``/`` and coalesces adjacent directory separators +- `reveal`: now exposes ``unhideFlood(pos)`` functionality to Lua +- `xlsxreader`: added Lua class wrappers for the xlsxreader plugin API +- ``argparse.processArgsGetopt()`` (previously ``utils.processArgsGetopt()``): + - now returns negative numbers (e.g. ``-10``) in the list of positional parameters instead of treating it as an option string equivalent to ``-1 -0`` + - now properly handles ``--`` like GNU ``getopt`` as a marker to treat all further parameters as non-options + - now detects when required arguments to long-form options are missing +- ``gui.dwarfmode``: new function: ``enterSidebarMode(sidebar_mode, max_esc)`` which uses keypresses to get into the specified sidebar mode from whatever the current screen is +- ``gui.Painter``: fixed error when calling ``viewport()`` method + +Structures +---------- +- Identified remaining rhythm beat enum values +- ``ui_advmode.interactions``: identified some fields related to party members +- ``ui_advmode_menu``: identified several enum items +- ``ui_advmode``: + - identified several fields + - renamed ``wait`` to ``rest_mode`` and changed to an enum with correct values +- ``viewscreen_legendsst.cur_page``: added missing ``Books`` enum item, which fixes some other values + + +DFHack 0.47.05-r1 +================= + +Fixes +----- +- `confirm`: stopped exposing alternate names when convicting units +- `prospector`: improved pre embark rough estimates, particularly for small clusters + +Misc Improvements +----------------- +- `autohauler`: allowed the ``Alchemist`` labor to be enabled in `manipulator` and other labor screens so it can be used for its intended purpose of flagging that no hauling labors should be assigned to a dwarf. Before, the only way to set the flag was to use an external program like Dwarf Therapist. +- `embark-assistant`: slightly improved performance of surveying +- `gui/no-dfhack-init`: clarified how to dismiss dialog that displays when no ``dfhack.init`` file is found +- `quickfort`: + - Dreamfort blueprint set improvements: `significant `_ refinements across the entire blueprint set. Dreamfort is now much faster, much more efficient, and much easier to use. The `checklist `__ now includes a mini-walkthrough for quick reference. The spreadsheet now also includes `embark profile suggestions `__ + - added aliases for configuring masterwork and artifact core quality for all stockpile categories that have them; made it possible to take from multiple stockpiles in the ``quantumstop`` alias + - an active cursor is no longer required for running #notes blueprints (like the dreamfort walkthrough) + - you can now be in any mode with an active cursor when running ``#query`` blueprints (before you could only be in a few "approved" modes, like look, query, or place) + - refined ``#query`` blueprint sanity checks: cursor should still be on target tile at end of configuration, and it's ok for the screen ID to change if you are destroying (or canceling destruction of) a building + - now reports how many work orders were added when generating manager orders from blueprints in the gui dialog + - added ``--dry-run`` option to process blueprints but not change any game state + - you can now specify the number of desired barrels, bins, and wheelbarrows for individual stockpiles when placing them + - ``quickfort orders`` on a ``#place`` blueprint will now enqueue manager orders for barrels, bins, or wheelbarrows that are explicitly set in the blueprint. + - you can now add alias definitions directly to your blueprint files instead of having to put them in a separate aliases.txt file. makes sharing blueprints with custom alias definitions much easier. + +Documentation +------------- +- `digfort`: added deprecation warnings - digfort has been replaced by `quickfort` +- `fortplan`: added deprecation warnings - fortplan has been replaced by `quickfort` + +Structures +---------- +- Identified scattered enum values (some rhythm beats, a couple of corruption unit thoughts, and a few language name categories) +- ``viewscreen_loadgamest``: renamed ``cur_step`` enumeration to match style of ``viewscreen_adopt_regionst`` and ``viewscreen_savegamest`` +- ``viewscreen_savegamest``: identified ``cur_step`` enumeration + + +DFHack 0.47.05-beta1 +==================== + +Fixes +----- +- `embark-assistant`: fixed bug in soil depth determination for ocean tiles +- `orders`: don't crash when importing orders with malformed JSON +- `quickfort`: raw numeric `quickfort-dig-priorities` (e.g. ``3``, which is a valid shorthand for ``d3``) now works when used in .xlsx blueprints + +Misc Improvements +----------------- +- `quickfort`: new commandline options for setting the initial state of the gui dialog. for example: ``quickfort gui -l dreamfort notes`` will start the dialog filtered for the dreamfort walkthrough blueprints + +Structures +---------- +- Dropped support for 0.47.03-0.47.04 + + +DFHack 0.47.04-r5 +================= + +New Scripts +----------- +- `gui/quickfort`: fast access to the quickfort interactive dialog +- `workorder-recheck`: resets the selected work order to the ``Checking`` state + +Fixes +----- +- `embark-assistant`: + - fixed order of factors when calculating min temperature + - improved performance of surveying +- `quickfort`: + - fixed eventual crashes when creating zones + - fixed library aliases for tallow and iron, copper, and steel weapons + - zones are now created in the active state by default + - solve rare crash when changing UI modes +- `search-plugin`: fixed crash when searching the ``k`` sidebar and navigating to another tile with certain keys, like ``<`` or ``>`` +- `seedwatch`: fixed an issue where the plugin would disable itself on map load +- `stockflow`: fixed ``j`` character being intercepted when naming stockpiles +- `stockpiles`: no longer outputs hotkey help text beneath `stockflow` hotkey help text + +Misc Improvements +----------------- +- Lua label widgets (used in all standard message boxes) are now scrollable with Up/Down/PgUp/PgDn keys +- `autofarm`: now fallows farms if all plants have reached the desired count +- `buildingplan`: + - added ability to set global settings from the console, e.g. ``buildingplan set boulders false`` + - added "enable all" option for buildingplan (so you don't have to enable all building types individually). This setting is not persisted (just like quickfort_mode is not persisted), but it can be set from onMapLoad.init + - modified ``Planning Mode`` status in the UI to show whether the plugin is in quickfort mode, "enable all" mode, or whether just the building type is enabled. +- `quickfort`: + - Dreamfort blueprint set improvements: added a streamlined checklist for all required dreamfort commands and gave names to stockpiles, levers, bridges, and zones + - added aliases for bronze weapons and armor + - added alias for tradeable crafts + - new blueprint mode: ``#ignore``, useful for scratch space or personal notes + - implement ``{Empty}`` keycode for use in quickfort aliases; useful for defining blank-by-default alias values + - more flexible commandline parsing allowing for more natural parameter ordering (e.g. where you used to have to write ``quickfort list dreamfort -l`` you can now write ``quickfort list -l dreamfort``) + - print out blueprint names that a ``#meta`` blueprint is applying so it's easier to understand what meta blueprints are doing + - whitespace is now allowed between a marker name and the opening parenthesis in blueprint modelines. for example, ``#dig start (5; 5)`` is now valid (you used to be required to write ``#dig start(5; 5)``) + +Documentation +------------- +- Added documentation for Lua's ``dfhack.run_command()`` and variants + +Lua +--- +- ``dfhack.run_command()``: changed to interface directly with the console when possible, which allows interactive commands and commands that detect the console encoding to work properly +- ``processArgsGetopt()`` added to utils.lua, providing a callback interface for parameter parsing and getopt-like flexibility for parameter ordering and combination (see docs in ``library/lua/utils.lua`` and ``library/lua/3rdparty/alt_getopt.lua`` for details). + +Structures +---------- +- ``job``: identified ``order_id`` field + + +DFHack 0.47.04-r4 +================= + +New Scripts +----------- +- `fix/corrupt-equipment`: fixes some military equipment-related corruption issues that can cause DF crashes + +Fixes +----- +- Fixed an issue on some Linux systems where DFHack installed through a package manager would attempt to write files to a non-writable folder (notably when running `exportlegends` or `gui/autogems`) +- `adaptation`: fixed handling of units with no cave adaptation suffered yet +- `assign-goals`: fixed error preventing new goals from being created +- `assign-preferences`: fixed handling of preferences for flour +- `buildingplan`: + - fixed an issue preventing artifacts from being matched when the maximum item quality is set to ``artifacts`` + - stopped erroneously matching items to buildings while the game is paused + - fixed a crash when pressing 0 while having a noble room selected +- `deathcause`: fixed an error when inspecting certain corpses +- `dwarfmonitor`: fixed a crash when opening the ``prefs`` screen if units have vague preferences +- `dwarfvet`: fixed a crash that could occur when discharging patients +- `embark-assistant`: + - fixed an issue causing incursion resource matching (e.g. sand/clay) to skip some tiles if those resources were provided only through incursions + - corrected river size determination by performing it at the MLT level rather than the world tile level +- `quickfort`: + - fixed handling of modifier keys (e.g. ``{Ctrl}`` or ``{Alt}``) in query blueprints + - fixed misconfiguration of nest boxes, hives, and slabs that were preventing them from being built from build blueprints + - fixed valid placement detection for floor hatches, floor grates, and floor bars (they were erroneously being rejected from open spaces and staircase tops) + - fixed query blueprint statistics being added to the wrong metric when both a query and a zone blueprint are run by the same meta blueprint + - added missing blueprint labels in gui dialog list + - fixed occupancy settings for extent-based structures so that stockpiles can be placed within other stockpiles (e.g. in a checkerboard or bullseye pattern) +- `search-plugin`: fixed an issue where search options might not display if screens were destroyed and recreated programmatically (e.g. with `quickfort`) +- `unsuspend`: now leaves buildingplan-managed buildings alone and doesn't unsuspend underwater tasks +- `workflow`: fixed an error when creating constraints on "mill plants" jobs and some other plant-related jobs +- `zone`: fixed an issue causing the ``enumnick`` subcommand to run when attempting to run ``assign``, ``unassign``, or ``slaughter`` + +Misc Improvements +----------------- +- `buildingplan`: + - added support for all buildings, furniture, and constructions (except for instruments) + - added support for respecting building job_item filters when matching items, so you can set your own programmatic filters for buildings before submitting them to buildingplan + - changed default filter setting for max quality from ``artifact`` to ``masterwork`` + - changed min quality adjustment hotkeys from 'qw' to 'QW' to avoid conflict with existing hotkeys for setting roller speed - also changed max quality adjustment hotkeys from 'QW' to 'AS' to make room for the min quality hotkey changes + - added a new global settings page accessible via the ``G`` hotkey when on any building build screen; ``Quickfort Mode`` toggle for legacy Python Quickfort has been moved to this page + - added new global settings for whether generic building materials should match blocks, boulders, logs, and/or bars - defaults are everything but bars +- `devel/export-dt-ini`: updated for Dwarf Therapist 41.2.0 +- `embark-assistant`: split the lair types displayed on the local map into mound, burrow, and lair +- `gui/advfort`: added support for linking to hatches and pressure plates with mechanisms +- `modtools/add-syndrome`: added support for specifying syndrome IDs instead of names +- `probe`: added more output for designations and tile occupancy +- `quickfort`: + - The Dreamfort sample blueprints now have complete walkthroughs for each fort level and importable orders that automate basic fort stock management + - added more blueprints to the blueprints library: several bedroom layouts, the Saracen Crypts, and the complete fortress example from Python Quickfort: TheQuickFortress + - query blueprint aliases can now accept parameters for dynamic expansion - see dfhack-config/quickfort/aliases.txt for details + - alias names can now include dashes and underscores (in addition to letters and numbers) + - improved speed of first call to ``quickfort list`` significantly, especially for large blueprint libraries + - added ``query_unsafe`` setting to disable query blueprint error checking - useful for query blueprints that send unusual key sequences + - added support for bookcases, display cases, and offering places (altars) + - added configuration support for zone pit/pond, gather, and hospital sub-menus in zone blueprints + - removed ``buildings_use_blocks`` setting and replaced it with more flexible functionality in `buildingplan` + - added support for creating uninitialized stockpiles with :kbd:`c` + +Documentation +------------- +- `quickfort-alias-guide`: alias syntax and alias standard library documentation for `quickfort` blueprints +- `quickfort-library-guide`: overview of the quickfort blueprint library + +API +--- +- `buildingplan`: added Lua interface API +- ``Buildings::setSize()``: changed to reuse existing extents when possible +- ``dfhack.job.isSuitableMaterial()``: added an item type parameter so the ``non_economic`` flag can be properly handled (it was being matched for all item types instead of just boulders) + +Lua +--- +- ``utils.addressof()``: fixed for raw userdata + +Structures +---------- +- ``building_extents_type``: new enum, used for ``building_extents.extents`` +- ``world_mountain_peak``: new struct (was previously inline) - used in ``world_data.mountain_peaks`` + + +DFHack 0.47.04-r3 +================= + +New Plugins +----------- +- `xlsxreader`: provides an API for Lua scripts to read Excel spreadsheets + +New Scripts +----------- +- `quickfort`: DFHack-native implementation of quickfort with many new features and integrations - see the `quickfort-user-guide` for details +- `timestream`: controls the speed of the calendar and creatures +- `uniform-unstick`: prompts units to reevaluate their uniform, by removing/dropping potentially conflicting worn items + +Fixes +----- +- `ban-cooking`: fixed an error in several subcommands +- `buildingplan`: fixed handling of buildings that require buckets +- `getplants`: fixed a crash that could occur on some maps +- `search-plugin`: fixed an issue causing item counts on the trade screen to display inconsistently when searching +- `stockpiles`: + - fixed a crash when loading food stockpiles + - fixed an error when saving furniture stockpiles + +Misc Improvements +----------------- +- `createitem`: + - added support for plant growths (fruit, berries, leaves, etc.) + - added an ``inspect`` subcommand to print the item and material tokens of existing items, which can be used to create additional matching items +- `embark-assistant`: added support for searching for taller waterfalls (up to 50 z-levels tall) +- `search-plugin`: added support for searching for names containing non-ASCII characters using their ASCII equivalents +- `stocks`: added support for searching for items containing non-ASCII characters using their ASCII equivalents +- `unretire-anyone`: made undead creature names appear in the historical figure list +- `zone`: + - added an ``enumnick`` subcommand to assign enumerated nicknames (e.g "Hen 1", "Hen 2"...) + - added slaughter indication to ``uinfo`` output + +Documentation +------------- +- Fixed syntax highlighting of most code blocks to use the appropriate language (or no language) instead of Python + +API +--- +- Added ``DFHack::to_search_normalized()`` (Lua: ``dfhack.toSearchNormalized()``) to convert non-ASCII alphabetic characters to their ASCII equivalents + +Structures +---------- +- ``history_event_masterpiece_createdst``: fixed alignment, including subclasses, and identified ``skill_at_time`` +- ``item_body_component``: fixed some alignment issues and identified some fields (also applies to subclasses like ``item_corpsest``) +- ``stockpile_settings``: removed ``furniture.sand_bags`` (no longer present) + + +DFHack 0.47.04-r2 +================= + +New Scripts +----------- +- `animal-control`: helps manage the butchery and gelding of animals +- `devel/kill-hf`: kills a historical figure +- `geld`: gelds or ungelds animals +- `list-agreements`: lists all guildhall and temple agreements +- `list-waves`: displays migration wave information for citizens/units +- `ungeld`: ungelds animals (wrapper around `geld`) + +New Tweaks +---------- +- `tweak` do-job-now: adds a job priority toggle to the jobs list +- `tweak` reaction-gloves: adds an option to make reactions produce gloves in sets with correct handedness + +Fixes +----- +- Fixed a segfault when attempting to start a headless session with a graphical PRINT_MODE setting +- Fixed an issue with the macOS launcher failing to un-quarantine some files +- Fixed ``Units::isEggLayer``, ``Units::isGrazer``, ``Units::isMilkable``, ``Units::isTrainableHunting``, ``Units::isTrainableWar``, and ``Units::isTamable`` ignoring the unit's caste +- Linux: fixed ``dfhack.getDFPath()`` (Lua) and ``Process::getPath()`` (C++) to always return the DF root path, even if the working directory has changed +- `digfort`: + - fixed y-line tracking when .csv files contain lines with only commas + - fixed an issue causing blueprints touching the southern or eastern edges of the map to be rejected (northern and western edges were already allowed). This allows blueprints that span the entire embark area. +- `embark-assistant`: fixed a couple of incursion handling bugs. +- `embark-skills`: fixed an issue with structures causing the ``points`` option to do nothing +- `exportlegends`: + - fixed an issue where two different ```` tags could be included in a ```` + - stopped including some tags with ``-1`` values which don't provide useful information +- `getplants`: fixed issues causing plants to be collected even if they have no growths (or unripe growths) +- `gui/advfort`: fixed "operate pump" job +- `gui/load-screen`: fixed an issue causing longer timezones to be cut off +- `labormanager`: + - fixed handling of new jobs in 0.47 + - fixed an issue preventing custom furnaces from being built +- `modtools/moddable-gods`: + - fixed an error when creating the historical figure + - removed unused ``-domain`` and ``-description`` arguments + - made ``-depictedAs`` argument work +- `names`: + - fixed an error preventing the script from working + - fixed an issue causing renamed units to display their old name in legends mode and some other places +- `pref-adjust`: fixed some compatibility issues and a potential crash +- `RemoteFortressReader`: + - fixed a couple crashes that could result from decoding invalid enum items (``site_realization_building_type`` and ``improvement_type``) + - fixed an issue that could cause block coordinates to be incorrect +- `rendermax`: fixed a hang that could occur when enabling some renderers, notably on Linux +- `stonesense`: + - fixed a crash when launching Stonesense + - fixed some issues that could cause the splash screen to hang + +Misc Improvements +----------------- +- Linux/macOS: Added console keybindings for deleting words (Alt+Backspace and Alt+d in most terminals) +- `add-recipe`: + - added tool recipes (minecarts, wheelbarrows, stepladders, etc.) + - added a command explanation or error message when entering an invalid command +- `armoks-blessing`: added adjustments to values and needs +- `blueprint`: + - now writes blueprints to the ``blueprints/`` subfolder instead of the df root folder + - now automatically creates folder trees when organizing blueprints into subfolders (e.g. ``blueprint 30 30 1 rooms/dining dig`` will create the file ``blueprints/rooms/dining-dig.csv``); previously it would fail if the ``blueprints/rooms/`` directory didn't already exist +- `confirm`: added a confirmation dialog for convicting dwarves of crimes +- `devel/query`: added many new query options +- `digfort`: + - handled double quotes (") at the start of a string, allowing .csv files exported from spreadsheets to work without manual modification + - documented that removing ramps, cutting trees, and gathering plants are indeed supported + - added a ``force`` option to truncate blueprints if the full blueprint would extend off the edge of the map +- `dwarf-op`: + - added ability to select dwarves based on migration wave + - added ability to protect dwarves based on symbols in their custom professions +- `exportlegends`: + - changed some flags to be represented by self-closing tags instead of true/false strings (e.g. ````) - note that this may require changes to other XML-parsing utilities + - changed some enum values from numbers to their string representations + - added ability to save all files to a subfolder, named after the region folder and date by default +- `gui/advfort`: added support for specifying the entity used to determine available resources +- `gui/gm-editor`: added support for automatically following ref-targets when pressing the ``i`` key +- `manipulator`: added a new column option to display units' goals +- `modtools/moddable-gods`: added support for ``neuter`` gender +- `pref-adjust`: + - added support for adjusting just the selected dwarf + - added a new ``goth`` profile +- `remove-stress`: added a ``-value`` argument to enable setting stress level directly +- `workorder`: changed default frequency from "Daily" to "OneTime" + +Documentation +------------- +- Added some new dev-facing pages, including dedicated pages about the remote API, memory research, and documentation +- Expanded the installation guide +- Made a couple theme adjustments + +API +--- +- Added ``Filesystem::mkdir_recursive`` +- Extended ``Filesystem::listdir_recursive`` to optionally make returned filenames relative to the start directory +- ``Units``: added goal-related functions: ``getGoalType()``, ``getGoalName()``, ``isGoalAchieved()`` + +Internals +--------- +- Added support for splitting scripts into multiple files in the ``scripts/internal`` folder without polluting the output of `ls` + +Lua +--- +- Added a ``ref_target`` field to primitive field references, corresponding to the ``ref-target`` XML attribute +- Made ``dfhack.units.getRaceNameById()``, ``dfhack.units.getRaceBabyNameById()``, and ``dfhack.units.getRaceChildNameById()`` available to Lua + +Ruby +---- +- Updated ``item_find`` and ``building_find`` to use centralized logic that works on more screens + +Structures +---------- +- Added a new ````, which allows ``world.*.other`` collections of vectors to use the correct subtypes for items +- ``creature_raw``: renamed ``gender`` to ``sex`` to match the field in ``unit``, which is more frequently used +- ``crime``: identified ``witnesses``, which contains the data held by the old field named ``reports`` +- ``intrigue``: new type (split out from ``historical_figure_relationships``) +- ``items_other_id``: removed ``BAD``, and by extension, ``world.items.other.BAD``, which was overlapping with ``world.items.bad`` +- ``job_type``: added job types new to 0.47 +- ``plant_raw``: material_defs now contains arrays rather than loose fields +- ``pronoun_type``: new enum (previously documented in field comments) +- ``setup_character_info``: fixed a couple alignment issues (needed by `embark-skills`) +- ``ui_advmode_menu``: identified some new enum items + + +DFHack 0.47.04-r1 +================= + +Fixes +----- +- Fixed a crash in ``find()`` for some types when no world is loaded +- Fixed translation of certain types of in-game names +- `autogems`: fixed an issue with binned gems being ignored in linked stockpiles +- `catsplosion`: fixed error when handling races with only one caste (e.g. harpies) +- `exportlegends`: fixed error when exporting maps +- `spawnunit`: fixed an error when forwarding some arguments but not a location to `modtools/create-unit` +- `stocks`: fixed display of book titles +- `tweak` embark-profile-name: fixed handling of the native shift+space key + +Misc Improvements +----------------- +- `exportlegends`: + - made interaction export more robust and human-readable + - removed empty ```` and ```` tags +- `getplants`: added switches for designations for farming seeds and for max number designated per plant +- `manipulator`: added intrigue to displayed skills +- `modtools/create-unit`: + - added ``-equip`` option to equip created units + - added ``-skills`` option to give skills to units + - added ``-profession`` and ``-customProfession`` options to adjust unit professions +- `search-plugin`: added support for the fortress mode justice screen +- ``dfhack.init-example``: enabled `autodump` + +API +--- +- Added ``Items::getBookTitle`` to get titles of books. Catches titles buried in improvements, unlike getDescription. + +Lua +--- +- ``pairs()`` now returns available class methods for DF types + +Structures +---------- +- Added globals: ``cur_rain``, ``cur_rain_counter``, ``cur_snow``, ``cur_snow_counter``, ``weathertimer``, ``jobvalue``, ``jobvalue_setter``, ``interactitem``, ``interactinvslot``, ``handleannounce``, ``preserveannounce``, ``updatelightstate`` +- ``agreement_details_data_plot_sabotage``: new struct type, along with related ``agreement_details_type.PlotSabotage`` +- ``architectural_element``: new enum +- ``battlefield``: new struct type +- ``breed``: new struct type +- ``creature_handler``: identified vmethods +- ``crime``: removed fields of ``reports`` that are no longer present +- ``dance_form``: identified most fields +- ``history_event_context``: identified fields +- ``identity_type``: new enum +- ``identity``: renamed ``civ`` to ``entity_id``, identified ``type`` +- ``image_set``: new struct type +- ``interrogation_report``: new struct type +- ``itemdef_flags``: new enum, with ``GENERATED`` flag +- ``justification``: new enum +- ``lever_target_type``: identified ``LeverMechanism`` and ``TargetMechanism`` values +- ``musical_form``: identified fields, including some renames. Also identified fields in ``scale`` and ``rhythm`` +- ``region_weather``: new struct type +- ``squad_order_cause_trouble_for_entityst``: identified fields +- ``unit_thought_type``: added several new thought types +- ``viewscreen_workquota_detailsst``: identified fields + + +DFHack 0.47.04-beta1 +==================== + +New Scripts +----------- +- `color-schemes`: manages color schemes +- `devel/print-event`: prints the description of an event by ID or index +- `gui/color-schemes`: an in-game interface for `color-schemes` +- `light-aquifers-only`: changes heavy aquifers to light aquifers +- `on-new-fortress`: runs DFHack commands only in a new fortress +- `once-per-save`: runs DFHack commands unless already run in the current save +- `resurrect-adv`: brings your adventurer back to life +- `reveal-hidden-units`: exposes all sneaking units +- `workorder`: allows queuing manager jobs; smart about shear and milk creature jobs + +Fixes +----- +- Fixed a crash when starting DFHack in headless mode with no terminal +- `devel/visualize-structure`: fixed padding detection for globals +- `exportlegends`: + - added UTF-8 encoding and XML escaping for more fields + - added checking for unhandled structures to avoid generating invalid XML + - fixed missing fields in ``history_event_assume_identityst`` export +- `full-heal`: + - when resurrected by specifying a corpse, units now appear at the location of the corpse rather than their location of death + - resurrected units now have their tile occupancy set (and are placed in the prone position to facilitate this) + +Misc Improvements +----------------- +- Added "bit" suffix to downloads (e.g. 64-bit) +- Tests: + - moved from DF folder to hack/scripts folder, and disabled installation by default + - made test runner script more flexible +- `devel/export-dt-ini`: updated some field names for DT for 0.47 +- `devel/visualize-structure`: added human-readable lengths to containers +- `dfhack-run`: added color output support +- `embark-assistant`: + - updated embark aquifer info to show all aquifer kinds present + - added neighbor display, including kobolds (SKULKING) and necro tower count + - updated aquifer search criteria to handle the new variation + - added search criteria for embark initial tree cover + - added search criteria for necro tower count, neighbor civ count, and specific neighbors. Should handle additional entities, but not tested +- `exportlegends`: + - added evilness and force IDs to regions + - added profession and weapon info to relevant entities + - added support for many new history events in 0.47 + - added historical event relationships and supplementary data +- `full-heal`: + - made resurrection produce a historical event viewable in Legends mode + - made error messages more explanatory +- `install-info`: added DFHack build ID to report +- `modtools/create-item`: added ``-matchingGloves`` and ``-matchingShoes`` arguments +- `modtools/create-unit`: + - added ``-duration`` argument to make the unit vanish after some time + - added ``-locationRange`` argument to allow spawning in a random position within a defined area + - added ``-locationType`` argument to specify the type of location to spawn in +- `unretire-anyone`: added ``-dead`` argument to revive and enable selection of a dead historical figure to use as an adventurer in adv mode + +Internals +--------- +- Added separate changelogs in the scripts and df-structures repos +- Improved support for tagged unions, allowing tools to access union fields more safely +- Moved ``reversing`` scripts to df_misc repo + +Structures +---------- +- Added an XML schema for validating df-structures syntax +- Added ``divination_set_next_id`` and ``image_set_next_id`` globals +- ``activity_entry_type``: new enum type +- ``adventure_optionst``: identified many vmethods +- ``agreement_details``: identified most fields of most sub-structs +- ``artifact_claim``: identified several fields +- ``artifact_record``: identified several fields +- ``caste_raw_flags``: renamed and identified many flags to match information from Toady +- ``creature_raw_flags``: renamed and identified many flags to match information from Toady +- ``crime_type``: new enum type +- ``dfhack_room_quality_level``: added enum attributes for names of rooms of each quality +- ``entity_site_link_type``: new enum type +- ``export_map_type``: new enum type +- ``historical_entity.flags``: identified several flags +- ``historical_entity.relations``: renamed from ``unknown1b`` and identified several fields +- ``historical_figure.vague_relationships``: identified +- ``historical_figure_info.known_info``: renamed from ``secret``, identified some fields +- ``historical_figure``: renamed ``unit_id2`` to ``nemesis_id`` +- ``history_event_circumstance_info``: new struct type (and changed several ``history_event`` subclasses to use this) +- ``history_event_reason_info``: new struct type (and changed several ``history_event`` subclasses to use this) +- ``honors_type``: identified several fields +- ``interaction_effect_create_itemst``: new struct type +- ``interaction_effect_summon_unitst``: new struct type +- ``item``: identified several vmethods +- ``layer_type``: new enum type +- ``plant.damage_flags``: added ``is_dead`` +- ``plot_role_type``: new enum type +- ``plot_strategy_type``: new enum type +- ``relationship_event_supplement``: new struct type +- ``relationship_event``: new struct type +- ``specific_ref``: moved union data to ``data`` field +- ``ui_look_list``: moved union fields to ``data`` and renamed to match ``type`` enum +- ``ui_sidebar_menus.location``: added new profession-related fields, renamed and fixed types of deity-related fields +- ``ui_sidebar_mode``: added ``ZonesLocationInfo`` +- ``unit_action``: rearranged as tagged union with new sub-types; existing code should be compatible +- ``vague_relationship_type``: new enum type +- ``vermin_flags``: identified ``is_roaming_colony`` +- ``viewscreen_justicest``: identified interrogation-related fields +- ``world_data.field_battles``: identified and named several fields + + +DFHack 0.47.03-beta1 +==================== + +New Scripts +----------- +- `devel/sc`: checks size of structures +- `devel/visualize-structure`: displays the raw memory of a structure + +Fixes +----- +- `adv-max-skills`: fixed for 0.47 +- `deep-embark`: + - prevented running in non-fortress modes + - ensured that only the newest wagon is deconstructed +- `full-heal`: + - fixed issues with removing corpses + - fixed resurrection for non-historical figures +- `modtools/create-unit`: added handling for arena tame setting +- `teleport`: fixed setting new tile occupancy + +Misc Improvements +----------------- +- `deep-embark`: + - improved support for using directly from the DFHack console + - added a ``-clear`` option to cancel +- `exportlegends`: + - added identity information + - added creature raw names and flags +- `gui/prerelease-warning`: updated links and information about nightly builds +- `modtools/syndrome-trigger`: enabled simultaneous use of ``-synclass`` and ``-syndrome`` +- `repeat`: added ``-list`` option + +Structures +---------- +- Dropped support for 0.44.12-0.47.02 +- ``abstract_building_type``: added types (and subclasses) new to 0.47 +- ``agreement_details_type``: added enum +- ``agreement_details``: added struct type (and many associated data types) +- ``agreement_party``: added struct type +- ``announcement_type``: added types new to 0.47 +- ``artifact_claim_type``: added enum +- ``artifact_claim``: added struct type +- ``breath_attack_type``: added ``SHARP_ROCK`` +- ``building_offering_placest``: new class +- ``building_type``: added ``OfferingPlace`` +- ``caste_raw_flags``: renamed many items to match DF names +- ``creature_interaction_effect``: added subclasses new to 0.47 +- ``creature_raw_flags``: + - identified several more items + - renamed many items to match DF names +- ``d_init``: added settings new to 0.47 +- ``entity_name_type``: added ``MERCHANT_COMPANY``, ``CRAFT_GUILD`` +- ``entity_position_responsibility``: added values new to 0.47 +- ``fortress_type``: added enum +- ``general_ref_type``: added ``UNIT_INTERROGATEE`` +- ``ghost_type``: added ``None`` value +- ``goal_type``: added goals types new to 0.47 +- ``histfig_site_link``: added subclasses new to 0.47 +- ``history_event_collection``: added subtypes new to 0.47 +- ``history_event_context``: added lots of new fields +- ``history_event_reason``: + - added captions for all items + - added items new to 0.47 +- ``history_event_type``: added types for events new to 0.47, as well as corresponding ``history_event`` subclasses (too many to list here) +- ``honors_type``: added struct type +- ``interaction_effect``: added subtypes new to 0.47 +- ``interaction_source_experimentst``: added class type +- ``interaction_source_usage_hint``: added values new to 0.47 +- ``interface_key``: added items for keys new to 0.47 +- ``job_skill``: added ``INTRIGUE``, ``RIDING`` +- ``lair_type``: added enum +- ``monument_type``: added enum +- ``next_global_id``: added enum +- ``poetic_form_action``: added ``Beseech`` +- ``setup_character_info``: expanded significantly in 0.47 +- ``text_system``: added layout for struct +- ``tile_occupancy``: added ``varied_heavy_aquifer`` +- ``tool_uses``: added items: ``PLACE_OFFERING``, ``DIVINATION``, ``GAMES_OF_CHANCE`` +- ``viewscreen_counterintelligencest``: new class (only layout identified so far) + + +DFHack 0.44.12-r3 +================= + +New Plugins +----------- +- `autoclothing`: automatically manage clothing work orders +- `autofarm`: replaces the previous Ruby script of the same name, with some fixes +- `map-render`: allows programmatically rendering sections of the map that are off-screen +- `tailor`: automatically manages keeping your dorfs clothed + +New Scripts +----------- +- `assign-attributes`: changes the attributes of a unit +- `assign-beliefs`: changes the beliefs of a unit +- `assign-facets`: changes the facets (traits) of a unit +- `assign-goals`: changes the goals of a unit +- `assign-preferences`: changes the preferences of a unit +- `assign-profile`: sets a dwarf's characteristics according to a predefined profile +- `assign-skills`: changes the skills of a unit +- `combat-harden`: sets a unit's combat-hardened value to a given percent +- `deep-embark`: allows embarking underground +- `devel/find-twbt`: finds a TWBT-related offset needed by the new `map-render` plugin +- `dwarf-op`: optimizes dwarves for fort-mode work; makes managing labors easier +- `forget-dead-body`: removes emotions associated with seeing a dead body +- `gui/create-tree`: creates a tree at the selected tile +- `linger`: takes over your killer in adventure mode +- `modtools/create-tree`: creates a tree +- `modtools/pref-edit`: add, remove, or edit the preferences of a unit +- `modtools/set-belief`: changes the beliefs (values) of units +- `modtools/set-need`: sets and edits unit needs +- `modtools/set-personality`: changes the personality of units +- `modtools/spawn-liquid`: spawns water or lava at the specified coordinates +- `set-orientation`: edits a unit's orientation +- `unretire-anyone`: turns any historical figure into a playable adventurer + +Fixes +----- +- Fixed a crash in the macOS/Linux console when the prompt was wider than the screen width +- Fixed inconsistent results from ``Units::isGay`` for asexual units +- Fixed some cases where Lua filtered lists would not properly intercept keys, potentially triggering other actions on the same screen +- `autofarm`: + - fixed biome detection to properly determine crop assignments on surface farms + - reimplemented as a C++ plugin to make proper biome detection possible +- `bodyswap`: fixed companion list not being updated often enough +- `cxxrandom`: removed some extraneous debug information +- `digfort`: now accounts for z-level changes when calculating maximum y dimension +- `embark-assistant`: + - fixed bug causing crash on worlds without generated metals (as well as pruning vectors as originally intended). + - fixed bug causing mineral matching to fail to cut off at the magma sea, reporting presence of things that aren't (like DF does currently). + - fixed bug causing half of the river tiles not to be recognized. + - added logic to detect some river tiles DF doesn't generate data for (but are definitely present). +- `eventful`: fixed invalid building ID in some building events +- `exportlegends`: now escapes special characters in names properly +- `getplants`: fixed designation of plants out of season (note that picked plants are still designated incorrectly) +- `gui/autogems`: fixed error when no world is loaded +- `gui/companion-order`: + - fixed error when resetting group leaders + - ``leave`` now properly removes companion links +- `gui/create-item`: fixed module support - can now be used from other scripts +- `gui/stamper`: + - stopped "invert" from resetting the designation type + - switched to using DF's designation keybindings instead of custom bindings + - fixed some typos and text overlapping +- `modtools/create-unit`: + - fixed an error associating historical entities with units + - stopped recalculating health to avoid newly-created citizens triggering a "recover wounded" job + - fixed units created in arena mode having blank names + - fixed units created in arena mode having the wrong race and/or interaction effects applied after creating units manually in-game + - stopped units from spawning with extra items or skills previously selected in the arena + - stopped setting some unneeded flags that could result in glowing creature tiles + - set units created in adventure mode to have no family, instead of being related to the first creature in the world +- `modtools/reaction-product-trigger`: + - fixed an error dealing with reactions in adventure mode + - blocked ``\\BUILDING_ID`` for adventure mode reactions + - fixed ``-clear`` to work without passing other unneeded arguments +- `modtools/reaction-trigger`: + - fixed a bug when determining whether a command was run + - fixed handling of ``-resetPolicy`` +- `mousequery`: fixed calculation of map dimensions, which was sometimes preventing scrolling the map with the mouse when TWBT was enabled +- `RemoteFortressReader`: fixed a crash when a unit's path has a length of 0 +- `stonesense`: fixed crash due to wagons and other soul-less creatures +- `tame`: now sets the civ ID of tamed animals (fixes compatibility with `autobutcher`) +- `title-folder`: silenced error when ``PRINT_MODE`` is set to ``TEXT`` + +Misc Improvements +----------------- +- Added a note to `dfhack-run` when called with no arguments (which is usually unintentional) +- On macOS, the launcher now attempts to un-quarantine the rest of DFHack +- `bodyswap`: added arena mode support +- `combine-drinks`: added more default output, similar to `combine-plants` +- `createitem`: added a list of valid castes to the "invalid caste" error message, for convenience +- `devel/export-dt-ini`: added more size information needed by newer Dwarf Therapist versions +- `dwarfmonitor`: enabled widgets to access other scripts and plugins by switching to the core Lua context +- `embark-assistant`: + - added an in-game option to activate on the embark screen + - changed waterfall detection to look for level drop rather than just presence + - changed matching to take incursions, i.e. parts of other biomes, into consideration when evaluating tiles. This allows for e.g. finding multiple biomes on single tile embarks. + - changed overlay display to show when incursion surveying is incomplete + - changed overlay display to show evil weather + - added optional parameter "fileresult" for crude external harness automated match support + - improved focus movement logic to go to only required world tiles, increasing speed of subsequent searches considerably +- `exportlegends`: added rivers to custom XML export +- `exterminate`: added support for a special ``enemy`` caste +- `gui/gm-unit`: + - added support for editing: + - added attribute editor + - added orientation editor + - added editor for bodies and body parts + - added color editor + - added belief editor + - added personality editor +- `modtools/create-item`: documented already-existing ``-quality`` option +- `modtools/create-unit`: + - added the ability to specify ``\\LOCAL`` for the fort group entity + - now enables the default labours for adult units with CAN_LEARN. + - now sets historical figure orientation. + - improved speed of creating multiple units at once + - made the script usable as a module (from other scripts) +- `modtools/reaction-trigger`: + - added ``-ignoreWorker``: ignores the worker when selecting the targets + - changed the default behavior to skip inactive/dead units; added ``-dontSkipInactive`` to include creatures that are inactive + - added ``-range``: controls how far eligible targets can be from the workshop + - syndromes now are applied before commands are run, not after + - if both a command and a syndrome are given, the command only runs if the syndrome could be applied +- `mousequery`: made it more clear when features are enabled +- `RemoteFortressReader`: + - added a basic framework for controlling and reading the menus in DF (currently only supports the building menu) + - added support for reading item raws + - added a check for whether or not the game is currently saving or loading, for utilities to check if it's safe to read from DF + - added unit facing direction estimate and position within tiles + - added unit age + - added unit wounds + - added tree information + - added check for units' current jobs when calculating the direction they are facing + +API +--- +- Added new ``plugin_load_data`` and ``plugin_save_data`` events for plugins to load/save persistent data +- Added ``Maps::GetBiomeType`` and ``Maps::GetBiomeTypeByRef`` to infer biome types properly +- Added ``Units::getPhysicalDescription`` (note that this depends on the ``unit_get_physical_description`` offset, which is not yet available for all DF builds) + +Internals +--------- +- Added new Persistence module +- Cut down on internal DFHack dependencies to improve build times +- Improved concurrency in event and server handlers +- Persistent data is now stored in JSON files instead of historical figures - existing data will be migrated when saving +- `stonesense`: fixed some OpenGL build issues on Linux + +Lua +--- +- Exposed ``gui.dwarfmode.get_movement_delta`` and ``gui.dwarfmode.get_hotkey_target`` +- ``dfhack.run_command`` now returns the command's return code + +Ruby +---- +- Made ``unit_ishostile`` consistently return a boolean + +Structures +---------- +- Added ``unit_get_physical_description`` function offset on some platforms +- Added/identified types: + - ``assume_identity_mode`` + - ``musical_form_purpose`` + - ``musical_form_style`` + - ``musical_form_pitch_style`` + - ``musical_form_feature`` + - ``musical_form_vocals`` + - ``musical_form_melodies`` + - ``musical_form_interval`` + - ``unit_emotion_memory`` +- ``need_type``: fixed ``PrayOrMeditate`` typo +- ``personality_facet_type``, ``value_type``: added ``NONE`` values +- ``twbt_render_map``: added for 64-bit 0.44.12 (for `map-render`) + + +DFHack 0.44.12-r2 +================= + +New Plugins +----------- +- `debug`: manages runtime debug print category filtering +- `nestboxes`: automatically scan for and forbid fertile eggs incubating in a nestbox + +New Scripts +----------- +- `devel/query`: searches for field names in DF objects +- `extinguish`: puts out fires +- `tame`: sets tamed/trained status of animals + +Fixes +----- +- `building-hacks`: fixed error when dealing with custom animation tables +- `devel/test-perlin`: fixed Lua error (``math.pow()``) +- `embark-assistant`: fixed crash when entering finder with a 16x16 embark selected, and added 16 to dimension choices +- `embark-skills`: fixed missing ``skill_points_remaining`` field +- `full-heal`: + - stopped wagon resurrection + - fixed a minor issue with post-resurrection hostility +- `gui/companion-order`: + - fixed issues with printing coordinates + - fixed issues with move command + - fixed cheat commands (and removed "Power up", which was broken) +- `gui/gm-editor`: fixed reinterpret cast (``r``) +- `gui/pathable`: fixed error when sidebar is hidden with ``Tab`` +- `labormanager`: + - stopped assigning labors to ineligible dwarves, pets, etc. + - stopped assigning invalid labors + - added support for crafting jobs that use pearl + - fixed issues causing cleaning jobs to not be assigned + - added support for disabling management of specific labors +- `prospector`: (also affected `embark-tools`) - fixed a crash when prospecting an unusable site (ocean, mountains, etc.) with a large default embark size in d_init.txt (e.g. 16x16) +- `siege-engine`: fixed a few Lua errors (``math.pow()``, ``unit.relationship_ids``) +- `tweak`: fixed ``hotkey-clear`` + +Misc Improvements +----------------- +- `armoks-blessing`: improved documentation to list all available arguments +- `devel/export-dt-ini`: + - added viewscreen offsets for DT 40.1.2 + - added item base flags offset + - added needs offsets +- `embark-assistant`: + - added match indicator display on the right ("World") map + - changed 'c'ancel to abort find if it's under way and clear results if not, allowing use of partial surveys. + - added Coal as a search criterion, as well as a coal indication as current embark selection info. +- `full-heal`: + - added ``-all``, ``-all_civ`` and ``-all_citizens`` arguments + - added module support + - now removes historical figure death dates and ghost data +- `growcrops`: added ``all`` argument to grow all crops +- `gui/load-screen`: improved documentation +- `labormanager`: now takes nature value into account when assigning jobs +- `open-legends`: added warning about risk of save corruption and improved related documentation +- `points`: added support when in ``viewscreen_setupdwarfgamest`` and improved error messages +- `siren`: removed break handling (relevant ``misc_trait_type`` was no longer used - see "Structures" section) + +API +--- +- New debug features related to `debug` plugin: + - Classes (C++ only): ``Signal``, ``DebugCategory``, ``DebugManager`` + - Macros: ``TRACE``, ``DEBUG``, ``INFO``, ``WARN``, ``ERR``, ``DBG_DECLARE``, ``DBG_EXTERN`` + +Internals +--------- +- Added a usable unit test framework for basic tests, and a few basic tests +- Added ``CMakeSettings.json`` with intellisense support +- Changed ``plugins/CMakeLists.custom.txt`` to be ignored by git and created (if needed) at build time instead +- Core: various thread safety and memory management improvements +- Fixed CMake build dependencies for generated header files +- Fixed custom ``CMAKE_CXX_FLAGS`` not being passed to plugins +- Linux/macOS: changed recommended build backend from Make to Ninja (Make builds will be significantly slower now) + +Lua +--- +- ``utils``: new ``OrderedTable`` class + +Structures +---------- +- Win32: added missing vtables for ``viewscreen_storesst`` and ``squad_order_rescue_hfst`` +- ``activity_event_performancest``: renamed poem as written_content_id +- ``body_part_status``: identified ``gelded`` +- ``dance_form``: named musical_form_id and musical_written_content_id +- ``incident_sub6_performance.participants``: named performance_event and role_index +- ``incident_sub6_performance``: + - made performance_event an enum + - named poetic_form_id, musical_form_id, and dance_form_id +- ``misc_trait_type``: removed ``LikesOutdoors``, ``Hardened``, ``TimeSinceBreak``, ``OnBreak`` (all unused by DF) +- ``musical_form_instruments``: named minimum_required and maximum_permitted +- ``musical_form``: named voices field +- ``plant_tree_info``: identified ``extent_east``, etc. +- ``plant_tree_tile``: gave connection bits more meaningful names (e.g. ``connection_east`` instead of ``thick_branches_1``) +- ``poetic_form``: identified many fields and related enum/bitfield types +- ``setup_character_info``: identified ``skill_points_remaining`` (for `embark-skills`) +- ``ui.main``: identified ``fortress_site`` +- ``ui.squads``: identified ``kill_rect_targets_scroll`` +- ``ui``: fixed alignment of ``main`` and ``squads`` (fixes `tweak` hotkey-clear and DF-AI) +- ``unit_action.attack``: + - identified ``attack_skill`` + - added ``lightly_tap`` and ``spar_report`` flags +- ``unit_flags3``: identified ``marked_for_gelding`` +- ``unit_personality``: identified ``stress_drain``, ``stress_boost``, ``likes_outdoors``, ``combat_hardened`` +- ``unit_storage_status``: newly identified type, stores noble holdings information (used in ``viewscreen_layer_noblelistst``) +- ``unit_thought_type``: added new expulsion thoughts from 0.44.12 +- ``viewscreen_layer_arena_creaturest``: identified item- and name-related fields +- ``viewscreen_layer_militaryst``: identified ``equip.assigned.assigned_items`` +- ``viewscreen_layer_noblelistst``: identified ``storage_status`` (see ``unit_storage_status`` type) +- ``viewscreen_new_regionst``: + - identified ``rejection_msg``, ``raw_folder``, ``load_world_params`` + - changed many ``int8_t`` fields to ``bool`` +- ``viewscreen_setupadventurest``: identified some nemesis and personality fields, and ``page.ChooseHistfig`` +- ``world_data``: added ``mountain_peak_flags`` type, including ``is_volcano`` +- ``world_history``: identified names and/or types of some fields +- ``world_site``: identified names and/or types of some fields +- ``written_content``: named poetic_form + + +DFHack 0.44.12-r1 +================= + +Fixes +----- +- Console: fixed crash when entering long commands on Linux/macOS +- Fixed special characters in `command-prompt` and other non-console in-game outputs on Linux/macOS (in tools using ``df2console``) +- Removed jsoncpp's ``include`` and ``lib`` folders from DFHack builds/packages +- `die`: fixed Windows crash in exit handling +- `dwarfmonitor`, `manipulator`: fixed stress cutoffs +- `modtools/force`: fixed a bug where the help text would always be displayed and nothing useful would happen +- `ruby`: fixed calling conventions for vmethods that return strings (currently ``enabler.GetKeyDisplay()``) +- `startdwarf`: fixed on 64-bit Linux + +Misc Improvements +----------------- +- Reduced time for designation jobs from tools like `digv` to be assigned workers +- `embark-assistant`: + - Switched to standard scrolling keys, improved spacing slightly + - Introduced scrolling of Finder search criteria, removing requirement for 46 lines to work properly (Help/Info still formatted for 46 lines). + - Added Freezing search criterion, allowing searches for NA/Frozen/At_Least_Partial/Partial/At_Most_Partial/Never Freezing embarks. +- `rejuvenate`: + - Added ``-all`` argument to apply to all citizens + - Added ``-force`` to include units under 20 years old + - Clarified documentation + +API +--- +- Added to ``Units`` module: + - ``getStressCategory(unit)`` + - ``getStressCategoryRaw(level)`` + - ``stress_cutoffs`` (Lua: ``getStressCutoffs()``) + +Internals +--------- +- Added documentation for all RPC functions and a build-time check +- Added support for build IDs to development builds +- Changed default build architecture to 64-bit +- Use ``dlsym(3)`` to find vtables from libgraphics.so + +Structures +---------- +- Added ``start_dwarf_count`` on 64-bit Linux again and fixed scanning script +- ``army_controller``: added new vector from 0.44.11 +- ``belief_system``: new type, few fields identified +- ``mental_picture``: new type, some fields identified +- ``mission_report``: + - new type (renamed, was ``mission`` before) + - identified some fields +- ``mission``: new type (used in ``viewscreen_civlistst``) +- ``spoils_report``: new type, most fields identified +- ``viewscreen_civlistst``: + - split ``unk_20`` into 3 pointers + - identified new pages + - identified new messenger-related fields +- ``viewscreen_image_creatorst``: + - fixed layout + - identified many fields +- ``viewscreen_reportlistst``: added new mission and spoils report-related fields (fixed layout) +- ``world.languages``: identified (minimal information; whole languages stored elsewhere) +- ``world.status``: + - ``mission_reports``: renamed, was ``missions`` + - ``spoils_reports``: identified +- ``world.unk_131ec0``, ``world.unk_131ef0``: researched layout +- ``world.worldgen_status``: identified many fields +- ``world``: ``belief_systems``: identified + + +DFHack 0.44.12-alpha1 +===================== + +Fixes +----- +- macOS: fixed ``renderer`` vtable address on x64 (fixes `rendermax`) +- `stonesense`: fixed ``PLANT:DESERT_LIME:LEAF`` typo + +API +--- +- Added C++-style linked list interface for DF linked lists + +Structures +---------- +- Dropped 0.44.11 support +- ``ui.squads``: Added fields new in 0.44.12 + + +DFHack 0.44.11-beta2.1 +====================== + +Internals +--------- +- `stonesense`: fixed build + + +DFHack 0.44.11-beta2 +==================== + +Fixes +----- +- Windows: Fixed console failing to initialize +- `command-prompt`: added support for commands that require a specific screen to be visible, e.g. `spotclean` +- `gui/workflow`: fixed advanced constraint menu for crafts + +API +--- +- Added ``Screen::Hide`` to temporarily hide screens, like `command-prompt` + + +DFHack 0.44.11-beta1 +==================== + +Fixes +----- +- Fixed displayed names (from ``Units::getVisibleName``) for units with identities +- Fixed potential memory leak in ``Screen::show()`` +- `fix/dead-units`: fixed script trying to use missing isDiplomat function + +Misc Improvements +----------------- +- Console: + - added support for multibyte characters on Linux/macOS + - made the console exit properly when an interactive command is active (`liquids`, `mode`, `tiletypes`) +- Linux: added automatic support for GCC sanitizers in ``dfhack`` script +- Made the ``DFHACK_PORT`` environment variable take priority over ``remote-server.json`` +- `dfhack-run`: added support for port specified in ``remote-server.json``, to match DFHack's behavior +- `digfort`: added better map bounds checking +- `remove-stress`: + - added support for ``-all`` as an alternative to the existing ``all`` argument for consistency + - sped up significantly + - improved output/error messages + - now removes tantrums, depression, and obliviousness +- `ruby`: sped up handling of onupdate events + +API +--- +- Exposed ``Screen::zoom()`` to C++ (was Lua-only) +- New functions: ``Units::isDiplomat(unit)`` + +Internals +--------- +- jsoncpp: updated to version 1.8.4 and switched to using a git submodule + +Lua +--- +- Added ``printall_recurse`` to print tables and DF references recursively. It can be also used with ``^`` from the `lua` interpreter. +- ``gui.widgets``: ``List:setChoices`` clones ``choices`` for internal table changes + +Structures +---------- +- ``history_event_entity_expels_hfst``: added (new in 0.44.11) +- ``history_event_site_surrenderedst``: added (new in 0.44.11) +- ``history_event_type``: added ``SITE_SURRENDERED``, ``ENTITY_EXPELS_HF`` (new in 0.44.11) +- ``syndrome``: identified a few fields +- ``viewscreen_civlistst``: fixed layout and identified many fields + + +DFHack 0.44.11-alpha1 +===================== + +Structures +---------- +- Added support for automatically sizing arrays indexed with an enum +- Dropped 0.44.10 support +- Removed stale generated CSV files and DT layouts from pre-0.43.05 +- ``announcement_type``: new in 0.44.11: ``NEW_HOLDING``, ``NEW_MARKET_LINK`` +- ``breath_attack_type``: added ``OTHER`` +- ``historical_figure_info.relationships.list``: added ``unk_3a``-``unk_3c`` fields at end +- ``interface_key``: added bindings new in 0.44.11 +- ``occupation_type``: new in 0.44.11: ``MESSENGER`` +- ``profession``: new in 0.44.11: ``MESSENGER`` +- ``ui_sidebar_menus``: + - ``unit.in_squad``: renamed to ``unit.squad_list_opened``, fixed location + - ``unit``: added ``expel_error`` and other unknown fields new in 0.44.11 + - ``hospital``: added, new in 0.44.11 + - ``num_speech_tokens``, ``unk_17d8``: moved out of ``command_line`` to fix layout on x64 +- ``viewscreen_civlistst``: added a few new fields (incomplete) +- ``viewscreen_locationsst``: identified ``edit_input`` + + +DFHack 0.44.10-r2 +================= + +New Plugins +----------- +- `cxxrandom`: exposes some features of the C++11 random number library to Lua + +New Scripts +----------- +- `add-recipe`: adds unknown crafting recipes to the player's civ +- `gui/stamper`: allows manipulation of designations by transforms such as translations, reflections, rotations, and inversion + +Fixes +----- +- Fixed many tools incorrectly using the ``dead`` unit flag (they should generally check ``flags2.killed`` instead) +- Fixed many tools passing incorrect arguments to printf-style functions, including a few possible crashes (`changelayer`, `follow`, `forceequip`, `generated-creature-renamer`) +- Fixed several bugs in Lua scripts found by static analysis (df-luacheck) +- Fixed ``-g`` flag (GDB) in Linux ``dfhack`` script (particularly on x64) +- `autochop`, `autodump`, `autogems`, `automelt`, `autotrade`, `buildingplan`, `dwarfmonitor`, `fix-unit-occupancy`, `fortplan`, `stockflow`: fix issues with periodic tasks not working for some time after save/load cycles +- `autogems`: + - stop running repeatedly when paused + - fixed crash when furnaces are linked to same stockpiles as jeweler's workshops +- `autogems`, `fix-unit-occupancy`: stopped running when a fort isn't loaded (e.g. while embarking) +- `autounsuspend`: now skips planned buildings +- `ban-cooking`: fixed errors introduced by kitchen structure changes in 0.44.10-r1 +- `buildingplan`, `fortplan`: stopped running before a world has fully loaded +- `deramp`: fixed deramp to find designations that already have jobs posted +- `dig`: fixed "Inappropriate dig square" announcements if digging job has been posted +- `fixnaked`: fixed errors due to emotion changes in 0.44 +- `remove-stress`: fixed an error when running on soul-less units (e.g. with ``-all``) +- `revflood`: stopped revealing tiles adjacent to tiles above open space inappropriately +- `stockpiles`: ``loadstock`` now sets usable and unusable weapon and armor settings +- `stocks`: stopped listing carried items under stockpiles where they were picked up from + +Misc Improvements +----------------- +- Added script name to messages produced by ``qerror()`` in Lua scripts +- Fixed an issue in around 30 scripts that could prevent edits to the files (adding valid arguments) from taking effect +- Linux: Added several new options to ``dfhack`` script: ``--remotegdb``, ``--gdbserver``, ``--strace`` +- `bodyswap`: improved error handling +- `buildingplan`: added max quality setting +- `caravan`: documented (new in 0.44.10-alpha1) +- `deathcause`: added "slaughtered" to descriptions +- `embark-assistant`: + - changed region interaction matching to search for evil rain, syndrome rain, and reanimation rather than interaction presence (misleadingly called evil weather), reanimation, and thralling + - gave syndrome rain and reanimation wider ranges of criterion values +- `fix/dead-units`: added a delay of around 1 month before removing units +- `fix/retrieve-units`: now re-adds units to active list to counteract `fix/dead-units` +- `modtools/create-unit`: + - added quantity argument + - now selects a caste at random if none is specified +- `mousequery`: + - migrated several features from TWBT's fork + - added ability to drag with left/right buttons + - added depth display for TWBT (when multilevel is enabled) + - made shift+click jump to lower levels visible with TWBT +- `title-version`: added version to options screen too +- ``item-descriptions``: fixed several grammatical errors + +API +--- +- New functions (also exposed to Lua): + - ``Units::isKilled()`` + - ``Units::isActive()`` + - ``Units::isGhost()`` +- Removed Vermin module (unused and obsolete) + +Internals +--------- +- Added build option to generate symbols for large generated files containing df-structures metadata +- Added fallback for YouCompleteMe database lookup failures (e.g. for newly-created files) +- Improved efficiency and error handling in ``stl_vsprintf`` and related functions +- jsoncpp: fixed constructor with ``long`` on Linux + +Lua +--- +- Added ``profiler`` module to measure lua performance +- Enabled shift+cursor movement in WorkshopOverlay-derived screens + +Structures +---------- +- ``incident_sub6_performance``: identified some fields +- ``item_body_component``: fixed location of ``corpse_flags`` +- ``job_handler``: fixed static array layout +- ``job_type``: added ``is_designation`` attribute +- ``unit_flags1``: renamed ``dead`` to ``inactive`` to better reflect its use +- ``unit_personality``: fixed location of ``current_focus`` and ``undistracted_focus`` +- ``unit_thought_type``: added ``SawDeadBody`` (new in 0.44.10) + + +DFHack 0.44.10-r1 +================= + +New Scripts +----------- +- `bodyswap`: shifts player control over to another unit in adventure mode + +New Tweaks +---------- +- `tweak` kitchen-prefs-all: adds an option to toggle cook/brew for all visible items in kitchen preferences +- `tweak` stone-status-all: adds an option to toggle the economic status of all stones + +Fixes +----- +- Lua: registered ``dfhack.constructions.designateRemove()`` correctly +- `prospector`: fixed crash due to invalid vein materials +- `tweak` max-wheelbarrow: fixed conflict with building renaming +- `view-item-info`: stopped appending extra newlines permanently to descriptions + +Misc Improvements +----------------- +- Added logo to documentation +- Documented several missing ``dfhack.gui`` Lua functions +- `adv-rumors`: bound to Ctrl-A +- `command-prompt`: added support for ``Gui::getSelectedPlant()`` +- `gui/advfort`: bound to Ctrl-T +- `gui/room-list`: added support for ``Gui::getSelectedBuilding()`` +- `gui/unit-info-viewer`: bound to Alt-I +- `modtools/create-unit`: made functions available to other scripts +- `search-plugin`: + - added support for stone restrictions screen (under ``z``: Status) + - added support for kitchen preferences (also under ``z``) + +API +--- +- New functions (all available to Lua as well): + - ``Buildings::getRoomDescription()`` + - ``Items::checkMandates()`` + - ``Items::canTrade()`` + - ``Items::canTradeWithContents()`` + - ``Items::isRouteVehicle()`` + - ``Items::isSquadEquipment()`` + - ``Kitchen::addExclusion()`` + - ``Kitchen::findExclusion()`` + - ``Kitchen::removeExclusion()`` +- syndrome-util: added ``eraseSyndromeData()`` + +Internals +--------- +- Fixed compiler warnings on all supported build configurations +- Windows build scripts now work with non-C system drives + +Structures +---------- +- ``dfhack_room_quality_level``: new enum +- ``glowing_barrier``: identified ``triggered``, added comments +- ``item_flags2``: renamed ``has_written_content`` to ``unk_book`` +- ``kitchen_exc_type``: new enum (for ``ui.kitchen``) +- ``mandate.mode``: now an enum +- ``unit_personality.emotions.flags.memory``: identified +- ``viewscreen_kitchenprefst.forbidden``, ``possible``: now a bitfield, ``kitchen_pref_flag`` +- ``world_data.feature_map``: added extensive documentation (in XML) + + +DFHack 0.44.10-beta1 +==================== + +New Scripts +----------- +- `devel/find-primitive`: finds a primitive variable in memory + +Fixes +----- +- Units::getAnyUnit(): fixed a couple problematic conditions and potential segfaults if global addresses are missing +- `autodump`, `automelt`, `autotrade`, `stocks`, `stockpiles`: fixed conflict with building renaming +- `exterminate`: fixed documentation of ``this`` option +- `full-heal`: + - units no longer have a tendency to melt after being healed + - healed units are no longer treated as patients by hospital staff + - healed units no longer attempt to clean themselves unsuccessfully + - wounded fliers now regain the ability to fly upon being healing + - now heals suffocation, numbness, infection, spilled guts and gelding +- `modtools/create-unit`: + - creatures of the appropriate age are now spawned as babies or children where applicable + - fix: civ_id is now properly assigned to historical_figure, resolving several hostility issues (spawned pets are no longer attacked by fortress military!) + - fix: unnamed creatures are no longer spawned with a string of numbers as a first name +- `stockpiles`: stopped sidebar option from overlapping with `autodump` +- `tweak` block-labors: fixed two causes of crashes related in the v-p-l menu + +Misc Improvements +----------------- +- `blueprint`: added a basic Lua API +- `devel/export-dt-ini`: added tool offsets for DT 40 +- `devel/save-version`: added current DF version to output +- `install-info`: added information on tweaks + +Internals +--------- +- Added function names to DFHack's NullPointer and InvalidArgument exceptions +- Added ``Gui::inRenameBuilding()`` +- Linux: required plugins to have symbols resolved at link time, for consistency with other platforms + + +DFHack 0.44.10-alpha1 +===================== + +New Scripts +----------- +- `caravan`: adjusts properties of caravans +- `gui/autogems`: a configuration UI for the `autogems` plugin + +Fixes +----- +- Fixed uninitialized pointer being returned from ``Gui::getAnyUnit()`` in rare cases +- `autohauler`, `autolabor`, `labormanager`: fixed fencepost error and potential crash +- `dwarfvet`: fixed infinite loop if an animal is not accepted at a hospital +- `liquids`: fixed "range" command to default to 1 for dimensions consistently +- `search-plugin`: fixed 4/6 keys in unit screen search +- `view-item-info`: fixed an error with some armor + +Misc Improvements +----------------- +- `autogems`: can now blacklist arbitrary gem types (see `gui/autogems`) +- `exterminate`: added more words for current unit, removed warning +- `fpause`: now pauses worldgen as well + +Internals +--------- +- Added some build scripts for Sublime Text +- Changed submodule URLs to relative URLs so that they can be cloned consistently over different protocols (e.g. SSH) + + +DFHack 0.44.09-r1 +================= + +Fixes +----- +- `modtools/item-trigger`: fixed token format in help text + +Misc Improvements +----------------- +- Reorganized changelogs and improved changelog editing process +- `modtools/item-trigger`: added support for multiple type/material/contaminant conditions + +Internals +--------- +- OS X: Can now build with GCC 7 (or older) + +Structures +---------- +- ``army``: added vector new in 0.44.07 +- ``building_type``: added human-readable ``name`` attribute +- ``furnace_type``: added human-readable ``name`` attribute +- ``renderer``: fixed vtable addresses on 64-bit OS X +- ``site_reputation_report``: named ``reports`` vector +- ``workshop_type``: added human-readable ``name`` attribute + + +DFHack 0.44.09-alpha1 +===================== + +Fixes +----- +- `digtype`: stopped designating non-vein tiles (open space, trees, etc.) +- `labormanager`: fixed crash due to dig jobs targeting some unrevealed map blocks + + +DFHack 0.44.08-alpha1 +===================== + +Fixes +----- +- `fix/dead-units`: fixed a bug that could remove some arriving (not dead) units + + +DFHack 0.44.07-beta1 +==================== + +Misc Improvements +----------------- +- `modtools/item-trigger`: added the ability to specify inventory mode(s) to trigger on + +Structures +---------- +- Added symbols for Toady's `0.44.07 Linux test build `_ to fix :bug:`10615` +- ``world_site``: fixed alignment + + +DFHack 0.44.07-alpha1 +===================== + +Fixes +----- +- Fixed some CMake warnings (CMP0022) +- Support for building on Ubuntu 18.04 +- `embark-assistant`: fixed detection of reanimating biomes + +Misc Improvements +----------------- +- `embark-assistant`: + - Added search for adamantine + - Now supports saving/loading profiles +- `fillneeds`: added ``-all`` option to apply to all units +- `remotefortressreader`: added flows, instruments, tool names, campfires, ocean waves, spiderwebs + +Structures +---------- +- Several new names in instrument raw structures +- ``identity``: identified ``profession``, ``civ`` +- ``manager_order_template``: fixed last field type +- ``viewscreen_createquotast``: fixed layout +- ``world.language``: moved ``colors``, ``shapes``, ``patterns`` to ``world.descriptors`` +- ``world.reactions``, ``world.reaction_categories``: moved to new compound, ``world.reactions``. Requires renaming: + - ``world.reactions`` to ``world.reactions.reactions`` + - ``world.reaction_categories`` to ``world.reactions.reaction_categories`` + + +DFHack 0.44.05-r2 +================= + +New Plugins +----------- +- `embark-assistant`: adds more information and features to embark screen + +New Scripts +----------- +- `adv-fix-sleepers`: fixes units in adventure mode who refuse to wake up (:bug:`6798`) +- `hermit`: blocks caravans, migrants, diplomats (for hermit challenge) + +New Features +------------ +- With ``PRINT_MODE:TEXT``, setting the ``DFHACK_HEADLESS`` environment variable will hide DF's display and allow the console to be used normally. (Note that this is intended for testing and is not very useful for actual gameplay.) + +Fixes +----- +- `devel/export-dt-ini`: fix language_name offsets for DT 39.2+ +- `devel/inject-raws`: fixed gloves and shoes (old typo causing errors) +- `remotefortressreader`: fixed an issue with not all engravings being included +- `view-item-info`: fixed an error with some shields + +Misc Improvements +----------------- +- `adv-rumors`: added more keywords, including names +- `autochop`: can now exclude trees that produce fruit, food, or cookable items +- `remotefortressreader`: added plant type support + + +DFHack 0.44.05-r1 +================= + +New Scripts +----------- +- `break-dance`: Breaks up a stuck dance activity +- `fillneeds`: Use with a unit selected to make them focused and unstressed +- `firestarter`: Lights things on fire: items, locations, entire inventories even! +- `flashstep`: Teleports adventurer to cursor +- `ghostly`: Turns an adventurer into a ghost or back +- `questport`: Sends your adventurer to the location of your quest log cursor +- `view-unit-reports`: opens the reports screen with combat reports for the selected unit + +Fixes +----- +- `devel/inject-raws`: now recognizes spaces in reaction names +- `dig`: added support for designation priorities - fixes issues with designations from ``digv`` and related commands having extremely high priority +- `dwarfmonitor`: + - fixed display of creatures and poetic/music/dance forms on ``prefs`` screen + - added "view unit" option + - now exposes the selected unit to other tools +- `names`: fixed many errors +- `quicksave`: fixed an issue where the "Saving..." indicator often wouldn't appear + +Misc Improvements +----------------- +- `binpatch`: now reports errors for empty patch files +- `force`: now provides useful help +- `full-heal`: + - can now select corpses to resurrect + - now resets body part temperatures upon resurrection to prevent creatures from freezing/melting again + - now resets units' vanish countdown to reverse effects of `exterminate` +- `gui/gm-unit`: + - added a profession editor + - misc. layout improvements +- `launch`: can now ride creatures +- `names`: can now edit names of units +- `remotefortressreader`: + - support for moving adventurers + - support for vehicles, gem shapes, item volume, art images, item improvements + +Removed +------- +- `tweak`: ``kitchen-keys``: :bug:`614` fixed in DF 0.44.04 + +Internals +--------- +- ``Gui::getAnyUnit()`` supports many more screens/menus + +Structures +---------- +- New globals: ``soul_next_id`` + + +DFHack 0.44.05-alpha1 +===================== + +Misc Improvements +----------------- +- `gui/liquids`: added more keybindings: 0-7 to change liquid level, P/B to cycle backwards + +Structures +---------- +- ``incident``: re-aligned again to match disassembly + + +DFHack 0.44.04-alpha1 +===================== + +Fixes +----- +- `devel/inject-raws`: now recognizes spaces in reaction names +- `exportlegends`: fixed an error that could occur when exporting empty lists + +Structures +---------- +- ``artifact_record``: fixed layout (changed in 0.44.04) +- ``incident``: fixed layout (changed in 0.44.01) - note that many fields have moved + + +DFHack 0.44.03-beta1 +==================== + +Fixes +----- +- `autolabor`, `autohauler`, `labormanager`: added support for "put item on display" jobs and building/destroying display furniture +- `gui/gm-editor`: fixed an error when editing primitives in Lua tables + +Misc Improvements +----------------- +- `devel/dump-offsets`: now ignores ``index`` globals +- `gui/pathable`: added tile types to sidebar +- `modtools/skill-change`: + - now updates skill levels appropriately + - only prints output if ``-loud`` is passed + +Structures +---------- +- Added ``job_type.PutItemOnDisplay`` +- Added ``twbt_render_map`` code offset on x64 +- Fixed an issue preventing ``enabler`` from being allocated by DFHack +- Found ``renderer`` vtable on osx64 +- New globals: + - ``version`` + - ``min_load_version`` + - ``movie_version`` + - ``basic_seed`` + - ``title`` + - ``title_spaced`` + - ``ui_building_resize_radius`` +- ``adventure_movement_optionst``, ``adventure_movement_hold_tilest``, ``adventure_movement_climbst``: named coordinate fields +- ``mission``: added type +- ``unit``: added 3 new vmethods: ``getCreatureTile``, ``getCorpseTile``, ``getGlowTile`` +- ``viewscreen_assign_display_itemst``: fixed layout on x64 and identified many fields +- ``viewscreen_reportlistst``: fixed layout, added ``mission_id`` vector +- ``world.status``: named ``missions`` vector + + +DFHack 0.44.03-alpha1 +===================== + +Lua +--- +- Improved ``json`` I/O error messages +- Stopped a crash when trying to create instances of classes whose vtable addresses are not available + + +DFHack 0.44.02-beta1 +==================== + +New Scripts +----------- +- `devel/check-other-ids`: Checks the validity of "other" vectors in the ``world`` global +- `gui/cp437-table`: An in-game CP437 table + +Fixes +----- +- Fixed issues with the console output color affecting the prompt on Windows +- `createitem`: stopped items from teleporting away in some forts +- `gui/gm-unit`: can now edit mining skill +- `gui/quickcmd`: stopped error from adding too many commands +- `modtools/create-unit`: fixed error when domesticating units + +Misc Improvements +----------------- +- The console now provides suggestions for built-in commands +- `devel/export-dt-ini`: avoid hardcoding flags +- `exportlegends`: + - reordered some tags to match DF's order + - added progress indicators for exporting long lists +- `gui/gm-editor`: added enum names to enum edit dialogs +- `gui/gm-unit`: made skill search case-insensitive +- `gui/rename`: added "clear" and "special characters" options +- `remotefortressreader`: + - includes item stack sizes + - some performance improvements + +Removed +------- +- `warn-stuck-trees`: :bug:`9252` fixed in DF 0.44.01 + +Lua +--- +- Exposed ``get_vector()`` (from C++) for all types that support ``find()``, e.g. ``df.unit.get_vector() == df.global.world.units.all`` + +Structures +---------- +- Added ``buildings_other_id.DISPLAY_CASE`` +- Fixed ``unit`` alignment +- Fixed ``viewscreen_titlest.start_savegames`` alignment +- Identified ``historical_entity.unknown1b.deities`` (deity IDs) +- Located ``start_dwarf_count`` offset for all builds except 64-bit Linux; `startdwarf` should work now + + +DFHack 0.44.02-alpha1 +===================== + +New Scripts +----------- +- `devel/dump-offsets`: prints an XML version of the global table included in in DF + +Fixes +----- +- Fixed a crash that could occur if a symbol table in symbols.xml had no content + +Lua +--- +- Added a new ``dfhack.console`` API +- API can now wrap functions with 12 or 13 parameters + +Structures +---------- +- The former ``announcements`` global is now a field in ``d_init`` +- The ``ui_menu_width`` global is now a 2-byte array; the second item is the former ``ui_area_map_width`` global, which is now removed +- ``world`` fields formerly beginning with ``job_`` are now fields of ``world.jobs``, e.g. ``world.job_list`` is now ``world.jobs.list`` + + +DFHack 0.43.05-r3 +================= + +Internals +--------- +- Fixed an uncommon crash that could occur when printing text to the console +- Added lots of previously-missing DF classes +- More names for fields: https://github.com/DFHack/df-structures/compare/0.43.05-r2...0.43.05 + +Fixes +----- +- Linux: fixed argument to ``setarch`` in the ``dfhack`` launcher script +- Ruby: fixed an error that occurred when the DF path contained an apostrophe +- `diggingInvaders` now compiles again and is included +- `labormanager`: + + - stopped waiting for on-duty military dwarves with minor injuries to obtain care + - stopped waiting for meetings when participant(s) are dead + - fixed a crash for dwarves with no cultural identity + +- `luasocket`: fixed ``receive()`` with a byte count +- `orders`: fixed an error when importing orders with material categories +- `siren`: fixed an error +- `stockpiles`: fixed serialization of barrel and bin counts +- `view-item-info`: fixed a ``CHEESE_MAT``-related error + +Misc Improvements +----------------- +- `devel/export-dt-ini`: added more offsets for new DT versions +- `digfort`: added support for changing z-levels +- `exportlegends`: suppressed ABSTRACT_BUILDING warning +- `gui/dfstatus`: excluded logs in constructions +- `labormanager`: + + - stopped assigning woodcutting jobs to elves + - "recover wounded" jobs now weighted based on altruism + +- `remotefortressreader`: added support for buildings, grass, riders, and + hair/beard styles + + +DFHack 0.43.05-r2 +================= + +Internals +--------- +- Rebuilding DFHack can be faster if nothing Git-related has changed +- Plugins can now hook Screen::readTile() +- Improved Lua compatibility with plugins that hook into GUI functions (like TWBT) +- Expanded focus strings for jobmanagement and workquota_condition viewscreens +- ``Gui::getAnyUnit()``: added support for viewscreen_unitst, + viewscreen_textviewerst, viewscreen_layer_unit_relationshipst +- Fixed (limited) keybinding support in PRINT_MODE:TEXT on macOS +- Added a new standardized ``Gui::refreshSidebar()`` function to fix behavior of + some plugins on the lowest z-level +- New ``Buildings`` module functions: ``markedForRemoval()``, ``getCageOccupants()`` +- Limited recursive command invocations to 20 to prevent crashes +- Added an ``onLoad.init-example`` file + +Lua +--- +- Improved C++ exception handling for some native functions that aren't direct + wrappers around C++ functions (in this case, error messages could be nil and + cause the Lua interpreter to quit) +- Added support for a ``key_pen`` option in Label widgets +- Fixed ``to_first`` argument to ``dfhack.screen.dismiss()`` +- Added optional ``map`` parameters to some screen functions +- Exposed some more functions to Lua: + + - ``dfhack.gui.refreshSidebar()`` + - ``dfhack.gui.getAnyUnit()`` + - ``dfhack.gui.getAnyBuilding()`` + - ``dfhack.gui.getAnyItem()`` + - ``dfhack.gui.getAnyPlant()`` + - ``dfhack.gui.getDepthAt()`` + - ``dfhack.units.getUnitsInBox()`` + - ``dfhack.units.isVisible()`` + - ``dfhack.maps.isTileVisible()`` + - ``dfhack.buildings.markedForRemoval()`` + - ``dfhack.buildings.getCageOccupants()`` + - ``dfhack.internal.md5()`` + - ``dfhack.internal.md5File()`` + - ``dfhack.internal.threadid()`` + +- New function: ``widgets.Pages:getSelectedPage()`` +- Added a ``key`` option to EditField and FilteredList widgets +- Fixed an issue preventing ``repeatUtil.cancel()`` from working when called + from the callback + +Ruby +---- +- Fixed a crash when creating new instances of DF virtual classes (e.g. fixes a + `lever` crash) +- Ruby scripts can now be loaded from any script paths specified (from script- + paths.txt or registered through the Lua API) +- ``unit_find()`` now uses ``Gui::getSelectedUnit()`` and works in more places + (e.g. `exterminate` now works from more screens, like `command-prompt`) + +New Internal Commands +--------------------- +- `alias`: allows configuring aliases for other commands + +New Plugins +----------- +- `orders`: Manipulate manager orders +- `pathable`: Back-end for `gui/pathable` + +New Scripts +----------- +- `clear-smoke`: Removes all smoke from the map +- `empty-bin`: Empty a bin onto the floor +- `fix/retrieve-units`: Spawns stuck invaders/guests +- `fix/stuck-merchants`: Dismisses stuck merchants that haven't entered the map yet +- `gui/pathable`: View whether tiles on the map can be pathed to +- `gui/teleport`: A front-end for the `teleport` script +- `warn-stuck-trees`: Detects citizens stuck in trees + +New Tweaks +---------- +- `tweak` burrow-name-cancel: Implements the "back" option when renaming a + burrow, which currently does nothing (:bug:`1518`) +- `tweak` cage-butcher: Adds an option to butcher units when viewing cages with "q" + +Fixes +----- +- Enforced use of ``stdout.log`` and ``stderr.log`` (instead of their ``.txt`` + counterparts) on Windows +- Fixed ``getItemBaseValue()`` for cheese, sheets and instruments +- Fixed alignment in: + + - ``viewscreen_choose_start_sitest`` + - ``viewscreen_export_graphical_mapst`` + - ``viewscreen_setupadventurest`` + - ``viewscreen_setupdwarfgamest`` + +- `adv-max-skills`: fixed error due to viewscreen changes +- `autolabor`: fixed a crash when assigning haulers while traders are active +- `buildingplan`: fixed an issue that prevented certain numbers from being used + in building names +- `confirm`: + + - dialogs are now closed permanently when disabled from the settings UI + - fixed an issue that could have prevented closing dialogs opened by pressing "s" + +- `embark-tools`: stopped the sand indicator from overlapping dialogs +- `exportlegends`: fixed some crashes and site map issues +- `devel/find-offsets`: fixed ``current_weather`` scan +- `gui/extended-status`: fixed an error when no beds are available +- `gui/family-affairs`: fixed issues with assigning lovers +- `gui/gm-editor`: + + - made keybinding display order consistent + - stopped keys from performing actions in help screen + +- `gui/manager-quantity`: + + - now allows orders with a limit of 0 + - fixed screen detection + +- `gui/mechanisms`, `gui/room-list`: fixed an issue when recentering the map when exiting +- `lever`: prevented pulling non-lever buildings, which can cause crashes +- `markdown`: fixed file encoding +- `modtools/create-unit`: + + - fixed when popup announcements are present + - added checks to ensure that the current game mode is restored + +- `resume`: stopped drawing on the map border +- `show-unit-syndromes`: fixed an error when handling some syndromes +- `strangemood`: fixed some issues with material searches +- `view-item-info`: fixed a color-related error for some materials + +Misc Improvements +----------------- +- Docs: prevented automatic hyphenation in some browsers, which was producing + excessive hyphenation sometimes +- `command-prompt`: invoking ``command-prompt`` a second time now hides the prompt +- `gui/extended-status`: added an option to assign/replace the manager +- `gui/load-screen`: + + - adjusted dialog width for long folder names + - added modification times and DF versions to dialog + +- `gui/mechanisms`, `gui/room-list`, `gui/siege-engine`: add and list "exit to map" options +- `lever`: added support for pulling levers at high priority +- `markdown`: now recognizes ``-n`` in addition to ``/n`` +- `remotefortressreader`: more data exported, used by Armok Vision v0.17.0 +- `resume`, `siege-engine`: improved compatibility with GUI-hooking plugins (like TWBT) +- `sc-script`: improved help text +- `teleport`: can now be used as a module +- `tweak` embark-profile-name: now enabled in ``dfhack.init-example`` +- `tweak` hotkey-clear: fixed display on larger screens + + +DFHack 0.43.05-r1 +================= + +Internals +--------- +- 64-bit support on all platforms +- Several structure fixes to match 64-bit DF's memory layout +- Added ``DFHack::Job::removeJob()`` function +- New module: ``Designations`` - handles designation creation (currently for plants only) +- Added ``Gui::getSelectedPlant()`` +- Added ``Units::getMainSocialActivity()``, ``Units::getMainSocialEvent()`` +- Visual Studio 2015 now required to build on Windows instead of 2010 +- GCC 4.8 or newer required to build on Linux and OS X (and now supported on OS X) +- Updated TinyXML from 2.5.3 to 2.6.2 +- Added the ability to download files manually before building + +Lua +--- +- Lua has been updated to 5.3 - see https://www.lua.org/manual/5.3/readme.html for details + + - Floats are no longer implicitly converted to integers in DFHack API calls + +- ``df.new()`` supports more types: ``char``, ``intptr_t``, ``uintptr_t``, ``long``, ``unsigned long`` +- String representations of vectors and a few other containers now include their lengths +- Added a ``tile-material`` module +- Added a ``Painter:key_string()`` method +- Made ``dfhack.gui.revealInDwarfmodeMap()`` available + +Ruby +---- +- Added support for loading ruby 2.x libraries + +New Plugins +----------- +- `dwarfvet` enables animal caretaking +- `generated-creature-renamer`: Renames generated creature IDs for use with graphics packs +- `labormanager` (formerly autolabor2): a more advanced alternative to `autolabor` +- `misery`: re-added and updated for the 0.4x series +- `title-folder`: shows DF folder name in window title bar when enabled + +New Scripts +----------- +- `adv-rumors`: improves the "Bring up specific incident or rumor" menu in adventure mode +- `fix/tile-occupancy`: Clears bad occupancy flags on the selected tile. +- `install-info`: Logs basic troubleshooting information about the current DFHack installation +- `load-save`: loads a save non-interactively +- `modtools/change-build-menu`: Edit the build mode sidebar menus +- `modtools/if-entity`: Run a command if the current entity matches a given ID +- `season-palette`: Swap color palettes with the changes of the seasons +- `unforbid`: Unforbids all items + +New Tweaks +---------- +- `tweak condition-material `: fixes a crash in the work order condition material list +- `tweak hotkey-clear `: adds an option to clear bindings from DF hotkeys + +Fixes +----- +- The DF path on OS X can now contain spaces and ``:`` characters +- Buildings::setOwner() changes now persist properly when saved +- ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable +- Fixed ``plug`` output alignment for plugins with long names +- `add-thought`: fixed support for emotion names +- `autochop`: + + - fixed several issues with job creation and removal + - stopped designating the center tile (unreachable) for large trees + - stopped options from moving when enabling and disabling burrows + - fixed display of unnamed burrows + +- `devel/find-offsets`: fixed a crash when vtables used by globals aren't available +- `getplants`: + + - fixed several issues with job creation and removal + - stopped designating the center tile (unreachable) for large trees + +- `gui/workflow`: added extra keybinding to work with `gui/extended-status` +- `manipulator`: + + - Fixed crash when selecting a profession from an empty list + - Custom professions are now sorted alphabetically more reliably + +- `modtools/create-item`: + + - made gloves usable by specifying handedness + - now creates pairs of boots and gloves + +- `modtools/create-unit`: + + - stopped permanently overwriting the creature creation menu in arena mode + - now uses non-English names + - added ``-setUnitToFort`` option to make a unit a civ/group member more easily + - fixed some issues where units would appear in unrevealed areas of the map + +- `modtools/item-trigger`: fixed errors with plant growths +- `remotefortressreader`: fixed a crash when serializing the local map +- `ruby`: fixed a crash when unloading the plugin on Windows +- `stonesense`: disabled overlay in STANDARD-based print modes to prevent crashes +- `title-version`: now hidden when loading an arena + +Misc Improvements +----------------- +- Documented all default keybindings (from :file:`dfhack.init-example`) in the + docs for the relevant commands; updates enforced by build system. +- `autounsuspend`: reduced update frequency to address potential performance issues +- `gui/extended-status`: added a feature to queue beds +- `lua` and `gui/gm-editor` now support the same aliases (``scr``, ``unit``, etc.) +- `manipulator`: added social activities to job column +- `remotefortressreader`: Added support for + + - world map snow coverage + - spatters + - wall info + - site towers, world buildings + - surface material + - building items + - DF version info + +- `title-version`: Added a prerelease indicator +- `workflow`: Re-added ``Alt-W`` keybindings + + +DFHack 0.43.05-beta2 +==================== + +Fixes +----- +- Fixed Buildings::updateBuildings(), along with building creation/deletion events +- Fixed ``plug`` output alignment for plugins with long names +- Fixed a crash that happened when a ``LUA_PATH`` environment variable was set +- `add-thought`: fixed number conversion +- `gui/workflow`: fixed range editing producing the wrong results for certain numbers +- `modtools/create-unit`: now uses non-English names +- `modtools/item-trigger`: fixed errors with plant growths +- `remotefortressreader`: fixed a crash when serializing the local map +- `stockflow`: fixed an issue with non-integer manager order limits +- `title-folder`: fixed compatibility issues with certain SDL libraries on macOS + +Structures +---------- +- Added some missing renderer VTable addresses on macOS +- ``entity.resources.organic``: identified ``parchment`` +- ``entity_sell_category``: added ``Parchment`` and ``CupsMugsGoblets`` +- ``ui_advmode_menu``: added ``Build`` +- ``ui_unit_view_mode``: added ``PrefOccupation`` +- ``unit_skill``: identified ``natural_skill_lvl`` (was ``unk_1c``) +- ``viewscreen_jobmanagementst``: identified ``max_workshops`` +- ``viewscreen_overallstatusst``: made ``visible_pages`` an enum +- ``viewscreen_pricest``: identified fields +- ``viewscreen_workquota_conditionst``: gave some fields ``unk`` names + +API Changes +----------- +- Allowed the Lua API to accept integer-like floats and strings when expecting an integer +- Lua: New ``Painter:key_string()`` method +- Lua: Added ``dfhack.getArchitecture()`` and ``dfhack.getArchitectureName()`` + +Additions/Removals: +------------------- +- Added `adv-rumors` script: improves the "Bring up specific incident or rumor" menu in adventure mode +- Added `install-info` script for basic troubleshooting +- Added `tweak condition-material `: fixes a crash in the work order condition material list +- Added `tweak hotkey-clear `: adds an option to clear bindings from DF hotkeys +- `autofarm`: reverted local biome detection (from 0.43.05-alpha3) + +Other Changes +------------- +- Added a DOWNLOAD_RUBY CMake option, to allow use of a system/external ruby library +- Added the ability to download files manually before building +- `gui/extended-status`: added a feature to queue beds +- `remotefortressreader`: added building items, DF version info +- `stonesense`: Added support for 64-bit macOS and Linux + +DFHack 0.43.05-beta1 +==================== + +Fixes +----- +- Fixed various crashes on 64-bit Windows related to DFHack screens, notably `manipulator` +- Fixed addresses of next_id globals on 64-bit Linux (fixes an `automaterial`/box-select crash) +- ``ls`` now lists scripts in folders other than ``hack/scripts``, when applicable +- `modtools/create-unit`: stopped permanently overwriting the creature creation + menu in arena mode +- `season-palette`: fixed an issue where only part of the screen was redrawn + after changing the color scheme +- `title-version`: now hidden when loading an arena + +Structures +---------- +- ``file_compressorst``: fixed field sizes on x64 +- ``historical_entity``: fixed alignment on x64 +- ``ui_sidebar_menus.command_line``: fixed field sizes on x64 +- ``viewscreen_choose_start_sitest``: added 3 missing fields, renamed ``in_embark_only_warning`` +- ``viewscreen_layer_arena_creaturest``: identified more fields +- ``world.math``: identified +- ``world.murky_pools``: identified + +Additions/Removals +------------------ +- `generated-creature-renamer`: Renames generated creature IDs for use with graphics packs + +Other Changes +------------- +- `title-version`: Added a prerelease indicator + +DFHack 0.43.05-alpha4 +===================== + +Fixes +----- +- Fixed an issue with uninitialized bitfields that was causing several issues + (disappearing buildings in `buildingplan`'s planning mode, strange behavior in + the extended `stocks` screen, and likely other problems). This issue was + introduced in 0.43.05-alpha3. +- `stockflow`: Fixed an "integer expected" error + +Structures +---------- +- Located several globals on 64-bit Linux: flows, timed_events, ui_advmode, + ui_building_assign_type, ui_building_assign_is_marked, + ui_building_assign_units, ui_building_assign_items, and ui_look_list. This + fixes `search-plugin`, `zone`, and `force`, among others. +- ``ui_sidebar_menus``: Fixed some x64 alignment issues + +Additions/Removals +------------------ +- Added `fix/tile-occupancy`: Clears bad occupancy flags on the selected tile. + Useful for fixing blocked tiles introduced by the above buildingplan issue. +- Added a Lua ``tile-material`` module + +Other Changes +------------- +- `labormanager`: Add support for shell crafts +- `manipulator`: Custom professions are now sorted alphabetically more reliably + +DFHack 0.43.05-alpha3 +===================== + +Fixes +----- +- `add-thought`: fixed support for emotion names +- `autofarm`: Made surface farms detect local biome +- `devel/export-dt-ini`: fixed squad_schedule_entry size +- `labormanager`: + + - Now accounts for unit attributes + - Made instrument-building jobs work (constructed instruments) + - Fixed deconstructing constructed instruments + - Fixed jobs in bowyer's shops + - Fixed trap component jobs + - Fixed multi-material construction jobs + - Fixed deconstruction of buildings containing items + - Fixed interference caused by "store item in vehicle" jobs + +- `manipulator`: Fixed crash when selecting a profession from an empty list +- `ruby`: + + - Fixed crash on Win64 due to truncated global addresses + - Fixed compilation on Win64 + - Use correct raw string length with encodings + +Structures +---------- +- Changed many ``comment`` XML attributes with version numbers to use new + ``since`` attribute instead +- ``activity_event_conflictst.sides``: named many fields +- ``building_def.build_key``: fixed size on 64-bit Linux and OS X +- ``historical_kills``: + + - ``unk_30`` -> ``killed_underground_region`` + - ``unk_40`` -> ``killed_region`` + +- ``historical_kills.killed_undead``: removed ``skeletal`` flag +- ``ui_advmode``: aligned enough so that it doesn't crash (64-bit OS X/Linux) +- ``ui_advmode.show_menu``: changed from bool to enum +- ``unit_personality.emotions.flags``: now a bitfield + +API Changes +----------- +- Added ``DFHack::Job::removeJob()`` function +- C++: Removed bitfield constructors that take an initial value. These kept + bitfields from being used in unions. Set ``bitfield.whole`` directly instead. +- Lua: ``bitfield.whole`` now returns an integer, not a decimal + +Additions/Removals +------------------ +- Removed source for treefarm plugin (wasn't built) +- Added `modtools/change-build-menu`: Edit the build mode sidebar menus +- Added `modtools/if-entity`: Run a command if the current entity matches a + given ID +- Added `season-palette`: Swap color palettes with the changes of the seasons + +Other changes +------------- +- Changed minimum GCC version to 4.8 on OS X and Linux (earlier versions + wouldn't have worked on Linux anyway) +- Updated TinyXML from 2.5.3 to 2.6.2 + +DFHack 0.43.03-r1 +================= + +Lua +--- +- Label widgets can now easily register handlers for mouse clicks + +New Features +------------ +- `add-thought`: allow syndrome name as ``-thought`` argument +- `gui/gm-editor` + + - Added ability to insert default types into containers. For primitive types leave the type entry empty, and for references use ``*``. + - Added ``shift-esc`` binding to fully exit from editor + - Added ``gui/gm-editor toggle`` command to toggle editor visibility (saving position) + +- `modtools/create-unit`: + + - Added an option to attach units to an existing wild animal population + - Added an option to attach units to a map feature + +Fixes +----- +- `autofarm`: Can now handle crops that grow for more than a season +- `combine-plants`: Fixed recursion into sub-containers +- `createitem`: Now moves multiple created items to cursor correctly +- `exportlegends`: Improved handling of unknown enum items (fixes many errors) +- `gui/create-item`: Fixed quality when creating multiple items +- `gui/mod-manager`: Fixed error when mods folder doesn't exist +- `modtools/item-trigger`: Fixed handling of items with subtypes +- `reveal`: ``revflood`` now handles constructed stairs with floors in generated fortresses +- `stockflow`: + + - Can order metal mechanisms + - Fixed material category of thread-spinning jobs + +Misc Improvements +----------------- +- The built-in ``ls`` command now wraps the descriptions of commands +- `catsplosion`: now a lua script instead of a plugin +- `fix/diplomats`: replaces ``fixdiplomats`` +- `fix/merchants`: replaces ``fixmerchants`` +- `prefchange`: added a ``help`` option +- `probe`: now displays raw tiletype names +- Unified script documentation and in-terminal help options + +Removed +------- +- `tweak` manager-quantity: no longer needed + +DFHack 0.42.06-r1 +================= + +Internals +--------- +- Commands to run on startup can be specified on the command line with ``+`` + + Example:: + + ./dfhack +devel/print-args example + "Dwarf Fortress.exe" +devel/print-args example + +- Prevented plugins with active viewscreens from being unloaded and causing a crash +- Additional script search paths can be specified in dfhack-config/script-paths.txt + +Lua +--- +- `building-hacks` now supports ``auto_gears`` flags. It automatically finds and animates gears in building definition +- Changed how `eventful` triggers reaction complete. Now it has ``onReactionComplete`` and ``onReactionCompleting``. Second one can be canceled + +New Plugins +----------- +- `autogems`: Creates a new Workshop Order setting, automatically cutting rough gems + +New Scripts +----------- +- `devel/save-version`: Displays DF version information about the current save +- `modtools/extra-gamelog`: replaces ``log-region``, ``soundsense-season``, and ``soundsense`` + +New Features +------------ +- `buildingplan`: Support for floodgates, grates, and bars +- `colonies`: new ``place`` subcommand and supports any vermin (default honey bees) +- `confirm`: Added a confirmation for retiring locations +- `exportlegends`: Exports more information (poetic/musical/dance forms, written/artifact content, landmasses, extra histfig information, and more) +- `search-plugin`: Support for new screens: + + - location occupation assignment + - civilization animal training knowledge + - animal trainer assignment + +- `tweak`: + + - ``tweak block-labors``: Prevents labors that can't be used from being toggled + - ``tweak hide-priority``: Adds an option to hide designation priority indicators + - ``tweak title-start-rename``: Adds a safe rename option to the title screen "Start Playing" menu + +- `zone`: + + - Added ``unassign`` subcommand + - Added ``only`` option to ``assign`` subcommand + +Fixes +----- +- Fixed a crash bug caused by the historical figures DFHack uses to store persistent data. +- More plugins should recognize non-dwarf citizens +- Fixed a possible crash from cloning jobs +- moveToBuilding() now sets flags for items that aren't a structural part of the building properly +- `autotrade`, `stocks`: Made trading work when multiple caravans are present but only some can trade +- `confirm` note-delete: No longer interferes with name entry +- `exportlegends`: Handles entities without specific races, and a few other fixes for things new to v0.42 +- `fastdwarf`: Fixed a bug involving teleporting mothers but not the babies they're holding. +- `gaydar`: Fixed text display on OS X/Linux and failure with soul-less creatures +- `manipulator`: + + - allowed editing of non-dwarf citizens + - stopped ghosts and visitors from being editable + - fixed applying last custom profession + +- `modtools/create-unit`: Stopped making units without civs historical figures +- `modtools/force`: + + - Removed siege option + - Prevented a crash resulting from a bad civilization option + +- `showmood`: Fixed name display on OS X/Linux +- `view-item-info`: Fixed density units + +Misc Improvements +----------------- +- `autochop`: Can now edit log minimum/maximum directly and remove limit entirely +- `autolabor`, `autohauler`, `manipulator`: Added support for new jobs/labors/skills +- `colonies`: now implemented by a script +- `createitem`: Can now create items anywhere without specifying a unit, as long as a unit exists on the map +- `devel/export-dt-ini`: Updated for 0.42.06 +- `devel/find-offsets`: Automated several more scans +- `gui/gm-editor`: Now supports finding some items with a numeric ID (with ``i``) +- `lua`: Now supports some built-in variables like `gui/gm-editor`, e.g. ``unit``, ``screen`` +- `remotefortressreader`: Can now trigger keyboard events +- `stockflow`: Now offers better control over individual craft jobs +- `weather`: now implemented by a script +- `zone`: colored output + +Removed +------- +- DFusion: legacy script system, obsolete or replaced by better alternatives + + +DFHack 0.40.24-r5 +================= + +New Features +------------ +- `confirm`: + + - Added a ``uniform-delete`` option for military uniform deletion + - Added a basic in-game configuration UI + +Fixes +----- +- Fixed a rare crash that could result from running `keybinding` in onLoadWorld.init +- Script help that doesn't start with a space is now recognized correctly +- `confirm`: Fixed issues with haul-delete, route-delete, and squad-disband confirmations intercepting keys too aggressively +- `emigration` should work now +- `fix-unit-occupancy`: Significantly optimized - up to 2,000 times faster in large fortresses +- `gui/create-item`: Allow exiting quantity prompt +- `gui/family-affairs`: Fixed an issue where lack of relationships wasn't recognized and other issues +- `modtools/create-unit`: Fixed a possible issue in reclaim fortress mode +- `search-plugin`: Fixed a crash on the military screen +- `tweak` max-wheelbarrow: Fixed a minor display issue with large numbers +- `workflow`: Fixed a crash related to job postings (and added a fix for existing, broken jobs) + +Misc Improvements +----------------- +- Unrecognized command feedback now includes more information about plugins +- `fix/dry-buckets`: replaces the ``drybuckets`` plugin +- `feature`: now implemented by a script + +DFHack 0.40.24-r4 +================= + +Internals +--------- +- A method for caching screen output is now available to Lua (and C++) +- Developer plugins can be ignored on startup by setting the ``DFHACK_NO_DEV_PLUGINS`` environment variable +- The console on Linux and OS X now recognizes keyboard input between prompts +- JSON libraries available (C++ and Lua) +- More DFHack build information used in plugin version checks and available to plugins and lua scripts +- Fixed a rare overflow issue that could cause crashes on Linux and OS X +- Stopped DF window from receiving input when unfocused on OS X +- Fixed issues with keybindings involving :kbd:`Ctrl`:kbd:`A` and :kbd:`Ctrl`:kbd:`Z`, + as well as :kbd:`Alt`:kbd:`E`/:kbd:`U`/:kbd:`N` on OS X +- Multiple contexts can now be specified when adding keybindings +- Keybindings can now use :kbd:`F10`-:kbd:`F12` and :kbd:`0`-:kbd:`9` +- Plugin system is no longer restricted to plugins that exist on startup +- :file:`dfhack.init` file locations significantly generalized + +Lua +--- +- Scripts can be enabled with the built-in `enable`/`disable ` commands +- A new function, ``reqscript()``, is available as a safer alternative to ``script_environment()`` +- Lua viewscreens can choose not to intercept the OPTIONS keybinding + +New internal commands +--------------------- +- `kill-lua`: Interrupt running Lua scripts +- `type`: Show where a command is implemented + +New plugins +----------- +- `confirm`: Adds confirmation dialogs for several potentially dangerous actions +- `fix-unit-occupancy`: Fixes issues with unit occupancy, such as faulty "unit blocking tile" messages (:bug:`3499`) +- `title-version` (formerly ``vshook``): Display DFHack version on title screen + +New scripts +----------- +- `armoks-blessing`: Adjust all attributes, personality, age and skills of all dwarves in play +- `brainwash`: brainwash a dwarf (modifying their personality) +- `burial`: sets all unowned coffins to allow burial ("-pets" to allow pets too) +- `deteriorateclothes`: make worn clothes on the ground wear far faster to boost FPS +- `deterioratecorpses`: make body parts wear away far faster to boost FPS +- `deterioratefood`: make food vanish after a few months if not used +- `elevate-mental`: elevate all the mental attributes of a unit +- `elevate-physical`: elevate all the physical attributes of a unit +- `emigration`: stressed dwarves may leave your fortress if they see a chance +- `fix-ster`: changes fertility/sterility of animals or dwarves +- `gui/family-affairs`: investigate and alter romantic relationships +- `make-legendary`: modify skill(s) of a single unit +- `modtools/create-unit`: create new units from nothing +- `modtools/equip-item`: a script to equip items on units +- `points`: set number of points available at embark screen +- `pref-adjust`: Adjust all preferences of all dwarves in play +- `rejuvenate`: make any "old" dwarf 20 years old +- `starvingdead`: make undead weaken after one month on the map, and crumble after six +- `view-item-info`: adds information and customisable descriptions to item viewscreens +- `warn-starving`: check for starving, thirsty, or very drowsy units and pause with warning if any are found + +New tweaks +---------- +- embark-profile-name: Allows the use of lowercase letters when saving embark profiles +- kitchen-keys: Fixes DF kitchen meal keybindings +- kitchen-prefs-color: Changes color of enabled items to green in kitchen preferences +- kitchen-prefs-empty: Fixes a layout issue with empty kitchen tabs + +Fixes +----- +- Plugins with vmethod hooks can now be reloaded on OS X +- Lua's ``os.system()`` now works on OS X +- Fixed default arguments in Lua gametype detection functions +- Circular lua dependencies (reqscript/script_environment) fixed +- Prevented crash in ``Items::createItem()`` +- `buildingplan`: Now supports hatch covers +- `gui/create-item`: fixed assigning quality to items, made :kbd:`Esc` work properly +- `gui/gm-editor`: handles lua tables properly +- `help`: now recognizes built-in commands, like ``help`` +- `manipulator`: fixed crash when selecting custom professions when none are found +- `remotefortressreader`: fixed crash when attempting to send map info when no map was loaded +- `search-plugin`: fixed crash in unit list after cancelling a job; fixed crash when disabling stockpile category after searching in a subcategory +- `stockpiles`: now checks/sanitizes filenames when saving +- `stocks`: fixed a crash when right-clicking +- `steam-engine`: fixed a crash on arena load; number keys (e.g. 2/8) take priority over cursor keys when applicable +- tweak fps-min fixed +- tweak farm-plot-select: Stopped controls from appearing when plots weren't fully built +- `workflow`: Fixed some issues with stuck jobs. Existing stuck jobs must be cancelled and re-added +- `zone`: Fixed a crash when using ``zone set`` (and a few other potential crashes) + +Misc Improvements +----------------- +- DFHack documentation: + + - massively reorganised, into files of more readable size + - added many missing entries + - indexes, internal links, offline search all documents + - includes documentation of linked projects (df-structures, third-party scripts) + - better HTML generation with Sphinx + - documentation for scripts now located in source files + +- `autolabor`: + + - Stopped modification of labors that shouldn't be modified for brokers/diplomats + - Prioritize skilled dwarves more efficiently + - Prevent dwarves from running away with tools from previous jobs + +- `automaterial`: Fixed several issues with constructions being allowed/disallowed incorrectly when using box-select +- `dwarfmonitor`: + + - widgets' positions, formats, etc. are now customizable + - weather display now separated from the date display + - New mouse cursor widget + +- `gui/dfstatus`: Can enable/disable individual categories and customize metal bar list +- `full-heal`: ``-r`` option removes corpses +- `gui/gm-editor` + + - Pointers can now be displaced + - Added some useful aliases: "item" for the selected item, "screen" for the current screen, etc. + - Now avoids errors with unrecognized types + +- `gui/hack-wish`: renamed to `gui/create-item` +- `keybinding list ` accepts a context +- `lever`: + + - Lists lever names + - ``lever pull`` can be used to pull the currently-selected lever + +- ``memview``: Fixed display issue +- `modtools/create-item`: arguments are named more clearly, and you can specify the creator to be the unit with id ``df.global.unit_next_id-1`` (useful in conjunction with `modtools/create-unit`) +- ``nyan``: Can now be stopped with dfhack-run +- `plug`: lists all plugins; shows state and number of commands in plugins +- `prospect`: works from within command-prompt +- `quicksave`: Restricted to fortress mode +- `remotefortressreader`: Exposes more information +- `search-plugin`: + + - Supports noble suggestion screen (e.g. suggesting a baron) + - Supports fortress mode loo[k] menu + - Recognizes ? and ; keys + +- `stocks`: can now match beginning and end of item names +- `teleport`: Fixed cursor recognition +- `tidlers`, `twaterlvl`: now implemented by scripts instead of a plugin +- `tweak`: + + - debug output now logged to stderr.log instead of console - makes DFHack start faster + - farm-plot-select: Fixed issues with selecting undiscovered crops + +- `workflow`: Improved handling of plant reactions + +Removed +------- +- `embark-tools` nano: 1x1 embarks are now possible in vanilla 0.40.24 + +DFHack 0.40.24-r3 +================= + +Internals +--------- +- Ruby library now included on OS X - Ruby scripts should work on OS X 10.10 +- libstdc++ should work with older versions of OS X +- Added support for `onMapLoad.init / onMapUnload.init ` scripts +- game type detection functions are now available in the World module +- The ``DFHACK_LOG_MEM_RANGES`` environment variable can be used to log information to ``stderr.log`` on OS X +- Fixed adventure mode menu names +- Fixed command usage information for some commands + +Lua +--- +- Lua scripts will only be reloaded if necessary +- Added a ``df2console()`` wrapper, useful for printing DF (CP437-encoded) text to the console in a portable way +- Added a ``strerror()`` wrapper + +New Internal Commands +--------------------- +- `hide`, `show`: hide and show the console on Windows +- `sc-script`: Allows additional scripts to be run when certain events occur (similar to `onLoad.init` scripts) + +New Plugins +----------- +- `autohauler`: A hauling-only version of autolabor + +New Scripts +----------- +- `modtools/reaction-product-trigger`: triggers callbacks when products are produced (contrast with when reactions complete) + +New Tweaks +---------- +- `fps-min `: Fixes the in-game minimum FPS setting +- `shift-8-scroll `: Gives Shift+8 (or ``*``) priority when scrolling menus, instead of scrolling the map +- `tradereq-pet-gender `: Displays pet genders on the trade request screen + +Fixes +----- +- Fixed game type detection in `3dveins`, `gui/create-item`, `reveal`, `seedwatch` +- ``PRELOAD_LIB``: More extensible on Linux +- `add-spatter`, `eventful`: Fixed crash on world load +- `add-thought`: Now has a proper subthought arg. +- `building-hacks`: Made buildings produce/consume correct amount of power +- `fix-armory`: compiles and is available again (albeit with issues) +- `gui/gm-editor`: Added search option (accessible with "s") +- `hack-wish `: Made items stack properly. +- `modtools/skill-change`: Made level granularity work properly. +- `show-unit-syndromes`: should work +- `stockflow`: + + - Fixed error message in Arena mode + - no longer checks the DF version + - fixed ballistic arrow head orders + - convinces the bookkeeper to update records more often + +- `zone`: Stopped crash when scrolling cage owner list + +Misc Improvements +----------------- +- `autolabor`: A negative pool size can be specified to use the most unskilled dwarves +- `building-hacks`: + + - Added a way to allow building to work even if it consumes more power than is available. + - Added setPower/getPower functions. + +- `catsplosion`: Can now trigger pregnancies in (most) other creatures +- `exportlegends`: ``info`` and ``all`` options export ``legends_plus.xml`` with more data for legends utilities +- `manipulator`: + + - Added ability to edit nicknames/profession names + - added "Job" as a View Type, in addition to "Profession" and "Squad" + - added custom profession templates with masking + +- `remotefortressreader`: Exposes more information + + +DFHack 0.40.24-r2 +================= + +Internals +--------- +- Lua scripts can set environment variables of each other with ``dfhack.run_script_with_env`` +- Lua scripts can now call each others internal nonlocal functions with ``dfhack.script_environment(scriptName).functionName(arg1,arg2)`` +- `eventful`: Lua reactions no longer require LUA_HOOK as a prefix; you can register a callback for the completion of any reaction with a name +- Filesystem module now provides file access/modification times and can list directories (normally and recursively) +- Units Module: New functions:: + + isWar + isHunter + isAvailableForAdoption + isOwnCiv + isOwnRace + getRaceName + getRaceNamePlural + getRaceBabyName + getRaceChildName + isBaby + isChild + isAdult + isEggLayer + isGrazer + isMilkable + isTrainableWar + isTrainableHunting + isTamable + isMale + isFemale + isMerchant + isForest + isMarkedForSlaughter + +- Buildings Module: New Functions:: + + isActivityZone + isPenPasture + isPitPond + isActive + findPenPitAt + +Fixes +----- +- ``dfhack.run_script`` should correctly find save-specific scripts now. +- `add-thought`: updated to properly affect stress. +- `hfs-pit`: should work now +- `autobutcher`: takes gelding into account +- :file:`init.lua` existence checks should be more reliable (notably when using non-English locales) + +Misc Improvements +----------------- +Multiline commands are now possible inside dfhack.init scripts. See :file:`dfhack.init-example` for example usage. + + +DFHack 0.40.24-r1 +================= + +Internals +--------- +CMake shouldn't cache DFHACK_RELEASE anymore. People may need to manually update/delete their CMake cache files to get rid of it. + + +DFHack 0.40.24-r0 +================= + +Internals +--------- +- `EventManager`: fixed crash error with EQUIPMENT_CHANGE event. +- key modifier state exposed to Lua (ie :kbd:`Ctrl`, :kbd:`Alt`, :kbd:`Shift`) + +Fixes +----- +``dfhack.sh`` can now be run from other directories on OS X + +New Plugins +----------- +- `blueprint`: export part of your fortress to quickfort .csv files + +New Scripts +----------- +- `hotkey-notes`: print key, name, and jump position of hotkeys + +Removed +------- +- needs_porting/* + +Misc Improvements +----------------- +- Added support for searching more lists + +DFHack 0.40.23-r1 +================= + +Internals +--------- +- plugins will not be loaded if globals they specify as required are not located (should prevent some crashes) + +Fixes +----- +- Fixed numerous (mostly Lua-related) crashes on OS X by including a more up-to-date libstdc++ +- :kbd:`Alt` should no longer get stuck on Windows (and perhaps other platforms as well) +- `gui/advfort` works again +- `autobutcher`: takes sexualities into account +- devel/export-dt-ini: Updated for 0.40.20+ +- `digfort`: now checks file type and existence +- `exportlegends`: Fixed map export +- `full-heal`: Fixed a problem with selecting units in the GUI +- `gui/hack-wish`: Fixed restrictive material filters +- `mousequery`: Changed box-select key to Alt+M +- `dwarfmonitor`: correct date display (month index, separator) +- `putontable`: added to the readme +- `siren` should work again +- stderr.log: removed excessive debug output on OS X +- `trackstop`: No longer prevents cancelling the removal of a track stop or roller. +- Fixed a display issue with ``PRINT_MODE:TEXT`` +- Fixed a symbol error (MapExtras::BiomeInfo::MAX_LAYERS) when compiling DFHack in Debug mode + +New Plugins +----------- +- `fortplan`: designate construction of (limited) buildings from .csv file, quickfort-style + +New Scripts +----------- +- `gui/stockpiles`: an in-game interface for saving and loading stockpile settings files. +- `position`: Reports the current date, time, month, and season, plus some location info. Port/update of position.py +- `hfs-pit`: Digs a hole to hell under the cursor. Replaces needs_porting/hellhole.cpp + +Removed +------- +- embark.lua: Obsolete, use `embark-tools` + +New tweaks +---------- +- `eggs-fertile `: Displays an egg fertility indicator on nestboxes +- `max-wheelbarrow `: Allows assigning more than 3 wheelbarrows to a stockpile + +Misc Improvements +----------------- +- `embark-tools`: Added basic mouse support on the local map +- Made some adventure mode keybindings in :file:`dfhack.init-example` only work in adventure mode +- `gui/companion-order`: added a default keybinding +- further work on needs_porting + + +DFHack 0.40.19-r1 +================= + +Fixes +----- +- `modtools/reaction-trigger`: fixed typo +- `modtools/item-trigger`: should now work with item types + +New plugins +----------- +- `savestock, loadstock `: save and load stockpile settings across worlds and saves + +New scripts +----------- +- `remove-stress`: set selected or all units unit to -1,000,000 stress (this script replaces removebadthoughts) + +Misc improvements +----------------- +- `command-prompt`: can now access selected items, units, and buildings +- `autolabor`: add an optional talent pool parameter + + +DFHack 0.40.16-r1 +================= + +Internals +--------- +- `EventManager` should handle INTERACTION triggers a little better. It still can get confused about who did what but only rarely. +- `EventManager` should no longer trigger REPORT events for old reports after loading a save. +- lua/persist-table: a convenient way of using persistent tables of arbitrary structure and dimension in Lua + +Fixes +----- +- `mousequery`: Disabled when linking levers +- `stocks`: Melting should work now +- `full-heal`: Updated with proper argument handling +- `modtools/reaction-trigger-transition`: should produce the correct syntax now +- `superdwarf`: should work better now +- `forum-dwarves`: update for new df-structures changes + +New Scripts +----------- +- `adaptation`: view or set the cavern adaptation level of your citizens +- `add-thought`: allows the user to add thoughts to creatures. +- `gaydar`: detect the sexual orientation of units on the map +- `markdown`: Save a copy of a text screen in markdown (for reddit among others). +- devel/all-bob: renames everyone Bob to help test interaction-trigger + +Misc Improvements +----------------- +- `autodump`: Can now mark a stockpile for auto-dumping (similar to `automelt` and `autotrade`) +- `buildingplan`: Can now auto-allocate rooms to dwarves with specific positions (e.g. expedition leader, mayor) +- `dwarfmonitor`: now displays a weather indicator and date +- lua/syndrome-util, `modtools/add-syndrome`: now you can remove syndromes by SYN_CLASS +- No longer write empty :file:`.history` files + + +DFHack 0.40.15-r1 +================= + +Fixes +----- +- mousequery: Fixed behavior when selecting a tile on the lowest z-level + +Misc Improvements +----------------- +- `EventManager`: deals with frame_counter getting reset properly now. +- `modtools/item-trigger`: fixed equip/unequip bug and corrected minor documentation error +- `teleport`: Updated with proper argument handling and proper unit-at-destination handling. +- `autotrade`: Removed the newly obsolete :guilabel:`Mark all` functionality. +- `search-plugin`: Adapts to the new trade screen column width +- `tweak fast-trade `: Switching the fast-trade keybinding to Shift-Up/Shift-Down, due to Select All conflict + + +DFHack 0.40.14-r1 +================= + +Internals +--------- +- The DFHack console can now be disabled by setting the DFHACK_DISABLE_CONSOLE environment variable: ``DFHACK_DISABLE_CONSOLE=1 ./dfhack`` + +Fixes +----- +- Stopped duplicate load/unload events when unloading a world +- Stopped ``-e`` from being echoed when DFHack quits on Linux +- `automelt`: now uses a faster method to locate items +- `autotrade`: "Mark all" no longer double-marks bin contents +- `drain-aquifer`: new script replaces the buggy plugin +- `embark-tools`: no longer conflicts with keys on the notes screen +- `fastdwarf`: Fixed problems with combat/attacks +- `forum-dwarves`: should work now +- `manipulator`: now uses a stable sort, allowing sorting by multiple categories +- `rendermax`: updated to work with 0.40 + +New Plugins +----------- +- `trackstop`: Shows track stop friction and dump direction in its :kbd:`q` menu + +New Tweaks +---------- +- farm-plot-select: Adds "Select all" and "Deselect all" options to farm plot menus +- import-priority-category: Allows changing the priority of all goods in a category when discussing an import agreement with the liaison +- manager-quantity: Removes the limit of 30 jobs per manager order +- civ-view-agreement: Fixes overlapping text on the "view agreement" screen +- nestbox-color: Fixes the color of built nestboxes + +Misc Improvements +----------------- +- `exportlegends`: can now handle site maps + + +DFHack 0.40.13-r1 +================= + +Internals +--------- +- unified spatter structs +- added ruby df.print_color(color, string) method for dfhack console + +Fixes +----- +- no more ``-e`` after terminating +- fixed `superdwarf` + + +DFHack 0.40.12-r1 +================= + +Internals +--------- +- support for global `onLoad.init` and `onUnload.init` files, called when loading and unloading a world +- Close file after loading a `binary patch `. + +New Plugins +----------- +- `hotkeys`: Shows in-game viewscreen with all dfhack keybindings active in current mode. +- `automelt`: allows marking stockpiles so any items placed in them will be designated for melting + +Fixes +----- +- possible crash fixed for `gui/hack-wish` +- `search-plugin`: updated to not conflict with BUILDJOB_SUSPEND +- `workflow`: job_material_category -> dfhack_material_category + +Misc Improvements +----------------- +- now you can use ``@`` to print things in interactive Lua with subtly different semantics +- optimizations for stockpiles for `autotrade` and `stockflow` +- updated `exportlegends` to work with new maps, dfhack 40.11 r1+ + + +DFHack 0.40.11-r1 +================= + +Internals +--------- +- Plugins on OS X now use ``.plug.dylib`` as an extension instead of ``.plug.so`` + +Fixes +----- +- `3dveins`: should no longer hang/crash on specific maps +- `autotrade`, `search-plugin`: fixed some layout issues +- `deathcause`: updated +- `gui/hack-wish`: should work now +- `reveal`: no longer allocates data for nonexistent map blocks +- Various documentation fixes and updates + + +DFHack v0.40.10-r1 +================== + +A few bugfixes. + +DFHack v0.40.08-r2 +================== + +Internals +--------- +- supported per save script folders +- Items module: added createItem function +- Sorted CMakeList for plugins and plugins/devel +- `diggingInvaders` no longer builds if plugin building is disabled +- `EventManager`: EQUIPMENT_CHANGE now triggers for new units. New events:: + + ON_REPORT + UNIT_ATTACK + UNLOAD + INTERACTION + +New Scripts +----------- +- lua/repeat-util: makes it easier to make things repeat indefinitely +- lua/syndrome-util: makes it easier to deal with unit syndromes +- `forum-dwarves`: helps copy df viewscreens to a file +- `full-heal`: fully heal a unit +- `remove-wear`: removes wear from all items in the fort +- `repeat`: repeatedly calls a script or a plugin +- ShowUnitSyndromes: shows syndromes affecting units and other relevant info +- `teleport`: teleports units +- `devel/print-args` +- `fix/blood-del`: makes it so civs don't bring barrels full of blood ichor or goo +- `fix/feeding-timers`: reset the feeding timers of all units +- `gui/hack-wish`: creates items out of any material +- `gui/unit-info-viewer`: displays information about units +- `modtools/add-syndrome`: add a syndrome to a unit or remove one +- `modtools/anonymous-script`: execute an lua script defined by a string. Useful for the ``*-trigger`` scripts. +- `modtools/force`: forces events: caravan, migrants, diplomat, megabeast, curiousbeast, mischievousbeast, flier, siege, nightcreature +- `modtools/item-trigger`: triggers commands based on equipping, unequipping, and wounding units with items +- `modtools/interaction-trigger`: triggers commands when interactions happen +- `modtools/invader-item-destroyer`: destroys invaders' items when they die +- `modtools/moddable-gods`: standardized version of Putnam's moddable gods script +- `modtools/projectile-trigger`: standardized version of projectileExpansion +- `modtools/reaction-trigger`: trigger commands when custom reactions complete; replaces autoSyndrome +- `modtools/reaction-trigger-transition`: a tool for converting mods from autoSyndrome to reaction-trigger +- `modtools/random-trigger`: triggers random scripts that you register +- `modtools/skill-change`: for incrementing and setting skills +- `modtools/spawn-flow`: creates flows, like mist or dragonfire +- `modtools/syndrome-trigger`: trigger commands when syndromes happen +- `modtools/transform-unit`: shapeshifts a unit, possibly permanently + +Misc improvements +----------------- +- new function in utils.lua for standardized argument processing + +Removed +------- +- digmat.rb: digFlood does the same functionality with less FPS impact +- invasionNow: `modtools/force` does it better +- autoSyndrome replaced with `modtools/reaction-trigger` +- syndromeTrigger replaced with `modtools/syndrome-trigger` +- devel/printArgs plugin converted to `devel/print-args` +- outsideOnly plugin replaced by `modtools/outside-only` + + +DFHack v0.40.08-r1 +================== + +Was a mistake. Don't use it. + +DFHack v0.34.11-r5 +================== + +Internals +--------- +- support for calling a lua function via a protobuf request (demonstrated by dfhack-run --lua). +- support for basic filesystem operations (e.g. chdir, mkdir, rmdir, stat) in C++ and Lua +- Lua API for listing files in directory. Needed for `gui/mod-manager` +- Lua API for creating unit combat reports and writing to gamelog. +- Lua API for running arbitrary DFHack commands +- support for multiple ``raw/init.d/*.lua`` init scripts in one save. +- eventful now has a more friendly way of making custom sidebars +- on Linux and OS X the console now supports moving the cursor back and forward by a whole word. + +New scripts +----------- +- `gui/mod-manager`: allows installing/uninstalling mods into df from ``df/mods`` directory. +- `gui/clone-uniform`: duplicates the currently selected uniform in the military screen. +- `fix/build-location`: partial work-around for :bug:`5991` (trying to build wall while standing on it) +- `undump-buildings`: removes dump designation from materials used in buildings. +- `exportlegends`: exports data from legends mode, allowing a set-and-forget export of large worlds. +- log-region: each time a fort is loaded identifying information will be written to the gamelog. +- `dfstatus `: show an overview of critical stock quantities, including food, drinks, wood, and bars. +- `command-prompt`: a dfhack command prompt in df. + +New plugins +----------- +- `rendermax`: replace the renderer with something else, eg ``rendermax light``- a lighting engine +- `automelt`: allows marking stockpiles for automelt (i.e. any items placed in stockpile will be designated for melting) +- `embark-tools`: implementations of Embark Anywhere, Nano Embark, and a few other embark-related utilities +- `building-hacks`: Allows to add custom functionality and/or animations to buildings. +- `petcapRemover`: triggers pregnancies in creatures so that you can effectively raise the default pet population cap +- `plant create `: spawn a new shrub under the cursor + +New tweaks +---------- +- craft-age-wear: make crafted items wear out with time like in old versions (:bug:`6003`) +- adamantine-cloth-wear: stop adamantine clothing from wearing out (:bug:`6481`) +- confirm-embark: adds a prompt before embarking (on the "prepare carefully" screen) + +Misc improvements +----------------- +- `plant`: move the 'grow', 'extirpate' and 'immolate' commands as 'plant' subcommands +- `digfort`: improved csv parsing, add start() comment handling +- `exterminate`: allow specifying a caste (exterminate gob:male) +- `createitem`: in adventure mode it now defaults to the controlled unit as maker. +- `autotrade`: adds "(Un)mark All" options to both panes of trade screen. +- `mousequery`: several usability improvements; show live overlay (in menu area) of what's on the tile under the mouse cursor. +- `search-plugin`: workshop profile search added. +- `dwarfmonitor`: add screen to summarise preferences of fortress dwarfs. +- `getplants`: add autochop function to automate woodcutting. +- `stocks`: added more filtering and display options. + +- `siege-engine`: + + - engine quality and distance to target now affect accuracy + - firing the siege engine at a target produces a combat report + - improved movement speed computation for meandering units + - operators in Prepare To Fire mode are released from duty once hungry/thirsty if there is a free replacement + + +DFHack v0.34.11-r4 +================== + +New commands +------------ +- `diggingInvaders` - allows invaders to dig and/or deconstruct walls and buildings in order to get at your dwarves. +- `digFlood` - automatically dig out specified veins as they are revealed +- `enable, disable ` - Built-in commands that can be used to enable/disable many plugins. +- `restrictice` - Restrict traffic on squares above visible ice. +- `restrictliquids` - Restrict traffic on every visible square with liquid. +- treefarm - automatically chop trees and dig obsidian + +New Scripts +----------- +- `autobutcher`: A GUI front-end for the autobutcher plugin. +- invasionNow: trigger an invasion, or many +- `locate-ore`: scan the map for unmined ore veins +- `masspit`: designate caged creatures in a zone for pitting +- `multicmd`: run a sequence of dfhack commands, separated by ';' +- `startdwarf`: change the number of dwarves for a new embark +- digmat: dig veins/layers tile by tile, as discovered + +Misc improvements +----------------- +- autoSyndrome: + + - disable by default + - reorganized special tags + - minimized error spam + - reset policies: if the target already has an instance of the syndrome you can skip, + add another instance, reset the timer, or add the full duration to the time remaining + +- core: fix SC_WORLD_(UN)LOADED event for arena mode +- `exterminate`: renamed from slayrace, add help message, add butcher mode +- `fastdwarf`: fixed bug involving fastdwarf and teledwarf being on at the same time +- magmasource: rename to `source`, allow water/magma sources/drains +- Add df.dfhack_run "somecommand" to Ruby +- syndromeTrigger: replaces and extends trueTransformation. Can trigger things when syndromes are added for any reason. +- `tiletypes`: support changing tile material to arbitrary stone. +- `workNow`: can optionally look for jobs when jobs are completed + +New tweaks +---------- +- hive-crash: Prevent crash if bees die in a hive with ungathered products (:bug:`6368`). + +New plugins +----------- +- `3dveins`: Reshapes all veins on the map in a way that flows between Z levels. May be unstable. Backup before using. +- `autotrade`: Automatically send items in marked stockpiles to trade depot, when trading is possible. +- `buildingplan`: Place furniture before it's built +- `dwarfmonitor`: Records dwarf activity to measure fort efficiency +- `mousequery`: Look and poke at the map elements with the mouse. +- outsideOnly: make raw-specified buildings impossible to build inside +- `resume`: A plugin to help display and resume suspended constructions conveniently +- `stocks`: An improved stocks display screen. + +Internals +--------- +- Core: there is now a per-save dfhack.init file for when the save is loaded, and another for when it is unloaded +- EventManager: fixed job completion detection, fixed removal of TICK events, added EQUIPMENT_CHANGE event +- Lua API for a better `random number generator ` and perlin noise functions. +- Once: easy way to make sure something happens once per run of DF, such as an error message + + +DFHack v0.34.11-r3 +================== + +Internals +--------- +- support for displaying active keybindings properly. +- support for reusable widgets in lua screen library. +- Maps::canStepBetween: returns whether you can walk between two tiles in one step. +- EventManager: monitors various in game events centrally so that individual plugins + don't have to monitor the same things redundantly. +- Now works with OS X 10.6.8 + +Notable bugfixes +---------------- +- `autobutcher` can be re-enabled again after being stopped. +- stopped `Dwarf Manipulator ` from unmasking vampires. +- `stonesense` is now fixed on OS X + +Misc improvements +----------------- +- `fastdwarf`: new mode using debug flags, and some internal consistency fixes. +- added a small stand-alone utility for applying and removing `binary patches `. +- removebadthoughts: add --dry-run option +- `superdwarf`: work in adventure mode too +- `tweak` stable-cursor: carries cursor location from/to Build menu. +- `deathcause`: allow selection from the unitlist screen +- slayrace: allow targeting undeads +- `workflow` plugin: + + - properly considers minecarts assigned to routes busy. + - code for deducing job outputs rewritten in lua for flexibility. + - logic fix: collecting webs produces silk, and ungathered webs are not thread. + - items assigned to squads are considered busy, even if not in inventory. + - shearing and milking jobs are supported, but only with generic MILK or YARN outputs. + - workflow announces when the stock level gets very low once a season. + +- Auto syndrome plugin: A way of automatically applying boiling rock syndromes and calling dfhack commands controlled by raws. +- `infiniteSky` plugin: Create new z-levels automatically or on request. +- True transformation plugin: A better way of doing permanent transformations that allows later transformations. +- `workNow` plugin: Makes the game assign jobs every time you pause. + +New tweaks +---------- +- tweak military-training: speed up melee squad training up to 10x (normally 3-5x). + +New scripts +----------- +- `binpatch`: the same as the stand-alone binpatch.exe, but works at runtime. +- region-pops: displays animal populations of the region and allows tweaking them. +- `lua`: lua interpreter front-end converted to a script from a native command. +- dfusion: misc scripts with a text based menu. +- embark: lets you embark anywhere. +- `lever`: list and pull fort levers from the dfhack console. +- `stripcaged`: mark items inside cages for dumping, eg caged goblin weapons. +- soundsense-season: writes the correct season to gamelog.txt on world load. +- create-items: spawn items +- fix/cloth-stockpile: fixes :bug:`5739`; needs to be run after savegame load every time. + +New GUI scripts +--------------- +- `gui/guide-path`: displays the cached path for minecart Guide orders. +- `gui/workshop-job`: displays inputs of a workshop job and allows tweaking them. +- `gui/workflow`: a front-end for the workflow plugin (part inspired by falconne). +- `gui/assign-rack`: works together with a binary patch to fix weapon racks. +- `gui/gm-editor`: an universal editor for lots of dfhack things. +- `gui/companion-order`: a adventure mode command interface for your companions. +- `gui/advfort`: a way to do jobs with your adventurer (e.g. build fort). + +New binary patches +------------------ +(for use with `binpatch`) + +- armorstand-capacity: doubles the capacity of armor stands. +- custom-reagent-size: lets custom reactions use small amounts of inputs. +- deconstruct-heapfall: stops some items still falling on head when deconstructing. +- deconstruct-teleport: stops items from 16x16 block teleporting when deconstructing. +- hospital-overstocking: stops hospital overstocking with supplies. +- training-ammo: lets dwarves with quiver full of combat-only ammo train. +- weaponrack-unassign: fixes bug that negates work done by gui/assign-rack. + +New Plugins +----------- +- `fix-armory`: Together with a couple of binary patches and the `gui/assign-rack` script, this plugin makes weapon racks, armor stands, chests and cabinets in properly designated barracks be used again for storage of squad equipment. +- `search-plugin`: Adds an incremental search function to the Stocks, Trading, Stockpile and Unit List screens. +- `automaterial`: Makes building constructions (walls, floors, fortifications, etc) a little bit easier by saving you from having to trawl through long lists of materials each time you place one. +- Dfusion: Reworked to make use of lua modules, now all the scripts can be used from other scripts. +- Eventful: A collection of lua events, that will allow new ways to interact with df world. + +DFHack v0.34.11-r2 +================== + +Internals +--------- +- full support for Mac OS X. +- a plugin that adds scripting in `ruby `. +- support for interposing virtual methods in DF from C++ plugins. +- support for creating new interface screens from C++ and lua. +- added various other API functions. + +Notable bugfixes +---------------- +- better terminal reset after exit on linux. +- `seedwatch` now works on reclaim. +- the sort plugin won't crash on cages anymore. + +Misc improvements +----------------- +- `autodump`: can move items to any walkable tile, not just floors. +- `stripcaged`: by default keep armor, new dumparmor option. +- `zone`: allow non-domesticated birds in nestboxes. +- `workflow`: quality range in constraints. +- cleanplants: new command to remove rain water from plants. +- `liquids`: can paint permaflow, i.e. what makes rivers power water wheels. +- `prospect`: pre-embark prospector accounts for caves & magma sea in its estimate. +- `rename`: supports renaming stockpiles, workshops, traps, siege engines. +- `fastdwarf`: now has an additional option to make dwarves teleport to their destination. +- `autolabor`: + + - can set nonidle hauler percentage. + - broker excluded from all labors when needed at depot. + - likewise, anybody with a scheduled diplomat meeting. + +New commands +------------ +- misery: multiplies every negative thought gained (2x by default). +- `digtype`: designates every tile of the same type of vein on the map for 'digging' (any dig designation). + +New tweaks +---------- +- tweak stable-cursor: keeps exact cursor position between d/k/t/q/v etc menus. +- tweak patrol-duty: makes Train orders reduce patrol timer, like the binary patch does. +- tweak readable-build-plate: fix unreadable truncation in unit pressure plate build ui. +- tweak stable-temp: fixes bug 6012; may improve FPS by 50-100% on a slow item-heavy fort. +- tweak fast-heat: speeds up item heating & cooling, thus making stable-temp act faster. +- tweak fix-dimensions: fixes subtracting small amounts from stacked liquids etc. +- tweak advmode-contained: fixes UI bug in custom reactions with container inputs in advmode. +- tweak fast-trade: Shift-Enter for selecting items quickly in Trade and Move to Depot screens. +- tweak military-stable-assign: Stop rightmost list of military->Positions from jumping to top. +- tweak military-color-assigned: In same list, color already assigned units in brown & green. + +New scripts +----------- +- `fixnaked`: removes thoughts about nakedness. +- `setfps`: set FPS cap at runtime, in case you want slow motion or speed-up. +- `siren`: wakes up units, stops breaks and parties - but causes bad thoughts. +- `fix/population-cap`: run after every migrant wave to prevent exceeding the cap. +- `fix/stable-temp`: counts items with temperature updates; does instant one-shot stable-temp. +- `fix/loyaltycascade`: fix units allegiance, eg after ordering a dwarf merchant kill. +- `deathcause`: shows the circumstances of death for a given body. +- `digfort`: designate areas to dig from a csv file. +- `drain-aquifer`: remove aquifers from the map. +- `growcrops`: cheat to make farm crops instantly grow. +- magmasource: continuously spawn magma from any map tile. +- removebadthoughts: delete all negative thoughts from your dwarves. +- slayrace: instakill all units of a given race, optionally with magma. +- `superdwarf`: per-creature `fastdwarf`. +- `gui/mechanisms`: browse mechanism links of the current building. +- `gui/room-list`: browse other rooms owned by the unit when assigning one. +- `gui/liquids`: a GUI front-end for the liquids plugin. +- `gui/rename`: renaming stockpiles, workshops and units via an in-game dialog. +- `gui/power-meter`: front-end for the Power Meter plugin. +- `gui/siege-engine`: front-end for the Siege Engine plugin. +- `gui/choose-weapons`: auto-choose matching weapons in the military equip screen. + +New Plugins +----------- +- `manipulator`: a Dwarf Therapist like UI in the game (:kbd:`u`:kbd:`l`) +- `steam-engine`: an alternative to Water Reactors which make more sense. + See ``hack/raw/*_steam_engine.txt`` for the necessary raw definitions. +- `power-meter`: a pressure plate modification to detect powered gear + boxes on adjacent tiles. `gui/power-meter` implements + the build configuration UI. +- `siege-engine`: massive overhaul for siege engines, configured via `gui/siege-engine` +- `add-spatter`: allows poison coatings via raw reactions, among other things. diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst new file mode 100644 index 0000000000..bf3d0118df --- /dev/null +++ b/docs/about/Removed.rst @@ -0,0 +1,406 @@ +############# +Removed tools +############# + +This page lists tools (plugins or scripts) that were previously included in +DFHack but have been removed. It exists primarily so that internal links still +work (e.g. links from the `changelog`). + +.. contents:: Contents + :local: + :depth: 1 + +.. _adv-rumors: + +adv-rumors +========== +Converted to an `overlay` and merged into `advtools`. + +.. _adv-fix-sleepers: + +adv-fix-sleepers +================ +Renamed to `fix/sleepers`. + +.. _autohauler: + +autohauler +========== +An automated labor management tool that only addressed hauling labors, leaving the assignment +of skilled labors entirely up to the player. Fundamentally incompatible with the work detail +system of labor management in v50 of Dwarf Fortress. + +.. _automaterial: + +automaterial +============ +Moved frequently used materials to the top of the materials list when building +buildings. Also offered extended options when building constructions. All +functionality has been merged into `buildingplan`. + +.. _automelt: + +automelt +======== +Automatically mark items for melting when they are brought to a monitored +stockpile. Merged into `logistics`. + +.. _autotrade: + +autotrade +========= +Automatically mark items for trading when they are brought to a monitored +stockpile. Merged into `logistics`. + +.. _autounsuspend: + +autounsuspend +============= +Replaced by `suspendmanager`. + +.. _combine-drinks: + +combine-drinks +============== +Replaced by the new `combine` script. Run +``combine here --types=drink`` + +.. _combine-plants: + +combine-plants +============== +Replaced by the new `combine` script. Run +``combine here --types=plants`` + +.. _command-prompt: + +command-prompt +============== +Replaced by `gui/launcher --minimal `. + +.. _create-items: + +create-items +============ +Replaced by `gui/create-item`. + +.. _deteriorateclothes: + +deteriorateclothes +================== +Replaced by the new combined `deteriorate` script. Run +``deteriorate --types=clothes``. + +.. _deterioratecorpses: + +deterioratecorpses +================== +Replaced by the new combined `deteriorate` script. Run +``deteriorate --types=corpses``. + +.. _deterioratefood: + +deterioratefood +=============== +Replaced by the new combined `deteriorate` script. Run +``deteriorate --types=food``. + +.. _devel/find-offsets: + +devel/find-offsets +================== +Used in pre-v50 times for memory structure analysis. No longer useful post-v50. + +.. _devel/find-twbt: + +devel/find-twbt +=============== +Used in pre-v50 times for memory structure analysis. No longer useful post-v50. + +.. _devel/prepare-save: + +devel/prepare-save +================== +Used in pre-v50 times for memory structure analysis. No longer useful post-v50. + +.. _devel/unforbidall: + +devel/unforbidall +================= +Replaced by the `unforbid` script. Run ``unforbid all --quiet`` to match the +behavior of the original ``devel/unforbidall`` script. + +.. _digfort: + +digfort +======= +A script to designate an area for digging according to a plan in csv format. +Please use DFHack's more powerful `quickfort` script instead. You can use your +existing .csv files. Just move them to the ``blueprints`` folder in your DF +installation, and instead of ``digfort file.csv``, run +``quickfort run file.csv``. + +.. _drain-aquifer: + +drain-aquifer +============= +Replaced by `aquifer` and `gui/aquifer`. + +.. _embark-tools: + +embark-tools +============ +Replaced by `gui/embark-anywhere`. Other functionality was replaced by the DF +v50 UI. + +.. _faststart: + +faststart +========= +Sped up the initial DF load sequence. Removed since Bay 12 rewrote the startup +sequence and it is now sufficiently fast on its own. + +.. _fix-armory: + +fix-armory +========== +Allowed the military to store equipment in barracks containers. Removed because +it required a binary patch to DF in order to function, and no such patch has +existed since DF 0.34.11. + +.. _fix/build-location: + +fix/build-location +================== +The corresponding DF :bug:`5991` was fixed in DF 0.40.05. + +.. _fix/diplomats: + +fix/diplomats +============= +The corresponding DF :bug:`3295` was fixed in DF 0.40.05. + +.. _fix/fat-dwarves: + +fix/fat-dwarves +=============== +The corresponding DF :bug:`5971` was fixed in DF 0.40.05. + +.. _fix/feeding-timers: + +fix/feeding-timers +================== +The corresponding DF :bug:`2606` was fixed in DF 0.40.12. + +.. _fix/item-occupancy: + +fix/item-occupancy +================== +Merged into `fix/occupancy`. + +.. _fix/merchants: + +fix/merchants +============= +Humans can now make trade agreements. This fix is no longer necessary. + +.. _fix/tile-occupancy: + +fix/tile-occupancy +================== +Merged into `fix/occupancy`. + +.. _fix-unit-occupancy: + +fix-unit-occupancy +================== +Merged into `fix/occupancy`. + +.. _fortplan: + +fortplan +======== +Designates furniture for building according to a ``.csv`` file with +quickfort-style syntax. Please use DFHack's more powerful `quickfort` +script instead. You can use your existing .csv files. Just move them to the +``blueprints`` folder in your DF installation, and instead of +``fortplan file.csv`` run ``quickfort run file.csv``. + +.. _gui/assign-rack: + +gui/assign-rack +=============== +This script is no longer useful in current DF versions. The script required a +binpatch `, which has not been available since DF +0.34.11. + +.. _gui/automelt: + +gui/automelt +============ +Replaced by the `stockpiles` overlay and the gui for `logistics`. + +.. _gui/create-tree: + +gui/create-tree +=============== +Replaced by `gui/sandbox`. + +.. _gui/dig: + +gui/dig +======= +Renamed to `gui/design`. + +.. _gui/hack-wish: + +gui/hack-wish +============= +Replaced by `gui/create-item`. + +.. _gui/logcleaner: + +gui/logcleaner +============== +Removed because changes to Dwarf Fortress internals made the functionality +impossible to implement safely. + +.. _gui/manager-quantity: + +gui/manager-quantity +==================== +Ability to modify manager order quantities has been added to the vanilla UI. + +.. _gui/mechanisms: + +gui/mechanisms +============== +Linked building interface has been added to the vanilla UI. + +.. _gui/no-dfhack-init: + +gui/no-dfhack-init +================== +Tool that warned the user when the ``dfhack.init`` file did not exist. Now that +``dfhack.init`` is autogenerated in ``dfhack-config/init``, this warning is no +longer necessary. + +.. _logcleaner: + +logcleaner +=============== +Removed because changes to Dwarf Fortress internals made the functionality +impossible to implement safely. + +.. _masspit: + +masspit +======= +Replaced with a GUI version: `gui/masspit`. + +.. _max-wave: + +max-wave +======== +Set population cap based on parameters. Merged into `pop-control`. + +.. _modtools/force: + +modtools/force +============== +Merged into `force`. + +.. _mousequery: + +mousequery +========== +Functionality superseded by vanilla v50 interface. + +.. _petcapRemover: + +petcapRemover +============= +Renamed to `pet-uncapper`. + +.. _plants: + +plants +====== +Renamed to `plant`. + +.. _rename: + +rename +====== +Superseded by vanilla rename capabilities and `gui/rename`. + +.. _resume: + +resume +====== +Allowed you to resume suspended jobs and displayed an overlay indicating +suspended building construction jobs. Replaced by `unsuspend` script. + +.. _ruby: +.. _rb: + +ruby +==== +Support for the Ruby language in DFHack scripts was removed due to the issues +the Ruby library causes when used as an embedded language. + +.. _search-plugin: + +search +====== +Functionality was merged into `sort`. + +.. _show-unit-syndromes: + +show-unit-syndromes +=================== +Replaced with a GUI version: `gui/unit-syndromes`. + +.. _stocksettings: + +stocksettings +============= +Along with ``copystock``, ``loadstock`` and ``savestock``, replaced with the new +`stockpiles` API. + +.. _title-version: + +title-version +============= +Replaced with an `overlay`. + +.. _unsuspend: + +unsuspend +========= +Merged into `suspendmanager`. + +.. _warn-starving: + +warn-starving +============= +Functionality was merged into `gui/notify`. + +.. _warn-stealers: + +warn-stealers +============= +Functionality was merged into `gui/notify`. + +.. _warn-stuck-trees: + +warn-stuck-trees +================ +The corresponding DF :bug:`9252` was fixed in DF 0.44.01. + +.. _workorder-recheck: + +workorder-recheck +================= +Tool to set 'Checking' status of the selected work order, allowing conditions +to be reevaluated. Merged into `orders`. diff --git a/docs/index-about.rst b/docs/about/index.rst similarity index 77% rename from docs/index-about.rst rename to docs/about/index.rst index 3dba1e5f85..e8dede969c 100644 --- a/docs/index-about.rst +++ b/docs/about/index.rst @@ -7,7 +7,7 @@ These pages contain information about the general DFHack project. .. toctree:: :maxdepth: 1 - /docs/NEWS - /docs/Authors + /docs/about/Authors /LICENSE - /docs/Removed + /docs/about/Removed + /docs/NEWS diff --git a/docs/api/Maps.rst b/docs/api/Maps.rst index cfffe79059..f6a0a98826 100644 --- a/docs/api/Maps.rst +++ b/docs/api/Maps.rst @@ -7,7 +7,7 @@ Maps API DFHack offers several ways to access and manipulate map data. * C++: the ``Maps`` and ``MapCache`` modules -* Lua: the `dfhack.maps module `_ +* Lua: the `dfhack.maps module` * All languages: the ``map`` field of the ``world`` global contains raw map data when the world is loaded. diff --git a/docs/api/index.rst b/docs/api/index.rst index 1fe03e9a82..e0748be2c5 100644 --- a/docs/api/index.rst +++ b/docs/api/index.rst @@ -1,6 +1,6 @@ -==================== -DFHack API Reference -==================== +=================== +DFHack API concepts +=================== .. toctree:: :maxdepth: 1 diff --git a/docs/build-pdf.sh b/docs/build-pdf.sh deleted file mode 100755 index 76908b49b3..0000000000 --- a/docs/build-pdf.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -# usage: -# ./build-pdf.sh -# SPHINX=/path/to/sphinx-build ./build-pdf.sh -# JOBS=3 ./build-pdf.sh ... -# all command-line arguments are passed directly to sphinx-build - run -# ``sphinx-build --help`` for a list, or see -# https://www.sphinx-doc.org/en/master/man/sphinx-build.html - -cd $(dirname "$0") -cd .. - -sphinx=sphinx-build -if [ -n "$SPHINX" ]; then - sphinx=$SPHINX -fi - -if [ -z "$JOBS" ]; then - JOBS=2 -fi - -"$sphinx" -M latexpdf . ./docs/pdf -w ./docs/_sphinx-warnings.txt -j "$JOBS" "$@" diff --git a/docs/build.py b/docs/build.py new file mode 100755 index 0000000000..bf0dd9e488 --- /dev/null +++ b/docs/build.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 + +# for help, run: python3 build.py --help + +import argparse +import os +import subprocess +import sys + +class SphinxOutputFormat: + def __init__(self, name, pre_args): + self.name = str(name) + self.pre_args = tuple(pre_args) + + @property + def args(self): + output_dir = os.path.join('docs', self.name) + artifacts_dir = os.path.join('build', 'docs', self.name) # for artifacts not part of the final documentation + os.makedirs(artifacts_dir, mode=0o755, exist_ok=True) + return [ + *self.pre_args, + '.', # source dir + output_dir, + '-d', artifacts_dir, + '-w', os.path.join(artifacts_dir, 'sphinx-warnings.txt'), + ] + +OUTPUT_FORMATS = { + 'html': SphinxOutputFormat('html', pre_args=['-b', 'html']), + 'text': SphinxOutputFormat('text', pre_args=['-b', 'text']), + 'pdf': SphinxOutputFormat('pdf', pre_args=['-M', 'latexpdf']), + 'xml': SphinxOutputFormat('xml', pre_args=['-b', 'xml']), + 'pseudoxml': SphinxOutputFormat('pseudoxml', pre_args=['-b', 'pseudoxml']), +} + +def _parse_known_args(parser, source_args): + # pass along any arguments after '--' + ignored_args = [] + if '--' in source_args: + source_args, ignored_args = source_args[:source_args.index('--')], source_args[source_args.index('--')+1:] + args, forward_args = parser.parse_known_args(source_args) + forward_args += ignored_args + return args, forward_args + +def parse_args(source_args): + def output_format(s): + if s in OUTPUT_FORMATS: + return s + raise ValueError + + parser = argparse.ArgumentParser(usage='%(prog)s [{} ...] [options] [--] [sphinx_options]'.format('|'.join(OUTPUT_FORMATS.keys())), description=''' + DFHack wrapper around sphinx-build. + + Any unrecognized options are passed directly to sphinx-build, as well as any + options following a '--' argument, if specified. + ''') + parser.add_argument('format', nargs='*', type=output_format, action='append', + help='Documentation format(s) to build - choose from {}'.format(', '.join(OUTPUT_FORMATS.keys()))) + parser.add_argument('-E', '--clean', action='store_true', + help='Re-read all input files') + parser.add_argument('--sphinx', type=str, default=os.environ.get('SPHINX', 'sphinx-build'), + help='Sphinx executable to run [environment variable: SPHINX; default: "sphinx-build"]') + parser.add_argument('-j', '--jobs', type=str, default=os.environ.get('JOBS', 'auto'), + help='Number of Sphinx threads to run [environment variable: JOBS; default: "auto"]') + parser.add_argument('-q', '--quiet', action='store_true', + help='Disable most output on stdout (also passed to sphinx-build)') + parser.add_argument('--debug', action='store_true', + help='Log commands that are run, etc.') + parser.add_argument('--offline', action='store_true', + help='Disable network connections') + args, forward_args = _parse_known_args(parser, source_args) + + # work around weirdness with list args + args.format = args.format[0] + if not args.format: + args.format = ['html'] + + return args, forward_args + +if __name__ == '__main__': + os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + if not os.path.isfile('conf.py'): + print('Could not find conf.py', file=sys.stderr) + exit(1) + + args, forward_args = parse_args(sys.argv[1:]) + + sphinx_env = os.environ.copy() + if args.offline: + sphinx_env['DFHACK_DOCS_BUILD_OFFLINE'] = '1' + + for format_name in args.format: + command = [args.sphinx] + OUTPUT_FORMATS[format_name].args + ['-j', args.jobs] + if args.clean: + command += ['-E'] + if args.quiet: + command += ['-q'] + command += forward_args + + if args.debug: + print('Building:', format_name) + print('Running:', command) + subprocess.run(command, check=True, env=sphinx_env) + + if not args.quiet: + print('') diff --git a/docs/build.sh b/docs/build.sh deleted file mode 100755 index 95a97e5399..0000000000 --- a/docs/build.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -# usage: -# ./build.sh -# SPHINX=/path/to/sphinx-build ./build.sh -# JOBS=3 ./build.sh ... -# all command-line arguments are passed directly to sphinx-build - run -# ``sphinx-build --help`` for a list, or see -# https://www.sphinx-doc.org/en/master/man/sphinx-build.html - -cd $(dirname "$0") -cd .. - -sphinx=sphinx-build -if [ -n "$SPHINX" ]; then - sphinx=$SPHINX -fi - -if [ -z "$JOBS" ]; then - JOBS=2 -fi - -"$sphinx" -a -b html . ./docs/html -w ./docs/_sphinx-warnings.txt -j "$JOBS" "$@" diff --git a/docs/builtins/alias.rst b/docs/builtins/alias.rst new file mode 100644 index 0000000000..69ca42ba0d --- /dev/null +++ b/docs/builtins/alias.rst @@ -0,0 +1,36 @@ +alias +===== + +.. dfhack-tool:: + :summary: Configure helper aliases for other DFHack commands. + :tags: dfhack + +Aliases are resolved immediately after built-in commands, which means that an +alias cannot override a built-in command, but can override a command implemented +by a plugin or script. + +Usage +----- + +``alias list`` + Lists all configured aliases +``alias add [arguments...]`` + Adds an alias +``alias replace [arguments...]`` + Replaces an existing alias with a new command, or adds the alias if it does + not already exist +``alias delete `` + Removes the specified alias + +Aliases can be given additional arguments when created and invoked, which will +be passed to the underlying command in order. + +Example +------- + +:: + + [DFHack]# alias add pargs devel/print-args example + [DFHack]# pargs text + example + text diff --git a/docs/builtins/cls.rst b/docs/builtins/cls.rst new file mode 100644 index 0000000000..a5fc391cdd --- /dev/null +++ b/docs/builtins/cls.rst @@ -0,0 +1,16 @@ +cls +=== + +.. dfhack-tool:: + :summary: Clear the terminal screen. + :tags: dfhack + +Can also be invoked as ``clear``. Note that this command does not delete command +history. It just clears the text on the screen. + +Usage +----- + +:: + + cls diff --git a/docs/builtins/devel/dump-rpc.rst b/docs/builtins/devel/dump-rpc.rst new file mode 100644 index 0000000000..957233b628 --- /dev/null +++ b/docs/builtins/devel/dump-rpc.rst @@ -0,0 +1,15 @@ +devel/dump-rpc +============== + +.. dfhack-tool:: + :summary: Dump RPC endpoint info. + :tags: dev + +Write RPC endpoint information to the specified file. + +Usage +----- + +:: + + devel/dump-rpc diff --git a/docs/builtins/die.rst b/docs/builtins/die.rst new file mode 100644 index 0000000000..3b9a083802 --- /dev/null +++ b/docs/builtins/die.rst @@ -0,0 +1,15 @@ +die +=== + +.. dfhack-tool:: + :summary: Instantly exit DF without saving. + :tags: dfhack + +Use to exit DF quickly and safely. + +Usage +----- + +:: + + die diff --git a/docs/builtins/disable.rst b/docs/builtins/disable.rst new file mode 100644 index 0000000000..7c64f4b39e --- /dev/null +++ b/docs/builtins/disable.rst @@ -0,0 +1,15 @@ +disable +======= + +.. dfhack-tool:: + :summary: Deactivate a DFHack tool that has some persistent effect. + :tags: dfhack + +See the `enable` command for more info. + +Usage +----- + +:: + + disable [ ...] diff --git a/docs/builtins/enable.rst b/docs/builtins/enable.rst new file mode 100644 index 0000000000..8525214b3c --- /dev/null +++ b/docs/builtins/enable.rst @@ -0,0 +1,36 @@ +enable +====== + +.. dfhack-tool:: + :summary: Activate a DFHack tool that has some persistent effect. + :tags: dfhack + +Many plugins and scripts can be in a distinct enabled or disabled state. Some +of them activate and deactivate automatically depending on the contents of the +world raws. Others store their state in world data. However a number of them +have to be enabled globally, and the init file is the right place to do it. + +Most such plugins or scripts support the built-in ``enable`` and `disable` +commands. Calling them at any time without arguments prints a list of enabled +and disabled plugins, and shows whether that can be changed through the same +commands. Passing plugin names to these commands will enable or disable the +specified plugins. + +If you are a script developer, see `script-enable-api` for how to expose whether +your script is currently enabled or disabled. + +Usage +----- + +:: + + enable + enable [ ...] + +Examples +-------- + +``enable manipulator`` + Enable the ``manipulator`` plugin. +``enable manipulator search`` + Enable multiple plugins at once. diff --git a/docs/builtins/fpause.rst b/docs/builtins/fpause.rst new file mode 100644 index 0000000000..ed5a40cad1 --- /dev/null +++ b/docs/builtins/fpause.rst @@ -0,0 +1,15 @@ +fpause +====== + +.. dfhack-tool:: + :summary: Forces DF to pause. + :tags: dfhack + +This is useful when your FPS drops below 1 and you lose control of the game. + +Usage +----- + +:: + + fpause diff --git a/docs/builtins/help.rst b/docs/builtins/help.rst new file mode 100644 index 0000000000..a744e8d69c --- /dev/null +++ b/docs/builtins/help.rst @@ -0,0 +1,29 @@ +help +==== + +.. dfhack-tool:: + :summary: Display help about a command or plugin. + :tags: dfhack + +Can also be invoked as ``?`` or ``man`` (short for "manual"). + +Usage +----- + +:: + + help|?|man + help|?|man + +Examples +-------- + +:: + + help blueprint + man blueprint + +Both examples above will display the help text for the `blueprint` command. + +Some commands also take ``help`` or ``?`` as an option on their command line +for the same effect -- e.g. ``blueprint help``. diff --git a/docs/builtins/hide.rst b/docs/builtins/hide.rst new file mode 100644 index 0000000000..037679d69c --- /dev/null +++ b/docs/builtins/hide.rst @@ -0,0 +1,18 @@ +hide +==== + +.. dfhack-tool:: + :summary: Hide the DFHack terminal window. + :tags: dfhack + +You can show it again with the `show` command, though you'll need to use it from +a `keybinding` set beforehand or the in-game `command-prompt`. + +Only available on Windows. + +Usage +----- + +:: + + hide diff --git a/docs/builtins/keybinding.rst b/docs/builtins/keybinding.rst new file mode 100644 index 0000000000..e8f206848d --- /dev/null +++ b/docs/builtins/keybinding.rst @@ -0,0 +1,84 @@ +keybinding +========== + +.. dfhack-tool:: + :summary: Create hotkeys that will run DFHack commands. + :tags: dfhack + +Like any other command, it can be used at any time from the console, but +bindings are not remembered between runs of the game unless re-created in +:file:`dfhack-config/init/dfhack.init`. + +Hotkeys can be any combinations of Ctrl/Alt/Super/Shift with any key recognized by SDL. +You can also represent mouse buttons beyond the first three with ``MOUSE4`` +through ``MOUSE15``. + +Usage +----- + +``keybinding`` + Show some useful information, including the current game context. +``keybinding list `` + List bindings active for the key combination. +``keybinding clear [...]`` + Remove bindings for the specified keys. +``keybinding add "" ["" ...]`` + Add bindings for the specified key. +``keybinding set "" ["" ...]`` + Clear, and then add bindings for the specified key. + +The ```` parameter above has the following case-insensitive syntax:: + + [Ctrl-][Alt-][Super-][Shift-]KEY[@context[|context...]] + +where the ``KEY`` part can be any recognized key and :kbd:`[`:kbd:`]` denote +optional parts. It is important to note that the key is the non-shifted version +of the key. For example ``!`` would be defined as ``Shift-0``. + +DFHack commands can advertise the contexts in which they can be usefully run. +For example, a command that acts on a selected unit can tell `keybinding` that +it is not "applicable" in the current context if a unit is not actively +selected. + +When multiple commands are bound to the same key combination, DFHack selects +the first applicable one. Later ``add`` commands, and earlier entries within one +``add`` command have priority. Commands that are not specifically intended for +use as a hotkey are always considered applicable. + +The ``context`` part in the key specifier above can be used to explicitly +restrict the UI state where the binding would be applicable. + +Only bindings with a ``context`` tag that either matches the current context +fully, or is a prefix ending at a ``/`` boundary would be considered for +execution, i.e. when in context ``foo/bar/baz``, keybindings restricted to any +of ``@foo/bar/baz``, ``@foo/bar``, ``@foo``, or none will be active. + +Multiple contexts can be specified by separating them with a pipe (``|``) - for +example, ``@foo|bar|baz/foo`` would match anything under ``@foo``, ``@bar``, or +``@baz/foo``. + +Commands like `liquids` or `tiletypes` cannot be used as hotkeys since they +require the console for interactive input. + +Examples +-------- + +Bind Ctrl-Shift-C to run the `hotkeys` command on any screen at any time:: + + keybinding add Ctrl-Shift-C hotkeys + +Bind Ctrl-M to run `gui/mass-remove`, but only when on the main map with +nothing else selected:: + + keybinding add Ctrl-M@dwarfmode/Default gui/mass-remove + +Bind the fourth mouse button to launch `gui/teleport` when a unit is selected +or `gui/autodump` when an item is selected:: + + keybinding add MOUSE4@dwarfmode/ViewSheets/UNIT gui/teleport + keybinding add MOUSE4@dwarfmode/ViewSheets/ITEM gui/autodump + +Bind Shift + the fifth mouse button to toggle the keyboard cursor in fort or +adventure mode:: + + keybinding add Shift-MOUSE5@dwarfmode|dungeonmode toggle-kbd-cursor diff --git a/docs/builtins/kill-lua.rst b/docs/builtins/kill-lua.rst new file mode 100644 index 0000000000..4cb3e203c4 --- /dev/null +++ b/docs/builtins/kill-lua.rst @@ -0,0 +1,18 @@ +kill-lua +======== + +.. dfhack-tool:: + :summary: Gracefully stop any currently-running Lua scripts. + :tags: dfhack + +Use this command to stop a misbehaving script that appears to be stuck. + +Usage +----- + +:: + + kill-lua + kill-lua force + +Use ``kill-lua force`` if just ``kill-lua`` doesn't seem to work. diff --git a/docs/builtins/load.rst b/docs/builtins/load.rst new file mode 100644 index 0000000000..a913162625 --- /dev/null +++ b/docs/builtins/load.rst @@ -0,0 +1,19 @@ +load +==== + +.. dfhack-tool:: + :summary: Load and register a plugin library. + :tags: dfhack + +Also see `unload` and `reload` for related actions. + +Usage +----- + +:: + + load [ ...] + load -a|--all + +You can load individual named plugins or all plugins at once. Note that plugins +are disabled after loading/reloading until you explicitly `enable` them. diff --git a/docs/builtins/ls.rst b/docs/builtins/ls.rst new file mode 100644 index 0000000000..cd6bc41261 --- /dev/null +++ b/docs/builtins/ls.rst @@ -0,0 +1,44 @@ +ls +== + +.. dfhack-tool:: + :summary: List available DFHack commands. + :tags: dfhack + +In order to group related commands, each command is associated with a list of +tags. You can filter the listed commands by a tag or a substring of the +command name. Can also be invoked as ``dir``. + +Usage +----- + +``ls []`` + Lists all available commands and the tags associated with them. +``ls []`` + Shows only commands that have the given tag. Use the `tags` command to see + the list of available tags. +``ls []`` + Shows commands that include the given string. E.g. ``ls quick`` will show + all the commands with "quick" in their names. If the string is also the + name of a tag, then it will be interpreted as a tag name. + +Examples +-------- + +``ls quick`` + List all commands that match the substring "quick". +``ls adventure`` + List all commands with the ``adventure`` tag. +``ls --dev trigger`` + List all commands, including developer and modding commands, that match the + substring "trigger". + +Options +------- + +``--notags`` + Don't print out the tags associated with each command. +``--dev`` + Include commands intended for developers and modders. +``--exclude [,...]`` + Exclude commands that match any of the given strings. diff --git a/docs/builtins/plug.rst b/docs/builtins/plug.rst new file mode 100644 index 0000000000..8df378d3c8 --- /dev/null +++ b/docs/builtins/plug.rst @@ -0,0 +1,16 @@ +plug +==== + +.. dfhack-tool:: + :summary: List available plugins and whether they are enabled. + :tags: dfhack + +Usage +----- + +:: + + plug [ [ ...]] + +If run with parameters, it lists only the named plugins. Otherwise it will list +all available plugins. diff --git a/docs/builtins/reload.rst b/docs/builtins/reload.rst new file mode 100644 index 0000000000..9ee9061a2b --- /dev/null +++ b/docs/builtins/reload.rst @@ -0,0 +1,21 @@ +reload +====== + +.. dfhack-tool:: + :summary: Reload a loaded plugin. + :tags: dfhack + +Developers use this command to reload a plugin that they are actively modifying. +Also see `load` and `unload` for related actions. + +Usage +----- + +:: + + reload [ ...] + reload -a|--all + +You can reload individual named plugins or all plugins at once. Note that +plugins are disabled after loading/reloading until you explicitly `enable` +them. diff --git a/docs/builtins/sc-script.rst b/docs/builtins/sc-script.rst new file mode 100644 index 0000000000..f66aeb412c --- /dev/null +++ b/docs/builtins/sc-script.rst @@ -0,0 +1,26 @@ +sc-script +========= + +.. dfhack-tool:: + :summary: Run commands when game state changes occur. + :tags: dfhack + +This is similar to the static `init-files` but is slightly more flexible since +it can be set dynamically. + +Usage +----- + +``sc-script [help]`` + Show the list of valid event names. +``sc-script list []`` + List the currently registered files for all events or the specified event. +``sc-script add|remove [ ...]`` + Register or unregister a file to be run for the specified event. + +Example +------- + +``sc-script add SC_MAP_LOADED spawn_extra_monsters.init`` + Registers the ``spawn_extra_monsters.init`` file to be run whenever a new + map is loaded. diff --git a/docs/builtins/script.rst b/docs/builtins/script.rst new file mode 100644 index 0000000000..0c4ca8c3d5 --- /dev/null +++ b/docs/builtins/script.rst @@ -0,0 +1,26 @@ +script +====== + +.. dfhack-tool:: + :summary: Execute a batch file of DFHack commands. + :tags: dfhack + +It reads a text file and runs each line as a DFHack command as if it had been +typed in by the user -- treating the input like `an init file `. + +Some other tools, such as `autobutcher` and `workflow`, export their settings as +the commands to create them - which can later be reloaded with ``script``. + +Usage +----- + +:: + + script + +Example +------- + +``script startup.txt`` + Executes the commands in ``startup.txt``, which exists in your DF game + directory. diff --git a/docs/builtins/show.rst b/docs/builtins/show.rst new file mode 100644 index 0000000000..cbfa3a386d --- /dev/null +++ b/docs/builtins/show.rst @@ -0,0 +1,19 @@ +show +==== + +.. dfhack-tool:: + :summary: Unhides the DFHack terminal window. + :tags: dfhack + +Useful if you have hidden the terminal with `hide` and you want it back. Since +the terminal window won't be available to run this command, you'll need to use +it from a `keybinding` set beforehand or the in-game `command-prompt`. + +Only available on Windows. + +Usage +----- + +:: + + show diff --git a/docs/builtins/tags.rst b/docs/builtins/tags.rst new file mode 100644 index 0000000000..698323ffe6 --- /dev/null +++ b/docs/builtins/tags.rst @@ -0,0 +1,26 @@ +tags +==== + +.. dfhack-tool:: + :summary: List the categories of DFHack tools or the tools with those tags. + :tags: dfhack + +DFHack tools are labeled with tags so you can find groups of related commands. +This builtin command lists the tags that you can explore, or, if called with the +name of a tag, lists the tools that have that tag. + +Usage +----- + +``tags`` + List the categories of DFHack tools and a description of those categories. +``tags `` + List the tools that are tagged with the given tag. + +Examples +-------- + +``tags`` + List the defined tags. +``tags design`` + List all the tools that have the ``design`` tag. diff --git a/docs/builtins/type.rst b/docs/builtins/type.rst new file mode 100644 index 0000000000..1bf86e588c --- /dev/null +++ b/docs/builtins/type.rst @@ -0,0 +1,17 @@ +type +==== + +.. dfhack-tool:: + :summary: Describe how a command is implemented. + :tags: dfhack + +DFHack commands can be provided by plugins, scripts, or by the core library +itself. The ``type`` command can tell you which is the source of a particular +command. + +Usage +----- + +:: + + type diff --git a/docs/builtins/unload.rst b/docs/builtins/unload.rst new file mode 100644 index 0000000000..6fa52ea9e0 --- /dev/null +++ b/docs/builtins/unload.rst @@ -0,0 +1,18 @@ +unload +====== + +.. dfhack-tool:: + :summary: Unload a plugin from memory. + :tags: dfhack + +Also see `load` and `reload` for related actions. + +Usage +----- + +:: + + unload [ ...] + unload -a|--all + +You can unload individual named plugins or all plugins at once. diff --git a/docs/changelog.txt b/docs/changelog.txt index 256fe12cb7..904fcc86fb 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -1,1325 +1,2310 @@ === Scroll down for changes ===[[[ -The text below is included in docs/Documentation.rst - see that file for more details on the changelog setup. -This is kept in this file as a quick syntax reference. +For information on how to edit/build the changelogs, see `docs/html/docs/dev/Documentation.html` or `docs/dev/Documentation.rst`. -===help +The text between the `syntax-reference` markers is included in `docs/dev/Documentation.rst`, so it must be valid RST. +It is kept in this file as a quick syntax reference. -changelog.txt uses a syntax similar to RST, with a few special sequences: +===syntax-reference-start + +The changelogs use a syntax similar to RST, with a few special sequences: - ``===`` indicates the start of a comment - ``#`` indicates the start of a release name (do not include "DFHack") -- ``##`` indicates the start of a section name (this must be listed in ``gen_changelog.py``) +- ``##`` indicates the start of a section name (which must be listed in ``docs/sphinx_extensions/dfhack/changelog.py``) - ``-`` indicates the start of a changelog entry. **Note:** an entry currently must be only one line. -- ``:`` (colon followed by space) separates the name of a feature from a description of a change to that feature. - Changes made to the same feature are grouped if they end up in the same section. -- ``:\`` (colon, backslash, space) avoids the above behavior -- ``- @`` (the space is optional) indicates the start of an entry that should only be displayed in NEWS-dev.rst. - Use this sparingly, e.g. for immediate fixes to one development build in another development build that - are not of interest to users of stable builds only. +- ``:`` (followed by space) separates the name of a feature from a description of a change to that feature. + - Changes made to the same feature are grouped if they end up in the same section. +- ``:\`` (followed by space) avoids the above behavior +- ``- @`` (the space is optional) indicates the start of an entry that should only be displayed in ``NEWS-dev.rst``. + - Use this sparingly, e.g. for immediate fixes to one development build in another development build that + are not of interest to users of stable builds only. - Three ``[`` characters indicate the start of a block (possibly a comment) that spans multiple lines. Three ``]`` characters indicate the end of such a block. -- ``!`` immediately before a phrase set up to be replaced (see gen_changelog.py) stops that occurrence from being replaced. +- ``!`` immediately before a configured replacement (see ``docs/sphinx_extensions/dfhack/changelog.py``) stops that occurrence from being replaced. + +===syntax-reference-end + +Template for new versions: + +## New Tools + +## New Features + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed -===end ]]] ================================================================================ -======== IMPORTANT: rename this, and add a new "future" section, BEFORE ======== +======== IMPORTANT: rename this, and add a new "Future" section, BEFORE ======== ======== making a new DFHack release, even if the only changes made ======== ======== were in submodules with their own changelogs! ======== ================================================================================ # Future +## New Tools + +## New Features + ## Fixes -- `blueprint`: fixed passing incorrect parameters to `gui/blueprint` when you run ``blueprint gui`` with optional params -- `blueprint`: key sequences for constructed walls and down stairs are now correct -- `tailor`: fixed some inconsistencies (and possible crashes) when parsing certain subcommands, e.g. ``tailor help`` ## Misc Improvements -- `automaterial`: ensure construction tiles are laid down in order when using `buildingplan` to plan the constructions -- `blueprint`: all blueprint phases are now written to a single file, using `quickfort` multi-blueprint file syntax. to get the old behavior of each phase in its own file, pass the ``--splitby=phase`` parameter to ``blueprint`` -- `blueprint`: you can now specify the position where the cursor should be when the blueprint is played back with `quickfort` by passing the ``--playback-start`` parameter -- `blueprint`: generated blueprints now have labels so `quickfort` can address them by name -- `blueprint`: all building types are now supported -- `blueprint`: multi-type stockpiles are now supported -- `blueprint`: non-rectangular stockpiles and buildings are now supported -- `blueprint`: blueprints are no longer generated for phases that have nothing to do (unless those phases are explicitly enabled on the commandline or gui) -- `blueprint`: new "track" phase that discovers and records carved tracks -- `blueprint`: new "zone" phase that discovers and records activity zones, including custom configuration for ponds, gathering, and hospitals -- `dig-now`: no longer leaves behind a designated tile when a tile was designated beneath a tile designated for channeling -- `quickfort`, `dfhack-examples-guide`: Dreamfort blueprint set improvements based on playtesting and feedback. includes updated profession definitions. + +## Documentation + +## API ## Lua -- ``argparse.processArgsGetopt()``: you can now have long form parameters that are not an alias for a short form parameter. For example, you can now have a parameter like ``--longparam`` without needing to have an equivalent one-letter ``-l`` param. -- ``dwarfmode.enterSidebarMode()``: ``df.ui_sidebar_mode.DesignateMine`` is now a suported target sidebar mode -# 0.47.05-r3 +## Removed + +# 53.16-r1.1 -## New Plugins -- `dig-now`: instantly completes dig designations (including smoothing and carving tracks) +## New Tools + +## New Features ## Fixes -- Core: ``alt`` keydown state is now cleared when DF loses and regains focus, ensuring the ``alt`` modifier state is not stuck on for systems that don't send standard keyup events in response to ``alt-tab`` window manager events -- Lua: ``memscan.field_offset()``: fixed an issue causing `devel/export-dt-ini` to crash sometimes, especially on Windows -- `autofarm`: autofarm will now count plant growths as well as plants toward its thresholds -- `autogems`: no longer assigns gem cutting jobs to workshops with gem cutting prohibited in the workshop profile +- `stockpiles` will no longer incorrectly size the "rough gem" and "cut gem" vectors, which avoids a crash when viewing stockpile settings. This potentially affects anything that uses blueprints to create a stockpile, including `gui/quantum` ## Misc Improvements -- `buildingplan`: now displays which items are attached and which items are still missing for planned buildings -- `orders`: support importing and exporting reaction-specific item conditions, like "lye-containing" for soap production orders -- `orders`: new ``sort`` command. sorts orders according to their repeat frequency. this prevents daily orders from blocking other orders for simlar items from ever getting completed. -- `tiletypes-here`, `tiletypes-here-point`: add ``--cursor`` and ``--quiet`` options to support non-interactive use cases -- `quickfort`: Dreamfort blueprint set improvements: extensive revision based on playtesting and feedback. includes updated ``onMapLoad_dreamfort.init`` settings file, enhanced automation orders, and premade profession definitions. see full changelog at https://github.com/DFHack/dfhack/pull/1921 and https://github.com/DFHack/dfhack/pull/1925 -- `tailor`: allow user to specify which materials to be used, and in what order + +## Documentation ## API -- The ``Items`` module ``moveTo*`` and ``remove`` functions now handle projectiles ## Lua -- new global function: ``safe_pairs(iterable[, iterator_fn])`` will iterate over the ``iterable`` (a table or iterable userdata) with the ``iterator_fn`` (``pairs`` if not otherwise specified) if iteration is possible. If iteration is not possible or would throw an error, for example if ``nil`` is passed as the ``iterable``, the iteration is just silently skipped. -## Documentation -- `quickfort-library-guide`: updated dreamfort documentation and added screenshots -- `dfhack-examples-guide`: documentation for all of `dreamfort`'s supporting files (useful for all forts, not just Dreamfort!) - -# 0.47.05-r2 - -## Fixes -- Fixed an issue where scrollable text in Lua-based screens could prevent other widgets from scrolling -- Fixed an issue preventing some external scripts from creating zones and other abstract buildings (see note about room definitions under "Internals") -- `buildingplan`: fixed an issue where planned constructions designated with DF's sizing keys (``umkh``) would sometimes be larger than requested -- `buildingplan`: fixed an issue preventing other plugins like `automaterial` from planning constructions if the "enable all" buildingplan setting was turned on -- `buildingplan`: made navigation keys work properly in the materials selection screen when alternate keybindings are used -- `command-prompt`: fixed issues where overlays created by running certain commands (e.g. `gui/liquids`, `gui/teleport`) would not update the parent screen correctly -- `dwarfvet`: fixed a crash that could occur with hospitals overlapping with other buildings in certain ways -- `orders`: fixed crash when importing orders with malformed IDs -- ``quickfortress.csv`` blueprint: fixed refuse stockpile config and prevented stockpiles from covering stairways -- `stonesense`: fixed a crash that could occur when ctrl+scrolling or closing the Stonesense window -- `embark-assistant`: fixed faulty early exit in first search attempt when searching for waterfalls - -## Misc Improvements -- Added adjectives to item selection dialogs, used in tools like `gui/create-item` - this makes it possible to differentiate between different types of high/low boots, shields, etc. (some of which are procedurally generated) -- `blueprint`: made ``depth`` and ``name`` parameters optional. ``depth`` now defaults to ``1`` (current level only) and ``name`` defaults to "blueprint" -- `blueprint`: ``depth`` can now be negative, which will result in the blueprints being written from the highest z-level to the lowest. Before, blueprints were always written from the lowest z-level to the highest. -- `blueprint`: added the ``--cursor`` option to set the starting coordinate for the generated blueprints. A game cursor is no longer necessary if this option is used. -- `quickfort`: the Dreamfort blueprint set can now be comfortably built in a 1x1 embark -- `stonesense`: sped up startup time -- `tweak` hide-priority: changed so that priorities stay hidden (or visible) when exiting and re-entering the designations menu -- `embark-assistant`: slightly improved performance of surveying and improved code a little - -## Lua -- new string utility functions: - - ``string:wrap(width)`` wraps a string at space-separated word boundaries - - ``string:trim()`` removes whitespace characters from the beginning and end of the string - - ``string:split(delimiter, plain)`` splits a string with the given delimiter and returns a table of substrings. if ``plain`` is specified and set to ``true``, ``delimiter`` is interpreted as a literal string instead of as a pattern (the default) -- new library: ``argparse`` is a collection of commandline argument processing functions -- ``gui.Painter``: fixed error when calling ``viewport()`` method -- ``gui.dwarfmode``: new function: ``enterSidebarMode(sidebar_mode, max_esc)`` which uses keypresses to get into the specified sidebar mode from whatever the current screen is -- `reveal`: now exposes ``unhideFlood(pos)`` functionality to Lua -- new utility function: ``utils.normalizePath()``: normalizes directory slashes across platoforms to ``/`` and coaleses adjacent directory separators -- ``argparse.processArgsGetopt()`` (previously ``utils.processArgsGetopt()``): - - now returns negative numbers (e.g. ``-10``) in the list of positional parameters instead of treating it as an option string equivalent to ``-1 -0`` - - now properly handles ``--`` like GNU ``getopt`` as a marker to treat all further parameters as non-options - - now detects when required arguments to long-form options are missing -- `xlsxreader`: added Lua class wrappers for the xlsxreader plugin API - -## API -- Added ``dfhack.units.teleport(unit, pos)`` -- Added ``dfhack.maps.getPlantAtTile(x, y, z)`` and ``dfhack.maps.getPlantAtTile(pos)``, and updated ``dfhack.gui.getSelectedPlant()`` to use it +## Removed -## Documentation -- Added more client library implementations to the `remote interface docs ` +# 53.16-r1 -## Internals -- The DFHack test harness is now much easier to use for iterative development. Configuration can now be specified on the commandline, there are more test filter options, and the test harness can now easily rerun tests that have been run before. -- The ``test/main`` command to invoke the test harness has been renamed to just ``test`` -- Unit tests must now match any output expected to be printed via ``dfhack.printerr()`` -- Unit tests now support fortress mode (allowing tests that require a fortress map to be loaded) - note that these tests are skipped by continuous integration for now, pending a suitable test fortress -- Unit tests can now use ``delay_until(predicate_fn, timeout_frames)`` to delay until a condition is met -- Room definitions and extents are now created for abstract buildings so callers don't have to initialize the room structure themselves +## New Tools -# 0.47.05-r1 +## New Features ## Fixes -- `confirm`: stopped exposing alternate names when convicting units -- `prospector`: improved pre embark rough estimates, particularly for small clusters +- ``TextArea`` widget corrected to use ``COLOR_BLACK`` instead of ``COLOR_RESET`` as default background color ## Misc Improvements -- `autohauler`: allowed the ``Alchemist`` labor to be enabled in `manipulator` and other labor screens so it can be used for its intended purpose of flagging that no hauling labors should be assigned to a dwarf. Before, the only way to set the flag was to use an external program like Dwarf Therapist. -- `embark-assistant`: slightly improved performance of surveying -- `quickfort`: Dreamfort blueprint set improvements: `significant `_ refinements across the entire blueprint set. Dreamfort is now much faster, much more efficient, and much easier to use. The `checklist `__ now includes a mini-walkthrough for quick reference. The spreadsheet now also includes `embark profile suggestions `__ -- `quickfort`: added aliases for configuring masterwork and artifact core quality for all stockpile categories that have them; made it possible to take from multiple stockpiles in the ``quantumstop`` alias +- a safety check was added to ``Screen::doSetTile_char`` for out of bound pen color values ## Documentation -- `fortplan`: added deprecation warnings - fortplan has been replaced by `quickfort` -# 0.47.05-beta1 +## API -## Fixes -- `embark-assistant`: fixed bug in soil depth determination for ocean tiles -- `orders`: don't crash when importing orders with malformed JSON +## Lua -# 0.47.04-r5 +## Removed + +# 53.15-r3 + +## New Tools + +## New Features ## Fixes -- `embark-assistant`: fixed order of factors when calculating min temperature -- `embark-assistant`: improved performance of surveying -- `quickfort`: fixed eventual crashes when creating zones -- `quickfort`: fixed library aliases for tallow and iron, copper, and steel weapons -- `seedwatch`: fixed an issue where the plugin would disable itself on map load -- `search`: fixed crash when searching the ``k`` sidebar and navigating to another tile with certain keys, like ``<`` or ``>`` -- `stockflow`: fixed ``j`` character being intercepted when naming stockpiles -- `stockpiles`: no longer outputs hotkey help text beneath `stockflow` hotkey help text +- `buildingplan`: restore planner UI elements: hollow constructions, only engraved slabs, only empty cages, weapon count ## Misc Improvements -- Lua label widgets (used in all standard message boxes) are now scrollable with Up/Down/PgUp/PgDn keys -- `autofarm`: now fallows farms if all plants have reached the desired count -- `buildingplan`: added ability to set global settings from the console, e.g. ``buildingplan set boulders false`` -- `buildingplan`: added "enable all" option for buildingplan (so you don't have to enable all building types individually). This setting is not persisted (just like quickfort_mode is not persisted), but it can be set from onMapLoad.init -- `buildingplan`: modified ``Planning Mode`` status in the UI to show whether the plugin is in quickfort mode, "enable all" mode, or whether just the building type is enabled. -- `quickfort`: Dreamfort blueprint set improvements: added a streamlined checklist for all required dreamfort commands and gave names to stockpiles, levers, bridges, and zones -- `quickfort`: added aliases for bronze weapons and armor -- `quickfort`: added alias for tradeable crafts +- `EventManager`: add safety check to potentially avoid a DFHack crash when DF's ``reports`` table is out of order + +## Documentation + +## API +- ``DFSDL``: added ``obtain_library_handle`` and ``obtain_image_library_handle`` so that a plugin can obtain DFHack's already-open handle to these libs instead of having to do it itself. +- ``Screen``: new functions ``paintMapPortTile`` and ``readMapPortTile`` to write and read world and region map tiles. +- ``Materials``: ``MaterialInfo`` constants ``NUM_BUILTIN``, ``GROUP_SIZE``, ``CREATURE_BASE``, ``FIGURE_BASE``, ``PLANT_BASE``, and ``END_BASE`` removed. New plugins should use appropriate members of the ``df::builtin_mats`` enum. ## Lua -- ``dfhack.run_command()``: changed to interface directly with the console when possible, which allows interactive commands and commands that detect the console encoding to work properly -- ``processArgsGetopt()`` added to utils.lua, providing a callback interface for parameter parsing and getopt-like flexibility for parameter ordering and combination (see docs in ``library/lua/utils.lua`` and ``library/lua/3rdparty/alt_getopt.lua`` for details). +- Added ``Screen::paintMapPortTile`` as ``dfhack.screen.paintMapPortTile`` +- Added ``Screen::readMapPortTile`` as ``dfhack.screen.readMapPortTile`` +- Deprecated ``gui.materials.CREATURE_BASE`` and ``gui.materials.PLANT_BASE`` - scripts should instead use ``df.builtin_mats.CREATURE_1`` and ``df.builtin_mats.PLANT_1``, respectively. -## Documentation -- Added documentation for Lua's ``dfhack.run_command()`` and variants - -# 0.47.04-r4 - -## Fixes -- Fixed an issue on some Linux systems where DFHack installed through a package manager would attempt to write files to a non-writable folder (notably when running `exportlegends` or `gui/autogems`) -- `buildingplan`: fixed an issue preventing artifacts from being matched when the maximum item quality is set to ``artifacts`` -- `buildingplan`: stopped erroneously matching items to buildings while the game is paused -- `buildingplan`: fixed a crash when pressing 0 while having a noble room selected -- `dwarfvet`: fixed a crash that could occur when discharging patients -- `dwarfmonitor`: fixed a crash when opening the ``prefs`` screen if units have vague preferences -- `embark-assistant`: fixed an issue causing incursion resource matching (e.g. sand/clay) to skip some tiles if those resources were provided only through incursions -- `embark-assistant`: corrected river size determination by performing it at the MLT level rather than the world tile level -- `search`: fixed an issue where search options might not display if screens were destroyed and recreated programmatically (e.g. with `quickfort`) -- `workflow`: fixed an error when creating constraints on "mill plants" jobs and some other plant-related jobs -- `zone`: fixed an issue causing the ``enumnick`` subcommand to run when attempting to run ``assign``, ``unassign``, or ``slaughter`` - -## Misc Improvements -- `buildingplan`: added support for all buildings, furniture, and constructions (except for instruments) -- `buildingplan`: added support for respecting building job_item filters when matching items, so you can set your own programmatic filters for buildings before submitting them to buildingplan -- `buildingplan`: changed default filter setting for max quality from ``artifact`` to ``masterwork`` -- `buildingplan`: changed min quality adjustment hotkeys from 'qw' to 'QW' to avoid conflict with existing hotkeys for setting roller speed - also changed max quality adjustment hotkeys from 'QW' to 'AS' to make room for the min quality hotkey changes -- `buildingplan`: added a new global settings page accessible via the ``G`` hotkey when on any building build screen; ``Quickfort Mode`` toggle for legacy Python Quickfort has been moved to this page -- `buildingplan`: added new global settings for whether generic building materials should match blocks, boulders, logs, and/or bars - defaults are everything but bars -- `embark-assistant`: split the lair types displayed on the local map into mound, burrow, and lair -- `probe`: added more output for designations and tile occupancy -- `quickfort`: The Dreamfort sample blueprints now have complete walkthroughs for each fort level and importable orders that automate basic fort stock management -- `quickfort`: added more blueprints to the blueprints library: several bedroom layouts, the Saracen Crypts, and the complete fortress example from Python Quickfort: TheQuickFortress +## Removed + +# 53.15-r2 + +## New Tools + +## New Features +- `buildingplan`: add a ``Pull`` button next to linked levers on a building's "Show linked buildings" tab so you can queue a high-priority pull-lever job (or cancel a queued one) without navigating to the lever + +## Fixes +- `autoclothing`: correct defect in validating material specification on command line +- `autolabor`: Fix running 1 tick less frequently than intended. +- `buildingplan`: fixed non-clickable pressure plates's triggers (issue #5736) +- `getplants`: added protective code to avoid misoperation when a plant has an invalid material (which should never happen, but...) + +## Misc Improvements +- `buildingplan`: added a slider on the weapontrap overlay +- `buildingplan`: added a small tooltip text about renaming favorites in the UI +- `buildingplan`: buildingplan can now generate work orders +- `orders`: exported orders now include a human-readable ``name`` field ## Documentation -- `quickfort-alias-guide`: alias syntax and alias standard library documentation for `quickfort` blueprints -- `quickfort-library-guide`: overview of the quickfort blueprint library ## API -- `buildingplan`: added Lua interface API -- ``dfhack.job.isSuitableMaterial()``: added an item type parameter so the ``non_economic`` flag can be properly handled (it was being matched for all item types instead of just boulders) -- ``Buildings::setSize()``: changed to reuse existing extents when possible +- Core: added ``getConfigPath()`` API for obtaining the path to user-specific configuration files +- ``widgets.RadioButton``: New button widget resembling those used in ``gui/control-panel`` ## Lua -- ``utils.addressof()``: fixed for raw userdata +- Added ``dfhack.getConfigPath()`` API, proxying ``Core::getConfigPath`` + +## Removed -# 0.47.04-r3 +# 53.15-r1 -## New Plugins -- `xlsxreader`: provides an API for Lua scripts to read Excel spreadsheets +## New Tools + +## New Features ## Fixes -- `buildingplan`: fixed handling of buildings that require buckets -- `getplants`: fixed a crash that could occur on some maps -- `search`: fixed an issue causing item counts on the trade screen to display inconsistently when searching -- `stockpiles`: fixed a crash when loading food stockpiles -- `stockpiles`: fixed an error when saving furniture stockpiles +- `autoclothing`: will no longer count gloves and pants as if they were helms +- `timestream`: do not skip ticks when a caravan is loading or unloading, and be more careful about skipping ticks when flows are active ## Misc Improvements -- `createitem`: added support for plant growths (fruit, berries, leaves, etc.) -- `createitem`: added an ``inspect`` subcommand to print the item and material tokens of existing items, which can be used to create additional matching items -- `embark-assistant`: added support for searching for taller waterfalls (up to 50 z-levels tall) -- `search`: added support for searching for names containing non-ASCII characters using their ASCII equivalents -- `stocks`: added support for searching for items containing non-ASCII characters using their ASCII equivalents -- `zone`: added an ``enumnick`` subcommand to assign enumerated nicknames (e.g "Hen 1", "Hen 2"...) -- `zone`: added slaughter indication to ``uinfo`` output ## Documentation -- Fixed syntax highlighting of most code blocks to use the appropriate language (or no language) instead of Python ## API -- Added ``DFHack::to_search_normalized()`` (Lua: ``dfhack.toSearchNormalized()``) to convert non-ASCII alphabetic characters to their ASCII equivalents -# 0.47.04-r2 +## Lua + +## Removed + +# 53.14-r2 -## New Tweaks -- `tweak` do-job-now: adds a job priority toggle to the jobs list -- `tweak` reaction-gloves: adds an option to make reactions produce gloves in sets with correct handedness +## New Tools + +## New Features ## Fixes -- Fixed a segfault when attempting to start a headless session with a graphical PRINT_MODE setting -- Fixed an issue with the macOS launcher failing to un-quarantine some files -- Linux: fixed ``dfhack.getDFPath()`` (Lua) and ``Process::getPath()`` (C++) to always return the DF root path, even if the working directory has changed -- `getplants`: fixed issues causing plants to be collected even if they have no growths (or unripe growths) -- `labormanager`: fixed handling of new jobs in 0.47 -- `labormanager`: fixed an issue preventing custom furnaces from being built -- `embark-assistant`: fixed a couple of incursion handling bugs. -- Fixed ``Units::isEggLayer``, ``Units::isGrazer``, ``Units::isMilkable``, ``Units::isTrainableHunting``, ``Units::isTrainableWar``, and ``Units::isTamable`` ignoring the unit's caste -- `RemoteFortressReader`: fixed a couple crashes that could result from decoding invalid enum items (``site_realization_building_type`` and ``improvement_type``) -- `RemoteFortressReader`: fixed an issue that could cause block coordinates to be incorrect -- `rendermax`: fixed a hang that could occur when enabling some renderers, notably on Linux -- `stonesense`: fixed a crash when launching Stonesense -- `stonesense`: fixed some issues that could cause the splash screen to hang ## Misc Improvements -- Linux/macOS: Added console keybindings for deleting words (Alt+Backspace and Alt+d in most terminals) -- `blueprint`: now writes blueprints to the ``blueprints/`` subfolder instead of the df root folder -- `blueprint`: now automatically creates folder trees when organizing blueprints into subfolders (e.g. ``blueprint 30 30 1 rooms/dining dig`` will create the file ``blueprints/rooms/dining-dig.csv``); previously it would fail if the ``blueprints/rooms/`` directory didn't already exist -- `confirm`: added a confirmation dialog for convicting dwarves of crimes -- `manipulator`: added a new column option to display units' goals +- Core: attempts to delete a pool-allocated DF object will now throw an exception instead of corrupting the heap -## API -- Added ``Filesystem::mkdir_recursive`` -- Extended ``Filesystem::listdir_recursive`` to optionally make returned filenames relative to the start directory -- ``Units``: added goal-related functions: ``getGoalType()``, ``getGoalName()``, ``isGoalAchieved()`` +## Documentation -## Internals -- Added support for splitting scripts into multiple files in the ``scripts/internal`` folder without polluting the output of `ls` +## API ## Lua -- Added a ``ref_target`` field to primitive field references, corresponding to the ``ref-target`` XML attribute -- Made ``dfhack.units.getRaceNameById()``, ``dfhack.units.getRaceBabyNameById()``, and ``dfhack.units.getRaceChildNameById()`` available to Lua -## Ruby -- Updated ``item_find`` and ``building_find`` to use centralized logic that works on more screens +## Removed +- `logcleaner`: Removed (cannot be safely implemented at this time) -## Documentation -- Expanded the installation guide -- Added some new dev-facing pages, including dedicated pages about the remote API, memory research, and documentation -- Made a couple theme adjustments +# 53.14-r1 -# 0.47.04-r1 +## New Tools + +## New Features +- Compatibility with Dwarf Fortress 53.14 ## Fixes -- Fixed translation of certain types of in-game names -- Fixed a crash in ``find()`` for some types when no world is loaded -- `autogems`: fixed an issue with binned gems being ignored in linked stockpiles -- `stocks`: fixed display of book titles -- `tweak` embark-profile-name: fixed handling of the native shift+space key ## Misc Improvements -- ``dfhack.init-example``: enabled `autodump` -- `getplants`: added switches for designations for farming seeds and for max number designated per plant -- `manipulator`: added intrigue to displayed skills -- `search`: added support for the fortress mode justice screen + +## Documentation ## API -- Added ``Items::getBookTitle`` to get titles of books. Catches titles buried in improvements, unlike getDescription. ## Lua -- ``pairs()`` now returns available class methods for DF types -# 0.47.04-beta1 +## Removed + +# 53.13-r2 + +## New Tools + +## New Features ## Fixes -- Fixed a crash when starting DFHack in headless mode with no terminal +- ``Gui::makeAnnoucement``, ``Gui::showPopupAnnouncement`, and ``Gui::autoDFAnnouncement`` will no longer attempt to cull the DF announcement vector ## Misc Improvements -- Added "bit" suffix to downloads (e.g. 64-bit) -- Tests: - - moved from DF folder to hack/scripts folder, and disabled installation by default - - made test runner script more flexible -- `dfhack-run`: added color output support -- `embark-assistant`: - - updated embark aquifer info to show all aquifer kinds present - - added neighbor display, including kobolds (SKULKING) and necro tower count - - updated aquifer search criteria to handle the new variation - - added search criteria for embark initial tree cover - - added search criteria for necro tower count, neighbor civ count, and specific neighbors. Should handle additional entities, but not tested -## Internals -- Improved support for tagged unions, allowing tools to access union fields more safely -- Added separate changelogs in the scripts and df-structures repos -- Moved ``reversing`` scripts to df_misc repo - -# 0.47.03-beta1 - -## New Scripts -- `devel/sc`: checks size of structures -- `devel/visualize-structure`: displays the raw memory of a structure - -## Fixes -- @ `adv-max-skills`: fixed for 0.47 -- `deep-embark`: - - prevented running in non-fortress modes - - ensured that only the newest wagon is deconstructed -- `full-heal`: - - fixed issues with removing corpses - - fixed resurrection for non-historical figures -- @ `modtools/create-unit`: added handling for arena tame setting -- `teleport`: fixed setting new tile occupancy - -## Misc Improvements -- `deep-embark`: - - improved support for using directly from the DFHack console - - added a ``-clear`` option to cancel -- `exportlegends`: - - added identity information - - added creature raw names and flags -- `gui/prerelease-warning`: updated links and information about nightly builds -- `modtools/syndrome-trigger`: enabled simultaneous use of ``-synclass`` and ``-syndrome`` -- `repeat`: added ``-list`` option - -## Structures -- Dropped support for 0.44.12-0.47.02 -- ``abstract_building_type``: added types (and subclasses) new to 0.47 -- ``agreement_details_type``: added enum -- ``agreement_details``: added struct type (and many associated data types) -- ``agreement_party``: added struct type -- ``announcement_type``: added types new to 0.47 -- ``artifact_claim_type``: added enum -- ``artifact_claim``: added struct type -- ``breath_attack_type``: added ``SHARP_ROCK`` -- ``building_offering_placest``: new class -- ``building_type``: added ``OfferingPlace`` -- ``creature_interaction_effect``: added subclasses new to 0.47 -- ``creature_raw_flags``: identified several more items -- ``creature_raw_flags``: renamed many items to match DF names -- ``caste_raw_flags``: renamed many items to match DF names -- ``d_init``: added settings new to 0.47 -- ``entity_name_type``: added ``MERCHANT_COMPANY``, ``CRAFT_GUILD`` -- ``entity_position_responsibility``: added values new to 0.47 -- ``fortress_type``: added enum -- ``general_ref_type``: added ``UNIT_INTERROGATEE`` -- ``ghost_type``: added ``None`` value -- ``goal_type``: added goals types new to 0.47 -- ``histfig_site_link``: added subclasses new to 0.47 -- ``history_event_collection``: added subtypes new to 0.47 -- ``history_event_context``: added lots of new fields -- ``history_event_reason``: added captions for all items -- ``history_event_reason``: added items new to 0.47 -- ``history_event_type``: added types for events new to 0.47, as well as corresponding ``history_event`` subclasses (too many to list here) -- ``honors_type``: added struct type -- ``interaction_effect``: added subtypes new to 0.47 -- ``interaction_source_experimentst``: added class type -- ``interaction_source_usage_hint``: added values new to 0.47 -- ``interface_key``: added items for keys new to 0.47 -- ``job_skill``: added ``INTRIGUE``, ``RIDING`` -- ``lair_type``: added enum -- ``monument_type``: added enum -- ``next_global_id``: added enum -- ``poetic_form_action``: added ``Beseech`` -- ``setup_character_info``: expanded significantly in 0.47 -- ``text_system``: added layout for struct -- ``tile_occupancy``: added ``varied_heavy_aquifer`` -- ``tool_uses``: added items: ``PLACE_OFFERING``, ``DIVINATION``, ``GAMES_OF_CHANCE`` -- ``viewscreen_counterintelligencest``: new class (only layout identified so far) - -# 0.44.12-r3 +## Documentation -## New Plugins -- `autoclothing`: automatically manage clothing work orders -- `autofarm`: replaces the previous Ruby script of the same name, with some fixes -- `map-render`: allows programmatically rendering sections of the map that are off-screen -- `tailor`: automatically manages keeping your dorfs clothed - -## New Scripts -- `assign-attributes`: changes the attributes of a unit -- `assign-beliefs`: changes the beliefs of a unit -- `assign-facets`: changes the facets (traits) of a unit -- `assign-goals`: changes the goals of a unit -- `assign-preferences`: changes the preferences of a unit -- `assign-profile`: sets a dwarf's characteristics according to a predefined profile -- `assign-skills`: changes the skills of a unit -- `combat-harden`: sets a unit's combat-hardened value to a given percent -- `deep-embark`: allows embarking underground -- `devel/find-twbt`: finds a TWBT-related offset needed by the new `map-render` plugin -- `dwarf-op`: optimizes dwarves for fort-mode work; makes managing labors easier -- `forget-dead-body`: removes emotions associated with seeing a dead body -- `gui/create-tree`: creates a tree at the selected tile -- `linger`: takes over your killer in adventure mode -- `modtools/create-tree`: creates a tree -- `modtools/pref-edit`: add, remove, or edit the preferences of a unit -- `modtools/set-belief`: changes the beliefs (values) of units -- `modtools/set-need`: sets and edits unit needs -- `modtools/set-personality`: changes the personality of units -- `modtools/spawn-liquid`: spawns water or lava at the specified coordinates -- `set-orientation`: edits a unit's orientation -- `unretire-anyone`: turns any historical figure into a playable adventurer - -## Fixes -- Fixed a crash in the macOS/Linux console when the prompt was wider than the screen width -- Fixed some cases where Lua filtered lists would not properly intercept keys, potentially triggering other actions on the same screen -- Fixed inconsistent results from ``Units::isGay`` for asexual units -- `autofarm`: - - fixed biome detection to properly determine crop assignments on surface farms - - reimplemented as a C++ plugin to make proper biome detection possible -- `bodyswap`: fixed companion list not being updated often enough -- `cxxrandom`: removed some extraneous debug information -- `digfort`: now accounts for z-level changes when calculating maximum y dimension -- `embark-assistant`: - - fixed bug causing crash on worlds without generated metals (as well as pruning vectors as originally intended). - - fixed bug causing mineral matching to fail to cut off at the magma sea, reporting presence of things that aren't (like DF does currently). - - fixed bug causing half of the river tiles not to be recognized. - - added logic to detect some river tiles DF doesn't generate data for (but are definitely present). -- `eventful`: fixed invalid building ID in some building events -- `exportlegends`: now escapes special characters in names properly -- `getplants`: fixed designation of plants out of season (note that picked plants are still designated incorrectly) -- `gui/autogems`: fixed error when no world is loaded -- `gui/companion-order`: - - fixed error when resetting group leaders - - ``leave`` now properly removes companion links -- `gui/create-item`: fixed module support - can now be used from other scripts -- `gui/stamper`: - - stopped "invert" from resetting the designation type - - switched to using DF's designation keybindings instead of custom bindings - - fixed some typos and text overlapping -- `modtools/create-unit`: - - fixed an error associating historical entities with units - - stopped recalculating health to avoid newly-created citizens triggering a "recover wounded" job - - fixed units created in arena mode having blank names - - fixed units created in arena mode having the wrong race and/or interaction effects applied after creating units manually in-game - - stopped units from spawning with extra items or skills previously selected in the arena - - stopped setting some unneeded flags that could result in glowing creature tiles - - set units created in adventure mode to have no family, instead of being related to the first creature in the world -- `modtools/reaction-product-trigger`: - - fixed an error dealing with reactions in adventure mode - - blocked ``\\BUILDING_ID`` for adventure mode reactions - - fixed ``-clear`` to work without passing other unneeded arguments -- `modtools/reaction-trigger`: - - fixed a bug when determining whether a command was run - - fixed handling of ``-resetPolicy`` -- `mousequery`: fixed calculation of map dimensions, which was sometimes preventing scrolling the map with the mouse when TWBT was enabled -- `RemoteFortressReader`: - - fixed a crash when a unit's path has a length of 0 -- `stonesense`: - - fixed crash due to wagons and other soul-less creatures -- `tame`: now sets the civ ID of tamed animals (fixes compatibility with `autobutcher`) -- `title-folder`: silenced error when ``PRINT_MODE`` is set to ``TEXT`` - -## Misc Improvements -- Added a note to `dfhack-run` when called with no arguments (which is usually unintentional) -- On macOS, the launcher now attempts to un-quarantine the rest of DFHack -- `bodyswap`: added arena mode support -- `createitem`: added a list of valid castes to the "invalid caste" error message, for convenience -- `combine-drinks`: added more default output, similar to `combine-plants` -- `devel/export-dt-ini`: added more size information needed by newer Dwarf Therapist versions -- `dwarfmonitor`: enabled widgets to access other scripts and plugins by switching to the core Lua context -- `embark-assistant`: - - added an in-game option to activate on the embark screen - - changed waterfall detection to look for level drop rather than just presence - - changed matching to take incursions, i.e. parts of other biomes, into consideration when evaluating tiles. This allows for e.g. finding multiple biomes on single tile embarks. - - changed overlay display to show when incursion surveying is incomplete - - changed overlay display to show evil weather - - added optional parameter "fileresult" for crude external harness automated match support - - improved focus movement logic to go to only required world tiles, increasing speed of subsequent searches considerably -- `exportlegends`: added rivers to custom XML export -- `exterminate`: added support for a special ``enemy`` caste -- `gui/gm-unit`: added support for editing: - - added attribute editor - - added orientation editor - - added editor for bodies and body parts - - added color editor - - added belief editor - - added personality editor -- `modtools/create-item`: - - documented already-existing ``-quality`` option -- `modtools/create-unit`: - - added the ability to specify ``\\LOCAL`` for the fort group entity - - now enables the default labours for adult units with CAN_LEARN. - - now sets historical figure orientation. - - improved speed of creating multiple units at once - - made the script usable as a module (from other scripts) -- `modtools/reaction-trigger`: - - added ``-ignoreWorker``: ignores the worker when selecting the targets - - changed the default behavior to skip inactive/dead units; added ``-dontSkipInactive`` to include creatures that are inactive - - added ``-range``: controls how far elligible targets can be from the workshop - - syndromes now are applied before commands are run, not after - - if both a command and a syndrome are given, the command only runs if the syndrome could be applied -- `mousequery`: made it more clear when features are enabled -- `RemoteFortressReader`: - - added a basic framework for controlling and reading the menus in DF (currently only supports the building menu) - - added support for reading item raws - - added a check for whether or not the game is currently saving or loading, for utilities to check if it's safe to read from DF - - added unit facing direction estimate and position within tiles - - added unit age - - added unit wounds - - added tree information - - added check for units' current jobs when calculating the direction they are facing - -## API -- Added ``Maps::GetBiomeType`` and ``Maps::GetBiomeTypeByRef`` to infer biome types properly -- Added ``Units::getPhysicalDescription`` (note that this depends on the ``unit_get_physical_description`` offset, which is not yet available for all DF builds) -- Added new ``plugin_load_data`` and ``plugin_save_data`` events for plugins to load/save persistent data +## API -## Internals -- Added new Persistence module -- Persistent data is now stored in JSON files instead of historical figures - existing data will be migrated when saving -- Cut down on internal DFHack dependencies to improve build times -- Improved concurrency in event and server handlers -- `stonesense`: fixed some OpenGL build issues on Linux - -## Lua -- Exposed ``gui.dwarfmode.get_movement_delta`` and ``gui.dwarfmode.get_hotkey_target`` -- ``dfhack.run_command`` now returns the command's return code - -## Ruby -- Made ``unit_ishostile`` consistently return a boolean - -## Structures -- Added ``unit_get_physical_description`` function offset on some platforms -- Added/identified types: - - ``assume_identity_mode`` - - ``musical_form_purpose`` - - ``musical_form_style`` - - ``musical_form_pitch_style`` - - ``musical_form_feature`` - - ``musical_form_vocals`` - - ``musical_form_melodies`` - - ``musical_form_interval`` - - ``unit_emotion_memory`` -- ``twbt_render_map``: added for 64-bit 0.44.12 (for `map-render`) -- ``personality_facet_type``, ``value_type``: added ``NONE`` values -- ``need_type``: fixed ``PrayOrMeditate`` typo - -# 0.44.12-r2 +## Lua -## New Plugins -- `debug`: manages runtime debug print category filtering -- `nestboxes`: automatically scan for and forbid fertile eggs incubating in a nestbox - -## New Scripts -- `devel/query`: searches for field names in DF objects -- `extinguish`: puts out fires -- `tame`: sets tamed/trained status of animals - -## Fixes -- `building-hacks`: fixed error when dealing with custom animation tables -- `devel/test-perlin`: fixed Lua error (``math.pow()``) -- `embark-assistant`: fixed crash when entering finder with a 16x16 embark selected, and added 16 to dimension choices -- `embark-skills`: fixed missing ``skill_points_remaining`` field -- `full-heal`: - - stopped wagon resurrection - - fixed a minor issue with post-resurrection hostility -- `gui/companion-order`: - - fixed issues with printing coordinates - - fixed issues with move command - - fixed cheat commands (and removed "Power up", which was broken) -- `gui/gm-editor`: fixed reinterpret cast (``r``) -- `gui/pathable`: fixed error when sidebar is hidden with ``Tab`` -- `labormanager`: - - stopped assigning labors to ineligible dwarves, pets, etc. - - stopped assigning invalid labors - - added support for crafting jobs that use pearl - - fixed issues causing cleaning jobs to not be assigned - - added support for disabling management of specific labors -- `prospector`: (also affected `embark-tools`) - fixed a crash when prospecting an unusable site (ocean, mountains, etc.) with a large default embark size in d_init.txt (e.g. 16x16) -- `siege-engine`: fixed a few Lua errors (``math.pow()``, ``unit.relationship_ids``) -- `tweak`: fixed ``hotkey-clear`` - -## Misc Improvements -- `armoks-blessing`: improved documentation to list all available arguments -- `devel/export-dt-ini`: - - added viewscreen offsets for DT 40.1.2 - - added item base flags offset - - added needs offsets -- `embark-assistant`: - - added match indicator display on the right ("World") map - - changed 'c'ancel to abort find if it's under way and clear results if not, allowing use of partial surveys. - - added Coal as a search criterion, as well as a coal indication as current embark selection info. -- `full-heal`: - - added ``-all``, ``-all_civ`` and ``-all_citizens`` arguments - - added module support - - now removes historical figure death dates and ghost data -- `growcrops`: added ``all`` argument to grow all crops -- `gui/load-screen`: improved documentation -- `labormanager`: now takes nature value into account when assigning jobs -- `open-legends`: added warning about risk of save corruption and improved related documentation -- `points`: added support when in ``viewscreen_setupdwarfgamest`` and improved error messages -- `siren`: removed break handling (relevant ``misc_trait_type`` was no longer used - see "Structures" section) +## Removed -## Internals -- Linux/macOS: changed recommended build backend from Make to Ninja (Make builds will be significantly slower now) -- Added a usable unit test framework for basic tests, and a few basic tests -- Core: various thread safety and memory management improvements -- Fixed CMake build dependencies for generated header files -- Fixed custom ``CMAKE_CXX_FLAGS`` not being passed to plugins -- Changed ``plugins/CMakeLists.custom.txt`` to be ignored by git and created (if needed) at build time instead -- Added ``CMakeSettings.json`` with intellisense support - -## Lua -- ``utils``: new ``OrderedTable`` class - -## Structures -- Win32: added missing vtables for ``viewscreen_storesst`` and ``squad_order_rescue_hfst`` -- ``activity_event_performancest``: renamed poem as written_content_id -- ``dance_form``: named musical_form_id and musical_written_content_id -- ``incident_sub6_performance.participants``: named performance_event and role_index -- ``incident_sub6_performance``: made performance_event an enum -- ``incident_sub6_performance``: named poetic_form_id, musical_form_id, and dance_form_id -- ``musical_form_instruments``: named minimum_required and maximum_permitted -- ``musical_form``: named voices field -- ``poetic_form``: identified many fields and related enum/bitfield types -- ``setup_character_info``: identified ``skill_points_remaining`` (for `embark-skills`) -- ``unit_thought_type``: added new expulsion thoughts from 0.44.12 -- ``viewscreen_layer_militaryst``: identified ``equip.assigned.assigned_items`` -- ``world_data``: added ``mountain_peak_flags`` type, including ``is_volcano`` -- ``written_content``: named poetic_form -- ``unit_action.attack``: identified ``attack_skill`` -- ``unit_action.attack``: added ``lightly_tap`` and ``spar_report`` flags -- ``misc_trait_type``: removed ``LikesOutdoors``, ``Hardened``, ``TimeSinceBreak``, ``OnBreak`` (all unused by DF) -- ``unit_personality``: identified ``stress_drain``, ``stress_boost``, ``likes_outdoors``, ``combat_hardened`` -- ``plant_tree_tile``: gave connection bits more meaningful names (e.g. ``connection_east`` instead of ``thick_branches_1``) -- ``plant_tree_info``: identified ``extent_east``, etc. -- ``ui``: fixed alignment of ``main`` and ``squads`` (fixes `tweak` hotkey-clear and DF-AI) -- ``ui.main``: identified ``fortress_site`` -- ``ui.squads``: identified ``kill_rect_targets_scroll`` -- ``world_site``: identified names and/or types of some fields -- ``world_history``: identified names and/or types of some fields -- ``viewscreen_setupadventurest``: identified some nemesis and personality fields, and ``page.ChooseHistfig`` -- ``unit_storage_status``: newly identified type, stores noble holdings information (used in ``viewscreen_layer_noblelistst``) -- ``viewscreen_layer_noblelistst``: identified ``storage_status`` (see ``unit_storage_status`` type) -- ``viewscreen_layer_arena_creaturest``: identified item- and name-related fields -- ``viewscreen_new_regionst``: identified ``rejection_msg``, ``raw_folder``, ``load_world_params`` -- ``viewscreen_new_regionst``: changed many ``int8_t`` fields to ``bool`` -- ``unit_flags3``: identified ``marked_for_gelding`` -- ``body_part_status``: identified ``gelded`` - -## API -- New debug features related to `debug` plugin: - - Classes (C++ only): ``Signal``, ``DebugCategory``, ``DebugManager`` - - Macros: ``TRACE``, ``DEBUG``, ``INFO``, ``WARN``, ``ERR``, ``DBG_DECLARE``, ``DBG_EXTERN`` +# 53.13-r1 -================================================================================ -# 0.44.12-r1 +## New Tools + +## New Features ## Fixes --@ Console: fixed crash when entering long commands on Linux/macOS --@ Removed jsoncpp's ``include`` and ``lib`` folders from DFHack builds/packages -- Fixed special characters in `command-prompt` and other non-console in-game outputs on Linux/macOS (in tools using ``df2console``) -- `die`: fixed Windows crash in exit handling -- `dwarfmonitor`, `manipulator`: fixed stress cutoffs -- `modtools/force`: fixed a bug where the help text would always be displayed and nothing useful would happen -- `ruby`: fixed calling conventions for vmethods that return strings (currently ``enabler.GetKeyDisplay()``) -- `startdwarf`: fixed on 64-bit Linux ## Misc Improvements -- Reduced time for designation jobs from tools like `digv` to be assigned workers -- `embark-assistant`: - - Switched to standard scrolling keys, improved spacing slightly - - Introduced scrolling of Finder search criteria, removing requirement for 46 lines to work properly (Help/Info still formatted for 46 lines). - - Added Freezing search criterion, allowing searches for NA/Frozen/At_Least_Partial/Partial/At_Most_Partial/Never Freezing embarks. -- `rejuvenate`: - - Added ``-all`` argument to apply to all citizens - - Added ``-force`` to include units under 20 years old - - Clarified documentation + +## Documentation +- updated documentation for ``autofarm`` for more clarity ## API -- Added to ``Units`` module: - - ``getStressCategory(unit)`` - - ``getStressCategoryRaw(level)`` - - ``stress_cutoffs`` (Lua: ``getStressCutoffs()``) +- add flexible casting to ``enum_field`` to enable explicit casting to more types +- Handle units without current soul in ``Units::getFocusPenalty`` -## Internals -- Changed default build architecture to 64-bit -- Added documentation for all RPC functions and a build-time check -- Added support for build IDs to development builds -- Use ``dlsym(3)`` to find vtables from libgraphics.so - -## Structures -- Added ``start_dwarf_count`` on 64-bit Linux again and fixed scanning script -- ``army_controller``: added new vector from 0.44.11 --@ ``viewscreen_civlistst``: split ``unk_20`` into 3 pointers -- ``belief_system``: new type, few fields identified -- ``mental_picture``: new type, some fields identified -- ``mission``: new type (used in ``viewscreen_civlistst``) -- ``mission_report``: - - new type (renamed, was ``mission`` before) - - identified some fields -- ``spoils_report``: new type, most fields identified -- ``viewscreen_civlistst``: - - identified new pages - - identified new messenger-related fields -- ``viewscreen_image_creatorst``: - - fixed layout - - identified many fields -- ``viewscreen_reportlistst``: - - added new mission and spoils report-related fields (fixed layout) -- ``world``: - - ``belief_systems``: identified -- ``world.languages``: identified (minimal information; whole languages stored elsewhere) -- ``world.status``: - - ``mission_reports``: renamed, was ``missions`` - - ``spoils_reports``: identified -- ``world.unk_131ec0``, ``world.unk_131ef0``: researched layout -- ``world.worldgen_status``: identified many fields +## Lua -================================================================================ -# 0.44.12-alpha1 +## Removed + +# 53.12-r1 + +## New Tools + +## New Features +- Compatibility with Dwarf Fortress 53.12 ## Fixes --@ macOS: fixed ``renderer`` vtable address on x64 (fixes `rendermax`) -- `stonesense`: fixed ``PLANT:DESERT_LIME:LEAF`` typo +- Stockpile definitions in the default library will be correctly found and used (fixed missing path separator) + +## Misc Improvements + +## Documentation ## API -- Added C++-style linked list interface for DF linked lists -## Structures -- Dropped 0.44.11 support -- ``ui.squads``: Added fields new in 0.44.12 +## Lua + +## Removed -================================================================================ -# 0.44.11-beta2.1 +# 53.11-r3 -## Internals --@ `stonesense`: fixed build +## New Tools -================================================================================ -# 0.44.11-beta2 +## New Features ## Fixes --@ Windows: Fixed console failing to initialize -- `command-prompt`: added support for commands that require a specific screen to be visible, e.g. `spotclean` -- `gui/workflow`: fixed advanced constraint menu for crafts +- Core: Windows console will always use UTF-8 regardless of system code page settings +- Steam launcher: Switch to injection strategy, allowing Dwarf Fortress and DFHack to be installed in disparate locations + +## Misc Improvements +- Make DFHack relocatable so that it doesn't depend on being fully co-installed with Dwarf Fortress + +## Documentation ## API -- Added ``Screen::Hide`` to temporarily hide screens, like `command-prompt` -================================================================================ -# 0.44.11-beta1 +## Lua + +## Removed + +# 53.11-r2 + +## New Tools + +## New Features ## Fixes -- Fixed displayed names (from ``Units::getVisibleName``) for units with identities -- Fixed potential memory leak in ``Screen::show()`` -- `fix/dead-units`: fixed script trying to use missing isDiplomat function +- `autoclothing`, `autoslab`, `tailor`: orders will no longer be created with a repetition frequency of ``NONE`` ## Misc Improvements -- Console: - - added support for multibyte characters on Linux/macOS - - made the console exit properly when an interactive command is active (`liquids`, `mode`, `tiletypes`) -- Made the ``DFHACK_PORT`` environment variable take priority over ``remote-server.json`` -- Linux: added automatic support for GCC sanitizers in ``dfhack`` script -- `digfort`: added better map bounds checking -- `dfhack-run`: added support for port specified in ``remote-server.json``, to match DFHack's behavior -- `remove-stress`: - - added support for ``-all`` as an alternative to the existing ``all`` argument for consistency - - sped up significantly - - improved output/error messages - - now removes tantrums, depression, and obliviousness -- `ruby`: sped up handling of onupdate events +- General: DFHack will unconditionally use UTF-8 for the console on Windows, now that DF forces the process effective system code page to 65001 during startup + +## Documentation ## API -- New functions: - - ``Units::isDiplomat(unit)`` -- Exposed ``Screen::zoom()`` to C++ (was Lua-only) ## Lua -- Added ``printall_recurse`` to print tables and DF references recursively. It can be also used with ``^`` from the `lua` interpreter. -- ``gui.widgets``: ``List:setChoices`` clones ``choices`` for internal table changes -## Internals -- jsoncpp: updated to version 1.8.4 and switched to using a git submodule +## Removed -## Structures -- ``history_event_entity_expels_hfst``: added (new in 0.44.11) -- ``history_event_site_surrenderedst``: added (new in 0.44.11) -- ``history_event_type``: added ``SITE_SURRENDERED``, ``ENTITY_EXPELS_HF`` (new in 0.44.11) -- ``syndrome``: identified a few fields -- ``viewscreen_civlistst``: fixed layout and identified many fields +# 53.11-r1 -================================================================================ -# 0.44.11-alpha1 - -## Structures -- Dropped 0.44.10 support -- Added support for automatically sizing arrays indexed with an enum -- Removed stale generated CSV files and DT layouts from pre-0.43.05 -- ``announcement_type``: new in 0.44.11: ``NEW_HOLDING``, ``NEW_MARKET_LINK`` -- ``breath_attack_type``: added ``OTHER`` -- ``historical_figure_info.relationships.list``: added ``unk_3a``-``unk_3c`` fields at end -- ``interface_key``: added bindings new in 0.44.11 -- ``occupation_type``: new in 0.44.11: ``MESSENGER`` -- ``profession``: new in 0.44.11: ``MESSENGER`` -- ``ui_sidebar_menus``: - - ``unit.in_squad``: renamed to ``unit.squad_list_opened``, fixed location - - ``unit``: added ``expel_error`` and other unknown fields new in 0.44.11 - - ``hospital``: added, new in 0.44.11 - - ``num_speech_tokens``, ``unk_17d8``: moved out of ``command_line`` to fix layout on x64 --@ ``viewscreen_civlistst``: added a few new fields (incomplete) -- ``viewscreen_locationsst``: identified ``edit_input`` +## New Tools -================================================================================ -# 0.44.10-r2 +## New Features -## New Plugins -- `cxxrandom`: exposes some features of the C++11 random number library to Lua - -## New Scripts -- `gui/stamper`: allows manipulation of designations by transforms such as translations, reflections, rotations, and inversion -- `add-recipe`: adds unknown crafting recipes to the player's civ - -## Fixes -- Fixed many tools incorrectly using the ``dead`` unit flag (they should generally check ``flags2.killed`` instead) -- Fixed many tools passing incorrect arguments to printf-style functions, including a few possible crashes (`changelayer`, `follow`, `forceequip`, `generated-creature-renamer`) -- Fixed ``-g`` flag (GDB) in Linux ``dfhack`` script (particularly on x64) -- Fixed several bugs in Lua scripts found by static analysis (df-luacheck) -- `autochop`, `autodump`, `autogems`, `automelt`, `autotrade`, `buildingplan`, `dwarfmonitor`, `fix-unit-occupancy`, `fortplan`, `stockflow`: fix issues with periodic tasks not working for some time after save/load cycles -- `autogems`, `fix-unit-occupancy`: stopped running when a fort isn't loaded (e.g. while embarking) -- `buildingplan`, `fortplan`: stopped running before a world has fully loaded -- `autogems`: - - stop running repeatedly when paused - - fixed crash when furnaces are linked to same stockpiles as jeweler's workshops -- `ban-cooking`: fixed errors introduced by kitchen structure changes in 0.44.10-r1 -- `remove-stress`: fixed an error when running on soul-less units (e.g. with ``-all``) -- `revflood`: stopped revealing tiles adjacent to tiles above open space inappropriately -- `dig`: fixed "Inappropriate dig square" announcements if digging job has been posted -- `stockpiles`: ``loadstock`` now sets usable and unusable weapon and armor settings -- `stocks`: stopped listing carried items under stockpiles where they were picked up from -- `deramp`: fixed deramp to find designations that already have jobs posted -- `fixnaked`: fixed errors due to emotion changes in 0.44 -- `autounsuspend`: now skips planned buildings - -## Misc Improvements -- Added script name to messages produced by ``qerror()`` in Lua scripts -- Fixed an issue in around 30 scripts that could prevent edits to the files (adding valid arguments) from taking effect -- Linux: Added several new options to ``dfhack`` script: ``--remotegdb``, ``--gdbserver``, ``--strace`` -- `bodyswap`: improved error handling -- `buildingplan`: added max quality setting -- `caravan`: documented (new in 0.44.10-alpha1) -- `deathcause`: added "slaughtered" to descriptions -- `fix/retrieve-units`: now re-adds units to active list to counteract `fix/dead-units` -- `item-descriptions`: fixed several grammatical errors -- `modtools/create-unit`: - - added quantity argument - - now selects a caste at random if none is specified -- `mousequery`: - - migrated several features from TWBT's fork - - added ability to drag with left/right buttons - - added depth display for TWBT (when multilevel is enabled) - - made shift+click jump to lower levels visible with TWBT -- `title-version`: added version to options screen too -- `embark-assistant`: - - changed region interaction matching to search for evil rain, syndrome rain, and reanimation rather than interaction presence (misleadingly called evil weather), reanimation, and thralling - - gave syndrome rain and reanimation wider ranges of criterion values -- `fix/dead-units`: added a delay of around 1 month before removing units - -## API -- New functions (also exposed to Lua): - - ``Units::isKilled()`` - - ``Units::isActive()`` - - ``Units::isGhost()`` -- Removed Vermin module (unused and obsolete) - -## Lua -- Added ``profiler`` module to measure lua performance -- Enabled shift+cursor movement in WorkshopOverlay-derived screens - -## Structures -- ``unit_flags1``: renamed ``dead`` to ``inactive`` to better reflect its use -- ``item_body_component``: fixed location of ``corpse_flags`` -- ``job_type``: added ``is_designation`` attribute -- ``unit_thought_type``: added ``SawDeadBody`` (new in 0.44.10) -- ``unit_personality``: fixed location of ``current_focus`` and ``undistracted_focus`` -- ``incident_sub6_performance``: identified some fields -- ``job_handler``: fixed static array layout +## Fixes +- `sort`: correct misspelling of ``PERSEVERENCE``; fixes "hates combat" filter in squad selection screen -## Internals -- Added fallback for YouCompleteMe database lookup failures (e.g. for newly-created files) -- jsoncpp: fixed constructor with ``long`` on Linux -- Improved efficiency and error handling in ``stl_vsprintf`` and related functions -- Added build option to generate symbols for large generated files containing df-structures metadata +## Misc Improvements -================================================================================ -# 0.44.10-r1 +## Documentation + +## API + +## Lua + +## Removed + +# 53.10-r2 -## New Scripts -- `bodyswap`: shifts player control over to another unit in adventure mode +## New Tools +- ``logcleaner``: New plugin for time-triggered clearing of combat, sparring, and hunting reports with configurable filtering and overlay UI. -## New Tweaks -- `tweak` stone-status-all: adds an option to toggle the economic status of all stones -- `tweak` kitchen-prefs-all: adds an option to toggle cook/brew for all visible items in kitchen preferences +## New Features +- `orders`: added search overlay to find and navigate to matching manager orders with arrow indicators +- `sort`: added ``Uniformed`` filter to squad assignment screen to filter dwarves with mining, woodcutting, or hunting labors +- `sort`: Add death cause button to dead/missing tab in the creatures screen ## Fixes -- Lua: registered ``dfhack.constructions.designateRemove()`` correctly -- `prospector`: fixed crash due to invalid vein materials -- `tweak` max-wheelbarrow: fixed conflict with building renaming -- `view-item-info`: stopped appending extra newlines permanently to descriptions ## Misc Improvements -- Added logo to documentation -- Documented several missing ``dfhack.gui`` Lua functions -- `adv-rumors`: bound to Ctrl-A -- `command-prompt`: added support for ``Gui::getSelectedPlant()`` -- `gui/advfort`: bound to Ctrl-T -- `gui/room-list`: added support for ``Gui::getSelectedBuilding()`` -- `gui/unit-info-viewer`: bound to Alt-I -- `modtools/create-unit`: made functions available to other scripts -- `search`: - - added support for stone restrictions screen (under ``z``: Status) - - added support for kitchen preferences (also under ``z``) +- Core: DFHack now validates vtable pointers in objects read from memory and will throw an exception instead of crashing when an invalid vtable pointer is encountered. This makes it easier to identify which DF data structure contains corrupted data when this manifests in the form of a bad vtable pointer, and shifts blame for such crashes from DFHack to DF. -## Internals -- Fixed compiler warnings on all supported build configurations -- Windows build scripts now work with non-C system drives - -## API -- New functions (all available to Lua as well): - - ``Buildings::getRoomDescription()`` - - ``Items::checkMandates()`` - - ``Items::canTrade()`` - - ``Items::canTradeWithContents()`` - - ``Items::isRouteVehicle()`` - - ``Items::isSquadEquipment()`` - - ``Kitchen::addExclusion()`` - - ``Kitchen::findExclusion()`` - - ``Kitchen::removeExclusion()`` -- syndrome-util: added ``eraseSyndromeData()`` - -## Structures -- ``dfhack_room_quality_level``: new enum -- ``glowing_barrier``: identified ``triggered``, added comments -- ``item_flags2``: renamed ``has_written_content`` to ``unk_book`` -- ``kitchen_exc_type``: new enum (for ``ui.kitchen``) -- ``mandate.mode``: now an enum -- ``unit_personality.emotions.flags.memory``: identified -- ``viewscreen_kitchenprefst.forbidden``, ``possible``: now a bitfield, ``kitchen_pref_flag`` -- ``world_data.feature_map``: added extensive documentation (in XML) +## Documentation -================================================================================ -# 0.44.10-beta1 - -## New Scripts -- `devel/find-primitive`: finds a primitive variable in memory - -## Fixes -- Units::getAnyUnit(): fixed a couple problematic conditions and potential segfaults if global addresses are missing -- `stockpiles`: stopped sidebar option from overlapping with `autodump` --@ `autodump`, `automelt`, `autotrade`, `stocks`, `stockpiles`: fixed conflict with building renaming -- `tweak` block-labors: fixed two causes of crashes related in the v-p-l menu -- `full-heal`: - - units no longer have a tendency to melt after being healed - - healed units are no longer treated as patients by hospital staff - - healed units no longer attempt to clean themselves unsuccessfully - - wounded fliers now regain the ability to fly upon being healing - - now heals suffocation, numbness, infection, spilled guts and gelding -- `modtools/create-unit`: - - creatures of the appropriate age are now spawned as babies or children where applicable - - fix: civ_id is now properly assigned to historical_figure, resolving several hostility issues (spawned pets are no longer attacked by fortress military!) - - fix: unnamed creatures are no longer spawned with a string of numbers as a first name -- `exterminate`: fixed documentation of ``this`` option - -## Misc Improvements -- `blueprint`: added a basic Lua API -- `devel/export-dt-ini`: added tool offsets for DT 40 -- `devel/save-version`: added current DF version to output -- `install-info`: added information on tweaks +## API +- Added ``Items::pickGrowthPrint``: given a plant material and a growth index, returns the print variant corresponding to the current in-game time. +- Added ``Items::useStandardMaterial``: given an item type, returns true if the item is made of a specific material and false if it has a race and caste instead. +- Added ``Maps::addItemSpatter``: add a spatter of the specified item + material + growth print to the indicated tile, returning whatever amount wouldn't fit in the tile. +- Added ``Maps::addMaterialSpatter``: add a spatter of the specified material + state to the indicated tile, returning whatever amount wouldn't fit in the tile. -## Internals -- Added ``Gui::inRenameBuilding()`` -- Added function names to DFHack's NullPointer and InvalidArgument exceptions -- Linux: required plugins to have symbols resolved at link time, for consistency with other platforms +## Lua +- Added ``Maps::addItemSpatter`` as ``dfhack.maps.addItemSpatter``. +- Added ``Maps::addMaterialSpatter`` as ``dfhack.maps.addMaterialSpatter``. -================================================================================ -# 0.44.10-alpha1 +## Removed + +# 53.10-r1 -## New Scripts -- `caravan`: adjusts properties of caravans -- `gui/autogems`: a configuration UI for the `autogems` plugin +## New Tools + +## New Features ## Fixes -- Fixed uninitialized pointer being returned from ``Gui::getAnyUnit()`` in rare cases -- `autohauler`, `autolabor`, `labormanager`: fixed fencepost error and potential crash -- `dwarfvet`: fixed infinite loop if an animal is not accepted at a hospital -- `liquids`: fixed "range" command to default to 1 for dimensions consistently -- `search`: fixed 4/6 keys in unit screen search -- `view-item-info`: fixed an error with some armor +- `autochop`: the report will no longer throw a C++ exception when burrows are defined. +- `suspendmanager`: Fix the overlay appearing where it should not when following a unit ## Misc Improvements -- `autogems`: can now blacklist arbitrary gem types (see `gui/autogems`) -- `exterminate`: added more words for current unit, removed warning -- `fpause`: now pauses worldgen as well -## Internals -- Added some build scripts for Sublime Text -- Changed submodule URLs to relative URLs so that they can be cloned consistently over different protocols (e.g. SSH) +## Documentation -================================================================================ -# 0.44.09-r1 +## API +- Added ``Burrows::getName``: obtains the name of a burrow, or the same placeholder name that DF would show if the burrow is unnamed. -## Internals -- OS X: Can now build with GCC 7 (or older) +## Lua +- Added ``Burrows::getName`` as ``dfhack.burrows.getName``. + +## Removed + +# 53.09-r1 + +## New Tools + +## New Features +- `tweak`: ``drawbridge-tiles``: Make it so raised bridges render with different tiles in ASCII mode to make it more obvious that they ARE raised (and to indicate their direction) ## Fixes -- `modtools/item-trigger`: fixed token format in help text +- ``Filesystem::as_string`` now always uses UTF-8 encoding rather than using the system locale encoding ## Misc Improvements -- Reorganized changelogs and improved changelog editing process -- `modtools/item-trigger`: added support for multiple type/material/contaminant conditions -## Structures --@ ``renderer``: fixed vtable addresses on 64-bit OS X -- ``building_type``: added human-readable ``name`` attribute -- ``furnace_type``: added human-readable ``name`` attribute -- ``workshop_type``: added human-readable ``name`` attribute -- ``army``: added vector new in 0.44.07 -- ``site_reputation_report``: named ``reports`` vector +## Documentation -================================================================================ -# 0.44.09-alpha1 +## API +- ``dfhack.job.getManagerOrderName``: New function to get the display name of a manager order -## Fixes -- `digtype`: stopped designating non-vein tiles (open space, trees, etc.) -- `labormanager`: fixed crash due to dig jobs targeting some unrevealed map blocks +## Lua + +## Removed +# 53.08-r1 -================================================================================ -# 0.44.08-alpha1 +## New Tools + +## New Features +- compatibility with DF 53.08 ## Fixes -- `fix/dead-units`: fixed a bug that could remove some arriving (not dead) units +## Misc Improvements -================================================================================ -# 0.44.07-beta1 +## Documentation + +## API -## Structures --@ Added symbols for Toady's `0.44.07 Linux test build `_ to fix :bug:`10615` --@ ``world_site``: fixed alignment +## Lua -## Misc improvements -- `modtools/item-trigger`: added the ability to specify inventory mode(s) to trigger on +## Removed +# 53.07-r1 -================================================================================ -# 0.44.07-alpha1 +## New Tools +- ``edgescroll``: Introduced plugin to pan the view automatically when the mouse reaches the screen border. +- `infinite-sky`: Re-enabled with compatibility with new siege map data. + +## New Features +- `sort`: Places search widget can search "Siege engines" subtab by name, loaded status, and operator status ## Fixes -- Support for building on Ubuntu 18.04 -- Fixed some CMake warnings (CMP0022) -- `embark-assistant`: fixed detection of reanimating biomes +- `sort`: Using the squad unit selector will no longer cause Dwarf Fortress to crash on exit +- `sort`: Places search widget moved to account for DF's new "Siege engines" subtab ## Misc Improvements -- `embark-assistant`: +- `createitem`: created items can now be placed onto/into tables, nests, bookcases, display cases, and altars +- The ``fpause`` console command can now be used to force world generation to pause (as it did prior to version 50). +- `keybinding`: keybinds may now include the super key, and are no longer limited to particular keys ranges of keys, allowing any recognized by SDL. + +## Documentation - - Added search for adamantine - - Now supports saving/loading profiles +## API +- ``Hotkey``: New module for hotkey functionality -- `fillneeds`: added ``-all`` option to apply to all units -- `remotefortressreader`: added flows, instruments, tool names, campfires, ocean waves, spiderwebs +## Lua +- The ``Lua interactive interpreter`` banner now documents keywords such as ``unit`` and ``item`` which reference the currently-selected object in the DF UI. +- ``dfhack.hotkey.addKeybind``: Creates new keybindings +- ``dfhack.hotkey.removeKeybind``: Removes existing keybindings +- ``dfhack.hotkey.listActiveKeybinds``: Lists all keybinds for the current context +- ``dfhack.hotkey.listAllKeybinds``: Lists all keybinds for all contexts +- ``dfhack.hotkey.requestKeybindingInput``: Requests the next keybind-compatible input is saved +- ``dfhack.hotkey.getKeybindingInput``: Reads the input saved in response to a request. -## Structures -- Several new names in instrument raw structures -- ``identity``: identified ``profession``, ``civ`` -- ``manager_order_template``: fixed last field type -- ``viewscreen_createquotast``: fixed layout -- ``world.language``: moved ``colors``, ``shapes``, ``patterns`` to ``world.descriptors`` -- ``world.reactions``, ``world.reaction_categories``:\ moved to new compound, ``world.reactions``. Requires renaming: +## Removed - - ``world.reactions`` to ``world.reactions.reactions`` - - ``world.reaction_categories`` to ``world.reactions.reaction_categories`` +# 53.06-r1 +## New Tools -================================================================================ -# 0.44.05-r2 +## New Features ## Fixes -- `devel/export-dt-ini`: fix language_name offsets for DT 39.2+ -- `devel/inject-raws`: fixed gloves and shoes (old typo causing errors) -- `remotefortressreader`: fixed an issue with not all engravings being included -- `view-item-info`: fixed an error with some shields ## Misc Improvements -- `adv-rumors`: added more keywords, including names -- `autochop`: can now exclude trees that produce fruit, food, or cookable items -- `remotefortressreader`: added plant type support -## New Plugins -- `embark-assistant`: adds more information and features to embark screen +## Documentation + +## API + +## Lua + +## Removed +- `infiniteSky`: Temporarily disabled due to incompatibility with changes made as part of DF's siege update + +# 53.05-r1 -## New Scripts -- `adv-fix-sleepers`: fixes units in adventure mode who refuse to wake up (:bug:`6798`) -- `hermit`: blocks caravans, migrants, diplomats (for hermit challenge) +## New Tools ## New Features -- With ``PRINT_MODE:TEXT``, setting the ``DFHACK_HEADLESS`` environment variable will hide DF's display and allow the console to be used normally. (Note that this is intended for testing and is not very useful for actual gameplay.) +- compatibility with 53.05 +## Fixes +- `sort`: Using the squad unit selector will no longer cause Dwarf Fortress to crash on exit -================================================================================ -# 0.44.05-r1 - -## New Scripts -- `break-dance`: Breaks up a stuck dance activity -- `fillneeds`: Use with a unit selected to make them focused and unstressed -- `firestarter`: Lights things on fire: items, locations, entire inventories even! -- `flashstep`: Teleports adventurer to cursor -- `ghostly`: Turns an adventurer into a ghost or back -- `questport`: Sends your adventurer to the location of your quest log cursor -- `view-unit-reports`: opens the reports screen with combat reports for the selected unit - -## Fixes -- `devel/inject-raws`: now recognizes spaces in reaction names -- `dig`: added support for designation priorities - fixes issues with designations from ``digv`` and related commands having extremely high priority -- `dwarfmonitor`: - - fixed display of creatures and poetic/music/dance forms on ``prefs`` screen - - added "view unit" option - - now exposes the selected unit to other tools - -- `names`: fixed many errors -- `quicksave`: fixed an issue where the "Saving..." indicator often wouldn't appear - -## Misc Improvements -- `gui/gm-unit`: - - added a profession editor - - misc. layout improvements -- `remotefortressreader`: - - support for moving adventurers - - support for vehicles, gem shapes, item volume, art images, item improvements -- `binpatch`: now reports errors for empty patch files -- `force`: now provides useful help -- `full-heal`: - - can now select corpses to resurrect - - now resets body part temperatures upon resurrection to prevent creatures from freezing/melting again - - now resets units' vanish countdown to reverse effects of `exterminate` -- `launch`: can now ride creatures -- `names`: can now edit names of units +## Misc Improvements + +## Documentation + +## API + +## Lua ## Removed -- `tweak`: ``kitchen-keys``: :bug:`614` fixed in DF 0.44.04 -## Internals -- ``Gui::getAnyUnit()`` supports many more screens/menus +# 53.04-r1.1 -## Structures -- New globals: ``soul_next_id`` +## New Tools -================================================================================ -# 0.44.05-alpha1 +## New Features + +## Fixes +- fixed misalignment in ``widgets::unit_list`` ## Misc Improvements -- `gui/liquids`: added more keybindings: 0-7 to change liquid level, P/B to cycle backwards -## Structures --@ ``incident``: re-aligned again to match disassembly +## Documentation +## API -================================================================================ -# 0.44.04-alpha1 +## Lua -## Fixes -- `devel/inject-raws`: now recognizes spaces in reaction names -- `exportlegends`: fixed an error that could occur when exporting empty lists +## Removed +# 53.04-r1 -## Structures -- ``artifact_record``: fixed layout (changed in 0.44.04) -- ``incident``: fixed layout (changed in 0.44.01) - note that many fields have moved +## New Tools +## New Features -================================================================================ -# 0.44.03-beta1 - -## Fixes -- `autolabor`, `autohauler`, `labormanager`: added support for "put item on display" jobs and building/destroying display furniture -- `gui/gm-editor`: fixed an error when editing primitives in Lua tables - -## Misc Improvements -- @ `devel/dump-offsets`: now ignores ``index`` globals -- `gui/pathable`: added tile types to sidebar -- `modtools/skill-change`: - - now updates skill levels appropriately - - only prints output if ``-loud`` is passed - -## Structures -- New globals: - - ``version`` - - ``min_load_version`` - - ``movie_version`` - - ``basic_seed`` - - ``title`` - - ``title_spaced`` - - ``ui_building_resize_radius`` -- Added ``twbt_render_map`` code offset on x64 -- Fixed an issue preventing ``enabler`` from being allocated by DFHack -- Added ``job_type.PutItemOnDisplay`` -- Found ``renderer`` vtable on osx64 -- ``adventure_movement_optionst``, ``adventure_movement_hold_tilest``, ``adventure_movement_climbst``: named coordinate fields -- ``mission``: added type -- ``unit``: added 3 new vmethods: ``getCreatureTile``, ``getCorpseTile``, ``getGlowTile`` -- ``viewscreen_assign_display_itemst``: fixed layout on x64 and identified many fields -- ``viewscreen_reportlistst``: fixed layout, added ``mission_id`` vector -- ``world.status``: named ``missions`` vector +## Fixes +- `buildingplan`: Bolt throwers will no longer be constructed using populated bins. +- `RemoteFortressReader`: updated siege engine facing enums for new diagonal directions +- `suspendmanager`: treat reinforced walls as a blocking construction and buildable platform +## Misc Improvements +- `autolabor`: support for new dying and siege-related labors +- `blueprint`: support for reinforced walls and bolt throwers -================================================================================ -# 0.44.03-alpha1 +## Documentation + +## API ## Lua -- Improved ``json`` I/O error messages -- Stopped a crash when trying to create instances of classes whose vtable addresses are not available +## Removed -================================================================================ -# 0.44.02-beta1 +# 53.03-r1 -## New Scripts -- `devel/check-other-ids`: Checks the validity of "other" vectors in the ``world`` global -- `gui/cp437-table`: An in-game CP437 table +## New Tools + +## New Features ## Fixes -- Fixed issues with the console output color affecting the prompt on Windows -- `createitem`: stopped items from teleporting away in some forts -- `gui/gm-unit`: can now edit mining skill -- `gui/quickcmd`: stopped error from adding too many commands -- `modtools/create-unit`: fixed error when domesticating units ## Misc Improvements -- The console now provides suggestions for built-in commands -- `devel/export-dt-ini`: avoid hardcoding flags -- `exportlegends`: - - reordered some tags to match DF's order - - added progress indicators for exporting long lists -- `gui/gm-editor`: added enum names to enum edit dialogs -- `gui/gm-unit`: made skill search case-insensitive -- `gui/rename`: added "clear" and "special characters" options -- `remotefortressreader`: - - includes item stack sizes - - some performance improvements +- Release builds for Linux are now compiled with gcc 11 -## Removed -- `warn-stuck-trees`: :bug:`9252` fixed in DF 0.44.01 +## Documentation + +## API ## Lua -- Exposed ``get_vector()`` (from C++) for all types that support ``find()``, e.g. ``df.unit.get_vector() == df.global.world.units.all`` -## Structures -- Located ``start_dwarf_count`` offset for all builds except 64-bit Linux; `startdwarf` should work now -- Added ``buildings_other_id.DISPLAY_CASE`` -- Fixed ``viewscreen_titlest.start_savegames`` alignment -- Fixed ``unit`` alignment -- Identified ``historical_entity.unknown1b.deities`` (deity IDs) +## Removed +# 53.02-r2 -================================================================================ -# 0.44.02-alpha1 +## New Tools -## New Scripts -- `devel/dump-offsets`: prints an XML version of the global table included in in DF +## New Features ## Fixes -- Fixed a crash that could occur if a symbol table in symbols.xml had no content +- `buildingplan`: Building costs for reinforced walls are now correct. +- `cleanconst`: do not attempt to clean Reinforced constructions + +## Misc Improvements +- `buildingplan`: Added support for bolt throwers and siege engine rotation. + +## Documentation + +## API ## Lua -- Added a new ``dfhack.console`` API -- API can now wrap functions with 12 or 13 parameters -## Structures -- The ``ui_menu_width`` global is now a 2-byte array; the second item is the former ``ui_area_map_width`` global, which is now removed -- The former ``announcements`` global is now a field in ``d_init`` -- ``world`` fields formerly beginning with ``job_`` are now fields of ``world.jobs``, e.g. ``world.job_list`` is now ``world.jobs.list`` +## Removed + +# 53.02-r1 + +## New Tools + +## New Features + +## Fixes + +## Misc Improvements +- Core: added ``gps`` (``graphicst``) to the set of globals whose sizes must agree for DFHack to pass initialization checks + +## Documentation + +## API + +## Lua + +## Removed + +# 53.01-r1 + +## New Tools + +## New Features + +## Fixes + +## Misc Improvements +- `stockpiles`: add support for managing the dyed, undyed, and color filter settings. + +## Documentation + +## API + +## Lua + +## Removed + +# 52.05-r2 + +## New Tools + +## New Features + +## Fixes +- `script-manager`: the ``scripts_modactive`` and ``scripts_modinstalled`` folders of a script-enabled mod will be properly added to the script path search list + +## Misc Improvements + +## Documentation +- added a clarification link to DF's Lua API documentation to the DFHack Lua API documentation, as a way to reduce end-user confusion + +## API + +## Lua + +## Removed + +# 52.05-r1 + +## New Tools + +## New Features + +## Fixes +- improved file system handling: gracefully handle errors from operations, preventing crashes. +- `zone`: animal assignment dialog now tolerates corrupt animal-to-pasture links. + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 52.04-r1 + +## New Tools + +## New Features +- Compatibility with DF 52.04 + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 52.03-r2 + +## New Tools + +## New Features +- `nestboxes`: allow limiting egg protection to nestboxes inside a designated burrow +- `tailor`: tailor now provides optional dye automation + +## Fixes +- ``Units::getReadableName`` will no longer append a comma to the names of histfigs with no profession +- `stockpiles`: fixed off-by-one error in exporting furniture stockpiles + +## Misc Improvements + +## Documentation + +## API +- ``Job``: new functions ``createLinked`` and ``assignToWorkshop`` +- ``Units``: new functions ``getFocusPenalty``, ``unbailableSocialActivity``, ``isJobAvailable`` + +## Lua +- New functions: ``dfhack.jobs.createLinked``, ``dfhack.jobs.assignToWorkshop``, ``dfhack.units.getFocusPenalty``, ``dfhack.units.unbailableSocialActivity``, and ``dfhack.units.isJobAvailable`` + +## Removed + +# 52.03-r1.1 + +## New Tools + +## New Features + +## Fixes +- job descriptions of mix dye job will display proper dye names + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 52.03-r1 + +## New Tools + +## New Features + +## Fixes +- `preserve-rooms` will no longer hang on startup in the presence of a cycle in the replacement relationship of noble positions + +## Misc Improvements + +## Documentation + +## API +- Adjusted the logic inside ``Military::removeFromSquad`` to more closely match the game's own behavior + +## Lua + +## Removed + +# 52.02-r2 + +## New Tools + +## New Features + +## Fixes +- Several fixes related to changes in file system handling in DF 52.01 +- `dig-now`: don't allow UNDIGGABLE stones to be excavated + +## Misc Improvements +- `autoclothing`: added a ``clear`` option to unset previously set orders + +## Documentation + +## API +- Added GUI focus strings for new_arena: ``/Loading`` and ``/Mods`` +- ``Filesystem::getBaseDir`` and ``Filesystem::getInstallDir`` added (and made available in Lua) +- Expanded the partial implementations of ``Military::addToSquad`` and ``Military::removeFromSquad`` + +## Lua +- Inserting values into STL containers containing nonprimitive types is now supported + +## Removed + +# 52.02-r1 + +## New Tools + +## New Features + +## Fixes +- Honor the "portable mode" preference setting for locating save folders. Fixes DFHack cosaves not working in most cases. + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 52.01-r1 + +## New Tools + +## New Features +- `tweak`: ``animaltrap-reuse``: make it so built animal traps automatically unload the vermin they catch into stockpiled animal traps, so that they can be automatically re-baited and reused + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua +- ``widgets.Slider``: new mouse-controlled single-headed slider widget + +## Removed + +# 51.13-r1 + +## New Features + +- Compatibility with DF 51.13 + +# 51.12-r1.1 + +## New Features + +- Compatibility with Itch release of DF 51.12 + +# 51.12-r1 + +## Fixes +- `getplants`: will no longer crash when faced with plants with growths that do not drop seeds when processed +- `getplants`: use updated formula for calculating whether plant growths are ripe +- `getplants`: fix logic for determining whether plant growths have been picked +- `gui/teleport`: adapt to new behavior in DF 51.11 to avoid a crash when teleporting items into mid-air +- `script-manager`: fix lua scripts in mods not being reloaded properly upon entering a saved world on Windows +- `preserve-rooms`: don't warn when a room is assigned to a non-existent unit. this is now common behavior for DF when it keeps a room for an unloaded unit +- fixed an overly restrictive type constraint that resulted in some object types being glossed as a boolean when passed as an argument from C++ to Lua +- `plants`: will no longer generate a traceback when a filter is used +- `createitem`: multiple items should be properly created in stacks again + +## Misc Improvements +- All places where units are listed in DFHack tools now show the translated English name in addition to the native name. In particular, this makes units searchable by English name in `gui/sitemap`. +- `dig`: ASCII overlay now displays priority of digging designations +- `spectate`: added prefer nicknamed units +- `blueprint`: support for recording zones +- `blueprint`: support for recording stockpile properties like names and stockpile links; does not yet support recording detailed contents configuration +- `strangemood`: support added for specifying unit id instead of selected unit or random one. + +## API +- ``Random`` module: added ``SplitmixRNG`` class, implements the Splitmix64 RNG used by Dwarf Fortress for "simple" randomness +- ``Items::getDescription``: fixed display of quality levels, now displays ALL item designations (in correct order) and obeys vanilla SHOW_IMP_QUALITY setting +- ``cuboid::forCoord``, ``Maps::forCoord``: take additional parameter to control whether iteration goes in column major or row major order + +## Lua +- ``script-manager``: new ``get_active_mods()`` function for getting information on active mods +- ``script-manager``: new ``get_mod_info_metadata()`` function for getting information out of mod ``info.txt`` files + +## Removed +- removed historically unused ``Core::RegisterData``/``Core::GetData`` API and associated internal data structures + +# 51.11-r1.2 + +## Fixes +- `preserve-tombs`: will no longer crash when a tomb is assigned to a unit that does not exist + +# 51.11-r1.1 + +## Fixes +- `preserve-rooms`: will no longer crash when a civzone is assigned to a unit that does not exist +- `gui/design`: fix misaligned shape icons + +# 51.11-r1 + +## Fixes +- `spectate`: don't show a hover tooltip for hidden units (e.g. invisible snatchers) +- `stockpiles`: fix one-off error in item type when importing furniture stockpile settings +- `dig-now`: fix cases where boulders/rough gems of incorrect material were being generated when digging through walls +- `dig-now`: properly generate ice boulders when digging through ice walls +- `gui/teleport`: now properly handles teleporting units that are currently falling or being flung +- `unload`: fix recent regression where `unload` would immediately `reload` the target +- ``Buildings`` module: do not crash if a ``map_block`` unexpectedly contains an item that is not on the master item vector +- `suspendmanager`: fix walls being treated as potential suitable access if another wall is built underneath +- text widgets no longer lose their cursor when the Ctrl-a (select all) hotkey is pressed when there is no text to select + +## Misc Improvements +- `spectate`: show dwarves' activities (like prayer) + +## API +- ``Military`` module: added ``addToSquad`` function +- ``Units`` module: added ``get_cached_unit_by_global_id`` to emulate how DF handles unit vector index caching (used in civzones and in general references) +- ``Buildings`` module: add ``getOwner`` (using the ``Units::get_cached_unit_by_global_id`` mechanic) to reflect changes in 51.11 +- ``Units::teleport``: projectile information is now cleared for teleported units +- ``Buildings::setOwner``: updated for changes in 51.11 + +## Lua +- ``dfhack.military.addToSquad``: expose Military API function +- ``dfhack.buildings.getOwner``: make new Buildings API available to Lua + +# 51.10-r1 + +## Misc Improvements +- Compatibility with DF 51.10 + +# 51.09-r1 + +## New Features +- `gui/journal`: Ctrl-j hotkey to launch `gui/journal` now works in adventure mode! + +## Fixes +- Fix processing error in the overlay that displays unit preferences in the baron selection list + +## API +- ``Filesystem`` module: rewritten to use C++ standard library components, for better portability + +# 51.08-r1 + +## Misc Improvements +- Compatibility update for DF 51.08 + +# 51.07-r1 + +## New Features +- `spectate`: can now specify number of seconds (in real time) before switching to follow a new unit +- `spectate`: new "cinematic-action" mode that dynamically speeds up perspective switches based on intensity of conflict +- `spectate`: new global keybinding for toggling spectate mode: Ctrl-Shift-S +- `spectate`: new overlay panel that allows you to cycle through following next/previous units (regardless of whether spectate mode is enabled) +- `gui/sitemap`: is now the official "go to" tool. new global hotkey for fort and adventure mode: Ctrl-G + +## Fixes +- Windows console: fix possible hang if the console returns a too-small window width (for any reason) +- `createitem`: produced items will now end up at the look cursor position (if it is active) +- `spectate`: don't allow temporarily modified announcement settings to be written to disk when "auto-unpause" mode is enabled +- `changevein`: fix a crash that could occur when attempting to change a vein into itself +- `overlay`: reset draw context between rendering widgets so context changes can't propagate from widget to widget +- `suspendmanager`: in ASCII mode, building planning mode overlay now only displays when viewing the default map, reducing issues with showing through the UI + +## Misc Improvements +- `spectate`: player-set configuration is now stored globally instead of per-fort +- `autobutcher`: treat animals on restraints as unavailable for slaughter +- `stockpiles`: add property filters for brewable, millable, and processable (e.g. at a Farmer's workshop) organic materials +- `quickfort`: redesigned ``library/aquifer_tap.cav`` to improve the water fill rate + +## Documentation +- `stonesense-art-guide`: guide for making sprite art for Stonesense + +## API +- ``Military::removeFromSquad``: removes unit from any squad assignments +- ``Buildings::checkFreeTiles``: now takes a building instead of a pointer to the building extents +- ``Units::isUnitInBox``, ``Units::getUnitsInBox``: don't include inactive units +- ``Items::getItemBaseValue``: adjust to the reduced value of prepared meals (changed in DF 51.06) +- ``Items::getValue``: magical powers now correctly contribute to item value + +## Lua +- ``dfhack.units.setAutomaticProfessions``: sets unit labors according to current work detail settings +- ``dfhack.military.removeFromSquad``: Lua API for ``Military::removeFromSquad`` +- ``gui.dwarfmode``: adventure mode cursor now supported in ``getCursorPos``, ``setCursorPos``, and ``clearCursorPos`` funcitons +- ``dfhack.buildings.checkFreeTiles``: now takes a building pointer instead of an extents parameter +- ``overlay.isOverlayEnabled``: new API for querying whether a given overlay is enabled +- ``overlay``: widgets can now declare ``overlay_onenable`` and ``overlay_ondisable`` functions to hook enable/disable + +## Removed +- `orders`: MakeCheese job removed from library/basic orders set. Please use `autocheese` instead! + +# 51.06-r1 + +## Misc Improvements +- Compatibility with DF 51.06 + +# 51.05-r1 + +## Misc Improvements +- Compatibility with DF 51.05 + +# 51.04-r1.1 + +## Fixes +- `gui/launcher`: ensure commandline is fully visible when searching through history and switching from a very long command to a short command +- `gui/launcher`: flatten text when pasting multi-line text from the clipboard +- Ctrl-a hotkeys have been changed to something else (Ctrl-n) for tools that also have an editable text field, where Ctrl-a is interpreted as select all text + +## API +- ``Core::getUnpausedMs``: new API for getting unpaused ms since load in a fort-mode game + +# 51.04-r1 + +## Misc Improvements +- Compatibility with Steam release of DF 51.04 + +# 51.03-r1.1 + +## Misc Improvements +- Compatibility with Itch release of DF 51.03 + +# 51.03-r1 + +## Fixes +- `gui/gm-editor`: fix Enter key not being recognized for opening the selected object + +# 51.02-r1 + +## Misc Improvements +- DFHack edit field widgets, such as the commandline editor in `gui/launcher`, now support text selection and other advanced text editing features from `gui/journal` + +# 50.15-r2 + +## New Features +- `stockpiles`: add simple import/export dialogs to stockpile overlay panel +- `orders`: add transparent overlays to the manager orders screen that allow right clicks to cancel edit of quantities or condition details instead of exiting to the main screen + +## Fixes +- `preserve-rooms`: don't erroneously release reservations for units that have returned from their missions but have not yet entered the fort map +- `preserve-rooms`: handle case where unit records are culled by DF immediately after a unit leaves the map +- `preserve-tombs`: properly re-enable after loading a game that had the tool enabled +- `zone`: assign animal to cage/restraint dialog now allows you to unassign a pet from the cage or restraint if the pet is already somehow assigned (e.g. war dog was in cage and was subsequently assigned to a dwarf) +- `stockpiles`: don't set ``use_links_only`` flag to a random value when the flag is not set to anything in the settings that are being imported +- `strangemood`: ensure generated names for artifacts match what the game itself would generate + +## Misc Improvements +- `strangemood`: add ability to choose Stone Cutting and Stone Carving as the mood skill +- `suspendmanager`: add more specific messages for submerged job sites and those managed by `buildingplan` +- `dig-now`: handle digging in pool and river tiles + +## Documentation +- Added example code for creating plugin RPC endpoints that can be used to extend the DFHack API + +## API +- ``Units::isUnitInBox``, ``Units::getUnitsInBox``: add versions accepting pos arguments +- ``Units::getVisibleName``: when acting on a unit without an impersonated identity, returns the unit's name structure instead of the associated histfig's name structure +- ``Translation::generateName``: generates in-game names, mirroring DF's internal logic +- ``Persistence::getUnsavedSeconds``: returns the number of seconds since last save or load + +## Lua +- ``dfhack.units.isUnitInBox``, ``dfhack.units.getUnitsInBox``: add versions accepting pos arguments +- ``widgets.FilteredList``: search keys for list items can now be functions that return a string +- ``dfhack.translation.generateName``: Lua API for ``Translation::generateName`` +- ``dfhack.persistent.getUnsavedSeconds``: Lua API for ``Persistence::getUnsavedSeconds`` + +## Removed +- ``dfhack.TranslateName`` has been renamed to ``dfhack.translation.translateName`` + +## Internals +- Plugin command callbacks are now called with the core suspended by default so DF memory is always safe to access without extra steps +- Errors when unloading a plugin's DLL are now checked and reported + +# 50.15-r1.2 + +## Misc Improvements + +- Updated support for Itch + +# 50.15-r1.1 + +## Misc Improvements + +- Updated support for Classic (Itch not available for analysis yet) + +# 50.15-r1 + +## Fixes + +- `gui/prerelease-warning`: don't pop up during worldgen, only after a fort has been loaded + +# 50.14-r2 + +## New Tools +- `infinite-sky`: (reinstated, renamed from ``infiniteSky``) automatically create new z-levels of sky to build in +- `forceequip`: (reinstated) forcibly move items into a unit's inventory + +## New Features +- `tweak`: ``realistic-melting``: change melting return for inorganic armor parts, shields, weapons, trap components and tools to stop smelters from creating metal, bring melt return for adamantine in line with other metals to ~95% of forging cost. wear reduces melt return by 10% per level + +## Fixes +- Fix mouse clicks bleeding through resizable DFHack windows when clicking in the space between the frame and the window content +- `autobutcher`: don't run a scanning and marking cycle on the first tick of a fortress to allow for all custom configuration to be set first +- `nestboxes`: don't consider eggs to be infertile just because the mother has left the nest; eggs can still hatch in this situation +- `timestream`: adjust the incubation counter on fertile eggs so they hatch at the expected time +- `timestream`: adjust the timeout on traps so they can be re-triggered at normal rates +- `logistics`: don't ignore rotten items when applying stockpile logistics operations (e.g. autodump, autoclaim, etc.) + +## Misc Improvements +- DFHack now verifies that critical DF data structures have known sizes and refuses to start if there is a mismatch +- DFHack text edit fields now delete the character at the cursor when you hit the Delete key +- DFHack text edit fields now move the cursor by one word left or right with Ctrl-Left and Ctrl-Right +- DFHack text edit fields now move the cursor to the beginning or end of the line with Home and End +- Quickfort blueprint library: ``aquifer_tap`` blueprint walkthough rewritten for clarity +- Quickfort blueprint library: ``aquifer_tap`` blueprint now designated at priority 3 and marks the stairway tile below the tap in "blueprint" mode to prevent drips while the drainage pipe is being prepared +- `preserve-rooms`: automatically release room reservations for captured squad members. we were kidding ourselves with our optimistic kept reservations. they're unlikely to come back : (( +- `buildingplan`: add value info to item selection dialog (effectively ungrouping items with different values) and add sorting by value +- `timestream`: improve FPS by a further 10% +- `fix/occupancy`: additionally handle the case where tile building occupancy needs to be set instead of cleared +- `orders`: ``orders sort`` now moves orders that are tied to a specific workshop to the top of the list in the global manager orders screen +- `gui/pathable`: make wagon path to depot representation more robust + +## Documentation +- Dreamfort: add link to Dreamfort tutorial youtube series: https://www.youtube.com/playlist?list=PLzXx9JcB9oXxmrtkO1y8ZXzBCFEZrKxve +- The error message that comes up if there is a version mismatch between DF and DFHack now informs you which DF versions are supported by the installed version of DFHack + +## API +- ``DFHack::Units``: new function ``setPathGoal`` +- ``Units::setAutomaticProfessions``: bay12-provided entry point to assign labors based on work details + +## Lua +- ``dfhack.units``: new function ``setPathGoal`` +- ``widgets.TabBar``: updated to allow for horizontal scrolling of tabs when there are too many to fit in the available space + +## Removed +- UI focus strings for squad panel flows combined into a single tree: ``dwarfmode/SquadEquipment`` -> ``dwarfmode/Squads/Equipment``, ``dwarfmode/SquadSchedule`` -> ``dwarfmode/Squads/Schedule`` +- `faststart`: removed since the vanilla startup sequence is now sufficiently fast + +# 50.14-r1 + +## Fixes +- `preserve-rooms`: don't reserve a room for citizens that you expel from the fort +- `autobutcher`: fix regression in ordering of butcherable animals + +# 50.13-r5 + +## New Tools +- `preserve-rooms`: manage room assignments for off-map units and noble roles. reserves rooms owned by traveling units and reinstates their ownership when they return to the site. also allows you to assign rooms to noble/administrator roles, and the rooms will be automatically assigned whenever the holder of the role changes + +## Fixes +- prevent hang when buildings in zones are destroyed in the case where the buildings were not added to the zone in the same order that they were created (uncommon) +- `buildingplan`: improved performance in forts with large numbers of items +- System clipboard: when pasting single lines from the system clipboard, replace newlines with spaces so they don't show up as strange CP437 glyphs in-game +- `exterminate`: don't kill friendly undead (unless ``--include-friendly`` is passed) when specifying ``undead`` as the target +- `gui/settings-manager`: work details overlay no longer disappears when you click on a unit in the unit list +- `buildingplan`: fixed processing errors when using quick material filter slot '0' +- DFHack screens that allow keyboard cursor and camera movement while focused now also allow diagonal and Z-change keyboard cursor keys +- `strangemood`: manually-triggered Macabre moods will now correctly request up to 3 bones/remains for the primary component instead of only 1 +- `regrass`: no longer add all compatible grass types when using ``--force`` without ``--new`` +- `regrass`: ``--mud`` now converts muddy slade to grass, consistent with normal DF behavior +- `gui/pathable`: fix hang when showing trade depot wagon access and a trade depot is submerged under water or magma +- `gui/pathable`: fix representation of wagon paths over stairs and through doors +- DFHack state for a site is now properly saved when retiring a fort +- `gui/teleport`: fix issue when teleporting units that are not prone, resulting in later issues with phantom "cannot build here: unit blocking tile" messages + +## Misc Improvements +- `sort`: can now search for stockpiles on the Places>Stockpile tab by name, number, or enabled item categories +- `gui/family-affairs`: you can start this tool by the name ``gui/pregnancy`` to start directly on the "Pregnancies" tab +- `buildingplan`: only consider building materials that can be accessed by at least one citizen/resident +- Dreamfort: integrate with `preserve-rooms` to assign relevant rooms to nobles/adimistrators +- Dreamfort: smooth tiles under statues and other large furniture that you can't easily smooth later + +## Documentation +- add documentation for ``dfhack.items.findType(string)`` and ``dfhack.items.findSubtype(string)`` +- `modding-guide`: added examples for reading and writing various types of persistent storage +- `modding-guide`: updated all code snippets for greater clarity + +## API +- ``Units``: new ``isWildlife`` and ``isAgitated`` property checks +- ``Items::createItem``: removed ``growth_print`` parameter; now determined automatically +- ``DFHack::cuboid``: ``cuboid::clampMap`` now returns the cuboid itself (instead of boolean) to allow method chaining; call ``cuboid::isValid`` to determine success + +## Lua +- ``dfhack.units``: ``isWildlife`` and ``isAgitated`` property checks +- ``dfhack.units.isDanger``: no longer unconditionally returns true for intelligent undead +- Overlay widgets can now assume their ``active`` and ``visible`` functions will only execute in a context that matches their ``viewscreens`` associations +- ``gui.simulateInput``: do not generate spurious keycode from ``_STRING`` key inputs +- ``dfhack.items.createItem``: removed ``growth_print`` parameter to match C++ API + +## Removed +- ``quickfortress.csv``: remove old sample blueprints for "The Quick Fortress", which were unmaintained and non-functional in DF v50+. Online blueprints are available at https://docs.google.com/spreadsheets/d/1WuLYZBM6S2nt-XsPS30kpDnngpOQCuIdlw4zjrcITdY if anyone is interested in giving these blueprints some love + +# 50.13-r4 + +## New Features +- `gui/journal`: new hotkey, accessible from anywhere in fort mode: Ctrl-j + +## Fixes +- `changelayer`: fix incorrect lookup of geological region in multi-region embarks +- Copy/Paste: Fix handling of multi-line text when interacting with the system clipboard on Windows +- `zone`: fix alignment of animal actions overlay panel (the one where you can click to geld/train/etc.) when the animal has a custom portrait (like named dragons) +- `autodump`: cancel any jobs that point to dumped items +- `add-spatter`: fix a crash related to unloading a savegame with add-spatter reactions, then loading a second savegame with add-spatter reactions +- `plant`: properly detect trees in a specified cuboid that only have branches/leaves in the cuboid area + +## Misc Improvements +- performance improvements for DFHack tools and infrastructure +- `gui/pathable`: give edge tiles where wagons can enter the map a special highlight to make them more identifiable. this is especially useful when the game decides that only a portion of the map edge is usable by wagons. +- `autodump`: allow dumping items into mid-air, converting them into projectiles like `gui/autodump` does + +## Documentation +- improved docs for ``dfhack.units`` module functions + +## API +- ``Units``: add overloads that take historical figures for ``getReadableName``, ``getVisibleName``, and ``getProfessionName`` +- ``Units::isUnitInBox``, ``getUnitsInBox``: add versions that take a cuboid range, add filter fn parameter for ``getUnitsInBox`` +- ``Units::getProfession``: account for units with fake identities +- ``Units::getCasteRaw``: get a caste_raw from a unit or race and caste +- ``cuboid``: construct from ``df::map_block*``, ``forBlock`` iterator to access map blocks in cuboid +- ``cuboid``: ``clamp(cuboid other)``, ``clampNew(cuboid other)`` for cuboid intersection. ``clampNew`` returns new cuboid instead of modifying. +- ``Items``: no longer need to pass MapCache parameter to ``moveToGround``, ``moveToContainer``, ``moveToBuilding``, ``moveToInventory``, ``makeProjectile``, or ``remove`` +- ``Units::isVisible``: account for units in cages +- ``Units::getReadableName``: correct display of ghost+curse names w/r/t each other and unit prof, use ``curse.name`` instead of iterating syndrome name effects +- ``setAreaAquifer``, ``removeAreaAquifer``: add overloads that take cuboid range specifiers +- ``Units::isNaked``: now only checks equipped items (including rings, for now). Setting bool ``no_items`` to true checks empty inventory like before. +- ``Units::isUndead``: bool ``include_vamps`` renamed to ``hiding_curse``. Fn now checks that instead of bloodsucker syndrome. +- ``Units::isDanger``: added bool ``hiding_curse``, passed to ``isUndead`` to avoid spoilers +- ``Units::getRaceChildName``, ``getRaceChildNameById``, ``getRaceBabyName``, ``getRaceBabyNameById``: bool ``plural`` to get plural form +- ``Units::getProfessionName``: bool ``land_title`` to append "of Sitename" where applicable, use Prisoner/Slave and noble spouse titles (controlled by ``ignore_noble``) + +## Lua +- ``gui.ZScreen``: new ``defocused`` property for starting screens without keyboard focus +- ``dfhack.units``: allow historical figures to be passed instead of units for ``getReadableName``, ``getVisibleName``, and ``getProfessionName`` +- ``dfhack.items.moveToInventory``: make ``use_mode`` and ``body_part`` args optional +- ``dfhack.units``: add ``getRaceReadableName``, ``getRaceReadableNameById``, ``getRaceNamePluralById`` + +## Removed +- The ``PRELOAD_LIB`` environment variable has been renamed to ``DF_PRELOAD`` to match the naming scheme of other environment variables used by the ``dfhack`` startup script. If you are preloading libraries (e.g. for performance testing) please define ``DF_PRELOAD`` instead of ``PRELOAD_LIB`` or ``LD_PRELOAD`` +- ``cuboid::clamp(bool block)``: renamed to ``cuboid::clampMap(bool block)``, name taken by ``cuboid::clamp(cuboid other)`` +- ``Units::MAX_COLORS``, ``Units::findIndexById``, ``Units::getNumUnits``, ``Units::getUnit``: replaced by ``DFHack::COLOR_MAX`` and the generated type-specific ``get_vector`` functions +- ``Units::getPhysicalDescription``: function requires DF call point that is no longer available. alternative is to navigate the unit info sheet and extract the description from the UI (see `markdown`) + +# 50.13-r3 + +## New Tools +- `plant`: (reinstated) tool for creating/growing/removing plants + +## New Features +- `tweak`: ``named-codices``: display book titles instead of a material description in the stocks/trade screens +- `logistics`: automatically forbid or claim items brought to a stockpile +- `plant`: can now ``remove`` shrubs and saplings; ``list`` all valid shrub/sapling raw IDs; ``grow`` can make mature trees older; many new command options +- Locale-sensitive number formatting: select your preferred format in `gui/control-panel`. prices and other large numbers in DFHack UIs can be displayed with commas (English formatting), the number formatting used by your system locale, in SI units (e.g. ``12.3k``), or even in scientific notation + +## Fixes +- ``Gui::makeAnnouncement``, ``Gui::autoDFAnnouncement``: fix case where a new announcement is created instead of adding to the count of an existing announcement if the existing announcement was the first one in the reports vector +- `regrass`: don't remove mud on regrass, consistent with vanilla behavior +- `seedwatch`: display a limit of ``-`` instead of ``0`` for a seed that is present in inventory but not being watched +- `tiletypes`: make aquifers functional when adding the ``aquifer`` property and there are no existing aquifer tiles in the same map block +- `seedwatch`: do not include unplantable tree seeds in status report +- ``Buildings::containsTile``: fix result for buildings that are solid and have no extent structures +- Mortal mode: prevent keybindings that run armok tools from being recognized when in mortal mode +- `dig`: don't leave phantom dig designations behind when autodigging warm/damp designated tiles +- `buildingplan`: properly identify appropriate construction items for modded buildings built from thread +- `overlay`: overlay positions are now adjusted according to the configured max interface width percentage in the DF settings +- `zone`: animal assignment overlay button moved to not conflict with vanilla aquarium/terrarium button on glass cages +- `zone`: allow friendly creatures to be released from cages by assigning them to a pasture zone and then unassigning them +- `autobutcher`: fix inverted ranking of which animals to butcher first + +## Misc Improvements +- `blueprint`: capture track carving designations in addition to already-carved tracks +- `changevein`: follow veins into adjacent map blocks so you can run the command once instead of once per map block that the vein crosses +- `regrass`: now accepts numerical IDs for grass raws; ``regrass --list`` replaces ``regrass --plant ""`` +- `tiletypes`: performance improvements when affecting tiles over a large area +- `tiletypes`: support for creating heavy aquifers +- `tiletypes`: new ``autocorrect`` property for autocorrecting adjacent tiles when making changes (e.g. adding ramp tops when you add a ramp) +- Dreamfort: add a full complement of beds and chests to both barracks +- Dreamfort: redesign guildhall/temple/library level for better accessibility +- Dreamfort: walkthrough documentation refresh +- Dreamfort: add milking/shearing station in surface grazing pasture +- Dreamfort: integrate building prioritization into the blueprints and remove `prioritize` checklist steps +- Dreamfort: add plumbing template for filling cisterns with running water +- `buildingplan`: add option to ignore items from a specified burrow +- `autobutcher`: do not butcher pregnant (or brooding) females +- `quickfort`: support buildable instruments +- `orders`: you can now delete your exported orders from the import dialog +- `nestboxes`: increase the scanning frequency for fertile eggs to reduce the chance that they get snarfed by eager dwarves +- `autonestbox`: wait until juveniles become adults before they are assigned to nestboxes +- `suspendmanager`: add option to ``unsuspend`` that unsuspends all jobs, regardless of potential issues (like blocking other construction jobs) +- `gui/create-item`: allow right click to cancel out of material dialog submenus + +## Documentation +- `installing`: add instructions for how to use Steam DFHack with non-Steam DF (e.g. to benefit from DFHack auto-updates and cloud backups) +- `modding-guide`: add a section on persistent storage, both for global settings and world-specific settings +- Developer's primer for DFHack's type identity system + +## API +- Focus strings have moved for stockpile states: ``dwarfmode/CustomStockpile`` is now ``dwarfmode/Stockpile/Some/Customize`` and similar for ``dwarfmode/StockpileTools`` and ``dwarfmode/StockpileLink`` +- ``Buildings::getName``: get a building's name +- ``Maps::isTileAquifer``, ``Maps::isTileHeavyAquifer``, ``Maps::setTileAquifer``, ``Maps::removeTileAquifer``, ``Maps::setAreaAquifer``, ``Maps::removeAreaAquifer``: new aquifer detection and modification API +- ``Units::create``, ``Units::makeown``: new APIs to use bay12-provided entry points for low-level operations +- ``format_number``: format numbers according to the configured player formatting preference +- ``Items::remove``: now cancels related jobs and marks the item as hidden and forbidden until it can be garbage collected +- ``Job::addGeneralRef``: new easy API for creating general references and adding them to a Job +- ``Job::addWorker``: new API function for assigning a job to unit + +## Lua +- ``dfhack.gui.getSelectedJob``: can now return the job with a destination under the keyboard cursor (e.g. digging/carving/engraving jobs) +- ``widgets.makeButtonLabelText``: create text and graphical buttons from character/color/tile maps and/or dynamically loaded tilesets +- ``widgets.DimensionsTooltip``: reusable selected dimensions tooltip that follows the mouse cursor around +- ``widgets.ButtonGroup``: subclass of CycleHotkeyLabel that additionally displays clickable graphical buttons +- ``widgets.CycleHotkeyLabel``: when the widget has both forward and backward hotkeys defined, support moving backwards by clicking on the appropriate hotkey hint +- ``safe_index``: will now return nil when attempting to index into a non-indexable object +- ``script-manager``: add ``getModSourcePath`` and ``getModStatePath`` so modders can get the directory path to their own files +- ``widgets.FilteredList``: don't restrict the player from inputting multiple successive space characters +- ``dfhack.maps.isTileAquifer``, ``dfhack.maps.isTileHeavyAquifer``, ``dfhack.maps.setTileAquifer``, ``dfhack.maps.removeTileAquifer``: access to new aquifer API +- ``plugins.tiletypes.tiletypes_setTile``: can now accept a table for access to previously unavailable options +- ``dialogs.showYesNoPrompt``: extend options so the standard dialog can be used for `gui/confirm`-style confirmation prompts +- ``dfhack.units.create``, ``dfhack.units.makeown``: Lua access to new module API +- ``dfhack.formatInt``, ``dfhack.formatFloat``: formats numbers according to the player preferences for number formatting set in `gui/control-panel` +- ``gui.get_interface_rect``, ``gui.get_interface_frame``: convenience functions for working with scaled interfaces +- ``overlay``: new attributes: ``fullscreen`` and ``full_interface`` for overlays that need access to the entire screen or the scaled interface area, respectively +- ``string:wrap``: now preserves inter-word spacing and can return the wrapped lines as a table of strings instead of a single multi-line string +- ``dfhack.internal.getClipboardTextCp437Multiline``: for retrieving multiline text from the system clipboard + +## Removed +- `plants`: renamed to `plant` +- ``gui.FramedScreen``: this class is now deprecated; please use ``gui.ZScreen`` and ``widgets.Window`` instead +- ``dfhack.HIDE_CONSOLE_ON_STARTUP`` and ``dfhack.HIDE_ARMOK_TOOLS`` are no longer directly accessible. Please use `control-panel` or `gui/control-panel` to interact with those settings. + +# 50.13-r2.1 + +## Fixes +- `suspendmanager`: stop suspending single tile stair constructions + +# 50.13-r2 + +## New Tools +- Updated for adventure mode: `reveal` + +## New Features +- `buildingplan`: quick material filter favorites on main planner panel +- DFHack and the Dwarf Fortress translation project can now both be run at the same time + +## Fixes +- `zone`: fix display of distance from cage/pit for small pets in assignment dialog +- `blueprint`: correctly define stockpile boundaries in recorded stockpile ("place") blueprints when there are adjacent non-rectangular stockpiles of identical types +- `dig`: refresh count of tiles that will be modified by "mark all designated tiles on this z-level for warm/damp dig" when the z-level changes +- `dig`: don't affect already-revealed tiles when marking z-level for warm/damp dig +- `zone`: refresh values in distance column when switching selected pastures when the assign animals dialog is open +- `logistics`: include semi-wild pets when autoretrain is enabled +- `suspendmanager`: fully suspend unbuildable dead ends (e.g. building second level of a wall when the wall top is only accessible via ramp, causing the planned wall to be pathable but not buildable) +- `prospect`: don't use scientific notation for representing large numbers + +## Misc Improvements +- `caravan`: display who is in the cages you are selecting for trade and whether they are hostile +- `regrass`: can now add grass to stairs, ramps, ashes, buildings, muddy stone, shrubs, and trees +- `regrass`: can now restrict area of effect to specified tile, block, cuboid, or z-levels +- `regrass`: can now add grass in map blocks where there hasn't been any +- `regrass`: can now choose specific grass type +- `dig`: warm/damp/aquifer status will now be shown in mining mode for tiles that your dwarves can see from the level below +- `dig`: warm/damp/aquifer status will now be shown when in smoothing/engraving modes +- `stockpiles`: support import and export "desired items" configuration for route stops +- New commandline options for controlling the Cloud Save coprocess when launching from Steam. See the `dfhack-core` documentation for details. +- `markdown`: new keybinding for triggering text export: Ctrl-t (when unit or item is selected) +- `flashstep`: new keybinding for teleporting adventurer to the mouse cursor: Ctrl-t (when adventure map is in the default state and mortal mode is disabled in DFHack preferences) +- Dreamfort: move wells on services level so brawling drunken tavern patrons are less likely to fall in +- `unretire-anyone`: new keybinding for adding a historical figure to the adventurer selection list in the adventure mode setup screen: Ctrl-a + +## Documentation +- Quickfort Blueprint Library: add demo videos for pump stack and light aquifer tap blueprints +- Update docs for dependency requirements and compilation procedures + +## API +- ``dfhack.items.getReadableDescription()``: easy API for getting a human-readable item description with useful annotations and information (like tattered markers or who is in a cage) +- ``Items::createItem``: now returns a list of item pointers rather than a single ID, moved creator parameter to beginning, added growth_print and no_floor parameters at end +- ``World::getAdventurer``: returns current adventurer unit +- ``World::ReadPauseState``: now returns true when the game is effectively paused due to a large panel obscuring the map. this aligns the return value with the visual state of the pause button when in fort mode. + +## Lua +- ``dfhack.internal.setClipboardTextCp437Multiline``: for copying multiline text to the system clipboard +- ``dfhack.world.getAdventurer``: returns current adventurer unit +- ``dfhack.items.createItem``: return value and parameters have changed as per C++ API + +# 50.13-r1.1 + +## Documentation +- Update docs on release procedures and symbol generation + +# 50.13-r1 + +## Fixes +- Fixed misidentification of visitors from your own civ as residents; affects all tools that iterate through citizens/residents +- `cursecheck`: act on selected unit only if a unit is selected +- Fixed incorrect DFHack background window texture when DF is started in ascii mode and subsequently switched to graphics mode + +## Misc Improvements +- `suspendmanager`: Account for walls planned on the z-layer below when determining accessibility to a job + +## Documentation +- `autoclothing`: add section comparing ``autoclothing`` and `tailor` to guide players choosing which to enable + +# 50.12-r3 + +## New Tools +- `aquifer`: commandline tool for creating, draining, and modifying aquifers + +## New Features +- `buildingplan`: add overlays for unlinking and freeing mechanisms from buildings +- `dig`: designate tiles for damp or warm dig, which allows you to dig through damp or warm tiles without designations being canceled +- `dig`: damp and warm tile icons now remain visible when included in the designation selection box (graphics mode) +- `dig`: aquifer tiles are now visually distinct from "just damp" tiles (graphics and ascii modes) +- `dig`: light aquifer tiles are now visually distinct from heavy aquifer tiles (graphics and ascii modes) +- `dig`: autodig designations that are marked for damp/warm dig propagate the damp/warm tag when expanding to newly exposed tiles +- `blueprint`: designations and active dig jobs are now captured in generated blueprints +- `blueprint`: warm/damp dig markers are captured in generated blueprints + +## Fixes +- fix behavior of Linux Steam launcher on systems that don't support the inotify API +- fix rendering of resize "notch" in lower right corner of resizable windows in ascii mode +- `quickfort`: stockpiles can now be placed even if there is water covering the tile, as per vanilla behavior +- `suspendmanager`: prevent cancellation spam when an item is preventing a building from being completed +- `stonesense`: fix a crash with buildings made of unusual materials (such as campsite tents made out of organic "walls") + +## Misc Improvements +- `tailor`: allow turning off automatic confiscation of tattered clothing +- aquifer_tap blueprint: now designates in damp dig mode for uninterrupted digging in a light aquifer +- pump_stack blueprint: now designates in warm and damp dig mode for uninterrupted digging through warm and damp tiles +- `keybinding`: you can now assign keybindings to mouse buttons (if your mouse has more than the three buttons already used by DF) + +## Documentation +- Lua API: documented existing ``enum:next_item(index)`` function + +## API +- ``Units::citizensRange``: c++-20 std::range filter for citizen units +- ``Units::forCitizens``: iterator callback function for citizen units +- ``Units::paintTile``, ``Units::readTile``: now takes an optional field specification for reading and writing to specific map compositing layers +- ``Buildings::checkFreeTiles``: now takes a ``allow_flow`` parameter to control whether water- or magma-filled tiles are valid + +## Lua +- ``dfhack.gui.matchFocusString``: focus string matching is now case sensitive (for performance reasons) + +# 50.12-r2.1 + +## Fixes +- `orders`: don't intercept keyboard input for setting skill or labor restrictions on workshop workers tab when the player is setting the building nickname + +# 50.12-r2 + +## New Features +- `stocks`: add button/hotkey for removing empty categories from the stocks list +- `sort`: updated and reinstated military status/squad membership/burrow membership filter for work animal assignment screen +- `logistics`: ``autoretrain`` will automatically assign trainers to your partially-trained (but not yet domesticated) livestock. this prevents children of partially-trained parents from reverting to wild if you don't notice they were born +- `orders`: add overlay for configuring labor and skill level restrictions for workshops + +## Fixes +- `autochop`: fix underestimation of log yield for cavern mushrooms +- `gui/notify`: prevent notification overlay from showing up in arena mode +- `logistics`: don't melt/trade/dump empty containers that happen to be sitting on the stockpile unless the stockpile accepts those item types +- `gui/launcher`: fix detection on Shift-Enter for running commands and autoclosing the launcher +- `logistics`: don't send autotrade items to forbidden depots +- `autoclothing`: don't produce clothes for dead units +- `caravan`: fix trade price calculations when the same item was requested for both import and export + +## Misc Improvements +- `autobutcher`: prefer butchering partially trained animals and save fully domesticated animals to assist in wildlife domestication programs +- `autodump`: can now teleport items loosely stored in buildings (clutter) +- When launched from the Steam client on Linux, both Dwarf Fortress and DFHack will be shown as "Running". This ensures that DF has proper accounting for Linux player usage. +- `suspendmanager`: improve performance when there are many active jobs +- `clean`: protect farm plots when cleaning mud +- `tweak`: add ``quiet`` option for silent enablement and disablement of tweaks +- `gui/teleport`: add global Ctrl-Shift-T keybinding (only available when DFHack mortal mode is disabled) +- Dreamfort: the four Craftsdwarf's workshops on the industry level are now specialized for Stonecrafting, Woodcrafting, Bone Carving, and miscellaneous tasks, respectively +- `dwarfvet`: automatically unassign animals from pastures when they need treatment so they can make their way to the hospital. reassign them to their original pasture when treatment is complete. +- `dwarfvet`: ignore animals assigned to cages or restraints +- Many tools that previously only worked for citizens or only for dwarves now work for all citizens and residents, e.g. `fastdwarf`, `rejuvenate`, etc. +- `buildingplan`: remember player preference for whether unavailable materials should be hidden in the filter selection dialog +- `buildingplan`: sort by available quantity by default int he filter selection dialog +- Dreamfort: update embark profile recommendations and example embark profile + +## Documentation +- `overlay-dev-guide`: updated examples and troubleshooting steps +- `introduction`: refresh getting started content +- `quickstart`: refresh quickstart guide + +## API +- ``Units::isForgottenBeast``: property check for forgotten beasts +- ``Units::isGreatDanger``: now includes forgotten beasts +- ``Units::isResident``: property check for residents (as opposed to citizens) +- ``Units::getCitizens``: now includes residents by default + +## Lua +- ``widgets.Label``: ``*pen`` attributes can now either be a pen or a function that dynamically returns a pen +- `helpdb`: ``search_entries`` now returns a match if *all* filters in the ``include`` list are matched. previous behavior was to match if *any* ``include`` filter matched. +- ``matinfo.decode``: now directly handles plant objects +- ``dfhack.units.isForgottenBeast``: make new units method available to Lua +- ``dfhack.units.getCitizens``: now includes residents by default + +# 50.12-r1.1 + +## Fixes +- `sort`: fix crash when assigning work animals to units + +## Removed +- offline HTML rendered docs are no longer distributed with DFHack since they are randomly triggering Windows Defender antivirus heuristics. If you want to download DFHack docs for offline browsing, you can still get them from the Downloads link at https://dfhack.org/docs + +# 50.12-r1 + +## Misc Improvements +- `sort`: squad assignment overlay rewritten for compatibility with new vanilla data structures and screen layouts + +## Fixes +- `gui/design`: no longer comes up when Ctrl-D is pressed but other DFHack windows have focus + +## API + +- ``Gui::getWidget``: retrieve a vanilla DF widget by name or index + +## Lua + +- ``dfhack.gui.getWidget``: retrieve a vanilla DF widget by hierarchy path, with each step specified by a widget name or index +- ``dfhack.gui.getWidgetChildren``: retrieve a list of child widgets for a given widget container + +## Removed +- `burrow`: removed overlay 3D box select since it is now provided by the vanilla UI +- `sort`: removed Search widgets for screens that now have vanilla search + +# 50.11-r7 + +## New Tools +- `tweak`: (reinstated) a collection of small bugfixes and gameplay tweaks +- `pet-uncapper`: (reinstated, renamed from ``petcapRemover``) allow pets to breed beyond the default population cap of 50 + +## New Features +- `cleanowned`: Add a "nodump" option to allow for confiscating items without dumping +- `tweak`: Add "flask-contents", makes flasks/vials/waterskins be named according to their contents + +## Fixes +- `dig`: overlay that shows damp designations in ASCII mode now properly highlights tiles that are damp because of an aquifer in the layer above +- `dig-now`: fix digging stairs in the surface sometimes creating underworld gates. +- ``Units::getVisibleName``: don't reveal the true identities of units that are impersonating other historical figures +- ``Gui::revealInDwarfmodeMap``: properly center the zoom even when the target tile is near the edge of the map +- `warn-stranded`: don't complain about units that aren't on the map (e.g. soldiers out on raids) +- `autoclothing`: Fix enabled behavior +- ``Gui::makeAnnouncement``, ``Gui::autoDFAnnouncement``: don't display popup for all announcement types +- ``gui.View:getMouseFramePos``: function now detects the correct coordinates even when the widget is nested within other frames +- `strangemood`: correctly recognize Stonecutter and Stone Carver as moodable skills, move the Mason's boosted mood chance to the Stone Carver, and select Fell/Macabre based on long-term stress + +## Misc Improvements +- `autonestbox`: assign egg layers to the nestbox they have chosen if they have already chosen a nestbox +- `regrass`: also regrow depleted cavern moss +- `probe`: act on the selected building/unit instead of requiring placement of the keyboard cursor for ``bprobe`` and ``cprobe`` +- `buildingplan`: use closest matching item rather than newest matching item +- `zone`: animal assignment dialog now shows distance to pasture/cage and allows sorting by distance +- `zone`: animal assignment dialog shows number of creatures assigned to this pasture/cage/etc. + +## API +- Gui module Announcement functions now use DF's new announcement alert system +- ``Gui::addCombatReport``, ``Gui::addCombatReportAuto``: add versions that take ``report *`` instead of report vector index +- ``Gui::MTB_clean``, ``Gui::MTB_parse``, ``Gui::MTB_set_width``: new functions for manipulating ``markup_text_boxst`` +- ``toupper_cp437(char)``, ``tolower_cp437(char)``: new ``MiscUtils`` functions, return a char with case changed, respecting CP437 +- ``toUpper``, ``toLower``: ``MiscUtils`` functions renamed to ``toUpper_cp437`` and ``toLower_cp437``, CP437 compliant +- Gui focus strings will now include ``dwarfmode/Default`` if the only other panel open is the Squads panel +- ``Gui::revealInDwarfmodeMap``: unfollow any currently followed units/items so the viewport doesn't just jump back to where it was + +## Lua +- Overlay framework now respects ``active`` and ``visible`` widget attributes +- ``dfhack.gui`` announcement functions use default arguments when omitted +- ``dfhack.units.getCitizens`` now only returns units that are on the map +- ``dfhack.upperCp437(string)``, ``dfhack.lowerCp437(string)``: new functions, return string with all chars changed, respecting CP437 code page + +# 50.11-r6 + +## New Features +- `zone`: Add overlay for toggling butchering/gelding/adoption/taming options in animal "Overview" tabs + +## Fixes +- `dig-now`: remove diagonal ramps rendered unusable by digging +- `dig-now`: fix error propagating "light" and "outside" properties to newly exposed tiles when piercing the surface +- `sort`: fix potential crash when switching between certain info tabs +- `suspendmanager`: overlays for suspended building info panels no longer disappear when another window has focus + +## Misc Improvements +- `reveal`: automatically reset saved map state when a new save is loaded +- `autonestbox`: don't automatically assign partially trained egg-layers to nestboxes if they don't have an ongoing trainer assigned since they might revert to wild +- `buildingplan`: replace ``[edit filters]`` button in planner overlay with abbreviated filter information + +## API +- ``Units::assignTrainer``: assign a trainer to a trainable animal +- ``Units::unassignTrainer``: unassign a trainer from an animal +- ``Gui::getAnyWorkshopJob``: get the first job associated with the selected workshop +- ``Gui::getAnyJob``: get the job associated with the selected game element (item, unit, workshop, etc.) + +## Lua +- ``dfhack.units.isTamable``: return false for invaders to match vanilla logic +- ``dfhack.units.assignTrainer``: expose API to Lua +- ``dfhack.units.unassignTrainer``: expose API to Lua +- ``dfhack.gui.getAnyWorkshopJob``: expose API to Lua +- ``dfhack.gui.getAnyJob``: expose API to Lua + +## Removed +- ``nopause``: functionality has moved to `spectate` + +# 50.11-r5 + +## New Tools +- `gui/embark-anywhere`: new keybinding (active when choosing an embark site): Ctrl-A + +## New Features +- `sort`: search and sort for the "choose unit to elevate to the barony" screen. units are sorted by the number of item preferences they have and the units are annotated with the items that they have preferences for +- `zone`: add button to location details page for retiring unused locations +- `gui/mass-remove`: new global keybinding: Ctrl-M while on the fort map + +## Fixes +- `reveal`: now avoids revealing blocks that contain divine treasures, encased horrors, and deep vein hollows (so the surprise triggers are not triggered prematurely) +- `sort`: fix mouse clicks falling through the squad assignment overlay panel when clicking on the panel but not on a clickable widget +- `sort`: fix potential crash when removing jobs directly from the Tasks info screen +- `misery`: fix error when changing the misery factor +- When passing map movement keys through to the map from DFHack tool windows, also pass fast z movements (shift-scroll by default) +- `getplants`: fix crash when processing mod-added plants with invalid materials +- Dreamfort: fix holes in the "Inside+" burrow on the farming level (burrow autoexpand is interrupted by the pre-dug miasma vents to the surface) +- ``Maps::getBiomeType``, ``Maps::getBiomeTypeWithRef``: fix identification of tropical oceans +- DFHack tabs (e.g. in `gui/control-panel`) are now rendered correctly when there are certain vanilla screen elements behind them +- `buildingplan`: when you save a game and load it again, newly planned buildings are now correctly placed in line after existing planned buildings of the same type +- `buildingplan`: treat items in wheelbarrows as unavailable, just as vanilla DF does. Make sure the `fix/empty-wheelbarrows` fix is enabled so those items aren't permanently unavailable! +- `buildingplan`: show correct number of materials required when laying down areas of constructions and some of those constructions are on invalid tiles +- `stonesense`: fix crash in cleanup code after mega screenshot (Ctrl-F5) completes; however, the mega screenshot will still make stonesense unresponsive. close and open the stonesense window to continue using it. +- `gui/design`: fix incorrect highlight when box selecting area in ASCII mode +- `fastdwarf`: prevent units from teleporting to inaccessible areas when in teledwarf mode +- `fastdwarf`: allow units to meander and satisfy needs when they have no current job and teledwarf mode is enabled + +## Misc Improvements +- `autochop`: better error output when target burrows are not specified on the commandline +- `autoclothing` : now does not consider worn (x) clothing as usable/available; reduces overproduction when using `tailor` at same time +- `buildingplan`: add option for preventing constructions from being planned on top of existing constructions (e.g. don't build floors on top of floors) +- `burrow`: flood fill now requires an explicit toggle before it is enabled to help prevent accidental flood fills +- wherever units are listed in DFHack tools, properties like "agitated" or (-trained-) are now shown +- `work-now`: now saves its enabled status with the fort +- `fastdwarf`: now saves its state with the fort +- `zone`: add include/only/exclude filter for juveniles to the pasture/pit/cage/restraint assignment screen +- The "PAUSE FORCED" badge will blink briefly to draw attention if the player attempts to unpause when a DFHack tool window requires the game to be paused +- `sort`: add "Toggle all filters" hotkey button to the squad assignment panel +- `sort`: rename "Weak mental fortitude" filter to "Dislikes combat", which should be more understandable +- Dreamfort: put more chairs adjacent to each other to make the tavern more "social" +- `zone`: show geld status and custom profession (if set, it's the lower editable line in creature description) in pasture/pit/cage/restraint assignment screen +- `orders`: reduce prepared meal target and raise booze target in ``basic`` importable orders in the orders library + +## Documentation +- `installing`: Add installation instructions for wineskin on Mac +- UTF-8 text in tool docs is now properly displayed in-game in `gui/launcher` (assuming that it can be converted to cp-437) +- `modding-guide`: Add examples for script-only and blueprint-only mods that you can upload to DF's Steam Workshop +- DFHack developer's guide updated, with refreshed `architectural-diagrams` + +## API +- ``random_index``, ``vector_get_random``: new ``MiscUtils`` functions, for getting a random entry in a vector +- ``capitalize_string_words``: new ``MiscUtils`` function, returns string with all words capitalized +- ``grab_token_string_pos``: new ``MiscUtils`` function, used for parsing tokens +- ``Items``: add item melting logic ``canMelt(item)``, ``markForMelting(item)``, and ``cancelMelting(item)`` +- ``World``: ``GetCurrentSiteId()`` returns the loaded fort site ID (or -1 if no site is loaded) +- ``World``: ``IsSiteLoaded()`` check to detect if a site (e.g. a player fort) is active (as opposed to the world or a map) +- ``World``: ``AddPersistentData`` and related functions replaced with ``AddPersistentSiteData`` and ``AddPersistentWorldData`` equivalents +- New plugin API for saving and loading persistent data. See plugins/examples/skeleton.cpp and plugins/examples/persistent_per_save_example.cpp for details +- Plugin ABI (binary interface) version bump! Any external plugins must be recompiled against this version of DFHack source code in order to load. +- ``Persistence``: persistent keys are now namespaced by an entity_id (e.g. a player fort site ID) +- ``Persistence``: data is now stored one file per entity ID (plus one for the global world) in the DF savegame directory +- ``Units.isDanger``: now returns true for agitated wildlife +- ``Constructions::designateRemove``: no longer designates the non-removable "pseudo" constructions that represent the top of walls + +## Lua +- ``dfhack.capitalizeStringWords``: new function, returns string with all words capitalized +- ``widgets.Divider``: linear divider to split an existing frame; configurable T-junction edges and frame style matching +- ``dfhack.persistent``: new, table-driven API for easier world- and site-associated persistent storage. See the Lua API docs for details. +- ``dfhack.isSiteLoaded``: returns whether a site (e.g. a player fort) is loaded +- ``dfhack.items``: access to ``canMelt(item)``, ``markForMelting(item)``, and ``cancelMelting(item)`` from ``Items`` module +- ``dfhack.world.getCurrentSite``: returns the ``df.world_site`` instance of the currently loaded fort + +## Removed +- ``persist-table``: replaced by new ``dfhack.persistent`` API +- `channel-safely`: (temporarily) removed due to stability issues with the underlying DF API + +# 50.11-r4 + +## Fixes +- `buildingplan`: fix choosing the wrong mechanism (or something that isn't a mechanism) when linking a lever and manually choosing a mechanism, but then canceling the selection +- RemoteServer: don't shut down the socket prematurely, allowing continuing connections from, for example, dfhack-run +- `sort`: fix potential crash when exiting and re-entering a creatures subtab with a search active +- `sort`: prevent keyboard keys from affecting the UI when search is active and multiple keys are hit at once +- `tailor`: fix corner case where existing stock was being ignored, leading to over-ordering + +## Misc Improvements +- `buildingplan`: save magma safe mechanisms for when magma safety is requested when linking levers and pressure plates to targets +- `buildingplan`: when choosing mechanisms for linking levers/pressure plates, filter out unreachable mechanisms +- `sort`: when searching on the Tasks tab, also search the names of the things the task is associated with, such as the name of the stockpile that an item will be stored in + +# 50.11-r3 + +## New Tools +- `burrow`: (reinstated) automatically expand burrows as you dig + +## New Features +- `prospect`: can now give you an estimate of resources from the embark screen. hover the mouse over a potential embark area and run `prospect`. +- `burrow`: integrated 3d box fill and 2d/3d flood fill extensions for burrow painting mode +- `buildingplan`: allow specific mechanisms to be selected when linking levers or pressure plates +- `sort`: military and burrow membership filters for the burrow assignment screen + +## Fixes +- `stockpiles`: hide configure and help buttons when the overlay panel is minimized +- `caravan`: price of vermin swarms correctly adjusted down. a stack of 10000 bees is worth 10, not 10000 +- `sort`: when filtering out already-established temples in the location assignment screen, also filter out the "No specific deity" option if a non-denominational temple has already been established +- RemoteServer: continue to accept connections as long as the listening socket is valid instead of closing the socket after the first disconnect +- `buildingplan`: overlay and filter editor gui now uses ctrl-d to delete the filter to avoid conflict with increasing the filter's minimum quality (shift-x) +- `tailor`: fix crash on Linux where scanned unit is wearing damaged non-clothing (e.g. a crown) + +## Misc Improvements +- `buildingplan`: display how many items are available on the planner panel +- `buildingplan`: make it easier to build single-tile staircases of any shape (up, down, or up/down) +- `sort`: allow searching by profession on the squad assignment page +- `sort`: add search for places screens +- `sort`: add search for work animal assignment screen; allow filtering by military/squad/civilian/burrow +- `sort`: on the squad assignment screen, make effectiveness and potential ratings use the same scale so effectiveness is always less than or equal to potential for a given unit. this way you can also tell when units are approaching their maximum potential +- `sort`: new overlay on the animal assignment screen that shows how many work animals each visible unit already has assigned to them +- `dreamfort`: Inside+ and Clearcutting burrows now automatically created and managed + +## Documentation +- Document the Lua API for the ``dfhack.world`` module + +## API +- ``Gui::revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target +- ``Maps::getWalkableGroup``: get the walkability group of a tile +- ``Units::getReadableName``: now returns the *untranslated* name +- ``Burrows::setAssignedUnit``: now properly handles inactive burrows +- ``Gui::getMousePos``: now takes an optional ``allow_out_of_bounds`` parameter so coordinates can be returned for mouse positions outside of the game map (i.e. in the blank space around the map) +- ``Buildings::completebuild``: used to link a newly created building into the world + +## Lua +- ``dfhack.gui.revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target +- ``dfhack.maps.getWalkableGroup``: get the walkability group of a tile +- ``dfhack.gui.getMousePos``: support new optional ``allow_out_of_bounds`` parameter +- ``gui.FRAME_THIN``: a panel frame suitable for floating tooltips +- ``dfhack.buildings.completebuild``: expose new module API + +# 50.11-r2 + +## New Tools +- `spectate`: (reinstated) automatically follow dwarves, cycling among interesting ones +- `preserve-tombs`: keep tombs assigned to units when they die + +## New Features +- `logistics`: ``automelt`` now optionally supports melting masterworks; click on gear icon on `stockpiles` overlay frame +- `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", candidate assignment on the "Noble" subtab, and the "Work details" subtab under "Labor" +- `sort`: new search and filter widgets for the "Interrogate" and "Convict" screens under "Justice" +- `sort`: new search widgets for location selection screen (when you're choosing what kind of guildhall or temple to dedicate) +- `sort`: new search widgets for burrow assignment screen and other unit assignment dialogs +- `sort`: new search widgets for artifacts on the world/raid screen +- `sort`: new search widgets for slab engraving menu; can filter for only units that need a slab to prevent rising as a ghost +- `stocks`: hotkey for collapsing all categories on stocks screen + +## Fixes +- `buildingplan`: remove bars of ash, coal, and soap as valid building materials to match v50 rules +- `buildingplan`: fix incorrect required items being displayed sometimes when switching the planner overlay on and off +- `zone`: races without specific child or baby names will now get generic child/baby names instead of an empty string +- `zone`: don't show animal assignment link for cages and restraints linked to dungeon zones (which aren't normally assignable) +- `sort`: don't count mercenaries as appointed officials in the squad assignment screen +- `dwarfvet`: fix invalid job id assigned to ``Rest`` job, which could cause crashes on reload + +## Misc Improvements +- `overlay`: allow ``overlay_onupdate_max_freq_seconds`` to be dynamically set to 0 for a burst of high-frequency updates +- Help icons added to several complex overlays. clicking the icon runs `gui/launcher` with the help text in the help area +- `orders`: ``recheck`` command now only resets orders that have conditions that can be rechecked +- `sort`: added help button for squad assignment search/filter/sort +- `zone`: animals trained for war or hunting are now labeled as such in animal assignment screens +- `buildingplan`: support filtering cages by whether they are occupied +- `buildingplan`: show how many items you need to make when planning buildings +- `tailor`: now adds to existing orders if possible instead of creating new ones + +## Documentation +- unavailable tools are no longer listed in the tag indices in the online docs + +## API +- added ``Items::getCapacity``, returns the capacity of an item as a container (reverse-engineered), needed for `combine` + +## Lua +- added ``GRAY`` color aliases for ``GREY`` colors +- added ``dfhack.items.getCapacity`` to expose the new module API +- ``utils.search_text``: text search routine (generalized from internal ``widgets.FilteredList`` logic) + +## Removed +- ``FILTER_FULL_TEXT``: moved from ``gui.widgets`` to ``utils``; if your full text search preference is lost, please reset it in `gui/control-panel` + +# 50.11-r1 + +## New Tools +- `tubefill`: (reinstated) replenishes mined-out adamantine + +## Fixes +- `autolabor`: ensure vanilla work details are reinstated when the fort or the plugin is unloaded +- ``dfhack.TranslateName()``: fixed crash on certain invalid names, which affected `warn-starving` +- EventManager: Unit death event no longer misfires on units leaving the map + +## Misc Improvements +- `digtype`: designate only visible tiles by default, and use "auto" dig mode for following veins +- `digtype`: added options for designating only current z-level, this z-level and above, and this z-level and below +- `hotkeys`: make the DFHack logo brighten on hover in ascii mode to indicate that it is clickable +- `hotkeys`: use vertical bars instead of "!" symbols for the DFHack logo in ascii mode to make it easier to read +- EventManager: guard against potential iterator invalidation if one of the event listeners were to modify the global data structure being iterated over +- EventManager: for ``onBuildingCreatedDestroyed`` events, changed firing order of events so destroyed events come before created events + +## Lua +- mouse key events are now aligned with internal DF semantics: ``_MOUSE_L`` indicates that the left mouse button has just been pressed and ``_MOUSE_L_DOWN`` indicates that the left mouse button is being held down. similarly for ``_MOUSE_R`` and ``_MOUSE_M``. 3rd party scripts may have to adjust. + +# 50.10-r1 + +## Fixes +- Linux launcher: allow Steam Overlay and game streaming to function +- `autobutcher`: don't ignore semi-wild units when marking units for slaughter + +## Misc Improvements +- 'sort': Improve combat skill scale thresholds + +# 50.09-r4 + +## New Features +- `dig`: new overlay for ASCII mode that visualizes designations for smoothing, engraving, carving tracks, and carving fortifications + +## Fixes +- `buildingplan`: make the construction dimensions readout visible again +- `seedwatch`: fix a crash when reading data saved by very very old versions of the plugin +- `gui/mod-manager`: don't continue to display overlay after the raws loading progress bar appears + +## Misc Improvements +- `sort`: add sort option for training need on squad assignment screen +- `sort`: filter mothers with infants, units with weak mental fortitude, and critically injured units on the squad assignment screen +- `sort`: display a rating relative to the current sort order next to the visible units on the squad assignment screen + +## Documentation +- add instructions for downloading development builds to the ``Installing`` page + +## API +- `overlay`: overlay widgets can now declare a ``version`` attribute. changing the version of a widget will reset its settings to defaults. this is useful when changing the overlay layout and old saved positions will no longer be valid. + +## Lua +- ``argparse.boolean``: convert arguments to lua boolean values. + +# 50.09-r3 + +## New Features +- `sort`: search, sort, and filter for squad assignment screen +- `zone`: advanced unit assignment screens for cages, restraints, and pits/ponds +- `buildingplan`: one-click magma/fire safety filter for planned buildings + +## Fixes +- Core: reload scripts in mods when a world is unloaded and immediately loaded again +- Core: fix text getting added to DFHack text entry widgets when Alt- or Ctrl- keys are hit +- `buildingplan`: ensure selected barrels and buckets are empty (or at least free of lye and milk) as per the requirements of the building +- `orders`: prevent import/export overlay from appearing on the create workorder screen +- `caravan`: corrected prices for cages that have units inside of them +- `tailor`: remove crash caused by clothing items with an invalid ``maker_race`` +- ``dialogs.MessageBox``: fix spacing around scrollable text +- `seedwatch`: ignore unplantable tree seeds +- `autobutcher`: fix ``ticks`` commandline option incorrectly rejecting positive integers as valid values + +## Misc Improvements +- Surround DFHack-specific UI elements with square brackets instead of red-yellow blocks for better readability +- `autobutcher`: don't mark animals for butchering if they are already marked for some kind of training (war, hunt) +- `hotkeys`: don't display DFHack logo in legends mode since it covers up important interface elements. the Ctrl-Shift-C hotkey to bring up the menu and the mouseover hotspot still function, though. +- `sort`: animals are now sortable by race on the assignment screens +- `createitem`: support creating items inside of bags + +## API +- ``Items::getValue()``: remove ``caravan_buying`` parameter since the identity of the selling party doesn't actually affect the item value +- `RemoteFortressReader`: add a ``force_reload`` option to the GetBlockList RPC API to return blocks regardless of whether they have changed since the last request +- ``Units``: new animal property check functions ``isMarkedForTraining(unit)``, ``isMarkedForTaming(unit)``, ``isMarkedForWarTraining(unit)``, and ``isMarkedForHuntTraining(unit)`` +- ``Gui``: ``getAnyStockpile`` and ``getAnyCivzone`` (along with their ``getSelected`` variants) now work through layers of ZScreens. This means that they will still return valid results even if a DFHack tool window is in the foreground. + +## Lua +- ``new()``: improved error handling so that certain errors that were previously uncatchable (creating objects with members with unknown vtables) are now catchable with ``pcall()`` +- ``dfhack.items.getValue()``: remove ``caravan_buying`` param as per C++ API change +- ``widgets.BannerPanel``: panel with distinctive border for marking DFHack UI elements on otherwise vanilla screens +- ``widgets.Panel``: new functions to override instead of setting corresponding properties (useful when subclassing instead of just setting attributes): ``onDragBegin``, ``onDragEnd``, ``onResizeBegin``, ``onResizeEnd`` +- ``dfhack.screen.readTile()``: now populates extended tile property fields (like ``top_of_text``) in the returned ``Pen`` object +- ``dfhack.units``: new animal property check functions ``isMarkedForTraining(unit)``, ``isMarkedForTaming(unit)``, ``isMarkedForWarTraining(unit)``, and ``isMarkedForHuntTraining(unit)`` +- ``dfhack.gui``: new ``getAnyCivZone`` and ``getAnyStockpile`` functions; also behavior of ``getSelectedCivZone`` and ``getSelectedStockpile`` functions has changes as per the related API notes + +# 50.09-r2 + +## New Plugins +- `3dveins`: reinstated for v50, this plugin replaces vanilla DF's blobby vein generation with veins that flow smoothly and naturally between z-levels +- `zone`: new searchable, sortable, filterable screen for assigning units to pastures +- `dwarfvet`: reinstated and updated for v50's new hospital mechanics; allow your animals to have their wounds treated at hospitals +- `dig`: new ``dig.asciiwarmdamp`` overlay that highlights warm and damp tiles when in ASCII mode. there is no effect in graphics mode since the tiles are already highlighted there + +## Fixes +- Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing +- `logistics`: don't autotrain domestic animals brought by invaders (they'll get attacked by friendly creatures as soon as you let them out of their cage) +- `logistics`: don't bring trade goods to depot if the only caravans present are tribute caravans +- `gui/create-item`: when choosing a citizen to create the chosen items, avoid choosing a dead citizen +- `logistics`: fix potential crash when removing stockpiles or turning off stockpile features + +## Misc Improvements +- `stockpiles`: include exotic pets in the "tameable" filter +- `logistics`: bring an autotraded bin to the depot if any item inside is tradeable instead of marking all items within the bin as untradeable if any individual item is untradeable +- `autonick`: add more variety to nicknames based on famous literary dwarves +- ``widgets.EditField``: DFHack edit fields now support cut/copy/paste with the system clipboard with Ctrl-X/Ctrl-C/Ctrl-V +- Suppress DF keyboard events when a DFHack keybinding is matched. This prevents, for example, a backtick from appearing in a textbox as text when you launch `gui/launcher` from the backtick keybinding. +- Dreamfort: give noble suites double-thick walls and add apartment doors + +## Documentation +- `misery`: rewrite the documentation to clarify the actual effects of the plugin + +## API +- ``Units::getUnitByNobleRole``, ``Units::getUnitsByNobleRole``: unit lookup API by role +- ``Items::markForTrade()``, ``Items::isRequestedTradeGood()``, ``Items::getValue``: see Lua notes below + +## Internals +- Price calculations fixed for many item types + +## Lua +- ``dfhack.units.getUnitByNobleRole``, ``dfhack.units.getUnitsByNobleRole``: unit lookup API by role +- ``dfhack.items.markForTrade``: mark items for trade +- ``dfhack.items.isRequestedTradeGood``: discover whether an item is named in a trade agreement with an active caravan +- ``dfhack.items.getValue``: gained optional ``caravan`` and ``caravan_buying`` parameters for prices that take trader races and agreements into account +- ``widgets.TextButton``: wraps a ``HotkeyLabel`` and decorates it to look more like a button + +# 50.09-r1 + +## Internals + +- Core: update SDL interface from SDL1 to SDL2 + +# 50.08-r4 + +## New Plugins +- `logistics`: automatically mark and route items or animals that come to monitored stockpiles. options are toggleable on an overlay that comes up when you have a stockpile selected. + +## Fixes +- `buildingplan`: don't include artifacts when max quality is masterful +- `dig-now`: clear item occupancy flags for channeled tiles that had items on them +- `RemoteFortressReader`: fix a crash with engravings with undefined images + +## Misc Improvements +- `autonick`: additional nicknames based on burrowing animals, colours, gems, and minerals +- `stockpiles`: added ``barrels``, ``organic``, ``artifacts``, and ``masterworks`` stockpile presets +- `orders`: only display import/export/sort/clear panel on main orders screen +- `orders`: refine order conditions for library orders to reduce cancellation spam +- Blueprint library: dreamfort: full rewrite and update for DF v50 +- Blueprint library: pump_stack: updated walkthrough and separated dig and channel steps so boulders can be cleared +- Blueprint library: aquifer_tap: updated walkthrough +- `dig-now`: can now handle digging obsidian that has been formed from magma and water + +## Documentation +- `blueprint-library-guide`: update Dreamfort screenshots and links, add ``aquifer_tap`` screenshot + +# 50.08-r3 + +## Fixes +- Fix crash for some players when they launch DF outside of the Steam client + +# 50.08-r2 + +## New Plugins +- `add-spatter`: (reinstated) allow mods to add poisons and magical effects to weapons +- `changeitem`: (reinstated) change item material, quality, and subtype +- `createitem`: (reinstated) create arbitrary items from the command line +- `deramp`: (reinstated) removes all ramps designated for removal from the map +- `flows`: (reinstated) counts map blocks with flowing liquids +- `lair`: (reinstated) mark the map as a monster lair (this avoids item scatter when the fortress is abandoned) +- `luasocket`: (reinstated) provides a Lua API for accessing network sockets +- `work-now`: (reinstated, renamed from ``workNow``) prevent dwarves from wandering aimlessly with "No job" after completing a task + +## Fixes +- DFHack screen backgrounds now use appropriate tiles in DF Classic +- RemoteServer: fix crash on malformed json in ``dfhack-config/remote-server.json`` +- `autolabor`: work detail override warning now only appears on the work details screen +- `RemoteFortressReader`: ensured names are transmitted in UTF-8 instead of CP437 + +## Misc Improvements +- `autodump`: no longer checks for a keyboard cursor before executing, so ``autodump destroy`` (which doesn't require a cursor) can still function +- Settings: recover gracefully when settings files become corrupted (e.g. by DF CTD) +- `orders`: update orders in library for prepared meals, bins, archer uniforms, and weapons +- `gui/control-panel`: new preference for whether filters in lists search for substrings in the middle of words (e.g. if set to true, then "ee" will match "steel") +- `gui/design`: Improved performance for drawing shapes +- Dreamfort: improve traffic patterns throughout the fortress +- `gui/blueprint`: recording of stockpile layouts and categories is now supported. note that detailed stockpile configurations will *not* be saved (yet) +- Core: new commandline flag/environment var: pass ``--disable-dfhack`` on the Dwarf Fortress commandline or specify ``DFHACK_DISABLE=1`` in the environment to disable DFHack for the current session. +- `overlay`: add links to the quickstart guide and the control panel on the DF title screen +- Window behavior: non-resizable windows now allow dragging by their frame edges by default +- `gui/autodump`: fort-mode keybinding: Ctrl-H (when ``armok`` tools are enabled in `gui/control-panel`) +- Window behavior: if you have multiple DFHack tool windows open, scrolling the mouse wheel while over an unfocused window will focus it and raise it to the top +- `stockpiles`: allow filtering creatures by tameability + +## Internals +- ``dfhack.internal``: added memory analysis functions: ``msizeAddress``, ``getHeapState``, ``heapTakeSnapshot``, ``isAddressInHeap``, ``isAddressActiveInHeap``, ``isAddressUsedAfterFreeInHeap``, ``getAddressSizeInHeap``, and ``getRootAddressOfHeapObject`` + +## Lua +- ``overlay.reload()``: has been renamed to ``overlay.rescan()`` so as not to conflict with the global ``reload()`` function. If you are developing an overlay, please take note of the new function name for reloading your overlay during development. +- ``gui``: changed frame naming scheme to ``FRAME_X`` rather than ``X_FRAME``, and added aliases for backwards compatibility. (for example ``BOLD_FRAME`` is now called ``FRAME_BOLD``) +- ``ensure_keys``: walks a series of keys, creating new tables for any missing values + +## Removed +- `orders`: ``library/military_include_artifact_materials`` library file removed since recent research indicates that platinum blunt weapons and silver crossbows are not more effective than standard steel. the alternate military orders file was also causing unneeded confusion. + +# 50.08-r1 + +## Fixes +- `autoclothing`: eliminate game lag when there are many inventory items in the fort +- `buildingplan`: fixed size limit calculations for rollers +- `buildingplan`: fixed items not being checked for accessibility in the filter and item selection dialogs +- `dig-now`: properly detect and complete smoothing designations that have been converted into active jobs + +## Misc Improvements +- `buildingplan`: planner panel is minimized by default and now remembers minimized state +- `buildingplan`: can now filter by gems (for gem windows) and yarn (for ropes in wells) +- ``toggle-kbd-cursor``: add hotkey for toggling the keyboard cursor (Alt-K) +- ``version``: add alias to display the DFHack help (including the version number) so something happens when players try to run "version" +- `gui/control-panel`: add preference option for hiding the terminal console on startup +- `gui/control-panel`: add preference option for hiding "armok" tools in command lists +- ``Dwarf Therapist``: add a warning to the Labors screen when Dwarf Therapist is active so players know that changes they make to that screen will have no effect. If you're starting a new embark and nobody seems to be doing anything, check your Labors tab for this warning to see if Dwarf Therapist thinks it is in control (even if it's not running). +- `overlay`: add the DFHack version string to the DF title screen + +## Lua +- ``widgets.RangeSlider``: new mouse-controlled two-headed slider widget +- ``gui.ZScreenModal``: ZScreen subclass for modal dialogs +- ``widgets.CycleHotkeyLabel``: exposed "key_sep" and "option_gap" attributes for improved stylistic control. + +## Removed +- `title-version`: replaced by an `overlay` widget + +# 50.07-r1 + +## New Plugins +- `faststart`: speeds up the "Loading..." screen so the Main Menu appears faster + +## Fixes +-@ `hotkeys`: hotkey hints on menu popup will no longer get their last character cut off by the scrollbar +-@ ``launchdf``: launch Dwarf Fortress via the Steam client so Steam Workshop is functional +- `blueprint`: interpret saplings, shrubs, and twigs as floors instead of walls +- `combine`: fix error processing stockpiles with boundaries that extend outside of the map +-@ `prospector`: display both "raw" Z levels and "cooked" elevations +- `stockpiles`: fix crash when importing settings for gems from other worlds +-@ `stockpiles`: allow numbers in saved stockpile filenames + +## Misc Improvements +-@ `buildingplan`: items in the item selection dialog should now use the same item quality symbols as the base game +-@ `buildingplan`: hide planner overlay while the DF tutorial is active so that it can detect when you have placed the carpenter's workshop and bed and allow you to finish the tutorial +- `buildingplan`: can now filter by cloth and silk materials (for ropes) +-@ `buildingplan`: rearranged elements of ``planneroverlay`` interface +-@ `buildingplan`: rearranged elements of ``itemselection`` interface +-@ Mods: scripts in mods that are only in the steam workshop directory are now accessible. this means that a script-only mod that you never mark as "active" when generating a world will still receive automatic updates and be usable from in-game +-@ Mods: scripts from only the most recent version of an installed mod are added to the script path +-@ Mods: give active mods a chance to reattach their load hooks when a world is reloaded +- `gui/control-panel`: bugfix services are now enabled by default +- Core: hide DFHack terminal console by default when running on Steam Deck + +## Documentation +- `installing`: updated to include Steam installation instructions + +## Lua +- added two new window borders: ``gui.BOLD_FRAME`` for accented elements and ``gui.INTERIOR_MEDIUM_FRAME`` for a signature-less frame that's thicker than the existing ``gui.INTERIOR_FRAME`` + +# 50.07-beta2 + +## New Plugins +- `getplants`: reinstated: designate trees for chopping and shrubs for gathering according to type +- `prospector`: reinstated: get stone, ore, gem, and other tile property counts in fort mode. + +## Fixes +-@ `buildingplan`: filters are now properly applied to planned stairs +-@ `buildingplan`: existing carved up/down stairs are now taken into account when determining which stair shape to construct +- `buildingplan`: upright spike traps are now placed extended rather than retracted +- `buildingplan`: you can no longer designate constructions on tiles with magma or deep water, mirroring the vanilla restrictions +-@ `buildingplan`: fixed material filters getting lost for planning buildings on save/reload +-@ `buildingplan`: respect building size limits (e.g. roads and bridges cannot be more than 31 tiles in any dimension) +- `tailor`: properly discriminate between dyed and undyed cloth +-@ `tailor`: no longer default to using adamantine cloth for producing clothes +- `tailor`: take queued orders into account when calculating available materials +- `tailor`: skip units who can't wear clothes +- `tailor`: identify more available items as available, solving issues with over-production + +## Misc Improvements +- `buildingplan`: filters and global settings are now ignored when manually choosing items for a building, allowing you to make custom choices independently of the filters that would otherwise be used +- `buildingplan`: if `suspendmanager` is running, then planned buildings will be left suspended when their items are all attached. `suspendmanager` will unsuspend them for construction when it is safe to do so. +- `buildingplan`: add option for autoselecting the last manually chosen item (like `automaterial` used to do) +- `confirm`: adds confirmation for removing burrows via the repaint menu +- `stockpiles`: support applying stockpile configurations with fully enabled categories to stockpiles in worlds other than the one where the configuration was exported from +- `stockpiles`: support partial application of a saved config based on dynamic filtering (e.g. disable all tallow in a food stockpile, even tallow from world-specific generated creatures) +- `stockpiles`: additive and subtractive modes when applying a second stockpile configuration on top of a first +- `stockpiles`: write player-exported stockpile configurations to the ``dfhack-config/stockpiles`` folder. If you have any stockpile configs in other directories, please move them to that folder. +- `stockpiles`: now includes a library of useful stockpile configs (see docs for details) +- `automelt`: now allows metal chests to be melted (workaround for DF bug 2493 is no longer needed) +- `orders`: add minimize button to overlay panel so you can get it out of the way to read long statue descriptions when choosing a subject in the details screen +- `orders`: add option to delete exported files from the import dialog +- `enable`: can now interpret aliases defined with the `alias` command +- Mods: scripts in mods are now automatically added to the DFHack script path. DFHack recognizes two directories in a mod's folder: ``scripts_modinstalled/`` and ``scripts_modactive/``. ``scripts_modinstalled/`` folders will always be added the script path, regardless of whether the mod is active in a world. ``scripts_modactive/`` folders will only be added to the script path when the mod is active in the current loaded world. + +## Documentation +- `modding-guide`: guide updated to include information for 3rd party script developers +- the ``untested`` tag has been renamed to ``unavailable`` to better reflect the status of the remaining unavailable tools. most of the simply "untested" tools have now been tested and marked as working. the remaining tools are known to need development work before they are available again. + +## Lua +- ``widgets.Label``: tokens can now specify a ``htile`` property to indicate the tile that should be shown when the Label is hovered over with the mouse +- ``widgets.Label``: click handlers no longer get the label itself as the first param to the click handler +- ``widgets.CycleHotkeyLabel``: options that are bare integers will no longer be interpreted as the pen color in addition to being the label and value +- ``widgets.CycleHotkeyLabel``: option labels and pens can now be functions that return a label or pen + +# 50.07-beta1 + +## Fixes +-@ `buildingplan`: items are now attached correctly to screw pumps and other multi-item buildings +-@ `buildingplan`: buildings with different material filters will no longer get "stuck" if one of the filters currently matches no items +- `showmood` properly count required number of bars and cloth when they aren't the main item for the strange mood + +## Misc Improvements +-@ `buildingplan`: can now filter by clay materials +-@ `buildingplan`: remember choice per building type for whether the player wants to choose specific items +-@ `buildingplan`: you can now attach multiple weapons to spike traps +-@ `buildingplan`: can now filter by whether a slab is engraved +-@ `buildingplan`: add "minimize" button to temporarily get the planner overlay out of the way if you would rather use the vanilla UI for placing the current building +-@ `buildingplan`: add ``buildingplan reset`` command for resetting all filters to defaults +-@ `buildingplan`: rename "Build" button to "Confirm" on the item selection dialog and change the hotkey from "B" to "C" +- `blueprint`: now writes blueprints to the ``dfhack-config/blueprints`` directory +- `blueprint-library-guide`: library blueprints have moved from ``blueprints`` to ``hack/data/blueprints`` +- `blueprint-library-guide`: player-created blueprints should now go in the ``dfhack-config/blueprints`` folder. please move your existing blueprints from ``blueprints`` to ``dfhack-config/blueprints``. you don't need to move the library blueprints -- those can be safely deleted from the old ``blueprints`` directory. +-@ `showmood`: clarify how many bars and/or cloth items are actually needed for the mood + +## Removed +-@ `buildingplan`: "heat safety" setting is temporarily removed while we investigate incorrect item matching + +# 50.07-alpha3 + +## Fixes +-@ ``widgets.HotkeyLabel``: don't trigger on click if the widget is disabled +- ``dfhack.job.isSuitableMaterial``: now properly detects lack of fire and magma safety for vulnerable materials with high melting points +- `dig-now`: fixed multi-layer channel designations only channeling every second layer + +## Misc Improvements +- `dig-now`: added handling of dig designations that have been converted into active jobs +- `buildingplan`: entirely new UI for building placement, item selection, and materials filtering! + +## API +- Gui focus strings will no longer get the "dfhack/" prefix if the string "dfhack/" already exists in the focus string +- ``Military``: New module for military functionality +- ``Military``: new ``makeSquad`` to create a squad +- ``Military``: changed ``getSquadName`` to take a squad identifier +- ``Military``: new ``updateRoomAssignments`` for assigning a squad to a barracks and archery range +- ``Maps::GetBiomeType`` renamed to ``Maps::getBiomeType`` for consistency +- ``Maps::GetBiomeTypeRef`` renamed to ``Maps::getBiomeTypeRef`` for consistency + +## Lua +- ``dfhack.job.attachJobItem()``: allows you to attach specific items to a job +- ``dfhack.screen.paintTile()``: you can now explicitly clear the interface cursor from a map tile by passing ``0`` as the tile value +- ``widgets.Label``: token ``tile`` properties can now be functions that return a value +- ``widgets.CycleHotkeyLabel``: add ``label_below`` attribute for compact 2-line output +-@ ``widgets.FilteredList``: search key matching is now case insensitive by default +-@ ``gui.INTERIOR_FRAME``: a panel frame style for use in highlighting off interior areas of a UI +- ``maps.getBiomeType``: exposed preexisting function to Lua + +## Removed +-@ ``gui.THIN_FRAME``: replaced by ``gui.INTERIOR_FRAME`` +- `automaterial`: all functionality has been merged into `buildingplan` + +# 50.07-alpha2 + +## Fixes +-@ `nestboxes`: fixed bug causing nestboxes themselves to be forbidden, which prevented citizens from using them to lay eggs. Now only eggs are forbidden. +-@ `autobutcher`: implemented work-around for Dwarf Fortress not setting nicknames properly, so that nicknames created in the in-game interface are detected & protect animals from being butchered properly. Note that nicknames for unnamed units are not currently saved by dwarf fortress - use ``enable fix/protect-nicks`` to fix any nicknames created/removed within dwarf fortress so they can be saved/reloaded when you reload the game. +-@ `seedwatch`: fix saving and loading of seed stock targets +- `autodump`: changed behaviour to only change ``dump`` and ``forbid`` flags if an item is successfully dumped. +-@ `autochop`: generate default names for burrows with no assigned names +- ``Buildings::StockpileIterator``: fix check for stockpile items on block boundary. +- `tailor`: block making clothing sized for toads; make replacement clothing orders use the size of the wearer, not the size of the garment +-@ `confirm`: fix fps drop when enabled +-@ `channel-safely`: fix an out of bounds error regarding the REPORT event listener receiving (presumably) stale id's + +## Misc Improvements +- `autobutcher`: logs activity to the console terminal instead of making disruptive in-game announcements +- DFHack tool windows that capture mouse clicks (and therefore prevent you from clicking on the "pause" button) now unconditionally pause the game when they open (but you can still unpause with the keyboard if you want to). Examples of this behavior: `gui/quickfort`, `gui/blueprint`, `gui/liquids` +- `showmood`: now shows the number of items needed for cloth and bars in addition to the technically correct but always confusing "total dimension" (150 per bar or 10,000 per cloth) +-@ Stopped mouse clicks from affecting the map when a click on a DFHack screen dismisses the window +- `confirm`: configuration data is now persisted globally. +- `tailor`: add support for adamantine cloth (off by default); improve logging + +## API +- ``Gui::any_civzone_hotkey``, ``Gui::getAnyCivZone``, ``Gui::getSelectedCivZone``: new functions to operate on the new zone system +- Units module: added new predicates for ``isGeldable()``, ``isMarkedForGelding()``, and ``isPet()`` + +## Lua +- ``dfhack.gui.getSelectedCivZone``: returns the Zone that the user has selected currently +- ``widgets.FilteredList``: Added ``edit_on_change`` optional parameter to allow a custom callback on filter edit change. +- ``widgets.TabBar``: new library widget (migrated from control-panel.lua) + +# 50.07-alpha1 + +## Fixes +- ``Units::isFortControlled``: Account for agitated wildlife +-@ Fix right click sometimes closing both a DFHack window and a vanilla panel +-@ Fixed issue with scrollable lists having some data off-screen if they were scrolled before being made visible +-@ `channel-safely`: fixed bug resulting in marker mode never being set for any designation +-@ `automelt`: fixed bug related to lua stack smashing behavior in returned stockpile configs +-@ `autochop`: fixed bug related to lua stack smashing behavior in returned stockpile configs +-@ `nestboxes`: now cancels any in-progress hauling jobs when it protects a fertile egg +-@ Fix persisted data not being written on manual save +-@ `nestboxes`: now scans for eggs more frequently and cancels any in-progress hauling jobs when it protects a fertile egg + +## Misc Improvements +-@ `automelt`: is now more resistent to vanilla savegame corruption +-@ `hotkeys`: DFHack logo is now hidden on screens where it covers important information when in the default position (e.g. when choosing an embark site) +- `misery`: now persists state with the fort +-@ `autodump`: reinstate ``autodump-destroy-item``, hotkey: Ctrl-K +- `autodump`: new hotkey for ``autodump-destroy-here``: Ctrl-H +-@ `dig`: new hotkeys for vein designation on z-level (Ctrl-V) and vein designation across z-levels (Ctrl-Shift-V) +-@ `clean`: new hotkey for `spotclean`: Ctrl-C +- `autobutcher`: changed defaults from 5 females / 1 male to 4 females / 2 males so a single unfortunate accident doesn't leave players without a mating pair +- `autobutcher`: now immediately loads races available at game start into the watchlist +-@ replaced DFHack logo used for the hover hotspot with a crisper image +-@ `orders`: recipe for silver crossbows removed from ``library/military`` as it is not a vanilla recipe, but is available in ``library/military_include_artifact_materials`` +- `stonesense`: added an ``INVERT_MOUSE_Z`` option to invert the mouse wheel direction + +## Documentation + +## API + +## Lua +- `overlay`: overlay widgets can now specify focus paths for the viewscreens they attach to so they only appear in specific contexts. see `overlay-dev-guide` for details. +- ``widgets.CycleHotkeyLabel``: Added ``key_back`` optional parameter to cycle backwards. +- ``widgets.HotkeyLabel``: Added ``setLabel`` method to allow easily updating the label text without mangling the keyboard shortcut. +- ``widgets.HotkeyLabel``: Added ``setOnActivate`` method to allow easily updating the ``on_activate`` callback. +- ``widgets.FilteredList``: Added ``case_sensitive`` optional parameter to determine if filtering is case sensitive. + +# 50.05-alpha3.1 + +## Fixes +-@ `seedwatch`: fix parameter parsing when setting targets + +# 50.05-alpha3 + +## New Plugins +- `autoslab`: automatically create work orders to engrave slabs for ghostly dwarves + +## Fixes +-@ DF screens can no longer get "stuck" on transitions when DFHack tool windows are visible. Instead, those DF screens are force-paused while DFHack windows are visible so the player can close them first and not corrupt the screen sequence. The "PAUSE FORCED" indicator will appear on these DFHack windows to indicate what is happening. +-@ allow launcher tools to launch themselves without hanging the game +-@ fix issues with clicks "passing through" some DFHack window elements to the screen below +- `getplants`: trees are now designated correctly +- `autoclothing`: fixed a crash that can happen when units are holding invalid items. +-@ `orders`: fix orders in library/basic that create bags +- `orders`: library/military now sticks to vanilla rules and does not add orders for normally-mood-only platinum weapons. A new library orders file ``library/military_include_artifact_materials`` is now offered as an alternate ``library/military`` set of orders that still includes the platinum weapons. +- `autochop`: fixed a crash when processing trees with corrupt data structures (e.g. when a trunk tile fails to fall when the rest of the tree is chopped down) + +## Misc Improvements +-@ DFHack windows can now be "defocused" by clicking somewhere not over the tool window. This has the same effect as pinning previously did, but without the extra clicking. +- `getplants`: ID values will now be accepted regardless of case +-@ Windows now display "PAUSE FORCED" on the lower border if the tool is forcing the game to pause +-@ New borders for DFHack tool windows -- tell us what you think! +-@ `autoclothing`: merged the two separate reports into the same command. +- `automelt`: stockpile configuration can now be set from the commandline +- `channel-safely`: new monitoring for cave-in prevention +-@ `gui/control-panel`: you can now configure whether DFHack tool windows should pause the game by default +- `gui/control-panel`: new global hotkey for quick access: Ctrl-Shift-E +-@ `hotkeys`: clicking on the DFHack logo no longer closes the popup menu +- `nestboxes`: now saves enabled state in your savegame +- `gui/launcher`: sped up initialization time for faster window appearance +- `orders`: orders plugin functionality is now accessible via an `overlay` widget when the manager orders screen is open +- `gui/quickcmd`: now has its own global keybinding for your convenience: Ctrl-Shift-A +- `seedwatch`: now persists enabled state in the savegame, automatically loads useful defaults, and respects reachability when counting available seeds +-@ `quickfort`: planned buildings are now properly attached to any pertinent overlapping zones + +## Documentation +- `compile`: instructions added for cross-compiling DFHack for Windows from a Linux Docker builder +-@ Quickstart guide has been updated with info on new window behavior and how to use the control panel + +## API +- ``Buildings::containsTile()``: no longer takes a ``room`` parameter since that's not how rooms work anymore. If the building has extents, the extents will be checked. otherwise, the result just depends on whether the tile is within the building's bounding box. +- ``Units::getCitizens()``: gets a list of citizens, which otherwise you'd have to iterate over all units the world to discover +- ``Screen::Pen``: now accepts ``top_of_text`` and ``bottom_of_text`` properties to support offset text in graphics mode +- `overlay`: overlay widgets can now specify a default enabled state if they are not already set in the player's overlay config file +- ``Lua::Push``: now supports ``std::unordered_map`` + +## Lua +- `helpdb`: new function: ``helpdb.refresh()`` to force a refresh of the database. Call if you are a developer adding new scripts, loading new plugins, or changing help text during play +- `helpdb`: changed from auto-refreshing every 60 seconds to only refreshing on explicit call to ``helpdb.refresh()``. docs very rarely change during a play session, and the automatic database refreshes were slowing down the startup of `gui/launcher` and anything else that displays help text. +- ``widgets.Label``: ``label.scroll()`` now understands ``home`` and ``end`` keywords for scrolling to the top or bottom +- ``widgets.List``: new callbacks for double click and shift double click +- ``dfhack.units.getCitizens()``: gets a list of citizens +-@ ``gui.ZScreen``: new attribute: ``defocusable`` for controlling whether a window loses keyboard focus when the map is clicked +- ``widgets.Label``: token ``tile`` properties can now be either pens or numeric texture ids +- `tiletypes`: now has a Lua API! ``tiletypes_setTile`` + +## Removed +- `autohauler`: no plans to port to v50, as it just doesn't make sense with the new work detail system + +# 50.05-alpha2 + +## Fixes +-@ `autofarm`: don't duplicate status line entries for crops with no current supply +-@ `orders`: allow the orders library to be listed and imported properly (if you previously copied the orders library into your ``dfhack-config/orders`` directory to work around this bug, you can remove those files now) +- `tailor`: now respects the setting of the "used dyed clothing" standing order toggle + +# 50.05-alpha1 + +## Fixes +- ``widgets.WrappedLabel``: no longer resets scroll position when window is moved or resized + +## Misc Improvements +- Scrollable widgets now react to mouse wheel events when the mouse is over the widget +- the ``dfhack-config/scripts/`` folder is now searched for scripts by default +- `hotkeys`: overlay hotspot widget now shows the DFHack logo in graphics mode and "DFHack" in text mode +- `script-paths`: removed "raw" directories from default script paths. now the default locations to search for scripts are ``dfhack-config/scripts``, ``save/*/scripts``, and ``hack/scripts`` +- ``init.d``: directories have moved from the ``raw`` subfolder (which no longer exists) to the root of the main DF folder or a savegame folder + +## Documentation +- `overlay-dev-guide`: added troubleshooting tips and common development workflows +- added DFHack architecture diagrams to the dev intro +- added DFHack Quickstart guide + +## API +- ``Gui::getDwarfmodeDims``: now only returns map viewport dimensions; menu dimensions are obsolete +- ``Gui::getDFViewscreen``: returns the topmost underlying DF viewscreen +- ``Screen::Pen``: now accepts ``keep_lower`` and ``write_to_lower`` properties to support foreground and background textures in graphics mode + +## Lua +- Removed ``os.execute()`` and ``io.popen()`` built-in functions +- ``gui.View``: ``visible`` and ``active`` can now be functions that return a boolean +- ``widgets.Panel``: new attributes to control window dragging and resizing with mouse or keyboard +- ``widgets.Window``: Panel subclass with attributes preset for top-level windows +- ``widgets.CycleHotkeyLabel``: now supports rendering option labels in the color of your choice +- ``widgets.CycleHotkeyLabel``: new functions ``setOption()`` and ``getOptionPen()`` +- ``widgets.ToggleHotkeyLabel``: now renders the ``On`` option in green text +- ``widgets.Label``: tiles can now have an associated width +- `overlay`: ``OverlayWidget`` now inherits from ``Panel`` instead of ``Widget`` to get all the frame and mouse integration goodies +- ``dfhack.gui.getDFViewscreen()``: returns the topmost underlying DF viewscreen +- ``gui.ZScreen``: Screen subclass that implements window raising, multi-viewscreen input handling, and viewscreen event pass-through so the underlying map can be interacted with and dragged around while DFHack screens are visible +- ``gui.View``: new function ``view:getMouseFramePos()`` for detecting whether the mouse is within (or over) the exterior frame of a view +- ``gui.CLEAR_PEN``: now clears the background and foreground and writes to the background (before it would always write to the foreground) +- ``gui.KEEP_LOWER_PEN``: a general use pen that writes associated tiles to the foreground while keeping the existing background + +## Removed +- ``fix-job-postings`` from the `workflow` plugin is now obsolete since affected savegames can no longer be loaded +- Ruby is no longer a supported DFHack scripting language diff --git a/docs/Binpatches.rst b/docs/dev/Binpatches.rst similarity index 89% rename from docs/Binpatches.rst rename to docs/dev/Binpatches.rst index 8af50fa450..d59b1f8482 100644 --- a/docs/Binpatches.rst +++ b/docs/dev/Binpatches.rst @@ -50,10 +50,20 @@ directly in memory at runtime:: If the name of the patch has no extension or directory separators, the script uses :file:`hack/patches//.dif`, thus auto-selecting -the version appropriate for the currently loaded executable. +the version appropriate for the currently loaded executable. The ``df-version`` +is the version string in the loaded symbol table. For example, if you want to +make a patch for all distributed verisons of DF 51.05, you'd provide a ``dif`` +file in each of the following directories: + +- :file:`hack/patches/v0.51.05 linux64 CLASSIC/mypatch.dif` +- :file:`hack/patches/v0.51.05 linux64 ITCH/mypatch.dif` +- :file:`hack/patches/v0.51.05 linux64 STEAM/mypatch.dif` +- :file:`hack/patches/v0.51.05 win64 CLASSIC/mypatch.dif` +- :file:`hack/patches/v0.51.05 win64 ITCH/mypatch.dif` +- :file:`hack/patches/v0.51.05 win64 STEAM/mypatch.dif` This is the preferred method; it's easier to debug, does not cause persistent -problems, and leaves file checksums alone. As with many other commands, users +problems, and leaves file checksums alone. As with many other commands, users can simply add it to `dfhack.init` to reapply the patch every time DF is run. @@ -155,7 +165,7 @@ gui/assign-rack Bind to a key (the example config uses :kbd:`P`), and activate when viewing a weapon rack in the :kbd:`q` mode. -.. image:: images/assign-rack.png +.. image:: /docs/images/assign-rack.png This script is part of a group of related fixes to make the armory storage work again. The existing issues are: @@ -175,4 +185,3 @@ The script interface simply lets you designate one of the squads that are assigned to the barracks/armory containing the selected stand as the intended user. In order to aid in the choice, it shows the number of currently assigned racks for every valid squad. - diff --git a/docs/Contributing.rst b/docs/dev/Contributing.rst similarity index 51% rename from docs/Contributing.rst rename to docs/dev/Contributing.rst index 1fcf6afc43..216d204969 100644 --- a/docs/Contributing.rst +++ b/docs/dev/Contributing.rst @@ -27,8 +27,7 @@ modify. GitHub has several documentation pages on these topics, including: In general, if you are not sure where or how to make a change, or would like advice before attempting to make a change, please see `support` for ways to -contact maintainers - DFHack-specific channels such as IRC or Bay12 are -preferred. If you are interested in addressing an issue reported on the +contact maintainers. If you are interested in addressing an issue reported on the :issue:`issue tracker <>`, you can start a discussion there if you prefer. The sections below cover some guidelines that contributions should follow: @@ -36,11 +35,24 @@ The sections below cover some guidelines that contributions should follow: .. contents:: :local: +General contribution guidelines +------------------------------- +* If convenient, compile on multiple platforms when changing anything that + compiles. Our CI should catch anything that fails to build, but checking in + advance can sometimes let you know of any issues sooner. +* Update documentation when applicable - see `docs-standards` for details. +* Update ``docs/changelog.txt`` and ``docs/about/Authors.rst`` when applicable. See + `build-changelog` for more information on the changelog format. +* Submit ideas and bug reports as :issue:`issues on GitHub <>`. + Posts in the forum thread or on Discord can easily get missed or forgotten. +* Work on :issue:`reported problems ` + will take priority over ideas or suggestions. + Code format ----------- * Four space indents for C++. Never use tabs for indentation in any language. * LF (Unix style) line terminators -* Avoid trailing whitespace +* No trailing whitespace * UTF-8 encoding * For C++: @@ -49,6 +61,19 @@ Code format * ``#include`` directives should be sorted: C++ libraries first, then DFHack modules, then ``df/`` headers, then local includes. Within each category they should be sorted alphabetically. +General C++ code guidelines +--------------------------- +* This project is currently built at the C++20 feature level, and C++20 features should be used when appropriate. C++23 features will be allowed once all of our build platforms support them. +* NEVER use ``using namespace`` in a header file. In source files, do not use ``using namespace std``; instead, import each STL identifier you need specifically (e.g. ``using std::string;``). +* Avoid platform specific code as much as possible. +* Avoid including ``Windows.h``; if you must, ensure that ``NOMINMAX`` and ``WIN32_LEAN_AND_MEAN`` are defined before including it. +* Do not include C headers (e.g. ````); use the C++ versions (e.g. ````) instead. +* Do not use ``std::string`` (or ``char *``) for path names; always use ``std::filesystem::path``. This avoids issues with encoding, especially on the Windows platform, which is roughly 80% of our user base. +* Do not use ``printf`` or similar functions for formatting strings; use C++ streams or ``fmt::format`` instead. We use the `fmt library `__ for formatting strings; this dependency is automatically fetched by our build system. +* Avoid out parameters; prefer returning a struct, pair, or tuple, or using ``std::optional`` instead. +* Prefer range for loops to traditional for loops when iterating over a container. +* Avoid macros when possible; prefer ``constexpr`` variables for constants and functions or templates for code generation. + .. _contributing-pr-guidelines: Pull request guidelines @@ -71,6 +96,15 @@ Pull request guidelines unless you indicate that it isn't ready (see below), but you can continue to push to the same branch and open new pull requests as needed. +* Our continuous integration (CI) will perform certain automatic checks, + ensuring that your code conforms to the code format described above. It is + recommended to install `pre-commit `__ (e.g. using + your distribution's package manager, if on Linux, or using ``pip``) and enable + it by running ``pre-commit install`` from the top-level of any repository from + which you plan to create pull requests. This will perform those checks when + you create the commit locally, allowing you to fix any style issues before + creating the actual pull request. + * Try to keep pull requests relatively small so that they are easier to review and merge. @@ -86,19 +120,36 @@ Pull request guidelines or add "WIP" to the title. Otherwise, your pull request may be reviewed and/or merged prematurely. -General contribution guidelines -------------------------------- -* If convenient, compile on multiple platforms when changing anything that - compiles. Our CI should catch anything that fails to build, but checking in - advance can sometimes let you know of any issues sooner. -* Update documentation when applicable - see `docs-standards` for details. -* Update ``changelog.txt`` and ``docs/Authors.rst`` when applicable. See - `build-changelog` for more information on the changelog format. -* Submit ideas and bug reports as :issue:`issues on GitHub <>`. - Posts in the forum thread can easily get missed or forgotten. -* Work on :issue:`reported problems ` - will take priority over ideas or suggestions. - +* Avoid using force pushes to your pull request branch after it has been reviewed, + as this can make it difficult for reviewers to see what has changed since their + last review. If you need to make changes, consider creating a new commit instead + of amending or rebasing. We neither enforce nor recommend a "single commit" rule; if you do + choose to squash your commits, please ensure that the commit message is clear and descriptive of the changes made. + If your pull request has an unusually large number of commits, a maintainer may + request that you squash your commits into a smaller number of commits before merging. + +* All pull requests must be accompanied by a description of the changes made, and + any relevant information for reviewers. If your pull request addresses an + issue, please include a reference to that issue in the description (e.g. + "Fixes #1234"). If your pull request is related to another pull request, please + include a reference to that pull request in the description (e.g. "Related to + #1234"). + +* All pull requests which have user facing changes, including all new features, bug fixes, or + changes to existing functionality, must include an entry in the "Future" section of + the changelog for the relevant repository. If your pull request is merged, this entry + will be added to the appropriate changelog. These entries are used when preparing the release + notes for each release, so please be sure to include a clear and concise description + of the changes made. See `build-changelog` for more information on the changelog format. + Changes that do not require a changelog entry are mainly those that are purely internal, + such as refactoring not intended to change semantics, code cleanup, changes to CI implementation + or to documentation, or changes directly related to the release process. When in doubt, + assume a changelog entry will be required. + +* Pull requests that add or modify tools must include a corresponding update to the documentation + for that tool. Similarly, pull requests that add or modify either the C++ or Lua APIs + must include a corresponding update to the appropriate API documentation. + See `docs-standards` for details. Other ways to help ================== @@ -106,10 +157,9 @@ DFHack is a software project, but there's a lot more to it than programming. If you're not comfortable programming, you can help by: * reporting bugs and incomplete documentation -* improving the documentation +* improving the documentation (C++ api is rife) * finding third-party scripts to add * writing tutorials for newbies All those things are crucial, and often under-represented. So if that's your thing, go get started! - diff --git a/docs/dev/Dev-intro.rst b/docs/dev/Dev-intro.rst new file mode 100644 index 0000000000..92967cf15e --- /dev/null +++ b/docs/dev/Dev-intro.rst @@ -0,0 +1,124 @@ +=========================== +DFHack development overview +=========================== + +This page provides an overview of DFHack components. If you are looking to +develop a tool for DFHack, developing a script or plugin is likely the most +straightforward choice. + +Other pages that may be relevant include: + +- `building-dfhack-index` +- `contributing` +- `documentation` +- `license` + +.. contents:: Contents + :local: + +.. _architectural-diagrams: + +Architecture diagrams +--------------------- + +These two diagrams give a very high level overview of where DFHack fits into +the DF call structure and how the pieces of DFHack itself fit together: + +.. image:: https://lh3.googleusercontent.com/d/1-2yeNMC7WHgMfZ9iQsDQ0dEbLukd_xyU + :alt: DFHack logic injection diagram + :target: https://drive.google.com/file/d/1-2yeNMC7WHgMfZ9iQsDQ0dEbLukd_xyU + :align: center + +When DF loads, it looks for a "dfhooks" library file (named appropriately per +platform, e.g. ``libdfhooks.so`` on Linux). DFHack provides this library file, +and DF calls the API functions at specific points in its initialization code +and main event loop. + +In addition, DFHack can "interpose" the virtual methods of DF classes. In +particular, it intercepts calls to the interface functions of each DF +viewscreen class to provide `overlay` functionality. + +The dfhooks API is defined in DF's open source component ``g_src``: +https://github.com/Putnam3145/Dwarf-Fortress--libgraphics--/blob/master/g_src/dfhooks.h + +.. image:: https://lh3.googleusercontent.com/d/1--JoEQbzKpVUOkRKDD9HxvuCqtom780F + :alt: DFHack tool call graph + :target: https://drive.google.com/file/d/1--JoEQbzKpVUOkRKDD9HxvuCqtom780F + :align: center + +DF memory layout is encoded in the xml files of the +`df-structures `__ repository. These +XML files are converted into C++ header files during the build process. + +The functionality of the DFHack core library is grouped by `Modules`_ that +access DF memory according to the defined structures. + +The Lua API layer makes DFHack core facilities available to Lua scripts. Both +the C++ and Lua APIs have a library of convenience functions, though only the +Lua API is `well-documented `. Notably, the entire +`UI widget library` is Lua-only, though C++ plugins can easily +access it via the plugin-Lua interop layer. + +Plugins +------- + +DFHack plugins are written in C++ and located in the ``plugins`` folder. +Currently, documentation on how to write plugins is somewhat sparse. There are +templates that you can use to get started in the :source:`plugins/examples` +folder, and the source code of existing plugins is also helpful. + +If you want to compile a plugin that you have just added, you will need to add a +call to ``DFHACK_PLUGIN`` in :source:`plugins/CMakeLists.txt`. + +Plugins have the ability to make one or more commands available to users of the +DFHack console. Examples include `3dveins` (which implements the ``3dveins`` +command) and `reveal` (which implements ``reveal``, ``unreveal``, and several +other commands). + +Plugins can also register handlers to run on every tick, and can interface with +the built-in `enable` and `disable` commands. For the full plugin API, see the +example :source:`skeleton ` plugin. + +Installed plugins live in the ``hack/plugins`` folder of a DFHack installation, +and the `load` family of commands can be used to load a recompiled plugin +without restarting DF. + +Run `plug` at the DFHack prompt for a list of all plugins included in DFHack. + +Scripts +------- + +DFHack scripts are written in Lua, with a `well-documented library `. +Referring to existing scripts as well as the API documentation is very helpful +when developing new scripts. + +Scripts included in DFHack live in a separate +:source-scripts:`scripts repository <>`. This can be found in the ``scripts`` +submodule if you have `cloned DFHack `, or the +``hack/scripts`` folder of an installed copy of DFHack. + +Core +---- + +The `DFHack core ` has a variety of low-level functions. It is +responsible for implementing the dfhooks API that DF calls, it provides a +console, and it provides an interface for plugins and scripts to interact with +DF. + +Modules +------- + +A lot of shared code to interact with DF in more complicated ways is contained +in **modules**. For example, the Units module contains functions for checking +various traits of units, changing nicknames properly, and more. Generally, code +that is useful to multiple plugins and scripts should go in the appropriate +module, if there is one. + +Most modules are also `exposed to Lua `, although some +functions (and some entire modules) are currently only available in C++. + +Remote access interface +----------------------- + +DFHack provides a remote access interface that external tools can connect to and +use to interact with DF. See `remote` for more information. diff --git a/docs/dev/Documentation.rst b/docs/dev/Documentation.rst new file mode 100644 index 0000000000..0ba61c404d --- /dev/null +++ b/docs/dev/Documentation.rst @@ -0,0 +1,607 @@ +.. _documentation: + +########################### +DFHack documentation system +########################### + + +DFHack documentation, like the file you are reading now, is created as a set of +``.rst`` files in `reStructuredText (reST) `_ +format. This is a documentation format common in the Python community. It is very +similar in concept -- and in syntax -- to Markdown, as found on GitHub and many other +places. However it is more advanced than Markdown, with more features available when +compiled to HTML, such as automatic tables of contents, cross-linking, special +external links (forum, wiki, etc) and more. The documentation is compiled by a +Python tool named `Sphinx `_. + +The DFHack build process will compile and install the documentation so it can be +displayed in-game by the `help` and `ls` commands (and any other command or GUI that +displays help text), but documentation compilation is disabled by default due to the +additional Python and Sphinx requirements. If you already have a version of the docs +installed (say from a downloaded release binary), then you only need to build the docs +if you're changing them and want to see the changes reflected in your game. + +You can also build the docs if you just want a local HTML- or text-rendered copy, though +you can always read the `online version `_ too. +The active development version of the documentation is tagged with ``latest`` and +is available `here `_ + +Note that even if you do want a local copy, it is certainly not necessary to +compile the documentation in order to read it. Like Markdown, reST documents are +designed to be just as readable in a plain-text editor as they are in HTML format. +The main thing you lose in plain text format is hyperlinking. + +.. contents:: Contents + :local: + +Concepts and general guidance +============================= + +The source ``.rst`` files are compiled to HTML for viewing in a browser and to text +format for viewing in-game. For in-game help, the help text is read from its installed +location in ``hack/docs`` under the DF directory. + +When writing documentation, remember that everything should be documented! If it's not +clear *where* a particular thing should be documented, ask on Discord or in the DFHack +thread on Bay12 -- you'll not only be getting help, you'll also be providing valuable +feedback that makes it easier for future contributors to find documentation on how to +write the documentation! + +Try to keep lines within 80-100 characters so it's readable in plain text in the +terminal - Sphinx (our documentation system) will make sure paragraphs flow. + +Short descriptions +------------------ + +Each command that a user can run -- as well as every plugin -- needs to have a +short (~54 character) descriptive string associated with it. This description text is: + +- used in-game by the `ls` command and DFHack UI screens that list commands +- used in the generated index entries in the HTML docs + +Tags +---- + +To make it easier for players to find related commands, all plugins and commands are marked +with relevant tags. These are used to compile indices and generate cross-links between the +commands, both in the HTML documents and in-game. See the list of available `tag-list` and +think about which categories your new tool belongs in. + +.. _docs-links: + +Links +----- + +If it would be helpful to mention another DFHack command, don't just type the +name - add a hyperlink! Specify the link target in backticks, and it will be +replaced with the corresponding title and linked: e.g. ```autolabor``` +=> `autolabor`. Scripts and plugins have link targets that match their names +created for you automatically. + +If you want to link to a heading in your own page, you can specify it like this:: + + `Heading text exactly as written`_ + +Note that the DFHack documentation is configured so that single backticks (with +no prefix or suffix) produce links to internal link targets, such as the +``autolabor`` target shown above. This is different from the reStructuredText +default behavior of rendering such text in italics (as a reference to a title). +For alternative link behaviors, see: + +- `The reStructuredText documentation on roles `__ +- `The reStructuredText documentation on external links `__ +- `The Sphinx documentation on roles `__ + - ``:doc:`` is useful for linking to another document outside of DFHack. + +.. _docs-standards: + +Documentation standards +======================= + +.. highlight:: rst + +Whether you're adding new code or just fixing old documentation (and there's plenty), +there are a few important standards for completeness and consistent style. Treat +this section as a guide rather than iron law, match the surrounding text, and you'll +be fine. + +Where do I add the help text? +----------------------------- + +For scripts and plugins that are distributed as part of DFHack, documentation files +should be added to the :source-scripts:`scripts/docs ` and :source:`docs/plugins` directories, +respectively, in a file named after the script or plugin. For example, a script named +``gui/foobar.lua`` (which provides the ``gui/foobar`` command) should be documented +in a file named ``docs/gui/foobar.rst`` in the scripts repo. Similarly, a plugin named +``foobaz`` should be documented in a file named ``docs/plugins/foobaz.rst`` in the dfhack repo. +For plugins, all commands provided by that plugin should be documented in that same file. + +Short descriptions (the ~54 character short help) for scripts and plugins are taken from +the ``summary`` attribute of the ``dfhack-tool`` directive that each tool help document must +have (see the `Header format`_ section below). Please make this brief but descriptive! + +Short descriptions for commands provided by plugins are taken from the ``description`` +parameter passed to the ``PluginCommand`` constructor used when the command is registered +in the plugin source file. + +Header format +------------- + +The docs **must** begin with a heading which exactly matches the script or plugin name, underlined +with ``=====`` to the same length. This must be followed by a ``.. dfhack-tool:`` directive with +at least the following parameters: + +* ``:summary:`` - a short, single-sentence description of the tool +* ``:tags:`` - a space-separated list of `tags ` that apply to the tool + +By default, ``dfhack-tool`` generates both a description of a tool and a command +with the same name. For tools (specifically plugins) that do not provide exactly +1 command with the same name as the tool, pass the ``:no-command:`` parameter (with +no content after it) to prevent the command block from being generated. + +For tools that provide multiple commands, or a command by the same name but with +significantly different functionality (e.g. a plugin that can be both enabled +and invoked as a command for different results), use the ``.. dfhack-command:`` +directive for each command. This takes only a ``:summary:`` argument, with the +same meaning as above. + +For example, documentation for the ``build-now`` script might look like:: + + build-now + ========= + + .. dfhack-tool:: + :summary: Instantly completes unsuspended building construction jobs. + :tags: fort armok buildings + + By default, all buildings on the map are completed, but the area of effect is configurable. + +And documentation for the ``autodump`` plugin might look like:: + + autodump + ======== + + .. dfhack-tool:: + :summary: Automatically set items in a stockpile to be dumped. + :tags: fort armok fps productivity items stockpiles + :no-command: + + .. dfhack-command:: autodump + :summary: Teleports items marked for dumping to the cursor position. + + .. dfhack-command:: autodump-destroy-here + :summary: Destroy items marked for dumping under the cursor. + + .. dfhack-command:: autodump-destroy-item + :summary: Destroys the selected item. + + When `enabled `, this plugin adds an option to the :kbd:`q` menu for + stockpiles. + + When invoked as a command, it can instantly move all unforbidden items marked + for dumping to the tile under the cursor. + +Usage help +---------- + +The first section after the header and introductory text should be the usage section. You can +choose between two formats, based on whatever is cleaner or clearer for your syntax. The first +option is to show usage formats together, with an explanation following the block:: + + Usage + ----- + + :: + + build-now [] + build-now here [] + build-now [ []] [] + + Where the optional ```` pair can be used to specify the + coordinate bounds within which ``build-now`` will operate. If + they are not specified, ``build-now`` will scan the entire map. + If only one ```` is specified, only the building at that + coordinate is built. + + The ```` parameters can either be an ``,,`` triple + (e.g. ``35,12,150``) or the string ``here``, which means the + position of the active game cursor. + +The second option is to arrange the usage options in a list, with the full command +and arguments in monospaced font. Then indent the next line and describe the effect:: + + Usage + ----- + + ``build-now []`` + Scan the entire map and build all unsuspended constructions + and buildings. + ``build-now here []`` + Build the unsuspended construction or building under the + cursor. + ``build-now [ []] []`` + Build all unsuspended constructions within the specified + coordinate box. + + The ```` parameters are specified as... + +Note that in both options, the entire commandline syntax is written, including the command itself. +Literal text is written as-is (e.g. the word ``here`` in the above example), and text that +describes the kind of parameter that is being passed (e.g. ``pos`` or ``options``) is enclosed in +angle brackets (``<`` and ``>``). Optional elements are enclosed in square brackets (``[`` and ``]``). +If the command takes an arbitrary number of elements, use ``...``, for example:: + + prioritize [] [ ...] + quickfort [,...] [,...] [] + +Examples +-------- + +If the only way to run the command is to type the command itself, then this section is not necessary. +Otherwise, please consider adding a section that shows some real, practical usage examples. For +many users, this will be the **only** section they will read. It is so important that it is a good +idea to include the ``Examples`` section **before** you describe any extended options your command +might take. Write examples for what you expect the popular use cases will be. Also be sure to write +examples showing specific, practical values being used for any parameter that takes a value or has +tricky formatting. + +Examples should go in their own subheading. The examples themselves should be organized as in +option 2 for Usage above. Here is an example ``Examples`` section:: + + Examples + -------- + + ``build-now`` + Completes all unsuspended construction jobs on the map. + ``build-now 37,20,154 here`` + Builds the unsuspended, unconstructed buildings in the box + bounded by the coordinate x=37,y=20,z=154 and the cursor. + +Options +------- + +The options header should follow the examples, with each option in the same format as the +examples:: + + Options + ------- + + ``-h``, ``--help`` + Show help text. + ``-l``, ``--quality `` + Set the quality of the architecture for built architected + buildings. + ``-q``, ``--quiet`` + Suppress informational output (error messages are still + printed). + +Note that for parameters that have both short and long forms, any values that those options +take only need to be specified once (e.g. ````). + +External scripts and plugins +============================ + +Scripts and plugins distributed separately from DFHack's release packages don't have the +opportunity to add their documentation to the rendered HTML or text output. However, these +scripts and plugins can use a different mechanism to at least make their help text available +in-game. + +Note that since help text for external scripts and plugins is not rendered by Sphinx, +it should be written in plain text. Any reStructuredText markup will not be processed and, +if present, will be shown verbatim to the player (which is probably not what you want). + +For external scripts, the short description comes from a comment on the first line +(the comment marker and extra whitespace is stripped): + +.. code-block:: lua + + -- A short description of my cool script. + +The main help text for an external script needs to appear between two markers -- ``[====[`` +and ``]====]``. The documentation standards above still apply to external tools, but there is +no need to include backticks for links or monospaced fonts. Here is an example for an +entire script header:: + + -- Inventory management for adventurers. + -- [====[ + gui/adv-inventory + ================= + + Tags: adventure | items + + Allows you to quickly move items between containers. This + includes yourself and any followers you have. + + Usage + ----- + + gui/adv-inventory [] + + Examples + -------- + + gui/adv-inventory + Opens the GUI with nothing preselected + + gui/adv-inventory take-all + Opens the GUI with all container items already selected and + ready to move into the adventurer's inventory. + + Options + ------- + + take-all + Starts the GUI with container items pre-selected + + give-all + Starts the GUI with your own items pre-selected + ]====] + +For external plugins, help text for provided commands can be passed as the ``usage`` +parameter when registering the commands with the ``PluginCommand`` constructor. There +is currently no way for associating help text with the plugin itself, so any +information about what the plugin does when enabled should be combined into the command +help. + +Required dependencies +===================== + +.. highlight:: shell + +In order to build the documentation, you must have Python with Sphinx +version |sphinx_min_version| or later and Python 3. + +When installing Sphinx from OS package managers, be aware that there is +another program called "Sphinx", completely unrelated to documentation management. +Be sure you are installing the right Sphinx; it may be called ``python-sphinx``, +for example. To avoid doubt, ``pip`` can be used instead as detailed below. + +Once you have installed Sphinx, ``sphinx-build --version`` should report the +version of Sphinx that you have installed. If this works, CMake should also be +able to find Sphinx. + +For more detailed platform-specific instructions, see the sections below: + +.. contents:: + :local: + :backlinks: none + +Linux +----- +Most Linux distributions will include Python by default. If not, start by +installing Python 3. On Debian-based distros:: + + sudo apt install python3 + +Check your package manager to see if Sphinx |sphinx_min_version| or later is +available. On Debian-based distros, this package is named ``python3-sphinx``. +If this package is new enough, you can install it directly. If not, or if you +want to use a newer Sphinx version (which may result in faster builds), you +can install Sphinx through the ``pip`` package manager instead. On Debian-based +distros, you can install pip with:: + + sudo apt install python3-pip + +Once pip is available, you can then install Sphinx with:: + + pip3 install sphinx + +If you run this as an unprivileged user, it may install a local copy of Sphinx +for your user only. The ``sphinx-build`` executable will typically end up in +``~/.local/bin/`` in this case. Alternatively, you can install Sphinx +system-wide by running pip with ``sudo``. In any case, you will need the folder +containing ``sphinx-build`` to be in your ``$PATH``. + +macOS +----- +macOS has Python 2.7 installed by default, but it does not have the pip package manager. + +You can install Homebrew's Python 3, which includes pip, and then install the +latest Sphinx using pip:: + + brew install python3 + pip3 install sphinx + +Windows +------- +Python for Windows can be downloaded `from python.org `_. +The latest version of Python 3 includes pip already. + +You can also install Python and pip through the Chocolatey package manager. +After installing Chocolatey as outlined in the `Windows compilation instructions `, +run the following command from an elevated (admin) command prompt (e.g. ``cmd.exe``):: + + choco install python pip -y + +Once you have pip available, you can install Sphinx with the following command:: + + pip install sphinx + +Note that this may require opening a new (admin) command prompt if you just +installed pip from the same command prompt. + +.. _docs-build: + +Building the documentation +========================== + +Once the required dependencies are installed, there are multiple ways to run +Sphinx to build the docs: + +Using CMake +----------- + +See our page on `build options `. + +Using the documentation build script +------------------------------------ + +You can also build the documentation without running CMake - this is faster if +you only want to rebuild the documentation regardless of any code changes. + +The recommended approach is the ``docs/build.py`` script. This is the same +script that CMake uses internally, which wraps Sphinx with a few additional +options to handle common cases and can build multiple documentation formats with +a single invocation. + +Examples: + +* ``docs/build.py`` + Build just the HTML docs + +* ``docs/build.py html text`` + Build both the HTML and text docs + +* ``docs/build.py --clean`` + Build HTML and force a clean build (all source files are re-read) + +* ``docs/build.py --help`` + Display a full list of available options + +The resulting documentation will be stored in ``docs/html`` and/or ``docs/text`` +(or generally, a subfolder of ``docs/`` named after the requested output format(s)). + +Building a PDF version +---------------------- + +ReadTheDocs automatically builds a PDF version of the documentation (available +under the "Downloads" section when clicking on the release selector). If you +want to build a PDF version locally, you will need the ``pdflatex`` command, which is part +of a TeX distribution. The following command will then build a PDF, located in +``docs/pdf/latex/DFHack.pdf``, with default options:: + + docs/build.py pdf + +Running Sphinx manually +----------------------- + +If ``docs/build.py`` does not support what you need, you can also run Sphinx +manually. This is primarily useful for low-level debugging. + +For a good starting point, add the ``--debug`` argument to your call to +``docs/build.py``. This will cause the script to print out the Sphinx command(s) +that it is running. + +Some examples: + +* ``sphinx-build . docs/html`` + Build the HTML docs (equivalent to ``docs/build.py``) + +* ``sphinx-build -b text . docs/text`` + Build the plain text docs (equivalent to ``docs/build.py text``) + +* ``sphinx-build -M latexpdf . docs/pdf`` + Build the PDF docs + +Sphinx has many options to enable clean builds, parallel builds, logging, and +more - run ``sphinx-build --help`` for details. If you specify a different +output path, be warned that Sphinx may overwrite existing files in the output +folder. Also be aware that when running ``sphinx-build`` directly, the +``docs/html`` folder may be polluted with intermediate build files that normally +get written in the cmake ``build`` directory. + +Troubleshooting +=============== + +Sphinx errors are typically printed by Sphinx, so ensure that you are not silencing Sphinx output. + +When built with ``docs/build.py`` or CMake, errors are also logged to +``build/docs//sphinx-warnings.txt`` (for instance, if you are building +the HTML docs, ``build/docs/html/sphinx-warnings.txt``). + + +"undefined label" +----------------- + +Typical causes: + +* You have used single backticks for an inline code snippet, where double backticks should be used instead (see `docs-links`):: + + `this is an invalid inline code snippet (actually a link)` + ``this is a valid inline code snippet`` + +* You are attempting to link to a section/label, but either it does not have a label defined or you have spelled it incorrectly:: + + .. my-label: + + This is where the link should go to. + + ... + + This is `a valid link to the earlier label `. So is `my-label`. + +"toctree contains reference to document that doesn't have a title" +------------------------------------------------------------------ + +Due to the nature of our autogenerated documentation, this can sometimes occur +when switching between branches that have different autogenerated files, and can +result in autogenerated documentation (e.g. for individual tools) being missing +from the table of contents, or links failing to generate. + +The quickest resolution is a clean docs build:: + + docs/build.py --clean + +.. _build-changelog: + +Building the changelogs +======================= +If you have Python installed, you can build just the changelogs without building +the rest of the documentation by running the ``docs/gen_changelog.py`` script. +This script provides additional options, including one to build individual +changelogs for all DFHack versions - run ``python docs/gen_changelog.py --help`` +for details. + +Changelog entries are obtained from ``changelog.txt`` files in multiple repos. +This allows changes to be listed in the same repo where they were made. These +changelogs are combined as part of the changelog build process: + +* ``docs/changelog.txt`` for changes in the main ``dfhack`` repo +* ``scripts/changelog.txt`` for changes made to scripts in the ``scripts`` repo +* ``library/xml/changelog.txt`` for changes made in the ``df-structures`` repo +* ``plugins/stonesense/changelog.txt`` for changes made in the ``stonesense`` + repo + +Building the changelogs generates two files: ``docs/changelogs/news.rst`` and +``docs/changelogs/news-dev.rst``. These correspond to `changelog` and +`dev-changelog` and contain changes organized by stable and development DFHack +releases, respectively. For example, an entry listed under "0.44.05-alpha1" in +changelog.txt will be listed under that version in the development changelog as +well, but under "0.44.05-r1" in the stable changelog (assuming that is the +closest stable release after 0.44.05-alpha1). An entry listed under a stable +release like "0.44.05-r1" in changelog.txt will be listed under that release in +both the stable changelog and the development changelog. + +Changelog syntax +---------------- + +.. include:: /docs/changelog.txt + :start-after: ===syntax-reference-start + :end-before: ===syntax-reference-end + +.. _docs-ci: + +GitHub Actions +============== + +Documentation is built automatically with GitHub Actions (a GitHub-provided +continuous integration service) for all pull requests and commits in the +"dfhack" and "scripts" repositories. These builds run with strict settings, i.e. +warnings are treated as errors. If a build fails, you will see a red "x" next to +the relevant commit or pull request. You can view detailed output from Sphinx in +a few ways: + +* Click on the red "x" (or green checkmark), then click "Details" next to + the "Build / docs" entry +* For pull requests only: navigate to the "Checks" tab, then click on "Build" in + the sidebar to expand it, then "docs" under it + +Sphinx output will be visible under the step named "Build docs". If a different +step failed, or you aren't sure how to interpret the output, leave a comment +on the pull request (or commit). + +You can also download the "docs" artifact from the summary page (typically +accessible by clicking "Build") if the build succeeded. This is a way to +visually inspect what the documentation looks like when built without installing +Sphinx locally, although we recommend installing Sphinx if you are planning to +do any significant work on the documentation. diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst new file mode 100644 index 0000000000..e8a1cd9f67 --- /dev/null +++ b/docs/dev/Lua API.rst @@ -0,0 +1,7775 @@ +.. highlight:: lua + +.. _lua-api: + +######################## +DFHack Lua API Reference +######################## + +DFHack has extensive support for +the Lua_ scripting language, providing access to: + +.. _Lua: https://www.lua.org + +1. Raw data structures used by the game. +2. Many C++ functions for high-level access to these + structures, and interaction with dfhack itself. +3. Some functions exported by C++ plugins. + +Lua code can be used both for writing scripts, which +are treated by DFHack command line prompt almost as +native C++ commands, and invoked by plugins written in C++. + +This document describes native API available to Lua in detail. +It does not describe all of the utility functions +implemented by Lua files located in :file:`hack/lua/*` +(:file:`library/lua/*` in the git repo). + +.. admonition:: Is this the DF or DFHack Lua API? + :class: warning + + This document describes the Lua API provided by DFHack, not + the Lua API provided by Dwarf Fortress. For information about DF's Lua API, see + :wiki:`Lua scripting` + on the Dwarf Fortress Wiki. + +.. contents:: Contents + :local: + :depth: 2 + +.. _lua-df: + +========================= +DF data structure wrapper +========================= + +.. contents:: + :local: + +Data structures of the game are defined in XML files located in :file:`library/xml` +(and `online `_, and automatically exported +to lua code as a tree of objects and functions under the ``df`` global, which +also broadly maps to the ``df`` namespace in the headers generated for C++. + +.. warning:: + + The wrapper provides almost raw access to the memory of the game, so + mistakes in manipulating objects are as likely to crash the game as + equivalent plain C++ code would be - e.g., null pointer access is safely + detected, but dangling pointers aren't. + +Objects managed by the wrapper can be broadly classified into the following groups: + +1. Typed object pointers (references). + + References represent objects in DF memory with a known type. + + In addition to fields and methods defined by the wrapped type, + every reference has some built-in properties and methods. + +2. Untyped pointers + + Represented as lightuserdata. + + In assignment to a pointer NULL can be represented either as + ``nil``, or a NULL lightuserdata; reading a NULL pointer field + returns ``nil``. + +3. Named types + + Objects in the ``df`` tree that represent identity of struct, class, + enum and bitfield types. They host nested named types, static + methods, builtin properties & methods, and, for enums and bitfields, + the bi-directional mapping between key names and values. + +4. The ``global`` object + + ``df.global`` corresponds to the ``df::global`` namespace, and + behaves as a mix between a named type and a reference, containing + both nested types and fields corresponding to global symbols. + +In addition to the ``global`` object and top-level types the ``df`` +global also contains a few global builtin utility functions. + +Typed object references +======================= + +The underlying primitive lua object is userdata with a metatable. +Every structured field access produces a new userdata instance. + +All typed objects have the following built-in features: + +* ``ref1 == ref2``, ``tostring(ref)`` + + References implement equality by type & pointer value, and string conversion. + +* ``pairs(ref)`` + + Returns an iterator for the sequence of actual C++ field names + and values. Fields are enumerated in memory order. Methods and + lua wrapper properties are not included in the iteration. + + .. warning:: + a few of the data structures (like ui_look_list) + contain unions with pointers to different types with vtables. + Using pairs on such structs is an almost sure way to crash with + an access violation. + +* ``ref._kind`` + + Returns one of: ``primitive``, ``struct``, ``container``, + or ``bitfield``, as appropriate for the referenced object. + +* ``ref._type`` + + Returns the named type object or a string that represents + the referenced object type. + +* ``ref:sizeof()`` + + Returns *size, address* + +* ``ref:new()`` + + Allocates a new instance of the same type, and copies data + from the current object. + +* ``ref:delete()`` + + Destroys the object with the C++ ``delete`` operator. If the destructor is not + available, returns *false*. (This typically only occurs when trying to delete + an instance of a DF class with virtual methods whose vtable address has not + been found; it is impossible for ``delete()`` to determine the validity of + ``ref``.) + + .. warning:: + ``ref`` **must** be an object allocated with ``new``, like in C++. Calling + ``obj.field:delete()`` where ``obj`` was allocated with ``new`` will not + work. After ``delete()`` returns, ``ref`` remains as a dangling pointer, + like a raw C++ pointer would. Any accesses to ``ref`` after ``ref:delete()`` + has been called are undefined behavior. + +* ``ref:assign(object)`` + + Assigns data from object to ref. Object must either be another + ref of a compatible type, or a lua table; in the latter case + special recursive assignment rules are applied. + +* ``ref:_displace(index[,step])`` + + Returns a new reference with the pointer adjusted by index*step. + Step defaults to the natural object size. + +Primitive references +-------------------- + +References of the *_kind* ``'primitive'`` are used for objects +that don't fit any of the other reference types. Such +references can only appear as a value of a pointer field, +or as a result of calling the ``_field()`` method. + +They behave as structs with a ``value`` field of the right type. If the +object's XML definition has a ``ref-target`` attribute, they will also have +a read-only ``ref_target`` field set to the corresponding type object. + +To make working with numeric buffers easier, they also allow +numeric indices. Note that other than excluding negative values +no bound checking is performed, since buffer length is not available. +Index 0 is equivalent to the ``value`` field. + + +Struct references +----------------- + +Struct references are used for class and struct objects. + +They implement the following features: + +* ``ref.field``, ``ref.field = value`` + + Valid fields of the structure may be accessed by subscript. + + Primitive typed fields, i.e., numbers & strings, are converted + to/from matching lua values. The value of a pointer is a reference + to the target, or ``nil``/NULL. Complex types are represented by + a reference to the field within the structure; unless recursive + lua table assignment is used, such fields can only be read. + + .. note:: + In case of inheritance, *superclass* fields have precedence + over the subclass, but fields shadowed in this way can still + be accessed as ``ref['subclasstype.field']``. + + This shadowing order is necessary because vtable-based classes + are automatically exposed in their exact type, and the reverse + rule would make access to superclass fields unreliable. + +* ``ref:_field(field)`` + + Returns a reference to a valid field. That is, unlike regular + subscript, it returns a reference to the field within the structure + even for primitive typed fields and pointers. Fails with an error + if the field is not found. + +* ``ref:vmethod(args...)`` + + Named virtual methods are also exposed, subject to the same + shadowing rules. + +* ``pairs(ref)`` + + Enumerates all real fields (but not methods) in memory + order, which is the same as declaration order. + +Container references +-------------------- + +Containers represent vectors and arrays, possibly resizable. + +A container field can associate an enum to the container +reference, which allows accessing elements using string keys +instead of numerical indices. + +Note that two-dimensional arrays in C++ (ie pointers to pointers) +are exposed to lua as one-dimensional. The best way to handle this +is probably ``array[x].value:_displace(y)``. + +Implemented features: + +* ``ref._enum`` + + If the container has an associated enum, returns the matching + named type object. + +* ``#ref`` + + Returns the *length* of the container. + +* ``ref[index]`` + + Accesses the container element, using either a *0-based* numerical + index, or, if an enum is associated, a valid enum key string. + + Accessing an invalid index is an error, but some container types + may return a default value, or auto-resize instead for convenience. + Currently this relaxed mode is implemented by df-flagarray aka BitArray. + +* ``ref:_field(index)`` + + Like with structs, returns a pointer to the array element, if possible. + Flag and bit arrays cannot return such pointer, so it fails with an error. + +* ``pairs(ref)``, ``ipairs(ref)`` + + If the container has no associated enum, both behave identically, + iterating over numerical indices in order. Otherwise, ipairs still + uses numbers, while pairs tries to substitute enum keys whenever + possible. + +* ``ref:resize(new_size)`` + + Resizes the container if supported, or fails with an error. + +* ``ref:insert(index,item)`` + + Inserts a new item at the specified index. To add at the end, + use ``#ref``, or just ``'#'`` as index. + +* ``ref:erase(index)`` + + Removes the element at the given valid index. + +Bitfield references +------------------- + +Bitfields behave like special fixed-size containers. +Consider them to be something in between structs and +fixed-size vectors. + +The ``_enum`` property points to the bitfield type. +Numerical indices correspond to the shift value, +and if a subfield occupies multiple bits, the +``ipairs`` order would have a gap. + +Additionally, bitfields have a ``whole`` property, +which returns the value of the bitfield as an +integer. + +Since currently there is no API to allocate a bitfield +object fully in GC-managed lua heap, consider using the +lua table assignment feature outlined below in order to +pass bitfield values to dfhack API functions that need +them, e.g., ``matinfo:matches{metal=true}``. + + +Named types +=========== + +Named types are exposed in the ``df`` tree with names identical +to the C++ version, except for the ``::`` vs ``.`` difference. + +All types and the global object have the following features: + +* ``type._kind`` + + Evaluates to one of ``struct-type``, ``class-type``, ``enum-type``, + ``bitfield-type`` or ``global``. + +* ``type._identity`` + + Contains a lightuserdata pointing to the underlying + ``DFHack::type_identity`` object. + +All compound types (structs, classes, unions, and the global object) support: + +* ``type._union`` + + ``true`` if the type represents a union, otherwise ``nil``. + +* ``type._fields`` + + Contains a table mapping field names to descriptions of the type's fields, + including data members and functions. Iterating with ``pairs()`` returns data + fields in the order they are defined in the type. Functions and globals may + appear in an arbitrary order. + + Each entry contains the following fields: + + * ``name``: the name of the field (matches the ``_fields`` table key) + * ``offset``: for data members, the position of the field relative to the start of the type, in bytes + * ``count``: for arrays, the number of elements + * ``mode``: implementation detail. See ``struct_field_info::Mode`` in ``DataDefs.h``. + + Each entry may also contain the following fields, depending on its type: + + * ``type_name``: present for most fields; a string representation of the field's type + * ``type``: the type object matching the field's type; present if such an object exists + (e.g., present for DF types, absent for primitive types) + * ``type_identity``: present for most fields; a lightuserdata pointing to the field's underlying ``DFHack::type_identity`` object + * ``index_enum``, ``ref_target``: the type object corresponding to the field's similarly-named XML attribute, if present + * ``union_tag_field``, ``union_tag_attr``, ``original_name``: the string value of the field's similarly-named XML attribute, if present + +Types excluding the global object also support: + +* ``type:sizeof()`` + + Returns the size of an object of the type. + +* ``type:new()`` + + Creates a new instance of an object of the type. + +* ``type:is_instance(object)`` + + Returns true if object is same or subclass type, or a reference + to an object of same or subclass type. It is permissible to pass + ``nil``, NULL or non-wrapper value as object; in this case the + method returns ``nil``. + +Enum types support the following: + +* ``type.next_item(index)`` + + Returns the next valid numeric value of the enum. It returns the + first enum value if ``index`` is greater than or equal to the max + enum value. + +* ``type.attrs`` + + A mapping of enum keys (usually integers) and values (usually strings) to + their attributes. e.g ``df.goal_type.attrs.STAY_ALIVE`` returns + ``{ short_name: "Stay Alive", achieved_short_name: "Stayed Alive" } }`` + +* ``type._attr_entry_type`` + + Returns the named ``struct-type`` type representing the table returned + by ``type.attrs``. + +In addition to this, enum and bitfield types contain a +bi-directional mapping between key strings and values, and +also map ``_first_item`` and ``_last_item`` to the min and +max values. + +Struct and class types with an instance-vector attribute in the XML also support: + +* ``type.find(key)`` + + Returns an object from the instance vector that matches the key, where the + field is determined by the 'key-field' specified in the XML. + +* ``type.get_vector()`` + + Returns the instance vector e.g ``df.item.get_vector() == df.global.world.items.all`` + +Global functions +================ + +The ``df`` table itself contains the following functions and values: + +* ``NULL``, ``df.NULL`` + + Contains the NULL lightuserdata. + +* ``df.isnull(obj)`` + + Evaluates to true if obj is nil or NULL; false otherwise. + +* ``df.isvalid(obj[,allow_null])`` + + For supported objects returns one of ``type``, ``voidptr``, ``ref``. + + If *allow_null* is true, and obj is nil or NULL, returns ``null``. + + Otherwise returns *nil*. + +* ``df.sizeof(obj)`` + + For types and refs identical to ``obj:sizeof()``. + For lightuserdata returns *nil, address* + +* ``df.new(obj)``, ``df.delete(obj)``, ``df.assign(obj, obj2)`` + + Equivalent to using the matching methods of obj. + +* ``df._displace(obj,index[,step])`` + + For refs equivalent to the method, but also works with + lightuserdata (step is mandatory then). + +* ``df.is_instance(type,obj)`` + + Equivalent to the method, but also allows a reference as proxy for its type. + +* ``df.new(ptype[,count])`` + + Allocate a new instance, or an array of built-in types. + The ``ptype`` argument is a string from the following list: + ``string``, ``int8_t``, ``uint8_t``, ``int16_t``, ``uint16_t``, + ``int32_t``, ``uint32_t``, ``int64_t``, ``uint64_t``, ``bool``, + ``float``, ``double``. All of these except ``string`` can be + used with the count argument to allocate an array. + +* ``df.reinterpret_cast(type,ptr)`` + + Converts ptr to a ref of specified type. The type may be anything + acceptable to ``df.is_instance``. Ptr may be *nil*, a ref, + a lightuserdata, or a number. + + Returns *nil* if NULL, or a ref. + +.. _lua-api-table-assignment: + +Recursive table assignment +========================== + +Recursive assignment is invoked when a lua table is assigned +to a C++ object or field, i.e., one of: + +* ``ref:assign{...}`` +* ``ref.field = {...}`` + +The general mode of operation is that all fields of the table +are assigned to the fields of the target structure, roughly +emulating the following code:: + + function rec_assign(ref,table) + for key,value in pairs(table) do + ref[key] = value + end + end + +Since assigning a table to a field using = invokes the same +process, it is recursive. + +There are however some variations to this process depending +on the type of the field being assigned to: + +1. If the table contains an ``assign`` field, it is + applied first, using the ``ref:assign(value)`` method. + It is never assigned as a usual field. + +2. When a table is assigned to a non-NULL pointer field + using the ``ref.field = {...}`` syntax, it is applied + to the target of the pointer instead. + + If the pointer is NULL, the table is checked for a ``new`` field: + + a. If it is *nil* or *false*, assignment fails with an error. + + b. If it is *true*, the pointer is initialized with a newly + allocated object of the declared target type of the pointer. + + c. Otherwise, ``table.new`` must be a named type, or an + object of a type compatible with the pointer. The pointer + is initialized with the result of calling ``table.new:new()``. + + After this auto-vivification process, assignment proceeds + as if the pointer wasn't NULL. + + Obviously, the ``new`` field inside the table is always skipped + during the actual per-field assignment processing. + +3. If the target of the assignment is a container, a separate + rule set is used: + + a. If the table contains neither ``assign`` nor ``resize`` + fields, it is interpreted as an ordinary *1-based* lua + array. The container is resized to the #-size of the + table, and elements are assigned in numeric order:: + + ref:resize(#table); + for i=1,#table do ref[i-1] = table[i] end + + b. Otherwise, ``resize`` must be *true*, *false*, or + an explicit number. If it is not false, the container + is resized. After that the usual struct-like 'pairs' + assignment is performed. + + In case ``resize`` is *true*, the size is computed + by scanning the table for the largest numeric key. + + This means that in order to reassign only one element of + a container using this system, it is necessary to use:: + + { resize=false, [idx]=value } + +Since ``nil`` inside a table is indistinguishable from missing key, +it is necessary to use ``df.NULL`` as a null pointer value. + +This system is intended as a way to define a nested object +tree using pure lua data structures, and then materialize it in +C++ memory in one go. Note that if pointer auto-vivification +is used, an error in the middle of the recursive walk would +not destroy any objects allocated in this way, so the user +should be prepared to catch the error and do the necessary +cleanup. + +========== +DFHack API +========== + +.. contents:: + :local: + +DFHack utility functions are placed in the ``dfhack`` global tree. + +Native utilities +================ + +Input & Output +-------------- + +* ``dfhack.print(args...)`` + + Output tab-separated args as standard lua print would do, + but without a newline. + +* ``print(args...)``, ``dfhack.println(args...)`` + + A replacement of the standard library print function that + works with DFHack output infrastructure. + +* ``dfhack.printerr(args...)`` + + Same as println; intended for errors. Uses red color and logs to stderr.log. + +* ``dfhack.color([color])`` + + Sets the current output color. If color is *nil* or *-1*, resets to default. + Returns the previous color value. + +* ``dfhack.is_interactive()`` + + Checks if the thread can access the interactive console and returns *true* or *false*. + +* ``dfhack.lineedit([prompt[,history_filename]])`` + + If the thread owns the interactive console, shows a prompt + and returns the entered string. Otherwise returns *nil, error*. + + Depending on the context, this function may actually yield the + running coroutine and let the C++ code release the core suspend + lock. Using an explicit ``dfhack.with_suspend`` will prevent + this, forcing the function to block on input with lock held. + +* ``dfhack.getCommandHistory(history_id, history_filename)`` + + Returns the list of strings in the specified history. Intended to be used by + GUI scripts that don't have access to a console and so can't use + ``dfhack.lineedit``. The ``history_id`` parameter is some unique string that + the script uses to identify its command history, such as the script's name. If + this is the first time the history with the given ``history_id`` is being + accessed, it is initialized from the given file. + +* ``dfhack.addCommandToHistory(history_id, history_filename, command)`` + + Adds a command to the specified history and saves the updated history to the + specified file. + +* ``dfhack.interpreter([prompt[,history_filename[,env]]])`` + + Starts an interactive lua interpreter, using the specified prompt + string, global environment and command-line history file. + + If the interactive console is not accessible, returns *nil, error*. + + +Exception handling +------------------ + +* ``dfhack.error(msg[,level[,verbose]])`` + + Throws a dfhack exception object with location and stack trace. + The verbose parameter controls whether the trace is printed by default. + +* ``qerror(msg[,level])`` + + Calls ``dfhack.error()`` with ``verbose`` being *false*. Intended to + be used for user-caused errors in scripts, where stack traces are not + desirable. + +* ``dfhack.pcall(f[,args...])`` + + Invokes f via xpcall, using an error function that attaches + a stack trace to the error. The same function is used by SafeCall + in C++, and dfhack.safecall. + +* ``safecall(f[,args...])``, ``dfhack.safecall(f[,args...])`` + + Just like pcall, but also prints the error using printerr before + returning. Intended as a convenience function. + +* ``dfhack.saferesume(coroutine[,args...])`` + + Compares to coroutine.resume like dfhack.safecall vs pcall. + +* ``dfhack.exception`` + + Metatable of error objects used by dfhack. The objects have the + following properties: + + ``err.where`` + The location prefix string, or *nil*. + ``err.message`` + The base message string. + ``err.stacktrace`` + The stack trace string, or *nil*. + ``err.cause`` + A different exception object, or *nil*. + ``err.thread`` + The coroutine that has thrown the exception. + ``err.verbose`` + Boolean, or *nil*; specifies if where and stacktrace should be printed. + ``tostring(err)``, or ``err:tostring([verbose])`` + Converts the exception to string. + +* ``dfhack.exception.verbose`` + + The default value of the ``verbose`` argument of ``err:tostring()``. + + +Miscellaneous +------------- + +* ``dfhack.VERSION`` + + DFHack version string constant. + +* ``dfhack.curry(func,args...)``, or ``curry(func,args...)`` + + Returns a closure that invokes the function with args combined + both from the curry call and the closure call itself. I.e., + ``curry(func,a,b)(c,d)`` equals ``func(a,b,c,d)``. + + +Locking and finalization +------------------------ + +* ``dfhack.with_suspend(f[,args...])`` + + Calls ``f`` with arguments after grabbing the DF core suspend lock. + Suspending is necessary for accessing a consistent state of DF memory. + + Returned values and errors are propagated through after releasing + the lock. It is safe to nest suspends. + + Every thread is allowed only one suspend per DF frame, so it is best + to group operations together in one big critical section. A plugin + can choose to run all lua code inside a C++-side suspend lock. + +* ``dfhack.call_with_finalizer(num_cleanup_args,always,cleanup_fn[,cleanup_args...],fn[,args...])`` + + Invokes ``fn`` with ``args``, and after it returns or throws an + error calls ``cleanup_fn`` with ``cleanup_args``. Any return values from + ``fn`` are propagated, and errors are re-thrown. + + The ``num_cleanup_args`` integer specifies the number of ``cleanup_args``, + and the ``always`` boolean specifies if cleanup should be called in any case, + or only in case of an error. + +* ``dfhack.with_finalize(cleanup_fn,fn[,args...])`` + + Calls ``fn`` with arguments, then finalizes with ``cleanup_fn``. + Implemented using ``call_with_finalizer(0,true,...)``. + +* ``dfhack.with_onerror(cleanup_fn,fn[,args...])`` + + Calls ``fn`` with arguments, then finalizes with ``cleanup_fn`` on any thrown error. + Implemented using ``call_with_finalizer(0,false,...)``. + +* ``dfhack.with_temp_object(obj,fn[,args...])`` + + Calls ``fn(obj,args...)``, then finalizes with ``obj:delete()``. + +.. _persistent-api: + +Persistent configuration storage +-------------------------------- + +This api is intended for storing tool state in the world savegame directory. It +is intended for data that is world-dependent. Global state that is independent +of the loaded world should be saved into a separate file named after the tool +in the ``dfhack-config/`` directory. + +Entries are associated with the current loaded site (fortress) and are +identified by a string ``key``. The data will still be associated with a fort +if the fort is retired and then later unretired. Entries are stored as +serialized strings, but there are convenience functions for working with +arbitrary Lua tables. + +* ``dfhack.persistent.getSiteData(key[, default])`` + + Retrieves the Lua table associated with the current site and the given string + ``key``. If ``default`` is supplied, then it is returned if the key isn't + found in the current site's persistent data. + + Example usage:: + + local state = dfhack.persistent.getSiteData('my-script-name', {somedata={}}) + +* ``dfhack.persistent.getSiteDataString(key)`` + + Retrieves the underlying serialized string associated with the current site + and the given string ``key``. Returns *nil* if the key isn't found in the + current site's persistent data. Most scripts will want to use ``getSiteData`` + instead. + +* ``dfhack.persistent.saveSiteData(key, data)`` + + Persists the given ``data`` (usually a table; can be of arbitrary complexity and depth) + in the world save, associated with the current site and the given ``key``. + +* ``dfhack.persistent.saveSiteDataString(key, data_str)`` + + Persists the given string in the world save, associated with the current site + and the given ``key``. + +* ``dfhack.persistent.deleteSiteData(key)`` + + Removes the existing entry associated with the current site and the given + ``key``. Returns *true* if succeeded. + +* ``dfhack.persistent.getWorldData(key[, default])`` +* ``dfhack.persistent.getWorldDataString(key)`` +* ``dfhack.persistent.saveWorldData(key, data)`` +* ``dfhack.persistent.saveWorldDataString(key, data_str)`` +* ``dfhack.persistent.deleteWorldData(key)`` + + Same semantics as for the ``Site`` functions, but will associated the data + with the global world context. + +* ``dfhack.persistent.getUnsavedSeconds()`` + + Returns the number of seconds since last save or load of a save. + +The data is kept in memory, so no I/O occurs when getting or saving keys. It is +all written to a json file in the game save directory when the game is saved. + +Material info lookup +-------------------- + +A material info record has fields: + +* ``type``, ``index``, ``material`` + + DF material code pair, and a reference to the material object. + +* ``mode`` + + One of ``'builtin'``, ``'inorganic'``, ``'plant'``, ``'creature'``. + +* ``inorganic``, ``plant``, ``creature`` + + If the material is of the matching type, contains a reference to the raw object. + +* ``figure`` + + For a specific creature material contains a ref to the historical figure. + +Functions: + +* ``dfhack.matinfo.decode(type,index)`` + + Looks up material info for the given number pair; if not found, returns *nil*. + +* ``....decode(matinfo|item|plant|obj)`` + + Uses type-specific methods for retrieving the code pair. + +* ``dfhack.matinfo.find(token[,token...])`` + + Looks up material by a token string, or a pre-split string token sequence. + +* ``dfhack.matinfo.getToken(...)``, ``info:getToken()`` + + Applies ``decode`` and constructs a string token. + +* ``info:toString([temperature[,named]])`` + + Returns the human-readable name at the given temperature. + +* ``info:getCraftClass()`` + + Returns the classification used for craft skills. + +* ``info:matches(obj)`` + + Checks if the material matches job_material_category or job_item. + Accept dfhack_material_category auto-assign table. + +.. _lua_api_random: + +Random number generation +------------------------ + +* ``dfhack.random.new([seed[,perturb_count]])`` + + Creates a new random number generator object. Without any + arguments, the object is initialized using current time. + Otherwise, the seed must be either a non-negative integer, + or a list of such integers. The second argument may specify + the number of additional randomization steps performed to + improve the initial state. + +* ``rng:init([seed[,perturb_count]])`` + + Re-initializes an already existing random number generator object. + +* ``rng:random([limit])`` + + Returns a random integer. If ``limit`` is specified, the value + is in the range [0, limit); otherwise it uses the whole 32-bit + unsigned integer range. + +* ``rng:drandom()`` + + Returns a random floating-point number in the range [0,1). + +* ``rng:drandom0()`` + + Returns a random floating-point number in the range (0,1). + +* ``rng:drandom1()`` + + Returns a random floating-point number in the range [0,1]. + +* ``rng:unitrandom()`` + + Returns a random floating-point number in the range [-1,1]. + +* ``rng:unitvector([size])`` + + Returns multiple values that form a random vector of length 1, + uniformly distributed over the corresponding sphere surface. + The default size is 3. + +* ``fn = rng:perlin([dim]); fn(x[,y[,z]])`` + + Returns a closure that computes a classical Perlin noise function + of dimension *dim*, initialized from this random generator. + Dimension may be 1, 2 or 3 (default). + + +.. _lua-cpp-func-wrappers: + +C++ function wrappers +===================== + +.. contents:: + :local: + +Thin wrappers around C++ functions, similar to the ones for virtual methods. +One notable difference is that these explicit wrappers allow argument count +adjustment according to the usual lua rules, so trailing false/nil arguments +can be omitted. + +* ``dfhack.getOSType()`` + + Returns the OS type string from ``symbols.xml``. + +* ``dfhack.getDFVersion()`` + + Returns the DF version string from ``symbols.xml``. + +* ``dfhack.getDFHackVersion()`` +* ``dfhack.getDFHackRelease()`` +* ``dfhack.getDFHackBuildID()`` +* ``dfhack.getCompiledDFVersion()`` +* ``dfhack.getGitDescription()`` +* ``dfhack.getGitCommit()`` +* ``dfhack.getGitXmlCommit()`` +* ``dfhack.getGitXmlExpectedCommit()`` +* ``dfhack.gitXmlMatch()`` +* ``dfhack.isRelease()`` +* ``dfhack.isPrerelease()`` + + Return information about the DFHack build in use. + + .. note:: + ``getCompiledDFVersion()`` returns the DF version specified at compile time, + while ``getDFVersion()`` returns the version and typically the OS as well. + These do not necessarily match - for example, DFHack 0.34.11-r5 worked with + DF 0.34.10 and 0.34.11, so the former function would always return ``0.34.11`` + while the latter would return ``v0.34.10 `` or ``v0.34.11 ``. + +* ``dfhack.getDFPath()`` + + Returns the DF directory path. + +* ``dfhack.getHackPath()`` + + Returns the DFHack installation directory path (the folder where DFHack is installed). + This may be the ``hack`` folder within the DF installation, but you should not rely on this. + Specifically, the installation folder is extremely likely to be somewhere else when DFHack is installed from Steam. + Always use this function to get the DFHack installation directory path instead of hardcoding it. + +* ``dfhack.getConfigPath()`` + + Returns the DFHack config directory path (the folder where user-specific configuration files are stored). + This is currently the ``dfhack-config`` folder within the DF installation, but you should not rely on this as it is likely to change in the future. + Always use this function to get the DFHack config directory path instead of hardcoding it. + Avoid storing this value in a long-lived variable, as it's possible that in future versions of DFHack, it may be possible for the config directory to be changed at runtime. + +* ``dfhack.getSavePath()`` + + Returns the path to the current save directory, or *nil* if no save loaded. + +* ``dfhack.getTickCount()`` + + Returns the tick count in ms, exactly as DF ui uses. + +* ``dfhack.isWorldLoaded()`` + + Checks if the world is loaded. + +* ``dfhack.isMapLoaded()`` + + Checks if the world and map are loaded. + +* ``dfhack.isSiteLoaded()`` + + Checks if a site (e.g., a player fort) is loaded. + +* ``dfhack.df2utf(string)`` + + Convert a string from DF's CP437 encoding to UTF-8. + +* ``dfhack.df2console()`` + + Convert a string from DF's CP437 encoding to the correct encoding for the + DFHack console. + +.. warning:: + + When printing CP437-encoded text to the console (for example, names returned + from ``dfhack.units.getReadableName()``), use + ``print(dfhack.df2console(text))`` to ensure proper display on all platforms. + +* ``dfhack.utf2df(string)`` + + Convert a string from UTF-8 to DF's CP437 encoding. + +* ``dfhack.upperCp437(string)`` + + Return a version of the string with all letters capitalized. + Non-ASCII CP437 characters are capitalized if a CP437 version exists. + For example, ``ä`` is replaced by ``Ä``, but ``â`` is never capitalized. + + +* ``dfhack.lowerCp437(string)`` + + Return a version of the string with all letters in lower case. + Non-ASCII CP437 characters are downcased. For example, ``Ä`` is replaced by ``ä``. + +* ``dfhack.toSearchNormalized(string)`` + + Replace non-ASCII alphabetic characters in a CP437-encoded string with their + nearest ASCII equivalents, if possible, and returns a CP437-encoded string. + Note that the returned string may be longer than the input string. For + example, ``ä`` is replaced with ``a``, and ``æ`` is replaced with ``ae``. + +* ``dfhack.capitalizeStringWords(string)`` + + Return a version of the string with the first letter of each word capitalized. + The beginning of a word is determined by a space or quote ``"``. It is also + determined by an apostrophe ``'`` when preceded by a space or comma. + Non-ASCII CP437 characters will be capitalized if a CP437 version exists. + This function does not downcase characters. Use ``dfhack.lowerCp437`` + first, if desired. + +* ``dfhack.formatInt(num)`` + + Formats an integer value as a string according to the current system locale. + E.g., for American English, it would transform like: ``12345`` -> + ``'12,345'`` + +* ``dfhack.formatFloat(num)`` + + Formats a floating point value as a string according to the current system + locale. E.g., for American English, it would transform like: ``-12345.6789`` + -> ``'-12,345.678711'`` (because float imprecision). + +* ``dfhack.run_command(command[, ...])`` + + Run an arbitrary DFHack command, with the core suspended, and send output to + the DFHack console. The command can be passed as a table, multiple string + arguments, or a single string argument (not recommended - in this case, the + usual DFHack console tokenization is used). + + A ``command_result`` constant starting with ``CR_`` is returned, where ``CR_OK`` + indicates success. + + The following examples are equivalent:: + + dfhack.run_command({'ls', 'quick'}) + dfhack.run_command('ls', 'quick') + dfhack.run_command('ls quick') -- not recommended + +* ``dfhack.run_command_silent(command[, ...])`` + + Similar to ``run_command()``, but instead of printing to the console, + returns an ``output, command_result`` pair. ``output`` is a single string - + see ``dfhack.internal.runCommand()`` to obtain colors as well. + +Translation module +------------------ + +* ``dfhack.translation.translateName(name[,in_english[,only_last_name]])`` + + Convert a ``df.language_name`` (or only the last name part) to string. + +* ``dfhack.translation.generateName(name,language,type,major_selector,minor_selector)`` + + Dynamically generate a name using the same logic the game itself uses. + +Gui module +---------- + +Screens +~~~~~~~ + +* ``dfhack.gui.getCurViewscreen([skip_dismissed])`` + + Returns the topmost viewscreen. If ``skip_dismissed`` is *true*, + ignores screens already marked to be removed. + +* ``dfhack.gui.getFocusStrings(viewscreen)`` + + Returns a table of string representations of the current UI focuses. + The strings have a "screen/foo/bar/baz..." format e.g.:: + + [1] = "dwarfmode/Info/CREATURES/CITIZEN" + [2] = "dwarfmode/Squads" + +* ``dfhack.gui.matchFocusString(focus_string[, viewscreen])`` + + Returns ``true`` if the given ``focus_string`` is found in the current + focus strings, or as a prefix to any of the focus strings, or ``false`` + if no match is found. Matching is case insensitive. If ``viewscreen`` is + specified, gets the focus strings to match from the given viewscreen. + +* ``dfhack.gui.getCurFocus([skip_dismissed])`` + + Returns a list of focus strings for the current viewscreen. Equivalent to + ``dfhack.gui.getFocusStrings(dfhack.gui.getCurViewscreen(skip_dismissed))``. + +* ``dfhack.gui.getViewscreenByType(type[, depth])`` + + Returns the topmost viewscreen out of the top ``depth`` viewscreens with + the specified type (e.g., ``df.viewscreen_titlest``), or ``nil`` if none match. + If ``depth`` is not specified or is less than 1, all viewscreens are checked. + +* ``dfhack.gui.getDFViewscreen([skip_dismissed[, viewscreen]])`` + + Returns the topmost viewscreen not owned by DFHack. If ``skip_dismissed`` is + ``true``, ignores screens already marked to be removed. If ``viewscreen`` is + specified, starts the scan at the given viewscreen. + +* ``dfhack.gui.getWidget(container, [, ...])`` + + Returns the DF widget in the given widget container with the given name or + (zero-based) numeric index. You can follow a chain of widget containers by + passing additional names or indices. For example: + ``:lua ~dfhack.gui.getWidget(game.main_interface.info.labor, "Tabs", 0)`` + +* ``dfhack.gui.getWidgetChildren(container)`` + + Returns all the DF widgets in the given widget container. + +General-purpose selections +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ``dfhack.gui.getSelectedWorkshopJob([silent])`` +* ``dfhack.gui.getSelectedJob([silent])`` +* ``dfhack.gui.getSelectedUnit([silent])`` +* ``dfhack.gui.getSelectedItem([silent])`` +* ``dfhack.gui.getSelectedBuilding([silent])`` +* ``dfhack.gui.getSelectedCivZone([silent])`` +* ``dfhack.gui.getSelectedStockpile([silent])`` +* ``dfhack.gui.getSelectedPlant([silent])`` + + Returns the currently selected in-game object or the indicated thing + associated with the selected in-game object. For example, Calling + ``getSelectedJob`` when a building is selected will return the job associated + with the building (e.g., the ``ConstructBuilding`` job). If ``silent`` is + omitted or set to ``false`` and a selected object cannot be found, then an + error is printed to the console. + +* ``dfhack.gui.getAnyWorkshopJob(screen)`` +* ``dfhack.gui.getAnyJob(screen)`` +* ``dfhack.gui.getAnyUnit(screen)`` +* ``dfhack.gui.getAnyItem(screen)`` +* ``dfhack.gui.getAnyBuilding(screen)`` +* ``dfhack.gui.getAnyCivZone(screen)`` +* ``dfhack.gui.getAnyStockpile(screen)`` +* ``dfhack.gui.getAnyPlant(screen)`` + + Similar to the corresponding ``getSelected`` functions, but operate on the + given screen instead of the current screen and always return ``nil`` silently + on failure. + +Fortress mode +~~~~~~~~~~~~~ + +* ``dfhack.gui.getDwarfmodeViewDims()`` + + Returns dimensions of the displayed map viewport. See ``getPanelLayout()`` + in the ``gui.dwarfmode`` module for a more Lua-friendly version. + +* ``dfhack.gui.resetDwarfmodeView([pause])`` + + Resets the fortress mode sidebar menus and cursors to their default state. If + ``pause`` is true, also pauses the game. + +* ``dfhack.gui.pauseRecenter(pos[,pause])`` + ``dfhack.gui.pauseRecenter(x,y,z[,pause])`` + + Same as ``resetDwarfmodeView``, but also recenter if position is valid. If + ``pause`` is false, skip pausing. Respects ``RECENTER_INTERFACE_SHUTDOWN_MS`` + in DF's ``init.txt`` (the delay before input is recognized when a recenter + occurs.) + +* ``dfhack.gui.revealInDwarfmodeMap(pos[,center[,highlight]])`` + ``dfhack.gui.revealInDwarfmodeMap(x,y,z[,center[,highlight]])`` + + Centers the view on the given coordinates. If ``center`` is true, make sure + the position is in the exact center of the view, else just bring it on screen. + If ``highlight`` is true, then mark the target tile with a pulsing highlight + until the player clicks somewhere else. + + ``pos`` can be a ``df.coord`` instance or a table assignable to a ``df.coord`` + (see `lua-api-table-assignment`), + e.g.:: + + {x = 5, y = 7, z = 11} + getSelectedUnit().pos + copyall(df.global.cursor) + + If the position is invalid, the function will simply ensure the current + window position is clamped between valid values. + +* ``dfhack.gui.refreshSidebar()`` + + Refreshes the fortress mode sidebar. This can be useful when making changes to + the map, for example, because DF only updates the sidebar when the cursor + position changes. + +* ``dfhack.gui.inRenameBuilding()`` + + Returns ``true`` if a building is being renamed. + +Announcements +~~~~~~~~~~~~~ + +* ``dfhack.gui.writeToGamelog(text)`` + + Writes a string to :file:`gamelog.txt` without doing an announcement. + +* ``dfhack.gui.makeAnnouncement(type,flags,pos,text[,color[,is_bright]])`` + + Adds an announcement with given announcement_type, text, color, and brightness. + + The announcement is written to :file:`gamelog.txt`. The announcement_flags + argument provides a custom set of :file:`announcements.txt` options, + which specify if the message should actually be displayed in the + announcement list, and whether to recenter or show a popup. + + Returns the index of the new announcement in ``df.global.world.status.reports``, or -1. + +* ``dfhack.gui.addCombatReport(unit,slot,report_index[,update_alert])`` + + Adds the report with the given index (returned by makeAnnouncement) + to the specified group of the given unit. If ``update_alert`` is ``true``, + an alert badge will appear on the left side of the screen if not already visible. + Returns ``true`` on success. + +* ``dfhack.gui.addCombatReportAuto(unit,flags,report_index)`` + + Adds the report with the given index to the appropriate group(s) of the given unit + based on the unit's current job and as requested by the flags. + Always updates alert badges. Returns ``true`` on any success. + +* ``dfhack.gui.showAnnouncement(text[,color[,is_bright]])`` + + Adds a regular announcement with given text, color, and brightness. + The announcement type is always ``df.announcement_type.REACHED_PEAK``, + which uses the alert badge for ``df.announcement_alert_type.GENERAL``. + +* ``dfhack.gui.showZoomAnnouncement(type,pos,text[,color[,is_bright]])`` + + Like above, but also specifies a position you can zoom to from the announcement menu, + as well as being able to set the announcement type. + +* ``dfhack.gui.showPopupAnnouncement(text[,color[,is_bright]])`` + + Displays a megabeast-style modal announcement window. + DF is currently ignoring the color and brightness settings + (see: `bug report `_.) + Add ``[C:`` color ``:0:`` bright ``]`` (where color is 0-7 and bright is 0-1) + in front of your text string to force the popup text to be colored. + + Text is run through a parser as it is converted into a markup text box. + The parser accepts tokens in square brackets (``[`` ``]``.) + Use ``[[`` and ``]]`` to include actual square brackets in text. + + The following tokens are accepted: + + ``[R]``: (NEW_LINE) Ends the current line and begins on the next. + + ``[B]``: (BLANK_LINE) Ends the current line and adds an additional blank line, + beginning on the line after that. + + ``[P]``: (INDENT) Ends the current line and begins four spaces indented on the next. + + ``[CHAR:`` n ``]``, ``[CHAR:~`` ch ``]``: Add a single character. First version + takes a base-10 integer ``n`` representing a CP437 character. + Second version accepts a character ``ch`` instead. ``"[CHAR:154]"`` and + ``"[CHAR:~"..string.char(154).."]"`` both result in ``Ü``. Use ``[CHAR:32]`` or + ``[CHAR:~ ]`` to add extra spaces, which would normally be trimmed by the parser. + + ``[LPAGE:`` link_type ``:`` id ``]``, ``[LPAGE:`` link_type ``:`` id ``:`` subid ``]``: + Start a ``markup_text_linkst``. These are intended for Legends mode page links and + don't work in popups. The text will just be colored based on ``link_type``. + Valid link types are: ``HF`` (``HIST_FIG``,) ``SITE``, ``ARTIFACT``, ``BOOK``, + ``SR`` (``SUBREGION``,) ``FL`` (``FEATURE_LAYER``,) ``ENT`` (``ENTITY``,) + ``AB`` (``ABSTRACT_BUILDING``,) ``EPOP`` (``ENTITY_POPULATION``,) ``ART_IMAGE``, + ``ERA``, ``HEC``. + ``subid`` is only used for ``AB`` and ``ART_IMAGE``. ``[/LPAGE]`` ends the link text. + + ``[C:`` screenf ``:`` screenb ``:`` screenbright ``]``: Color text. Sets the + respective values in ``df.global.gps`` and then sets text color. + ``color`` = ``screenf``, ``bright`` = ``screenbright``, ``screenb`` does nothing + since popup backgrounds are always black. + Example: ``"Light gray, [C:4:0:0]red, [C:4:0:1]orange, [C:7:0:0]light gray."`` + + ``[KEY:`` n ``]``: Keybinding. Shows the (first) keybinding for the + ``df.interface_key`` ``n``. The keybinding will be displayed in light green, but + the previous text color will be restored afterwards. + +* ``dfhack.gui.showAutoAnnouncement(type,pos,text[,color[,is_bright[,unit_a[,unit_d]]]])`` + + Uses the type to look up options from announcements.txt, and calls the above + operations accordingly. The units are used to call ``addCombatReportAuto``. + +* ``dfhack.gui.autoDFAnnouncement(report,text)`` + ``dfhack.gui.autoDFAnnouncement(type,pos,text[,color[,is_bright[,unit_a[,unit_d[,is_sparring]]]]])`` + + Takes a ``df.announcement_infost`` (see: + `structure definition `_) + and a string and processes them just like DF does. Can also be built from parameters instead of + an ``announcement_infost``. Setting ``is_sparring`` to ``true`` means the report will be added + to sparring logs (if applicable) rather than hunting or combat. + + The announcement will not display if units are involved and the player can't see + them (or hear, for adventure mode sound announcement types.) + Returns ``true`` if a report was created or repeated. + For detailed info on why an announcement failed to display, enable + ``debugfilter set Debug core gui`` in the DFHack console. + If you want a guaranteed announcement, use ``dfhack.gui.showAutoAnnouncement`` instead. + +* ``dfhack.gui.getMousePos([allow_out_of_bounds])`` + + Returns the map coordinates of the map tile the mouse is over as a table of + ``{x, y, z}``. If the cursor is not over a valid tile, returns ``nil``. To + allow the function to return coordinates outside of the map, set + ``allow_out_of_bounds`` to ``true``. + +Other +~~~~~ + +* ``dfhack.gui.getDepthAt(x, y)`` + + Returns the distance from the z-level of the tile at map coordinates (x, y) to + the closest rendered ground z-level below. Defaults to 0, unless overridden by + plugins. + +Job module +---------- + +* ``dfhack.job.cloneJobStruct(job)`` + + Creates a deep copy of the given job. + +* ``dfhack.job.createLinked()`` + + Create a job and immediately link it into the global job list. + +* ``dfhack.job.printJobDetails(job)`` + + Prints info about the job. + +* ``dfhack.job.printItemDetails(jobitem,idx)`` + + Prints info about the job item. + +* ``dfhack.job.removeJob(job)`` + + Cancels a job, cleans up all references to it, and removes it from the world. + +* ``dfhack.job.addGeneralRef(job, type, id)`` + + Create a general reference of the given type, pointing to the object with the + specified id, and add the created general reference to the provided job. + +* ``dfhack.job.getGeneralRef(job, type)`` + + Searches for a general_ref with the given type. + +* ``dfhack.job.getSpecificRef(job, type)`` + + Searches for a specific_ref with the given type. + +* ``dfhack.job.assignToWorkshop(job, workshop)`` + + Assign job to workshop (i.e. establish the bidirectional link between the job + and the workshop). Does nothing and returns ``false`` if the workshop already + has the maximum of ten jobs. + +* ``dfhack.job.getHolder(job)`` + + Returns the building holding the job. + +* ``dfhack.job.getWorker(job)`` + + Returns the unit performing the job. + +* ``dfhack.job.setJobCooldown(building,worker,cooldown)`` + + Prevent the worker from taking jobs at the specified workshop for the + specified cooldown period (in ticks). This doesn't decrease the cooldown + period in any circumstances. + +* ``dfhack.job.addWorker(job, unit)`` + + Assign the specified job to the provided unit, unless the unit already has an + active job. Also cleans up a potential job posting for the provided job. + +* ``dfhack.job.removeWorker(job,cooldown)`` + + Removes the worker from the specified workshop job, and sets the cooldown + period (using the same logic as ``setJobCooldown``). Returns *true* on + success. + +* ``dfhack.job.checkBuildingsNow()`` + + Instructs the game to check buildings for jobs next frame and assign workers. + +* ``dfhack.job.checkDesignationsNow()`` + + Instructs the game to check designations for jobs next frame and assign workers. + +* ``dfhack.job.is_equal(job1,job2)`` + + Compares important fields in the job and nested item structures. + +* ``dfhack.job.is_item_equal(job_item1,job_item2)`` + + Compares important fields in the job item structures. + +* ``dfhack.job.linkIntoWorld(job,new_id)`` + + Adds job into ``df.global.job_list``, and if new_id + is true, then also sets its id and increases + ``df.global.job_next_id`` + +* ``dfhack.job.listNewlyCreated(first_id)`` + + Returns the current value of ``df.global.job_next_id``, and + if there are any jobs with ``first_id <= id < job_next_id``, + a lua list containing them. + +* ``dfhack.job.attachJobItem(job, item, role, filter_idx, insert_idx)`` + + Attach a real item to this job. If the item is intended to satisfy a job_item + filter, the index of that filter should be passed in ``filter_idx``; otherwise, + pass ``-1``. Similarly, if you don't care where the item is inserted, pass + ``-1`` for ``insert_idx``. The ``role`` param is a ``df.job_role_type``. + If the item needs to be brought to the job site, then the value should be + ``df.job_role_type.Hauled``. + +* ``dfhack.job.isSuitableItem(job_item, item_type, item_subtype)`` + + Does basic sanity checks to verify if the suggested item type matches + the flags in the job item. + +* ``dfhack.job.isSuitableMaterial(job_item, mat_type, mat_index, item_type)`` + + Likewise, if replacing material. + +* ``dfhack.job.getName(job)`` + + Returns the job's description, as seen in the Units and Jobs screens. + +* ``dfhack.job.getManagerOrderName(manager_order)`` + + Returns the manager order's description, as seen in the Work orders screen. + +Hotkey module +------------- + +* ``dfhack.hotkey.addKeybind(keyspec, command)`` + + Creates a new keybind with the provided keyspec (see the `keybinding` documentation + for details on format). + Returns false on failure to create keybind. + +* ``dfhack.hotkey.removeKeybind(keyspec, [match_focus=true, command])`` + + Removes keybinds matching the provided keyspec. + If match_focus is set, the focus portion of the keyspec is matched against. + If command is provided and not an empty string, the command is matched against. + Returns false if no keybinds were removed. + +* ``dfhack.hotkey.listActiveKeybinds()`` + + Returns a list of keybinds active within the current context. + The items are tables with the following attributes: + :spec: The keyspec for the hotkey + :command: The command the hotkey runs when pressed + +* ``dfhack.hotkey.listAllKeybinds()`` + + Returns a list of all keybinds currently registered. + The items are tables with the following attributes: + :spec: The keyspec for the hotkey + :command: The command the hotkey runs when pressed + +* ``dfhack.hotkey.requestKeybindingInput([cancel=false])`` + + Enqueues or cancels a request that the next hotkey-compatible input is saved + and not processed, retrievable with ``dfhack.hotkey.getKeybindingInput()``. + If cancel is true, any current request is cancelled. + +* ``dfhack.hotkey.getKeybindingInput()`` + + Reads the latest saved keybind input that was requested. + Returns a keyspec string for the input, or nil if no input has been saved. + +* ``dfhack.hotkey.isDisruptiveKeybind(keyspec)`` + + Determines if the provided keyspec could be disruptive to the game experience. + This includes the majority of standard characters and special keys such as escape, + backspace, and return when lacking modifiers other than Shift. + +Units module +------------ + +* ``dfhack.units.isActive(unit)`` + + The unit is active (non-dead and on the map). + +* ``dfhack.units.isVisible(unit)`` + + The unit is on a visible map tile. Doesn't account for sneaking. + +* ``dfhack.units.isCitizen(unit[,include_insane])`` + + The unit is a non-dead sane citizen of the fortress; wraps the + same checks the game uses to decide game-over by extinction, + with an additional sanity check. You can identify citizens, + regardless of their sanity, by passing ``true`` as the optional + second parameter. + +* ``dfhack.units.isResident(unit[,include_insane])`` + + The unit is a resident of the fortress. Same ``include_insane`` semantics as + ``isCitizen``. + +* ``dfhack.units.isFortControlled(unit)`` + + Similar to ``dfhack.units.isCitizen(unit)``, but is based on checks + for units hidden in ambush, and includes tame animals. Returns *false* + if not in fort mode. + +* ``dfhack.units.isOwnCiv(unit)`` + + The unit belongs to the player's civilization. + +* ``dfhack.units.isOwnGroup(unit)`` + + The unit belongs to the player's group. + +* ``dfhack.units.isOwnRace(unit)`` + + The unit belongs to the player's race. + +* ``dfhack.units.isAlive(unit)`` + + The unit isn't dead or undead. Naturally inorganic is okay. + +* ``dfhack.units.isDead(unit)`` + + The unit is completely dead and passive, or a ghost. Equivalent to + ``dfhack.units.isKilled(unit) or dfhack.units.isGhost(unit)``. + +* ``dfhack.units.isKilled(unit)`` + + The unit has been killed. + +* ``dfhack.units.isSane(unit)`` + + The unit is normally capable of rational action. I.e., not dead, insane, zombie, + nor crazed (unless active werebeast). + +* ``dfhack.units.isCrazed(unit)`` + + The unit is berserk and will attack all other creatures except crazed members of + its own species. (Can be modified by curses.) + +* ``dfhack.units.isGhost(unit)`` + + The unit is a ghost. + +* ``dfhack.units.isHidden(unit)`` + + The unit is hidden to the player, accounting for sneaking. Works for any game mode. + +* ``dfhack.units.isHidingCurse(unit)`` + + The unit is currently hiding a curse (i.e., vampire). + +* ``dfhack.units.isMale(unit)`` +* ``dfhack.units.isFemale(unit)`` +* ``dfhack.units.isBaby(unit)`` +* ``dfhack.units.isChild(unit)`` +* ``dfhack.units.isAdult(unit)`` + + Simple unit property checks + +* ``dfhack.units.isGay(unit)`` + + Not willing to breed. Also includes any creature caste without a gender. + +* ``dfhack.units.isNaked(unit[,no_items])`` + + Not wearing anything (including rings, etc.). Can optionally check for + empty inventory. + +* ``dfhack.units.isVisiting(unit)`` + + The unit is visiting. E.g., merchants, diplomats, and travelers. + +* ``dfhack.units.isTrainableHunting(unit)`` + + The unit is trainable for hunting. + +* ``dfhack.units.isTrainableWar(unit)`` + + The unit is trainable for war. + +* ``dfhack.units.isTrained(unit)`` + + The unit is trained for hunting or war, or is non-wild and non-domesticated. + +* ``dfhack.units.isHunter(unit)`` + + The unit is a trained hunter. + +* ``dfhack.units.isWar(unit)`` + + The unit is trained for war. + +* ``dfhack.units.isTame(unit)`` +* ``dfhack.units.isTamable(unit)`` +* ``dfhack.units.isDomesticated(unit)`` +* ``dfhack.units.isMarkedForTraining(unit)`` +* ``dfhack.units.isMarkedForTaming(unit)`` +* ``dfhack.units.isMarkedForWarTraining(unit)`` +* ``dfhack.units.isMarkedForHuntTraining(unit)`` +* ``dfhack.units.isMarkedForSlaughter(unit)`` +* ``dfhack.units.isMarkedForGelding(unit)`` +* ``dfhack.units.isGeldable(unit)`` +* ``dfhack.units.isGelded(unit)`` +* ``dfhack.units.isEggLayer(unit)`` +* ``dfhack.units.isEggLayerRace(unit)`` +* ``dfhack.units.isGrazer(unit)`` +* ``dfhack.units.isMilkable(unit)`` + + Simple unit property checks. + +* ``dfhack.units.isForest(unit)`` + + The unit is of the forest. + +* ``dfhack.units.isMischievous(unit)`` + + The unit is mischievous and will randomly pull levers, etc. + +* ``dfhack.units.isAvailableForAdoption(unit)`` + + The unit is available for adoption. + +* ``dfhack.units.isPet(unit)`` + + Unit has pet owner. + +* ``dfhack.units.hasExtravision(unit)`` +* ``dfhack.units.isOpposedToLife(unit)`` +* ``dfhack.units.isBloodsucker(unit)`` + + Simple checks of caste attributes that can be modified by curses. + +* ``dfhack.units.isDwarf(unit)`` + + The unit is of the same race for the fortress. (Includes active werebeasts.) + +* ``dfhack.units.isAnimal(unit)`` +* ``dfhack.units.isMerchant(unit)`` +* ``dfhack.units.isDiplomat(unit)`` + + Simple unit type checks. + +* ``dfhack.units.isVisitor(unit)`` + + The unit is a regular visitor with no special purpose (e.g., merchant). + +* ``dfhack.units.isWildlife(unit)`` + + The unit is surface or cavern wildlife. + +* ``dfhack.units.isAgitated(unit)`` + + The unit is an agitated creature. + +* ``dfhack.units.isInvader(unit)`` + + The unit is an active invader or marauder. + +* ``dfhack.units.isUndead(unit[,hiding_curse])`` + + The unit is undead. Pass ``true`` as the optional second parameter to + count undead hiding their curse (i.e., vampires). + +* ``dfhack.units.isNightCreature(unit)`` +* ``dfhack.units.isSemiMegabeast(unit)`` +* ``dfhack.units.isMegabeast(unit)`` +* ``dfhack.units.isTitan(unit)`` +* ``dfhack.units.isForgottenBeast(unit)`` +* ``dfhack.units.isDemon(unit)`` + + Simple enemy type checks. + +* ``dfhack.units.isDanger(unit)`` + + The unit is dangerous and probably hostile. This includes night creatures, + semi-megabeasts, invaders, agitated wildlife, crazed units, and Great Dangers + (see below). + +* ``dfhack.units.isGreatDanger(unit)`` + + The unit is of Great Danger. This includes megabeasts, titans, + forgotten beasts, and demons. + +* ``dfhack.units.isUnitInBox(unit, pos1, pos2)`` +* ``dfhack.units.isUnitInBox(unit,x1,y1,z1,x2,y2,z2)`` + + Returns true if the unit is within a box defined by the + specified coordinates. + +* ``dfhack.units.getUnitsInBox(pos1, pos2[, filter])`` +* ``dfhack.units.getUnitsInBox(x1,y1,z1,x2,y2,z2[,filter])`` + + Returns a table of all units within the specified coordinates. + If the ``filter`` argument is given, only units where ``filter(unit)`` + returns true will be included. + +* ``dfhack.units.getUnitByNobleRole(role_name)`` + + Returns the unit assigned to the given noble role, if any. + ``role_name`` must be one of the position codes associated with the + active fort or civilization government. For example: + ``CAPTAIN_OF_THE_GUARD``, ``MAYOR``, or ``BARON``. + Note that if more than one unit has the role, only the first will be + returned. See ``getUnitsByNobleRole`` below for retrieving all units + with a particular role. + +* ``dfhack.units.getUnitsByNobleRole(role_name)`` + + Returns a list of units (possibly empty) assigned to the given noble role. + +* ``dfhack.units.getCitizens([exclude_residents[,include_insane]])`` + + Returns a list of all living, sane citizens and residents that are + currently on the map. Can ``exclude_residents`` or ``include_insane`` + (both default to ``false``). + +* ``dfhack.units.getPosition(unit)`` + + Returns the true *x,y,z* of the unit, or *nil* if invalid. You should + generally use this method instead of reading *unit.pos* directly since + that field can be inaccurate when the unit is caged. + +* ``dfhack.units.teleport(unit, pos)`` + + Moves the specified unit and any riders to the target coordinates, setting + tile occupancy flags appropriately. Returns true if successful. + +* ``dfhack.units.getGeneralRef(unit, type)`` + + Searches for a ``general_ref`` with the given type. + +* ``dfhack.units.getSpecificRef(unit, type)`` + + Searches for a ``specific_ref`` with the given type. + +* ``dfhack.units.getContainer(unit)`` + + Returns the container (i.e., cage) holding the unit or *nil*. + +* ``dfhack.units.getOuterContainerRef(unit)`` + + Returns a table (in the style of a ``specific_ref`` struct) of the + outermost object that contains the unit (or one of the unit itself). + The ``type`` field contains a + ``specific_ref_type`` of ``UNIT``, ``ITEM_GENERAL``, or ``VERMIN_EVENT``. + The ``object`` field contains a pointer to a unit, item, or vermin, + respectively. + +* ``dfhack.units.getIdentity(unit)`` + + Returns the false identity of the unit if it has one, or *nil*. + +* ``dfhack.units.getNemesis(unit)`` + + Returns the nemesis record of the unit if it has one, or *nil*. + +* ``dfhack.units.setNickname(unit, nick)`` + + Sets the unit's nickname properly. + +* ``dfhack.units.getVisibleName(unit)`` + + Returns the ``language_name`` object visible in game, accounting for + false identities. + +* ``dfhack.units.assignTrainer(unit[,trainer_id])`` +* ``dfhack.units.unassignTrainer(unit)`` + + Assigns (or unassigns) a trainer for the specified trainable unit. The + trainer ID can be omitted if "any trainer" is desired. Returns a boolean + indicating whether the operation was successful. + +* ``dfhack.units.makeown(unit)`` + + Makes the selected unit a member of the current fortress and site. + Note that this operation may silently fail for any of several reasons, + so it may be prudent to check if the operation has succeeded by using + ``dfhack.units.isOwnCiv`` or another appropriate predicate on the unit + in question. + +* ``dfhack.units.setPathGoal(unit, pos, goal)`` + + Set target coordinates and goal (of type ``df.unit_path_goal``) for the given + unit. In case of a change, also clears the unit's current path. + +* ``dfhack.units.create(race, caste)`` + + Creates a new unit from scratch. The unit will be added to the + ``world.units.all`` vector, but not to the ``world.units.active`` vector. + The unit will not have an associated historical figure, nemesis record, + map position, labors, or any group associations. The unit *will* have a + race, caste, name, soul, and initialized body and mind (including + personality). The unit must be configured further as needed and put into + play by the client. + +* ``dfhack.units.getCasteRaw(unit)`` +* ``dfhack.units.getCasteRaw(race, caste)`` + + Returns the relevant ``caste_raw`` or *nil*. + +* ``dfhack.units.getPhysicalAttrValue(unit, attr_type)`` +* ``dfhack.units.getMentalAttrValue(unit, attr_type)`` + + Computes the effective attribute value, including curse effect. + +* ``dfhack.units.casteFlagSet(race, caste, flag)`` + + Returns whether the given ``df.caste_raw_flags`` flag is set for the given + race and caste. + +* ``dfhack.units.getMiscTrait(unit, type[, create])`` + + Finds (or creates if requested) a misc trait object with the given id. + +* ``dfhack.units.getRaceNameById(race)`` +* ``dfhack.units.getRaceName(unit)`` + + Get raw token name (e.g., "DWARF"). + +* ``dfhack.units.getRaceReadableNameById(race)`` +* ``dfhack.units.getRaceReadableName(unit)`` +* ``dfhack.units.getRaceNamePluralById(race)`` +* ``dfhack.units.getRaceNamePlural(unit)`` + + Get human-readable name (e.g., "dwarf" or "dwarves"). + +* ``dfhack.units.getRaceBabyNameById(race[,plural])`` +* ``dfhack.units.getRaceBabyName(unit[,plural])`` +* ``dfhack.units.getRaceChildNameById(race[,plural])`` +* ``dfhack.units.getRaceChildName(unit[,plural])`` + + Get human-readable baby or child name (e.g., "dwarven baby" or + "dwarven child"). + +* ``dfhack.units.getReadableName(unit or historical_figure[, skip_english])`` + + Returns a string that includes the native and english language name (if + ``skip_english`` is not ``true``) of the unit (if any), the race of the unit + (if different from fort), whether it is trained for war or hunting, any + syndrome-given descriptions (such as "necromancer"), the training level (if + tame), and profession or noble role. If a ``historical_figure`` is passed + instead of a unit, some information (e.g., agitation status) is not + available, and the profession may be different (e.g., "Monk") from what is + displayed in fort mode. + +* ``dfhack.units.getAge(unit[, true_age])`` + + Returns the age of the unit in years as a floating-point value. + If ``true_age`` is true, ignores false identities. + +* ``dfhack.units.getKillCount(unit)`` + + Returns the number of units the unit has killed. + +* ``dfhack.units.getNominalSkill(unit, skill[, use_rust])`` + + Retrieves the nominal skill level for the given unit. If ``use_rust`` + is *true*, subtracts the rust penalty. + +* ``dfhack.units.getEffectiveSkill(unit, skill)`` + + Computes the effective rating for the given skill, taking into account + skill rust, exhaustion, pain, etc. + +* ``dfhack.units.getExperience(unit, skill[, total])`` + + Returns the experience value for the given skill. If ``total`` is true, + adds experience implied by the current skill level. + +* ``dfhack.units.isValidLabor(unit, unit_labor)`` + + Returns whether the indicated labor is settable for the given unit. + +* ``dfhack.units.setLaborValidity(unit_labor, isValid)`` + + Sets the given labor to the given (boolean) validity for all units that are + part of your fortress civilization. Valid labors are allowed to be toggled + in the in-game labor management screens (including DFHack's `labor + manipulator screen `). + +* ``dfhack.units.setAutomaticProfessions(unit)`` + + Set appropriate labors on a unit based on current work detail settings. + +* ``dfhack.units.computeMovementSpeed(unit)`` + + Computes number of frames * 100 it takes the unit to move in its current + state of mind and body. **Currently broken due to move speed changes, + will always return 0!** + +* ``dfhack.units.computeSlowdownFactor(unit)`` + + Meandering and floundering in liquid introduces additional slowdown. + It is random, but the function computes and returns the expected mean + factor as a float. + +* ``dfhack.units.getNoblePositions(unit or historical_figure)`` + + Returns a list of tables describing noble position assignments, or *nil*. + Every table has fields ``entity``, ``assignment``, and ``position``. + +* ``dfhack.units.getProfession(unit)`` + + Returns unit's profession ID (``df.profession``), accounting for + false identity. + +* ``dfhack.units.getProfessionName(unit[,ignore_noble[,plural[,land_title]]])`` +* ``dfhack.units.getProfessionName(historical_figure[,ignore_noble[,plural[,land_title]]])`` + + Retrieves the profession name using custom profession, noble assignments, + or raws. The ``ignore_noble`` boolean disables the use of noble positions + ("Prisoner", "Slave", and noble spouse titles included). The ``land_title`` + boolean causes ``of Sitename`` to be appended when applicable. If a + ``historical_figure`` is passed instead of a unit, some information (e.g., + agitation status) is not available, and the profession may be different + (e.g., "Monk") from what is displayed in fort mode. + +* ``dfhack.units.getCasteProfessionName(race, caste, prof_id[, plural])`` + + Retrieves the profession name for the given race and caste using raws. + +* ``dfhack.units.getProfessionColor(unit[,ignore_noble])`` + + Retrieves the color associated with the profession, using noble assignments + or raws. The ``ignore_noble`` boolean disables the use of noble positions. + +* ``dfhack.units.getCasteProfessionColor(race, caste, prof_id)`` + + Retrieves the profession color for the given race and caste using raws. + +* ``dfhack.units.getGoalType(unit[,goalIndex])`` + + Retrieves the goal type of the dream that the given unit has. + By default the goal of the first dream is returned. + The ``goalIndex`` parameter may be used to retrieve additional dream goals. + Currently only one dream per unit is supported by Dwarf Fortress. + Support for multiple dreams may be added in future versions of + Dwarf Fortress. + +* ``dfhack.units.getGoalName(unit[,goalIndex])`` + + Retrieves the short name describing the goal of the dream that the given + unit has. By default the goal of the first dream is returned (see above). + +* ``dfhack.units.isGoalAchieved(unit[,goalIndex])`` + + Checks if given unit has achieved the goal of the dream. + By default the status of the goal of the first dream is returned (see above). + +* ``dfhack.units.getMainSocialActivity(unit)`` +* ``dfhack.units.getMainSocialEvent(unit)`` + + Return the ``df.activity_entry`` or ``df.activity_event`` representing the + unit's current social activity. + +* ``dfhack.units.hasUnbailableSocialActivity(unit)`` + + Unit has an uninterruptible social activity (e.g. a purple "Socialize!"). + +* ``dfhack.units.isJobAvailable(unit [, preserve_social])`` + + Check whether a unit can be assigned to (i.e. is looking for) a job. Will + return ``true`` if the unit is engaged in "green" social activities, unless + the boolean ``preserve_social`` is true. Will never interrupt uninterruptible + social activities (e.g. a purple "Socialize!"). + +* ``dfhack.units.getFocusPenalty(unit, need_type [, need_type, ...])`` + + Get largest (i.e. most negative) focus penalty associated to a collection of + ``df.need_type`` arguments. Returns a number strictly greater than 400 if the + unit does not have any of the requested needs. + +* ``dfhack.units.getStressCategory(unit)`` + + Returns a number from 0-6 indicating stress. 0 is most stressed; 6 is least. + Note that 0 is guaranteed to remain the most stressed but 6 could change in + the future. + +* ``dfhack.units.getStressCategoryRaw(stress_level)`` + + Identical to ``getStressCategory`` but takes a raw stress level instead + of a unit. + +* ``dfhack.units.getStressCutoffs()`` + + Returns a table of the cutoffs used by the above stress level functions. + +Action Timer API +~~~~~~~~~~~~~~~~ + +This is an API to allow manipulation of unit action timers, to speed them up or slow +them down. All functions in this API have overflow/underflow protection when modifying +action timers (the value will cap out). Actions with a timer of 0 (or less) will not +be modified as they are completed (or invalid in the case of negatives). +Timers will be capped to go no lower than 1. +``affectedActionType`` parameters are values from the DF enum ``unit_action_type`` +(e.g., ``df.unit_action_type.Move``). +``affectedActionTypeGroup`` parameters are values from the (custom) DF enum +``unit_action_type_group`` (see +`unit_action_type definition `_ +for which action types each group contains). They are as follows: + + * ``All`` + * ``Movement`` + * ``MovementFeet`` (affects only walking and crawling speed. If you need to + differentiate between walking and crawling, check the unit's ``flags1.on_ground`` flag, + like the Pegasus boots do in the `modding-guide`). + * ``MovementFeet`` (for walking speed, such as with pegasus boots from the `modding-guide`). + * ``Combat`` (includes bloodsucking). + * ``Work`` + +API functions: + +* ``dfhack.units.subtractActionTimers(unit, amount, affectedActionType)`` + + Subtract ``amount`` (32-bit integer) from the timers of any actions the unit is performing + of ``affectedActionType`` (usually one or zero actions in normal gameplay). Negative + amount adds to timers. + +* ``dfhack.units.subtractGroupActionTimers(unit, amount, affectedActionTypeGroup)`` + + Subtract ``amount`` (32-bit integer) from the timers of any actions the unit is performing + that match the ``affectedActionTypeGroup`` category. Negative amount adds to timers. + +* ``dfhack.units.multiplyActionTimers(unit, amount, affectedActionType)`` + + Multiply the timers of any actions of ``affectedActionType`` the unit is performing by + ``amount`` (float) (usually one or zero actions in normal gameplay). + +* ``dfhack.units.multiplyGroupActionTimers(unit, amount, affectedActionTypeGroup)`` + + Multiply the timers of any actions that match the ``affectedActionTypeGroup`` category + the unit is performing by ``amount`` (float). + +* ``dfhack.units.setActionTimers(unit, amount, affectedActionType)`` + + Set the timers of any action the unit is performing of ``affectedActionType`` to ``amount`` + (32-bit integer) (usually one or zero actions in normal gameplay). + +* ``dfhack.units.setGroupActionTimers(unit, amount, affectedActionTypeGroup)`` + + Set the timers of any action the unit is performing that match the + ``affectedActionTypeGroup`` category to ``amount`` (32-bit integer). + +Military module +--------------- + +* ``dfhack.military.makeSquad(assignment_id)`` + + Creates a new squad associated with the assignment (i.e., + ``df::entity_position_assignment``, via ``id``) and returns it. + Fails if a squad already exists that is associated with that assignment, or if + the assignment is not a fort mode player controlled squad. + Note: This function does not name the squad. Consider setting a nickname + (under ``squad.name.nickname``), and/or filling out the ``language_name`` object + at ``squad.name``. The returned squad is otherwise complete and requires no more + setup to work correctly. + +* ``dfhack.military.updateRoomAssignments(squad_id, assignment_id, squad_use_flags)`` + + Sets the sleep, train, indiv_eq, and squad_eq flags when training at a barracks. + +* ``dfhack.military.getSquadName(squad_id)`` + + Returns the name of a squad as a string. + +* ``dfhack.military.removeFromSquad(unit_id)`` + + Removes a unit from its squad. Unsets the unit's + military information (i.e., ``unit.military.squad_id`` and + ``unit.military.squad_pos``), the squad's position information (i.e., + ``squad.positions[squad_pos].occupant``), modifies the unit's entity links + to indicate former squad membership or command, and creates a corresponding + world history event. + + * ``dfhack.military.addToSquad(unit_id, squad_id, squad_pos)`` + + Adds a unit to a squad. Sets the unit's + military information (i.e., ``unit.military.squad_id`` and + ``unit.military.squad_pos``), the squad's position information (i.e., + ``squad.positions[squad_pos].occupant``), adds a unit's entity links to + indicate squad membership. Does not currently add world history events. + If ``squad_pos`` is -1, the unit will be added to the first open slot in + the squad. + + This API cannot be used to set or change the leader of a squad and will fail + if ``squad_pos`` is specified as 0 or if ``squad_pos`` is specified as -1 and + the squad leader position is currently vacant. It will also fail if + the requested squad position is already occupied, the squad does not exist, + the unit does not exist, or the requested unit is already a member of another + squad. + +Items module +------------ + +* ``dfhack.items.findType(string)`` + + Finds an item type by string and returns the ``df.item_type``. String is + case-sensitive (e.g., "TOOL"). + +* ``dfhack.items.findSubtype(string)`` + + Finds an item subtype by string and returns the subtype or *-1*. String is + case-sensitive (e.g., "TOOL:ITEM_TOOL_HIVE"). + +* ``dfhack.items.isCasteMaterial(item_type)`` + + Returns *true* if this item type uses a creature/caste pair as its material. + +* ``dfhack.items.getSubtypeCount(item_type)`` + + Returns the number of raw-defined subtypes of the given item type, or *-1* + if not applicable. + +* ``dfhack.items.getSubtypeDef(item_type, subtype)`` + + Returns the raw definition for the given item type and subtype, or *nil* + if invalid. + +* ``dfhack.items.getGeneralRef(item, type)`` + + Searches for a general_ref with the given type. + +* ``dfhack.items.getSpecificRef(item, type)`` + + Searches for a specific_ref with the given type. + +* ``dfhack.items.getOwner(item)`` + + Returns the owner unit or *nil*. + +* ``dfhack.items.setOwner(item,unit)`` + + Replaces the owner of the item. If unit is *nil*, removes ownership. + Returns *false* in case of error. + +* ``dfhack.items.getContainer(item)`` + + Returns the item's container item or *nil*. + +* ``dfhack.items.getOuterContainerRef(item)`` + + Returns a table (in the style of a ``specific_ref`` struct) of the outermost object + that contains the item (or one of the item itself.) The ``type`` field contains a + ``specific_ref_type`` of ``UNIT``, ``ITEM_GENERAL``, or ``VERMIN_EVENT``. + The ``object`` field contains a pointer to a unit, item, or vermin, respectively. + +* ``dfhack.items.getContainedItems(item)`` + + Returns a list of items contained in this one. + +* ``dfhack.items.getHolderBuilding(item)`` + + Returns the holder building or *nil*. + +* ``dfhack.items.getHolderUnit(item)`` + + Returns the holder unit or *nil*. + +* ``dfhack.items.getPosition(item)`` + + Returns the true *x,y,z* of the item, or *nil* if invalid. You should generally + use this method instead of reading *item.pos* directly since that field only stores + the last position where the item was on the ground. + +* ``dfhack.items.getBookTitle(item)`` + + Returns the title of the "book" item, or an empty string if the item isn't a "book" + or it doesn't have a title. A "book" is a codex or a tool item that has page or + writing improvements, such as scrolls and quires. + +* ``dfhack.items.getDescription(item, type[, decorate])`` + + Returns the string description of the item, as produced by the ``getItemDescription`` + method. A ``type`` of ``0`` results in a string like ``prickle berries [2]``. ``1`` + results in the singular ``prickle berry``, and ``2`` results in the plural + ``prickle berries``. If decorate is *true*, also adds markings for quality and + improvements, as well as ``(foreign)`` indicator (when applicable). + +* ``dfhack.items.getReadableDescription(item)`` + + Returns a string generally fit to usefully describe the item to the player. + When the item description appears anywhere in a script output or in the UI, + this is usually the string you should use. + +* ``dfhack.items.moveToGround(item,pos)`` + + Move the item to the ground at position. Returns *false* if impossible. + +* ``dfhack.items.moveToContainer(item,container)`` + + Move the item to the container. Returns *false* if impossible. + +* ``dfhack.items.moveToBuilding(item,building[,use_mode[,force_in_building])`` + + Move the item to the building. Returns *false* if impossible. + ``use_mode`` defaults to ``df.building_item_role_type.TEMP``. + If set to ``df.building_item_role_type.PERM``, the item will be treated as part + of the building. If ``force_in_building`` is true, the item will be considered + to be stored by the building (used for items temporarily used in traps in + vanilla DF). + +* ``dfhack.items.moveToInventory(item,unit[,use_mode[,body_part]])`` + + Move the item to the unit inventory. Returns *false* if impossible. + ``use_mode`` defaults to ``df.inv_item_role_type.Hauled``. + ``body_part`` defaults to ``-1``. + +* ``dfhack.items.remove(item[,no_uncat])`` + + Cancels any jobs associated with the item, removes the item from containers + and inventories, hides the item from the UI, and, unless ``no_uncat`` is + true, marks it for garbage collection. + +* ``dfhack.items.makeProjectile(item)`` + + Turns the item into a projectile, and returns the new object, or *nil* + if impossible. + +* ``dfhack.items.getItemBaseValue(item_type, subtype, material, mat_index)`` + + Calculates the base value for an item of the specified type and material. + +* ``dfhack.items.getValue(item[,caravan_state])`` + + Calculates the value of an item. If a ``df.caravan_state`` object is given + (from ``df.global.plotinfo.caravans`` or + ``df.global.game.main_interface.trade.mer``), then the value is modified by civ + properties and any trade agreements that might be in effect. + +* ``dfhack.items.createItem(unit, item_type, item_subtype, mat_type, mat_index, no_floor)`` + + Creates an item, similar to the `createitem` plugin. Returns a list of created + ``df.item`` objects. + +* ``dfhack.items.checkMandates(item)`` + + Returns true if the item is free from mandates, or false if mandates prevent + trading the item. + +* ``dfhack.items.canTrade(item)`` + + Checks whether the item can be traded. + +* ``dfhack.items.canTradeWithContents(item)`` + + Returns false if the item or any contained items cannot be traded. + +* ``canTradeAnyWithContents(item)`` + + Returns true if the item is empty and can be traded or if the item contains + any item that can be traded. + +* ``dfhack.items.markForTrade(item, depot)`` + + Marks the given item for trade at the given depot. + +* ``dfhack.items.isRequestedTradeGood(item[,caravan_state])`` + + Returns whether a caravan will pay extra for the given item. If caravan_state + is not given, checks all active caravans. + +* ``dfhack.items.canMelt(item[,game_ui])`` + + Returns true if the item can be melted (at a smelter). Unless ``game_ui`` is + given and true, bars, non-empty metal containers, and items in unit + inventories are not considered meltable, even though they can be designated + for melting using the game UI. + +* ``dfhack.items.markForMelting(item)`` + + Marks the given item for melting, unless already marked. Returns true if the + melting status was changed. + +* ``dfhack.items.cancelMelting(item)`` + + Removes melting designation, if present, from the given item. Returns true if + the melting status was changed. + +* ``dfhack.items.isRouteVehicle(item)`` + + Checks whether the item is an assigned hauling vehicle. + +* ``dfhack.items.isSquadEquipment(item)`` + + Checks whether the item is assigned to a squad. + +* ``dfhack.items.getCapacity(item)`` + + Returns the capacity volume of an item that can serve as a container for + other items. Return value will be ``0`` for items that cannot serve as a + container. + +.. _lua-world: + +World module +------------ + +* ``dfhack.world.ReadPauseState()`` + + Returns *true* if the game is paused. + +* ``dfhack.world.SetPauseState(paused)`` + + Sets the pause state of the game. + +* ``dfhack.world.ReadCurrentYear()`` + + Returns the current game year. + +* ``dfhack.world.ReadCurrentTick()`` + + Returns the number of game ticks (``df.global.world.frame_counter``) since the + start of the current game year. + +* ``dfhack.world.ReadCurrentMonth()`` + + Returns the current game month, ranging from 0-11. The Dwarven year has 12 months. + +* ``dfhack.world.ReadCurrentDay()`` + + Returns the current game day, ranging from 1-28. Each Dwarven month has 28 days. + +* ``dfhack.world.ReadCurrentWeather()`` + + Returns the current game weather (``df.weather_type``). + +* ``dfhack.world.SetCurrentWeather(weather)`` + + Sets the current game weather to ``weather``. + +* ``dfhack.world.ReadWorldFolder()`` + + Returns the name of the directory/folder the current saved game is under, or an + empty string if no game was loaded this session. + +* ``dfhack.world.isFortressMode([gametype])`` +* ``dfhack.world.isAdventureMode([gametype])`` +* ``dfhack.world.isArena([gametype])`` +* ``dfhack.world.isLegends([gametype])`` + + Without any arguments, returns *true* if the current gametype matches. + Optionally accepts a ``gametype`` id to match against. + +* ``dfhack.world.getCurrentSite()`` + + Returns the currently loaded ``df.world_site`` or ``nil`` if no site is loaded. + +* ``dfhack.world.getAdventurer()`` + + Returns the current adventurer unit (if in adventure mode). + +.. _lua-maps: + +Maps module +----------- + +* ``dfhack.maps.getSize()`` + + Returns map size in blocks: *x, y, z* + +* ``dfhack.maps.getTileSize()`` + + Returns map size in tiles: *x, y, z* + +* ``dfhack.maps.getBlock(x,y,z)`` + + Returns a map block object for given x,y,z in local block coordinates. + +* ``dfhack.maps.isValidTilePos(coords)``, or ``isValidTilePos(x,y,z)`` + + Checks if the given df::coord or x,y,z in local tile coordinates are valid. + +* ``dfhack.maps.isTileVisible(coords)``, or ``isTileVisible(x,y,z)`` + + Checks if the given df::coord or x,y,z in local tile coordinates is visible. + +* ``dfhack.maps.getTileBlock(coords)``, or ``getTileBlock(x,y,z)`` + + Returns a map block object for given df::coord or x,y,z in local + tile coordinates. + +* ``dfhack.maps.ensureTileBlock(coords)``, or ``ensureTileBlock(x,y,z)`` + + Like ``getTileBlock``, but if the block is not allocated, try creating it. + +* ``dfhack.maps.getTileType(coords)``, or ``getTileType(x,y,z)`` + + Returns the tile type at the given coordinates, or *nil* if invalid. + +* ``dfhack.maps.getTileFlags(coords)``, or ``getTileFlags(x,y,z)`` + + Returns designation and occupancy references for the given coordinates, or + *nil, nil* if invalid. + +* ``dfhack.maps.getRegionBiome(region_coord2d)``, or ``getRegionBiome(x,y)`` + + Returns the biome info struct for the given global map region. + + ``dfhack.maps.getBiomeType(region_coord2d)`` or ``getBiomeType(x,y)`` + + Returns the biome_type for the given global map region. + +* ``dfhack.maps.enableBlockUpdates(block[,flow[,temperature]])`` + + Enables updates for liquid flow or temperature, unless already active. + +* ``dfhack.maps.spawnFlow(pos,type,mat_type,mat_index,dimension)`` + + Spawns a new flow (i.e., steam/mist/dust/etc) at the given pos, and with + the given parameters. Returns it, or *nil* if unsuccessful. + +* ``dfhack.maps.getGlobalInitFeature(index)`` + + Returns the global feature object with the given index. + +* ``dfhack.maps.getLocalInitFeature(region_coord2d,index)`` + + Returns the local feature object with the given region coords and index. + +* ``dfhack.maps.getTileBiomeRgn(coords)``, or ``getTileBiomeRgn(x,y,z)`` + + Returns *x, y* for use with ``getRegionBiome`` and ``getBiomeType``. + +* ``dfhack.maps.getPlantAtTile(pos)``, or ``getPlantAtTile(x,y,z)`` + + Returns the plant struct that owns the tile at the specified position. + +* ``dfhack.maps.getWalkableGroup(pos)`` + + Returns the walkability group for the given tile position. A return value + of ``0`` indicates that the tile is not walkable. The data comes from a + pathfinding cache maintained by DF. + + .. note:: + This cache is only updated when the game is unpaused, and thus + can get out of date if doors are forbidden or unforbidden, or + tools like `liquids` or `tiletypes` are used. It also cannot possibly + take into account anything that depends on the actual units, like + burrows, or the presence of invaders. + +* ``dfhack.maps.canWalkBetween(pos1, pos2)`` + + Checks if both positions are walkable and also share a walkability group. + +* ``dfhack.maps.hasTileAssignment(tilemask)`` + + Checks if the tile_bitmask object is not *nil* and contains any set bits. + Returns *true* or *false*. + +* ``dfhack.maps.getTileAssignment(tilemask,x,y)`` + + Checks if the tile_bitmask object is not *nil* and has the relevant bit set. + Returns *true* or *false*. + +* ``dfhack.maps.setTileAssignment(tilemask,x,y,enable)`` + + Sets the relevant bit in the tile_bitmask object to the *enable* argument. + +* ``dfhack.maps.resetTileAssignment(tilemask[,enable])`` + + Sets all bits in the mask to the *enable* argument. + +* ``dfhack.maps.isTileAquifer(pos)``, or ``isTileAquifer(x,y,z)`` + + Checks if there's an aquifer on the given tile position. + Returns *true* or *false*. + +* ``dfhack.maps.isTileHeavyAquifer(pos)``, or ``isTileHeavyAquifer(x,y,z)`` + + Checks if there's a heavy aquifer on the given tile position. + Returns *true* or *false*. + +* ``dfhack.maps.setTileAquifer(pos[,heavy])``, or ``setTileAquifer(x,y,z[,heavy])`` + + Adds a light aquifer on the given tile position, or a heavy aquifer if the + *heavy* argument is *true*. Returns *true* or *false* depending on success. + +* ``dfhack.maps.removeTileAquifer(pos)``, or ``removeTileAquifer(x,y,z)`` + + Removes an aquifer from the given tile position. + Returns *true* or *false* depending on success. + +* ``dfhack.maps.addMaterialSpatter(pos, mat, matg, state, amount)`` + + Adds a material spatter to the specified map tile. If the tile is already + full of that spatter, returns the amount left over. + + Specifying a state of -1 (None) will automatically choose either Solid, + Liquid, or Gas based on the material properties and the tile temperature. + +* ``dfhack.maps.addItemSpatter(pos, i_type, i_subtype, subcat1, subcat2, print_variant, amount)`` + + Adds an item spatter to the specified map tile. If the tile is already + full of that spatter, returns the amount left over. + + For plant growths, specifying a print_variant of -1 will automatically + choose an appropriate value. For other item types, this field is ignored. + +Burrows module +-------------- + +* ``dfhack.burrows.getName(burrow)`` + + Returns the name of the burrow. + If the burrow has no set name, returns the same placeholder name that DF would show in the UI. + +* ``dfhack.burrows.findByName(name[, ignore_final_plus])`` + + Returns the burrow pointer or *nil*. if ``ignore_final_plus`` is ``true``, + then ``+`` characters at the end of the names are ignored, both for the + specified ``name`` and the names of the burrows that it matches against. + +* ``dfhack.burrows.clearUnits(burrow)`` + + Removes all units from the burrow. + +* ``dfhack.burrows.isAssignedUnit(burrow,unit)`` + + Checks if the unit is in the burrow. + +* ``dfhack.burrows.setAssignedUnit(burrow,unit,enable)`` + + Adds or removes the unit from the burrow. + +* ``dfhack.burrows.clearTiles(burrow)`` + + Removes all tiles from the burrow. + +* ``dfhack.burrows.listBlocks(burrow)`` + + Returns a table of map block pointers. + +* ``dfhack.burrows.isAssignedTile(burrow,tile_coord)`` + + Checks if the tile is in burrow. + +* ``dfhack.burrows.setAssignedTile(burrow,tile_coord,enable)`` + + Adds or removes the tile from the burrow. + Returns *false* if invalid coords. + +* ``dfhack.burrows.isAssignedBlockTile(burrow,block,x,y)`` + + Checks if the tile within the block is in burrow. + +* ``dfhack.burrows.setAssignedBlockTile(burrow,block,x,y,enable)`` + + Adds or removes the tile from the burrow. + Returns *false* if invalid coords. + +Buildings module +---------------- + +General +~~~~~~~ + +* ``dfhack.buildings.getGeneralRef(building, type)`` + + Searches for a general_ref with the given type. + +* ``dfhack.buildings.getSpecificRef(building, type)`` + + Searches for a specific_ref with the given type. + +* ``dfhack.buildings.getOwner(civzone)`` + + Returns the owner of the zone or *nil* if there isn't one. + +* ``dfhack.buildings.setOwner(civzone,unit)`` + + Replaces the owner of the civzone. If unit is *nil*, removes ownership. + Returns *false* in case of error. + + ``dfhack.buildings.getName(building)`` + + Returns the name of the building as it would appear in game. + +* ``dfhack.buildings.getSize(building)`` + + Returns *width, height, centerx, centery*. + +* ``dfhack.buildings.findAtTile(pos)``, or ``findAtTile(x,y,z)`` + + Scans the buildings for the one located at the given tile. + Does not work on civzones. Warning: linear scan if the map + tile indicates there are buildings at it. + +* ``dfhack.buildings.findCivzonesAt(pos)``, or ``findCivzonesAt(x,y,z)`` + + Scans civzones, and returns a lua sequence of those that touch + the given tile, or *nil* if none. + +* ``dfhack.buildings.getCorrectSize(width, height, type, subtype, custom, direction)`` + + Computes correct dimensions for the specified building type and orientation, + using width and height for flexible dimensions. + Returns *is_flexible, width, height, center_x, center_y*. + +* ``dfhack.buildings.checkFreeTiles(pos,size[,bld[,change_extents[,allow_occupied[,allow_wall[,allow_flow]]]]])`` + + Checks if the rectangle defined by ``pos`` and ``size``, and possibly the + extents associated with bld, can be used for placing a building. If + ``change_extents`` is true, bad tiles are removed from extents. If + ``allow_occupied``, the occupancy test is skipped. Set ``allow_wall`` to true + if the building is unhindered by walls (such as an activity zone). Set + ``allow_flow`` to true if the building can be built even if there is deep + water or any magma on the tile (such as abstract buildings). + +* ``dfhack.buildings.countExtentTiles(extents,defval)`` + + Returns the number of tiles included by extents, or defval. + +* ``dfhack.buildings.containsTile(building, x, y)`` + + Checks if the building contains the specified tile. If the building contains + extents, then the extents are checked. Otherwise, returns whether the x and y + map coordinates are within the building's bounding box. + +* ``dfhack.buildings.hasSupport(pos,size)`` + + Checks if a bridge constructed at specified position would have + support from terrain, and thus won't collapse if retracted. + +* ``dfhack.buildings.getStockpileContents(stockpile)`` + + Returns a list of items stored on the given stockpile. + Ignores empty bins, barrels, and wheelbarrows assigned as storage and + transport for that stockpile. + +* ``dfhack.buildings.getCageOccupants(cage)`` + + Returns a list of units in the given built cage. Note that this is different + from the list of units assigned to the cage, which can be accessed with + ``cage.assigned_units``. + +Low-level +~~~~~~~~~ +Low-level building creation functions: + +* ``dfhack.buildings.allocInstance(pos, type, subtype, custom)`` + + Creates a new building instance of given type, subtype and custom type, + at specified position. Returns the object, or *nil* in case of an error. + +* ``dfhack.buildings.setSize(building, width, height, direction)`` + + Configures an object returned by ``allocInstance``, using specified + parameters wherever appropriate. If the building has fixed size along + any dimension, the corresponding input parameter will be ignored. + Returns *false* if the building cannot be placed, or *true, width, + height, rect_area, true_area*. Returned width and height are the + final values used by the building; true_area is less than rect_area + if any tiles were removed from designation. You can specify a non-rectangular + designation for building types that support extents by setting the + ``room.extents`` bitmap before calling this function. The extents will be + reset, however, if the size returned by this function doesn't match the + input size parameter. + +* ``dfhack.buildings.constructAbstract(building)`` + + Links a fully configured object created by ``allocInstance`` into the + world. The object must be an abstract building, i.e., a stockpile or civzone. + Returns *true*, or *false* if impossible. + +* ``dfhack.buildings.constructWithItems(building, items)`` + + Links a fully configured object created by ``allocInstance`` into the + world for construction, using a list of specific items as material. + Returns *true*, or *false* if impossible. + +* ``dfhack.buildings.constructWithFilters(building, job_items)`` + + Links a fully configured object created by ``allocInstance`` into the + world for construction, using a list of job_item filters as inputs. + Returns *true*, or *false* if impossible. Filter objects are claimed + and possibly destroyed in any case. + Use a negative ``quantity`` field value to auto-compute the amount + from the size of the building. + +* ``dfhack.buildings.deconstruct(building)`` + + Destroys the building, or queues a deconstruction job. + Returns *true* if the building was destroyed and deallocated immediately. + +* ``dfhack.buildings.notifyCivzoneModified(building)`` + + Rebuilds the civzone <-> overlapping building association mapping. + Call after changing extents or modifying size in some fashion + +* ``dfhack.buildings.markedForRemoval(building)`` + + Returns *true* if the building is marked for removal (with :kbd:`x`), *false* + otherwise. + +* ``dfhack.buildings.getRoomDescription(building[, unit])`` + + If the building is a room, returns a description including quality modifiers, + e.g., "Royal Bedroom". Otherwise, returns an empty string. + + The unit argument is passed through to DF and may modify the room's value + depending on the unit given. + +* ``dfhack.buildings.completeBuild(building)`` + + Complete an unconstructed or partially-constructed building and link it into + the world. + +High-level +~~~~~~~~~~ +More high-level functions are implemented in lua and can be loaded by +``require('dfhack.buildings')``. See ``hack/lua/dfhack/buildings.lua``. + +Among them are: + +* ``dfhack.buildings.getFiltersByType(argtable,type,subtype,custom)`` + + Returns a sequence of lua structures, describing input item filters + suitable for the specified building type, or *nil* if unknown or invalid. + The returned sequence is suitable for use as the ``job_items`` argument + of ``constructWithFilters``. + Uses tables defined in ``buildings.lua``. + + Argtable members ``material`` (the default name), ``bucket``, ``barrel``, + ``chain``, ``mechanism``, ``screw``, ``pipe``, ``anvil``, ``weapon`` are used + to augment the basic attributes with more detailed information if the + building has input items with the matching name (see the tables for naming + details). Note that it is impossible to *override* any properties this way, + only supply those that are not mentioned otherwise. One exception is that + ``flags2.non_economic`` is automatically cleared if an explicit material + is specified. + +* ``dfhack.buildings.constructBuilding{...}`` + + Creates a building in one call, using options contained + in the argument table. Returns the building, or *nil, error*. + + .. note:: + Despite the name, unless the building is abstract, + the function creates it in an 'unconstructed' stage, with + a queued in-game job that will actually construct it. I.e., + the function replicates programmatically what can be done + through the construct building menu in the game ui, except + that it does less environment constraint checking. + + The following options can be used: + + - ``pos = coordinates``, or ``x = ..., y = ..., z = ...`` + + Mandatory. Specifies the left upper corner of the building. + + - ``type = df.building_type.FOO, subtype = ..., custom = ...`` + + Mandatory. Specifies the type of the building. Obviously, subtype + and custom are only expected if the type requires them. + + - ``fields = { ... }`` + + Initializes fields of the building object after creation with + ``df.assign``. If ``room.extents`` is assigned this way and this function + returns with error, the memory allocated for the extents is freed. + + - ``width = ..., height = ..., direction = ...`` + + Sets size and orientation of the building. If it is + fixed-size, specified dimensions are ignored. + + - ``full_rectangle = true`` + + For buildings like stockpiles or farm plots that can normally + accommodate individual tile exclusion, forces an error if any + tiles within the specified width*height are obstructed. + + - ``items = { item, item ... }``, or ``filters = { {...}, {...}... }`` + + Specifies explicit items or item filters to use in construction. + It is the job of the user to ensure they are correct for the building type. + + - ``abstract = true`` + + Specifies that the building is abstract and does not require construction. + Required for stockpiles and civzones; an error otherwise. + + - ``material = {...}, mechanism = {...}, ...`` + + If none of ``items``, ``filter``, or ``abstract`` is used, + the function uses ``getFiltersByType`` to compute the input + item filters, and passes the argument table through. If no filters + can be determined this way, ``constructBuilding`` throws an error. + + +Constructions module +-------------------- + +* ``dfhack.constructions.designateNew(pos,type,item_type,mat_index)`` + + Designates a new construction at given position. If there already is + a planned but not completed construction there, changes its type. + Returns *true*, or *false* if obstructed. + Note that designated constructions are technically buildings. + +* ``dfhack.constructions.designateRemove(pos)``, or ``designateRemove(x,y,z)`` + + If there is a construction or a planned construction at the specified + coordinates, designates it for removal, or instantly cancels the planned one. + Returns *true, was_only_planned* if removed; or *false* if none found. + +* ``dfhack.constructions.findAtTile(pos)``, or ``findAtTile(x,y,z)`` + + Returns the construction at the given position, or ``nil`` if there isn't one. + +* ``dfhack.constructions.insert(construction)`` + + Properly inserts the given construction into the game. Returns false and fails + to insert if there was already a construction at the position. + +Kitchen module +-------------- + +* ``dfhack.kitchen.findExclusion(type, item_type, item_subtype, mat_type, mat_index)`` + + Finds a kitchen exclusion in the vectors in ``df.global.ui.kitchen``. Returns + -1 if not found. + + * ``type`` is a ``df.kitchen_exc_type`` with exactly one flag set, i.e + ``{Cook=true}`` or ``{Brew=true}``. + * ``item_type`` is a ``df.item_type`` + * ``item_subtype``, ``mat_type``, and ``mat_index`` are all numeric + +* ``dfhack.kitchen.addExclusion(type, item_type, item_subtype, mat_type, mat_index)`` +* ``dfhack.kitchen.removeExclusion(type, item_type, item_subtype, mat_type, mat_index)`` + + Adds or removes a kitchen exclusion, using the same parameters as + ``findExclusion``. Both return ``true`` on success and ``false`` on failure, + e.g., when adding an exclusion that already exists or removing one that does + not. + +Screen API +---------- + +The screen module implements support for drawing to the tiled screen of the game. +Note that drawing only has any effect when done from callbacks, so it can only +be feasibly used in the `core context `. + +.. contents:: + :local: + +Basic painting functions +~~~~~~~~~~~~~~~~~~~~~~~~ + +Common parameters to these functions include: + +* ``x``, ``y``: screen coordinates in tiles; the upper left corner of the screen + is ``x = 0, y = 0`` +* ``pen``: a `pen object ` +* ``map``: a boolean (defaults to false) indicating whether to draw to a + separate map buffer. The Steam version uses separate map buffers with square + tiles for for all types of maps (i.e. fort, region, and world). + +Functions: + +* ``dfhack.screen.getWindowSize()`` + + Returns *width, height* of the screen. + +* ``dfhack.screen.getMousePos()`` + + Returns *x,y* of the UI interface tile the mouse is over, with the upper left + corner being ``0,0``. To get the map tile coordinate that the mouse is over, + see ``dfhack.gui.getMousePos()``. + +* ``dfhack.screen.getMousePixels()`` + + Returns *x,y* of the screen coordinates the mouse is over in pixels, with the + upper left corner being ``0,0``. + +* ``dfhack.screen.inGraphicsMode()`` + + Checks if [GRAPHICS:YES] was specified in init. + +* ``dfhack.screen.paintTile(pen,x,y[,char[,tile[,map]]])`` + + Paints a tile using given parameters. `See below ` for a + description of ``pen``. The map argument is only supported for local maps + (i.e. fort mode and adventure mode outside of fast travel). The ``char`` and + ``tile`` arguments allow overriding the respective parts of the ``pen`` + without constructing a new pen beforehand. + + Returns *false* on error, e.g., if coordinates are out of bounds + +* ``dfhack.screen.paintMapPortTile(pen,x,y[,char[,tile]])`` + + Paints a tile using given parameters onto the interface texpos layer of a map + port (e.g., the world map or the zoomed-in map for embark selection). The + ``char`` and ``tile`` arguments work as above. + +* ``dfhack.screen.readTile(x,y[,map])`` + + Retrieves the contents of the specified tile from the screen buffers. + Returns a `pen object `, or *nil* if invalid or TrueType. + +* ``dfhack.screen.readMapPortTile(x,y)`` + + Retrieves the contents of the specified tile from the screen buffers. Returns + a `pen object `, or *nil* if invalid. + + For now only looks at the ``sites`` textpos layer. + +* ``dfhack.screen.paintString(pen,x,y,text[,map])`` + + Paints the string starting at *x,y*. Uses the string characters + in sequence to override the ``ch`` field of `pen `. + + Returns *true* if painting at least one character succeeded. + +* ``dfhack.screen.fillRect(pen,x1,y1,x2,y2[,map])`` + + Fills the rectangle specified by the coordinates with the given + `pen `. Returns *true* if painting at least one + character succeeded. + +* ``dfhack.screen.findGraphicsTile(pagename,x,y)`` + + Finds a tile from a graphics set (i.e., the raws used for creatures), + if in graphics mode and loaded. + + Returns: *tile, tile_grayscale*, or *nil* if not found. + The values can then be used for the *tile* field of *pen* structures. + +* ``dfhack.screen.hideGuard(screen,callback[,args...])`` + + Removes screen from the viewscreen stack, calls the callback + (with optional supplied arguments), and then restores the screen on + the top of the viewscreen stack. + +* ``dfhack.screen.clear()`` + + Fills the screen with blank background. + +* ``dfhack.screen.invalidate()`` + + Requests repaint of the screen by setting a flag. Unlike other + functions in this section, this may be used at any time. + +* ``dfhack.screen.getKeyDisplay(key)`` + + Returns the string that should be used to represent the given + logical keybinding on the screen in texts like "press Key to ...". + +* ``dfhack.screen.keyToChar(key)`` + + Returns the integer character code of the string input + character represented by the given logical keybinding, + or *nil* if not a string input key. + +* ``dfhack.screen.charToKey(charcode)`` + + Returns the keybinding representing the given string input + character, or *nil* if impossible. + +.. _lua-screen-pen: + +Pen API +~~~~~~~ + +The ``pen`` argument used by ``dfhack.screen`` functions may be represented +by a table with the following possible fields: + + ``ch`` + Provides the ordinary tile character, as either a 1-character string or a number. + Can be overridden with the ``char`` function parameter. + ``fg`` + Foreground color for the ordinary tile. Defaults to COLOR_GREY (7). + ``bg`` + Background color for the ordinary tile. Defaults to COLOR_BLACK (0). + ``bold`` + Bright/bold text flag. If *nil*, computed based on (fg & 8); fg is masked to 3 bits. + Otherwise should be *true/false*. + ``tile`` + Graphical tile id. Ignored unless [GRAPHICS:YES] was in init.txt. + ``tile_color = true`` + Specifies that the tile should be shaded with *fg/bg*. + ``tile_fg, tile_bg`` + If specified, overrides *tile_color* and supplies shading colors directly. + ``keep_lower`` + If set to true, will not overwrite the background tile when filling in + the foreground tile. + ``write_to_lower`` + If set to true, the specified ``tile`` will be written to the background + instead of the foreground. + ``top_of_text`` + If set to true, the specified ``tile`` will have the top half of the specified + ``ch`` character superimposed over the lower half of the tile. + ``bottom_of_text`` + If set to true, the specified ``tile`` will have the bottom half of the specified + ``ch`` character superimposed over the top half of the tile. + +Alternatively, it may be a pre-parsed native object with the following API: + +* ``dfhack.pen.make(base[,pen_or_fg[,bg[,bold]]])`` + + Creates a new pre-parsed pen by combining its arguments according to the + following rules: + + 1. The ``base`` argument may be a pen object, a pen table as specified above, + or a single color value. In the single value case, it is split into + ``fg`` and ``bold`` properties, and others are initialized to 0. + This argument will be converted to a pre-parsed object and returned + if there are no other arguments. + + 2. If the ``pen_or_fg`` argument is specified as a table or object, it + completely replaces the base, and is returned instead of it. + + 3. Otherwise, the non-nil subset of the optional arguments is used + to update the ``fg``, ``bg`` and ``bold`` properties of the base. + If the ``bold`` flag is *nil*, but *pen_or_fg* is a number, ``bold`` + is deduced from it like in the simple base case. + + This function always returns a new pre-parsed pen, or *nil*. + +* ``dfhack.pen.parse(base[,pen_or_fg[,bg[,bold]]])`` + + Exactly like the above function, but returns ``base`` or ``pen_or_fg`` + directly if they are already a pre-parsed native object. + +* ``pen.property``, ``pen.property = value``, ``pairs(pen)`` + + Pre-parsed pens support reading and setting their properties, + but don't behave exactly like a simple table would; for instance, + assigning to ``pen.tile_color`` also resets ``pen.tile_fg`` and + ``pen.tile_bg`` to *nil*. + +Screen management +~~~~~~~~~~~~~~~~~ + +In order to actually be able to paint to the screen, it is necessary +to create and register a viewscreen (basically a modal dialog) with +the game. + +.. warning:: + As a matter of policy, in order to avoid user confusion, all + interface screens added by dfhack should bear the "DFHack" signature. + +Screens are managed with the following functions: + +* ``dfhack.screen.show(screen[,below])`` + + Displays the given screen, possibly placing it below a different one. + The screen must not be already shown. Returns *true* if success. + +* ``dfhack.screen.dismiss(screen[,to_first])`` + + Marks the screen to be removed when the game enters its event loop. + If ``to_first`` is *true*, all screens up to the first one will be deleted. + +* ``dfhack.screen.isDismissed(screen)`` + + Checks if the screen is already marked for removal. + +Apart from a native viewscreen object, these functions accept a table +as a screen. In this case, ``show`` creates a new native viewscreen +that delegates all processing to methods stored in that table. + +.. note:: + + * The `gui.Screen class ` provides stubs for all of the + functions listed below, and its use is recommended + * Lua-implemented screens are only supported in the `core context `. + +Supported callbacks and fields are: + +* ``screen._native`` + + Initialized by ``show`` with a reference to the backing viewscreen + object, and removed again when the object is deleted. + +* ``function screen:onShow()`` + + Called by ``dfhack.screen.show`` if successful. + +* ``function screen:onDismiss()`` + + Called by ``dfhack.screen.dismiss`` if successful. + +* ``function screen:onDestroy()`` + + Called from the destructor when the viewscreen is deleted. + +* ``function screen:onResize(w, h)`` + + Called before ``onRender`` or ``onIdle`` when the window size has changed. + +* ``function screen:onRender()`` + + Called when the viewscreen should paint itself. This is the only context + where the above painting functions work correctly. + + If omitted, the screen is cleared; otherwise it should do that itself. + In order to make a dialog where portions of the parent viewscreen are still + visible in the background, call ``screen:renderParent()``. + + If artifacts are left on the parent even after this function is called, such + as when the window is dragged or is resized, any code can set + ``gui.Screen.request_full_screen_refresh`` to ``true``. Then when + ``screen.renderParent()`` is next called, it will do a full flush of the + graphics and clear the screen of artifacts. + +* ``function screen:onIdle()`` + + Called every frame when the screen is on top of the stack. + +* ``function screen:onHelp()`` + + Called when the help keybinding is activated (usually '?'). + +* ``function screen:onInput(keys)`` + + Called when keyboard or mouse events are available. + If any keys are pressed, the keys argument is a table mapping them to *true*. + Note that this refers to logical keybindings computed from real keys via + options; if multiple interpretations exist, the table will contain multiple keys. + + The table also may contain special keys: + + ``_STRING`` + Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code + for convenience. + + ``_MOUSE_L, _MOUSE_R, _MOUSE_M`` + If the left, right, and/or middle mouse button was just pressed. + + ``_MOUSE_L_DOWN, _MOUSE_R_DOWN, _MOUSE_M_DOWN`` + If the left, right, and/or middle mouse button is being held down. + + If this method is omitted, the screen is dismissed on reception of the + ``LEAVESCREEN`` key. + +* ``function screen:onGetSelectedUnit()`` +* ``function screen:onGetSelectedItem()`` +* ``function screen:onGetSelectedJob()`` +* ``function screen:onGetSelectedBuilding()`` +* ``function screen:onGetSelectedStockpile()`` +* ``function screen:onGetSelectedCivZone()`` +* ``function screen:onGetSelectedPlant()`` + + Override these if you want to provide a custom return value for the matching + ``dfhack.gui.getSelected...`` function. + + +PenArray class +-------------- + +Screens that require significant computation in their onRender() method can use +a ``dfhack.penarray`` instance to cache their output. + +* ``dfhack.penarray.new(w, h)`` + + Creates a new penarray instance with an internal buffer of ``w * h`` tiles. + These dimensions currently cannot be changed after a penarray is instantiated. + +* ``penarray:clear()`` + + Clears the internal buffer, similar to ``dfhack.screen.clear()``. + +* ``penarray:get_dims()`` + + Returns the x and y dimensions of the internal buffer. + +* ``penarray:get_tile(x, y)`` + + Returns a pen corresponding to the tile at (``x``, ``y``) in the internal buffer. + Note that indices are 0-based. + +* ``penarray:set_tile(x, y, pen)`` + + Sets the tile at (``x``, ``y``) in the internal buffer to the pen given. + +* ``penarray:draw(x, y, w, h, bufferx, buffery)`` + + Draws the contents of the internal buffer, beginning at + (``bufferx``, ``buffery``) and spanning ``w`` columns and ``h`` rows, to the + screen starting at (``x``, ``y``). Any invalid screen and buffer coordinates + are skipped. + + ``bufferx`` and ``buffery`` default to 0. + + +Textures module +--------------- + +In order for the game to render a particular tile (graphic), it needs to know the +``texpos`` - the position in the vector of the registered game textures (also the +graphical tile id passed as the ``tile`` field in a `Pen `). +Adding new textures to the vector is not difficult, but the game periodically +deletes textures that are in the vector, and that's a problem since it +invalidates the ``texpos`` value that used to point to that texture. +The ``textures`` module solves this problem by providing a stable handle instead of a +raw ``texpos``. When we need to draw a particular tile, we can look up the current +``texpos`` value via the handle. +Texture module can register textures in two ways: to reserved and dynamic ranges. +Reserved range is a limit buffer in a game texture vector, that will never be wiped. +It is good for static assets, which need to be loaded at the very beginning and will +be used during the process running. In other cases, it is better to use dynamic range. +If reserved range buffer limit has been reached, dynamic range will be used by default. + +* ``loadTileset(file, tile_px_w, tile_px_h[, reserved])`` + + Loads a tileset from the image ``file`` with give tile dimensions in pixels. The + image will be sliced in row major order. Returns an array of ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). + + Example usage:: + + local logo_textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) + local first_texposhandle = logo_textures[1] + +* ``getTexposByHandle(handle)`` + + Get the current ``texpos`` for the given ``TexposHandle``. Always use this method to + get the ``texpos`` for your texture. ``texpos`` can change when game textures are + reset, but the handle will be the same. + +* ``createTile(pixels, tile_px_w, tile_px_h[, reserved])`` + + Create and register a new texture with the given tile dimensions and an array of + ``pixels`` in row major order. Each pixel is an integer representing color in packed + RBGA format (for example, #0022FF11). Returns a ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). + +* ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h[, reserved])`` + + Create and register a new texture with the given texture dimensions and an array of + ``pixels`` in row major order. Then slice it into tiles with the given tile + dimensions. Each pixel is an integer representing color in packed RBGA format (for + example #0022FF11). Returns an array of ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). + +* ``deleteHandle(handle)`` + + ``handle`` here can be single ``TexposHandle`` or an array of ``TexposHandle``. + Deletes all metadata and texture(s) related to the given handle(s). The handles + become invalid after this call. + + +Filesystem module +----------------- + +Most of these functions return ``true`` on success and ``false`` on failure, +unless otherwise noted. + +* ``dfhack.filesystem.exists(path)`` + + Returns ``true`` if ``path`` exists. + +* ``dfhack.filesystem.isfile(path)`` + + Returns ``true`` if ``path`` exists and is a file. + +* ``dfhack.filesystem.isdir(path)`` + + Returns ``true`` if ``path`` exists and is a directory. + +* ``dfhack.filesystem.getcwd()`` + + Returns the current working directory. To retrieve the DF path, use + ``dfhack.getDFPath()`` instead. + +* ``dfhack.filesystem.chdir(path)`` + + Changes the current directory to ``path``. Use with caution. + +* ``dfhack.filesystem.restore_cwd()`` + + Restores the current working directory to what it was when DF started. + +* ``dfhack.filesystem.get_initial_cwd()`` + + Returns the value of the working directory when DF was started. + +* ``dfhack.filesystem.mkdir(path)`` + + Creates a new directory. Returns ``false`` if unsuccessful, including if + ``path`` already exists. + +* ``dfhack.filesystem.mkdir_recursive(path)`` + + Creates a new directory, including any intermediate directories that + don't exist yet. Returns ``true`` if the folder was created or already + existed, or ``false`` if unsuccessful. + +* ``dfhack.filesystem.rmdir(path)`` + + Removes a directory. Only works if the directory is already empty. + +* ``dfhack.filesystem.mtime(path)`` + + Returns the modification time (in seconds) of the file or directory + specified by ``path``, or -1 if ``path`` does not exist. + This depends on the system clock and should only be used locally. + +* ``dfhack.filesystem.listdir(path)`` + + Lists files/directories in a directory. Returns ``{}`` if ``path`` does not exist. + +* ``dfhack.filesystem.listdir_recursive(path [, depth = 10[, include_prefix = true]])`` + + Lists all files/directories in a directory and its subdirectories. All + directories are listed before their contents. Returns a table with subtables + of the format: ``{path: 'path to file', isdir: true|false}`` + + Note that ``listdir()`` returns only the base name of each directory entry, + while ``listdir_recursive()`` returns the initial path and all components + following it for each entry. Set ``include_prefix`` to false if you don't + want the ``path`` string prepended to the returned filenames. + +* ``dfhack.filesystem.getBaseDir()`` + + Returns a directory to which DF (and thus DFHack) can save files. This will either + be DF's install directory, or the path returned by ``SDLGetPrefDir``, depending on whether + DF is in "portable mode" or not. + +* ``dfhack.filesystem.getInstallDir()`` + + Returns the the directory in which DF is installed. + +Console API +----------- + +* ``dfhack.console.clear()`` + + Clears the console; equivalent to the ``cls`` built-in command. + +* ``dfhack.console.flush()`` + + Flushes all output to the console. This can be useful when printing text that + does not end in a newline but should still be displayed. + +.. _lua-api-internal: + +Internal API +------------ + +These functions are intended for the use by dfhack developers, +and are only documented here for completeness: + +* ``dfhack.internal.getPE()`` + + Returns the PE timestamp of the DF executable (only on Windows) + +* ``dfhack.internal.getMD5()`` + + Returns the MD5 of the DF executable (only on OS X and Linux) + +* ``dfhack.internal.getAddress(name)`` + + Returns the global address ``name``, or *nil*. + +* ``dfhack.internal.setAddress(name, value)`` + + Sets the global address ``name``. Returns the value of ``getAddress`` + before the change. + +* ``dfhack.internal.getVTable(name)`` + + Returns the pre-extracted vtable address ``name``, or *nil*. + +* ``dfhack.internal.getImageBase()`` + + Returns the mmap base of the executable. + +* ``dfhack.internal.getRebaseDelta()`` + + Returns the ASLR rebase offset of the DF executable. + +* ``dfhack.internal.adjustOffset(offset[,to_file])`` + + Returns the re-aligned offset, or *nil* if invalid. + If ``to_file`` is true, the offset is adjusted from memory to file. + This function returns the original value everywhere except windows. + +* ``dfhack.internal.getMemRanges()`` + + Returns a sequence of tables describing virtual memory ranges of the process. + +* ``dfhack.internal.patchMemory(dest,src,count)`` + + Like memmove below, but works even if dest is read-only memory, e.g., code. + If destination overlaps a completely invalid memory region, or another error + occurs, returns false. + +* ``dfhack.internal.patchBytes(write_table[, verify_table])`` + + The first argument must be a lua table, which is interpreted as a mapping from + memory addresses to byte values that should be stored there. The second argument + may be a similar table of values that need to be checked before writing anything. + + The function takes care to either apply all of ``write_table``, or none of it. + An empty ``write_table`` with a nonempty ``verify_table`` can be used to reasonably + safely check if the memory contains certain values. + + Returns *true* if successful, or *nil, error_msg, address* if not. + +* ``dfhack.internal.memmove(dest,src,count)`` + + Wraps the standard memmove function. Accepts both numbers and refs as pointers. + +* ``dfhack.internal.memcmp(ptr1,ptr2,count)`` + + Wraps the standard memcmp function. + +* ``dfhack.internal.memscan(haystack,count,step,needle,nsize)`` + + Searches for ``needle`` of ``nsize`` bytes in ``haystack``, + using ``count`` steps of ``step`` bytes. + Returns: *step_idx, sum_idx, found_ptr*, or *nil* if not found. + +* ``dfhack.internal.diffscan(old_data, new_data, start_idx, end_idx, eltsize[, oldval[, newval[, delta]]])`` + + Searches for differences between buffers at ptr1 and ptr2, as integers of size eltsize. + The oldval, newval or delta arguments may be used to specify additional constraints. + Returns: *found_index*, or *nil* if end reached. + +* ``dfhack.internal.cxxDemangle(mangled_name)`` + + Decodes a mangled C++ symbol name. Returns the demangled name on success, or + ``nil, error_message`` on failure. + +* ``dfhack.internal.getDir(path)`` + + Lists files/directories in a directory. + Returns: *file_names* or empty table if not found. Identical to ``dfhack.filesystem.listdir(path)``. + +* ``dfhack.internal.strerror(errno)`` + + Wraps strerror() - returns a string describing a platform-specific error code + +* ``dfhack.internal.addScriptPath(path, search_before)`` + + Registers ``path`` as a `script path `. + If ``search_before`` is passed and ``true``, the path will be searched before + the default paths (e.g., ``dfhack-config/scripts``, ``hack/scripts``); otherwise, + it will be searched after. + + Returns ``true`` if successful or ``false`` otherwise (e.g., if the path does + not exist or has already been registered). + +* ``dfhack.internal.removeScriptPath(path)`` + + Removes ``path`` from the list of `script paths ` and returns + ``true`` if successful. + +* ``dfhack.internal.getScriptPaths()`` + + Returns the list of `script paths ` in the order they are + searched, including defaults. (This can change if a world is loaded.) + +* ``dfhack.internal.findScript(name)`` + + Searches `script paths ` for the script ``name`` (which + includes the ``.lua`` extension) and returns the absolute path of the first + file found, or ``nil`` on failure. Slashes in the path are canonicalized to + forward slashes. + + .. note:: + You can use the ``dfhack.findScript()`` wrapper if you want to specify the + script name without the ``.lua`` extension. + +* ``dfhack.internal.runCommand(command[, use_console])`` + + Runs a DFHack command with the core suspended. Used internally by the + ``dfhack.run_command()`` family of functions. + + - ``command``: either a table of strings or a single string which is parsed by + the default console tokenization strategy (not recommended) + - ``use_console``: if true, output is sent directly to the DFHack console + + Returns a table with a ``status`` key set to a ``command_result`` constant + (``status = CR_OK`` indicates success). Additionally, if ``use_console`` is + not true, enumerated table entries of the form ``{color, text}`` are included, + e.g., ``result[1][0]`` is the color of the first piece of text printed (a + ``COLOR_`` constant). These entries can be iterated over with ``ipairs()``. + +* ``dfhack.internal.md5(string)`` + + Returns the MD5 hash of the given string. + +* ``dfhack.internal.md5File(filename[,first_kb])`` + + Computes the MD5 hash of the given file. Returns ``hash, length`` on success + (where ``length`` is the number of bytes read from the file), or ``nil, + error`` on failure. + + If the parameter ``first_kb`` is specified and evaluates to ``true``, and the + hash was computed successfully, a table containing the first 1024 bytes of the + file is returned as the third return value. + +* ``dfhack.internal.threadid()`` + + Returns a numeric identifier of the current thread. + +* ``dfhack.internal.msizeAddress(address)`` + + Returns the allocation size of an address. + Does not require a heap snapshot. This function will crash on an invalid pointer. + Windows only. + +* ``dfhack.internal.getHeapState()`` + + Returns the state of the heap. 0 == ok or empty, 1 == heap bad ptr, 2 == heap bad begin, + 3 == heap bad node. Does not require a heap snapshot. This may be unsafe to use directly + from lua if the heap is corrupt. Windows only. + +* ``dfhack.internal.heapTakeSnapshot()`` + + Clears any existing heap snapshot, and takes an internal heap snapshot for later + consumption. Windows only. Returns the same values as getHeapState() + +* ``dfhack.internal.isAddressInHeap(address)`` + + Checks if an address is a member of the heap. It may be dangling. + Requires a heap snapshot. + +* ``dfhack.internal.isAddressActiveInHeap(address)`` + + Checks if an address is a member of the heap, and actively in use (i.e., valid). + Requires a heap snapshot. + +* ``dfhack.internal.isAddressUsedAfterFreeInHeap(address)`` + + Checks if an address is a member of the heap, but is not currently allocated + (i.e., use after free). Requires a heap snapshot. + Note that Windows eagerly removes freed pointers from the heap, + so this is unlikely to trigger. + +* ``dfhack.internal.getAddressSizeInHeap(address)`` + + Gets the allocated size of a member of the heap. Useful for detecting misaligns, + as this does not return block size. Requires a heap snapshot. + +* ``dfhack.internal.getRootAddressOfHeapObject(address)`` + + Gets the base heap allocation address of a address that lies internally within + a piece of allocated memory. E.g., if you have a heap allocated struct and call + this function on the address of the second member, it will return the address + of the struct. Returns 0 if the address is not found. Requires a heap snapshot. + +* ``dfhack.internal.getClipboardTextCp437()`` + + Gets the system clipboard text (and converts text to CP437 encoding). + +* ``dfhack.internal.setClipboardTextCp437(text)`` + + Sets the system clipboard text from a CP437 string. + +* ``dfhack.internal.getClipboardTextCp437Multiline()`` + + Gets the system clipboard text (and converts text to CP437 encoding). + Character 0x10 is interpreted as a newline instead of the usual CP437 glyph. + The text is returned as a list of strings, one for each line of text on the + clipboard. + +* ``dfhack.internal.setClipboardTextCp437Multiline(text)`` + + Sets the system clipboard text from a CP437 string. Character 0x10 is + interpreted as a newline instead of the usual CP437 glyph. + +* ``dfhack.internal.getModifiers()`` + + Returns the state of the keyboard modifier keys in a table of string -> + boolean. The keys are ``ctrl``, ``shift``, ``super``, and ``alt``. + +* ``dfhack.internal.getSuppressDuplicateKeyboardEvents()`` +* ``dfhack.internal.setSuppressDuplicateKeyboardEvents(suppress)`` + + Gets and sets the flag for whether to suppress DF key events when a DFHack + keybinding is matched and a command is launched. + +* ``dfhack.internal.setMortalMode(value)`` +* ``dfhack.internal.setArmokTools(tool_names)`` + + Used to sync mortal mode state to DFHack Core memory for use in keybinding + checks. + +* ``dfhack.internal.setPreferredNumberFormat(value)`` +* ``dfhack.internal.getPreferredNumberFormat()`` + + Sets (gets) the preferred numeric format. ``0`` means no formatting (e.g., + ``1234567``), ``1`` means English formatting (e.g., ``1,234,567``), ``2`` + means system locale formatting (e.g., ``12.345`` on German systems, + ``12,34,567`` on Indian systems, etc.), ``3`` means SI suffix formatting + (e.g., ``12.3M``), and ``4`` means scientific notation (e.g., ``1.23457e+06``). + +For the internal preference values, be aware that setting the values via these +functions will not persist the choice across program invocations. You must set +preferences via the `control-panel` or `gui/control-panel` interfaces for that. + +.. _lua-core-context: + +Core interpreter context +======================== + +While plugins can create any number of interpreter instances, +there is one special context managed by the DFHack core. It is the +only context that can receive events from DF and plugins. + +Core context specific functions: + +* ``dfhack.is_core_context`` + + Boolean value; *true* in the core context. + +* ``dfhack.timeout(time,mode,callback)`` + + Arranges for the callback to be called once the specified + period of time passes. The ``mode`` argument specifies the + unit of time used, and may be one of ``'frames'`` (raw FPS), + ``'ticks'`` (unpaused FPS), ``'days'``, ``'months'``, + ``'years'`` (in-game time). All timers other than + ``'frames'`` are canceled when the world is unloaded, + and cannot be queued until it is loaded again. + Returns the timer id, or *nil* if unsuccessful due to + world being unloaded. + +* ``dfhack.timeout_active(id[,new_callback])`` + + Returns the active callback with the given id, or *nil* + if inactive or nil id. If called with 2 arguments, replaces + the current callback with the given value, if still active. + Using ``timeout_active(id,nil)`` cancels the timer. + +* ``dfhack.onStateChange.foo = function(code)`` + + Creates a handler for state change events. Receives the same + `SC_ codes ` as ``plugin_onstatechange()`` in C++. + + +Event type +---------- + +An event is a native object transparently wrapping a lua table, +and implementing a __call metamethod. When it is invoked, it loops +through the table with next and calls all contained values. +This is intended as an extensible way to add listeners. + +This type itself is available in any context, but only the +`core context ` has the actual events defined by C++ code. + +Features: + +* ``dfhack.event.new()`` + + Creates a new instance of an event. + +* ``event[key] = function`` + + Sets the function as one of the listeners. Assign *nil* to remove it. + + .. note:: + The ``df.NULL`` key is reserved for the use by + the C++ owner of the event; it is an error to try setting it. + +* ``#event`` + + Returns the number of non-nil listeners. + +* ``pairs(event)`` + + Iterates over all listeners in the table. + +* ``event(args...)`` + + Invokes all listeners contained in the event in an arbitrary + order using ``dfhack.safecall``. + + +=========== +Lua Modules +=========== + +.. contents:: + :local: + +DFHack sets up the lua interpreter so that the built-in ``require`` +function can be used to load shared lua code from :file:`hack/lua/`. +The ``dfhack`` namespace reference itself may be obtained via +``require('dfhack')``, although it is initially created as a +global by C++ bootstrap code. + +The following module management functions are provided: + +* ``mkmodule(name)`` + + Creates an environment table for the module. Intended to be used as:: + + local _ENV = mkmodule('foo') + ... + return _ENV + + If called the second time, returns the same table, + thus providing reload support. + +* ``reload(name)`` + + Reloads a previously ``require``-d module *"name"* from the file. + Intended as a help for module development. + +* ``dfhack.BASE_G`` + + This variable contains the root global environment table, which is + used as a base for all module and script environments. Its contents + should be kept limited to the standard Lua library and API described + in this document. + +.. _lua-globals: + +Global environment +================== + +A number of variables and functions are provided in the base global +environment by the mandatory init file dfhack.lua: + +* Color constants + + These are applicable both for ``dfhack.color()`` and color fields + in DF functions or structures:: + + COLOR_RESET, COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, + COLOR_RED, COLOR_MAGENTA, COLOR_BROWN, COLOR_GREY, COLOR_DARKGREY, + COLOR_LIGHTBLUE, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN, COLOR_LIGHTRED, + COLOR_LIGHTMAGENTA, COLOR_YELLOW, COLOR_WHITE + + ``COLOR_GREY`` and ``COLOR_DARKGREY`` can also be spelled ``COLOR_GRAY`` and + ``COLOR_DARKGRAY``. + + Note: ``COLOR_RESET`` is not valid in a `Pen `, and using it in a Pen color field + will result in runtime warnings and may result in color flashing or other unexpected results. + +* State change event codes, used by ``dfhack.onStateChange`` + + Available only in the `core context `, as is the event itself: + + SC_WORLD_LOADED, SC_WORLD_UNLOADED, SC_MAP_LOADED, + SC_MAP_UNLOADED, SC_VIEWSCREEN_CHANGED, SC_CORE_INITIALIZED + +* Command result constants (equivalent to ``command_result`` in C++), used by + ``dfhack.run_command()`` and related functions: + + CR_OK, CR_LINK_FAILURE, CR_NEEDS_CONSOLE, CR_NOT_IMPLEMENTED, CR_FAILURE, + CR_WRONG_USAGE, CR_NOT_FOUND + +* Functions already described above + + safecall, qerror, mkmodule, reload + +* Miscellaneous constants + + ``NEWLINE``, ``COMMA``, ``PERIOD`` + evaluate to the relevant character strings. + ``DEFAULT_NIL`` + is an unspecified unique token used by the class module below. + +* ``printall(obj)`` + + If the argument is a lua table or DF object reference, prints all fields. + +* ``printall_recurse(obj)`` + + If the argument is a lua table or DF object reference, prints all fields recursively. + +* ``copyall(obj)`` + + Returns a shallow copy of the table or reference as a lua table. + +* ``pos2xyz(obj)`` + + The object must have fields x, y and z. Returns them as 3 values. + If obj is *nil*, or x is -30000 (the usual marker for undefined + coordinates), returns *nil*. + +* ``xyz2pos(x,y,z)`` + + Returns a table with x, y and z as fields. + +* ``same_xyz(a,b)`` + + Checks if ``a`` and ``b`` have the same x, y and z fields. + +* ``get_path_xyz(path,i)`` + + Returns ``path.x[i], path.y[i], path.z[i]``. + +* ``pos2xy(obj)``, ``xy2pos(x,y)``, ``same_xy(a,b)``, ``get_path_xy(a,b)`` + + Same as above, but for 2D coordinates. + +* ``safe_index(obj,index...)`` + + Walks a sequence of dereferences, which may be represented by numbers or strings. + Returns *nil* if any of obj or indices is *nil*, obj isn't indexable, or a numeric + index is out of array bounds. + +* ``ensure_key(t, key[, default_value])`` + + If the Lua table ``t`` doesn't include the specified ``key``, ``t[key]`` is + set to the value of ``default_value``, which defaults to ``{}`` if not set. + The new or existing value of ``t[key]`` is then returned. + +* ``ensure_keys(t, key...)`` + + Walks a series of keys, creating any missing keys as empty tables. The new or + existing table from the last specified key is returned from the function. + +.. _lua-string: + +String class extensions +----------------------- + +DFHack extends Lua's basic string class to include a number of convenience +functions. These are invoked just like standard string functions, e.g.:: + + if imastring:startswith('imaprefix') then + +* ``string:startswith(prefix)`` + + Returns ``true`` if the first ``#prefix`` characters of the string are equal + to ``prefix``. Note that ``prefix`` is not interpreted as a pattern. + +* ``string:endswith(suffix)`` + + Returns ``true`` if the last ``#suffix`` characters of the string are equal + to ``suffix``. Note that ``suffix`` is not interpreted as a pattern. + +* ``string:split([delimiter[, plain]])`` + + Split a string by the given delimiter. If no delimiter is specified, space + (``' '``) is used. The delimiter is treated as a pattern unless a ``plain`` is + specified and set to ``true``. To treat multiple successive delimiter + characters as a single delimiter, e.g., to avoid getting empty string elements, + pass a pattern like ``' +'``. Be aware that passing patterns that match empty + strings (like ``' *'``) will result in improper string splits. + +* ``string:trim()`` + + Removes spaces (i.e., everything that matches ``'%s'``) from the start and end + of a string. Spaces between non-space characters are left untouched. + +* ``string:wrap([width[, opts]])`` + + Inserts newlines into a string so no individual line exceeds the given width. + Lines are split at space-separated word boundaries. Any existing newlines are + kept in place. If a single word is longer than width, it is split over + multiple lines. If ``width`` is not specified, 72 is used. The ``opts`` + parameter can be a table with the following boolean fields specified: + + :return_as_table: if ``true``, then the function will return a table of + strings, with each string representing one wrapped line. Otherwise, a + single multi-line string is returned. + :keep_trailing_spaces: if ``true``, then spaces at the end of a wrapped + line will be kept. Normally, spaces at the end of a wrapped line are + elided. + :keep_original_newlines: if ``true`` (and ``return_as_table`` is also + ``true``), then if a newline was encountered in the original string, it + will be included in the relevant table entry. + +* ``string:escape_pattern()`` + + Escapes regex special chars in a string. E.g., ``'a+b'`` -> ``'a%+b'``. + +.. _script-manager: + +script-manager +============== + +This module contains functions useful for mods that contain DFHack scripts to +retrieve source and state paths. The value to pass as ``mod_id`` must be the +same as the mod ID in the mod's :file:`info.txt` metadata file. The returned +paths will be relative to the top level game directory and will end in a slash +(``/``). + +* ``scriptmanager.getModSourcePath(mod_id)`` + + Retrieve the source directory path for the mod with the given ID or ``nil`` + if the mod cannot be found. If multiple versions of a mod are found, the path + for the version loaded by the current world is used. If the current world + does not have the mod loaded (or if a world is not currently loaded) then the + path for the most recent version of the mod is returned. Example:: + + local scriptmanager = require('script-manager') + local path = scriptmanager.getModSourcePath('my_awesome_mod') + print(path) + + Which would print something like: ``mods/2945575779/`` or + ``data/installed_mods/my_awesome_mod (108)/``, depending on where the mod is + being loaded from. + +* ``scriptmanager.getModStatePath(mod_id)`` + + Retrieve the directory path where a mod with the given ID should store its + persistent state. Example:: + + local json = require('json') + local scriptmanager = require('script-manager') + local path = scriptmanager.getModStatePath('my_awesome_mod') + config = config or json.open(path .. 'settings.json') + + Which would open ``dfhack-config/mods/my_awesome_mod/settings.json``. After + calling ``getModStatePath``, the returned directory is guaranteed to exist. + +* ``get_active_mods()`` + + Returns a list of all active mods in the current world. The list elements are + tables containing the following fields: + + - id: mod id + - name: mod display name + - version: mod display version + - numeric_version: numeric mod version + - path: path to the mod directory + - vanilla: true if this is a vanilla mod + +* ``get_mod_info_metadata(mod_path, tags)`` + + Returns a table with the values of the given tags from the ``info.txt`` file + in the given mod directory. The ``mod_path`` argument must be a path to a mod + directory (retrieved, say, from ``get_active_mods()``). The ``tags`` argument + is a string or a list of strings representing the tags to retrieve. The + function will return a table with the tag names as keys and their values as + values. If a requested tag includes the string ``NUMERIC_``, it will return + the numeric value for that tag (e.g., ``NUMERIC_VERSION`` will return the + numeric version of the mod as a number instead of a string). + +utils +===== + +* ``utils.compare(a,b)`` + + Comparator function; returns *-1* if ab, *0* otherwise. + +* ``utils.compare_name(a,b)`` + + Comparator for names; compares empty string last. + +* ``utils.is_container(obj)`` + + Checks if obj is a container ref. + +* ``utils.make_index_sequence(start,end)`` + + Returns a lua sequence of numbers in start..end. + +* ``utils.invert(table)`` + + Returns a table where keys and values are reversed (i.e., a table containing a + ``value = key`` entry for every ``key = value`` entry in the argument). + +* ``utils.tabulate(fun, start, stop[, step])`` + + For numbers ``start``, ``stop`` and ``step``, with ``step`` defaulting to 1, + returns a lua sequence ``{ fun(start), fun(start+step), ... , fun(stop) }``. + +* ``utils.make_sort_order(data, ordering)`` + + Computes a sorted permutation of objects in data, as a table of integer + indices into the data sequence. Uses ``data.n`` as input length + if present. + + The ordering argument is a sequence of ordering specs, represented + as lua tables with following possible fields: + + ord.key = *function(value)* + Computes comparison key from input data value. Not called on nil. + If omitted, the comparison key is the value itself. + ord.key_table = *function(data)* + Computes a key table from the data table in one go. + ord.compare = *function(a,b)* + Comparison function. Defaults to ``utils.compare`` above. + Called on non-nil keys; nil sorts last. + ord.nil_first = *true/false* + If true, nil keys are sorted first instead of last. + ord.reverse = *true/false* + If true, sort non-nil keys in descending order. + + For every comparison during sorting the specs are applied in + order until an unambiguous decision is reached. Sorting is stable. + + Example of sorting a sequence by field foo:: + + local spec = { key = function(v) return v.foo end } + local order = utils.make_sort_order(data, { spec }) + local output = {} + for i = 1,#order do output[i] = data[order[i]] end + + Separating the actual reordering of the sequence in this + way enables applying the same permutation to multiple arrays. + This function is used by the sort plugin. + +* ``for link,item in utils.listpairs(list)`` + + Iterates a df-list structure, for example ``df.global.world.job_list``. + +* ``utils.assign(tgt, src)`` + + Does a recursive assignment of src into tgt. + Uses ``df.assign`` if tgt is a native object ref; otherwise + recurses into lua tables. + +* ``utils.clone(obj, deep)`` + + Performs a shallow, or semi-deep copy of the object as a lua table tree. + The deep mode recurses into lua tables and subobjects, except pointers + to other heap objects. + Null pointers are represented as ``df.NULL``. Zero-based native containers + are converted to 1-based lua sequences. + +* ``utils.clone_with_default(obj, default, force)`` + + Copies the object, using the ``default`` lua table tree + as a guide to which values should be skipped as uninteresting. + The ``force`` argument makes it always return a non-*nil* value. + +* ``utils.parse_bitfield_int(value, type_ref)`` + + Given an int ``value``, and a bitfield type in the ``df`` tree, + it returns a lua table mapping the enabled bit keys to *true*, + unless value is 0, in which case it returns *nil*. + +* ``utils.list_bitfield_flags(bitfield[, list])`` + + Adds all enabled bitfield keys to ``list`` or a newly-allocated + empty sequence, and returns it. The ``bitfield`` argument may + be *nil*. + +* ``utils.sort_vector(vector,field,cmpfun)`` + + Sorts a native vector or lua sequence using the comparator function. + If ``field`` is not *nil*, applies the comparator to the field instead + of the whole object. + +* ``utils.linear_index(vector,key[,field])`` + + Searches for ``key`` in the vector, and returns *index, found_value*, + or *nil* if none found. + +* ``utils.binsearch(vector,key,field,cmpfun,min,max)`` + + Does a binary search in a native vector or lua sequence for + ``key``, using ``cmpfun`` and ``field`` like sort_vector. + If ``min`` and ``max`` are specified, they are used as the + search subrange bounds. + + If found, returns *item, true, idx*. Otherwise returns + *nil, false, insert_idx*, where *insert_idx* is the correct + insertion point. + +* ``utils.insert_sorted(vector,item,field,cmpfun)`` + + Does a binary search, and inserts item if not found. + Returns *did_insert, vector[idx], idx*. + +* ``utils.insert_or_update(vector,item,field,cmpfun)`` + + Like ``insert_sorted``, but also assigns the item into + the vector cell if insertion didn't happen. + + As an example, you can use this to set skill values:: + + utils.insert_or_update(soul.skills, {new=true, id=..., rating=...}, 'id') + + (For an explanation of ``new=true``, see `lua-api-table-assignment`) + +* ``utils.erase_sorted_key(vector,key,field,cmpfun)`` + + Removes the item with the given key from the list. + Returns: *did_erase, vector[idx], idx*. + +* ``utils.erase_sorted(vector,item,field,cmpfun)`` + + Exactly like ``erase_sorted_key``, but if field is specified, + takes the key from ``item[field]``. + +* ``utils.search_text(text,search_tokens)`` + + Returns true if all the search tokens are found within ``text``. The text and + search tokens are normalized to lower case and special characters (e.g., ``A`` + with a circle on it) are converted to their "basic" forms (e.g., ``a``). + ``search_tokens`` can be a string or a table of strings. If it is a string, + it is split into space-separated tokens before matching. The search tokens + are treated literally, so any special regular expression characters do not + need to be escaped. If ``utils.FILTER_FULL_TEXT`` is ``true``, then the + search tokens can match any part of ``text``. If it is ``false``, then the + matches must happen at the beginning of words within ``text``. You can change + the value of ``utils.FILTER_FULL_TEXT`` in `gui/control-panel` on the + "Preferences" tab. + +* ``utils.call_with_string(obj,methodname,...)`` + + Allocates a temporary string object, calls ``obj:method(tmp,...)``, and + returns the value written into the temporary after deleting it. + +* ``utils.getBuildingName(building)`` + + Returns the string description of the given building. + +* ``utils.getBuildingCenter(building)`` + + Returns an x/y/z table pointing at the building center. + +* ``utils.split_string(string, delimiter)`` + + Splits the string by the given delimiter, and returns a sequence of results. + +* ``utils.prompt_yes_no(prompt, default)`` + + Presents a yes/no prompt to the user. If ``default`` is not *nil*, + allows just pressing Enter to submit the default choice. + If the user enters ``'abort'``, throws an error. + +* ``utils.prompt_input(prompt, checkfun, quit_str)`` + + Presents a prompt to input data, until a valid string is entered. + Once ``checkfun(input)`` returns *true, ...*, passes the values + through. If the user enters the quit_str (defaults to ``'~~~'``), + throws an error. + +* ``utils.check_number(text)`` + + A ``prompt_input`` ``checkfun`` that verifies a number input. + +argparse +======== + +The ``argparse`` module provides functions to help scripts process commandline +parameters. + +* ``argparse.processArgs(args, validArgs)`` + + A basic commandline processing function with simple syntax, useful if your + script doesn't need the more advanced features of + ``argparse.processArgsGetopt()``. + + If ``validArgs`` is specified, it should contain a set of valid option names + (without the leading dashes). For example:: + + argparse.processArgs(args, utils.invert{'opt1', 'opt2', 'opt3'}) + + ``processArgs`` returns a map of option names it found in ``args`` to: + + - the token that came after the option + - ``''`` if the next token was another option + - a list of strings if the next token was ``'['`` (see below) + + Options in ``args`` from the commandline can be prefixed with either one dash + (``'-'``) or two dashes (``'--'``). The user can add a backslash before the + dash to allow a string to be identified as an option value instead of another + option. For example: ``yourscript --opt1 \-arg1``. + + If a ``'['`` token is found in ``args``, the subsequent tokens will be + interpreted as elements of a list until the matching closing ``']'`` is found. + Brackets can be nested, but the inner brackets will be added to the list of + tokens as literal ``'['`` and ``']'`` strings. + + Example commandlines:: + + yourscript --optName --opt2 + yourscript --optName value + yourscript --optName [ list of values ] + yourscript --optName [ list of [ nested values ] [ in square brackets ] ] + yourscript --optName \--value + + Note that ``processArgs`` does not support non-option ("positional") + parameters. They are supported by ``processArgsGetopt`` (see below). + +* ``argparse.processArgsGetopt(args, optionActions)`` + + A fully-featured commandline processing function, with behavior based on the + popular ``getopt`` library. You would use this instead of the simpler + ``processArgs`` function if any of the following are true: + + * You want both short (e.g., ``-f``) and aliased long-form (e.g., + ``--filename``) options + * You have commandline components that are not arguments to options (e.g., you + want to run your script like ``yourscript command --verbose arg1 arg2 arg3`` + instead of + ``yourscript command --verbose --opt1 arg1 --opt2 arg2 --opt3 arg3)``. + * You want the convenience of combining options into shorter strings (e.g., + ``'-abcarg'`` instead of ``'-a -b -c arg``) + * You want to be able to parse and validate the option arguments as the + commandline is being processed, as opposed to validating everything after + commandline processing is complete. + + Commandlines processed by ``processArgsGetopt`` can have both "short" and + "long" options, with each short option often having a long-form alias that + behaves exactly the same as the short form. Short options have properties that + make them very easy to type quickly by users who are familiar with your script + options. Long options, on the other hand, are easily understandable by + everyone and are useful in places where clarity is more important than + brevity, e.g., in example commands. Each option can be configured to take an + argument, which will be the string token that follows the option name on the + commandline. + + Short options are a single letter long and are specified on a commandline by + prefixing them with a single dash (e.g., the short option ``a`` would appear + on the commandline as ``-a``). Multiple successive short options that do not + take arguments can be combined into a single option string (e.g., ``'-abc'`` + instead of ``'-a -b -c'``). Moreover, the argument for a short option can be + appended directly to the single-letter option without an intervening space + (e.g., ``-d param`` can be written as ``-dparam``). These two convenience + shorthand forms can be combined, allowing groups of short parameters to be + written together, as long as at most the last short option takes an argument + (e.g., combining the previous two examples into ``-abcdparam``) + + Long options focus on clarity. They are usually entire words, or several words + combined with hyphens (``-``) or underscores (``_``). If they take an + argument, the argument can be separated from the option name by a space or an + equals sign (``=``). For example, the following two commandlines are + equivalent: ``yourscript --style pretty`` and ``yourscript --style=pretty``. + + Another reason to use long options is if they represent an esoteric parameter + that you don't expect to be commonly used and that you don't want to "waste" a + single-letter option on. In this case, you can define a long option without a + corresponding short option. + + ``processArgsGetopt`` takes two parameters:: + + args: list of space-separated strings the user wrote on the commandline + optionActions: list of option specifications + + and returns a list of positional parameters -- that is, all strings that are + neither options nor arguments to options. Options and positional parameters + can appear in any order on the commandline, as long as arguments to options + immediately follow the option itself. + + Each option specification in ``optionActions`` has the following format: + ``{shortOptionName, longOptionAlias, hasArg=boolean, handler=fn}`` + + * ``shortOptionName`` is a one-character string (or ``''`` or ``nil`` if the + parameter only has a long form). Numbers cannot be short options, and + negative numbers (e.g., ``'-10'``) will be interpreted as positional + parameters and returned in the positional parameters list. + * ``longOptionAlias`` is an optional longer form of the short option name. If + no short option name is specified, then this element is required. + * ``hasArg`` indicates whether the handler function for the option takes a + parameter. + * ``handler`` is the handler function for the option. If ``hasArg`` is + ``true`` then the next token on the commandline is passed to the handler + function as an argument. + + Example usage:: + + local args = {...} + local open_readonly, filename = false, nil -- set defaults + + local positionals = argparse.processArgsGetopt(args, { + {'r', handler=function() open_readonly = true end}, + {'f', 'filename', hasArg=true, + handler=function(optarg) filename = optarg end} + }) + + In this example, if ``args`` is ``{'first', '-rf', 'fname', 'second'}`` or, + equivalently, ``{'first', '-r', '--filename', 'myfile.txt', 'second'}`` (note + the double dash in front of the long option alias), then ``open_readonly`` + will be ``true``, ``filename`` will be ``'myfile.txt'`` and ``positionals`` + will be ``{'first', 'second'}``. + +* ``argparse.stringList(arg, arg_name, list_length)`` + + Parses a comma-separated sequence of strings and returns a lua list. Leading + and trailing spaces are trimmed from the strings. If ``arg_name`` is + specified, it is used to make error messages more useful. If ``list_length`` + is specified and greater than ``0``, then exactly that number of elements must + be found or the function will error. Example:: + + stringList('hello , world,alist', 'words') => {'hello', 'world', 'alist'} + +* ``argparse.numberList(arg, arg_name, list_length)`` + + Parses a comma-separated sequence of numeric strings and returns a list of + the discovered numbers (as numbers, not strings). If ``arg_name`` is + specified, it is used to make error messages more useful. If ``list_length`` + is specified and greater than ``0``, exactly that number of elements must be + found or the function will error. Example:: + + numberList('10, -20 , 30.5') => {10, -20, 30.5} + +* ``argparse.coords(arg, arg_name, skip_validation)`` + + Parses a comma-separated coordinate string and returns a coordinate table of + ``{x, y, z}``. If the string ``'here'`` is passed, returns the coordinates of + the active game cursor, or throws an error if the cursor is not active. This + function also verifies that the coordinates are valid for the current map and + throws if they are not (unless ``skip_validation`` is set to true). + +* ``argparse.positiveInt(arg, arg_name)`` + + Throws if ``tonumber(arg)`` is not a positive integer; otherwise returns + ``tonumber(arg)``. If ``arg_name`` is specified, it is used to make error + messages more useful. + +* ``argparse.nonnegativeInt(arg, arg_name)`` + + Throws if ``tonumber(arg)`` is not a non-negative integer; otherwise returns + ``tonumber(arg)``. If ``arg_name`` is specified, it is used to make error + messages more useful. + +* ``argparse.boolean(arg, arg_name)`` + + Converts ``string.lower(arg)`` from "yes/no/on/off/true/false/etc..." to a lua + boolean. Throws if the value can't be converted, otherwise returns + ``true``/``false``. If ``arg_name`` is specified, it is used to make error + messages more useful. + +dumper +====== + +A third-party lua table dumper module from +http://lua-users.org/wiki/DataDumper. Defines one +function: + +* ``dumper.DataDumper(value, varname, fastmode, ident, indent_step)`` + + Returns ``value`` converted to a string. The ``indent_step`` + argument specifies the indentation step size in spaces. For + the other arguments see the original documentation link above. + +.. _helpdb: + +helpdb +====== + +Unified interface for DFHack tool help text. Help text is read from the rendered +text in ``hack/docs/docs/tools``. If no rendered text exists, help is read from +the script sources (for scripts) or the string passed to the ``PluginCommand`` +initializer (for plugins). See `documentation` for details on how DFHack's help +system works. + +The database is loaded when DFHack initializes, but can be explicitly refreshed +with a call to ``helpdb.refresh()`` if docs are added/changed during a play +session. + +Each entry has several properties associated with it: + +- The entry name, which is the name of a plugin, script, or command provided by + a plugin. +- The entry types, which can be ``builtin``, ``plugin``, and/or ``command``. + Entries for built-in commands (like ``ls`` or ``quicksave``) are both type + ``builtin`` and ``command``. Entries named after plugins are type ``plugin``, + and if that plugin also provides a command with the same name as the plugin, + then the entry is also type ``command``. Entry types are returned as a map + of one or more of the type strings to ``true``. +- Short help, a the ~54 character description string. +- Long help, the entire contents of the associated help file. +- A list of tags that define the groups that the entry belongs to. + +* ``helpdb.refresh()`` + + Scan for changes in available commands and their documentation. + +* ``helpdb.is_entry(str)``, ``helpdb.is_entry(list)`` + + Returns whether the given string (or list of strings) is an entry (are all + entries) in the db. + +* ``helpdb.get_entry_types(entry)`` + + Returns the set (that is, a map of string to ``true``) of entry types for the + given entry. + +* ``helpdb.get_entry_short_help(entry)`` + + Returns the short (~54 character) description for the given entry. + +* ``helpdb.get_entry_long_help(entry[, width])`` + + Returns the full help text for the given entry. If ``width`` is specified, the + text will be wrapped at that width, preserving block indents. The wrap width + defaults to 80. + +* ``helpdb.get_entry_tags(entry)`` + + Returns the set of tag names for the given entry. + +* ``helpdb.has_tag(entry, tag)`` + + Returns whether the given entry exists and has the specified tag. + +* ``helpdb.is_tag(str)``, ``helpdb.is_tag(list)`` + + Returns whether the given string (or list of strings) is a (are all) valid tag + name(s). + +* ``helpdb.get_tags()`` + + Returns the full alphabetized list of valid tag names. + +* ``helpdb.get_tag_data(tag)`` + + Returns a list of entries that have the given tag. The returned table also + has a ``description`` key that contains the string description of the tag. + +* ``helpdb.search_entries([include[, exclude]])`` + + Returns a list of names for entries that match the given filters. The list is + alphabetized by their last path component, with populated path components + coming before null path components (e.g., ``autobutcher`` will immediately + follow ``gui/autobutcher``). + The optional ``include`` and ``exclude`` filter params are maps (or lists of + maps) with the following elements: + + :str: if a string, filters by the given substring. if a table of strings, + includes entry names that match any of the given substrings. + :tag: if a string, filters by the given tag name. if a table of strings, + includes entries that match any of the given tags. + :entry_type: if a string, matches entries of the given type. if a table of + strings, includes entries that match any of the given types. + + Elements in a map are ANDed together (e.g., if both ``str`` and ``tag`` are + specified, the match is on any of the ``str`` elements AND any of the ``tag`` + elements). + + If lists of filters are passed instead of a single map, the match succeeds if + all of the filters match. + + If ``include`` is ``nil`` or empty, then all entries are included. If + ``exclude`` is ``nil`` or empty, then no entries are filtered out. + +profiler +======== + +A third-party lua profiler module from +http://lua-users.org/wiki/PepperfishProfiler. Module defines one function to +create profiler objects which can be used to profile and generate report. + +* ``profiler.newProfiler([variant[, sampling_frequency]])`` + + Returns a profile object with ``variant`` either ``'time'`` or ``'call'``. + ``'time'`` variant takes optional ``sampling_frequency`` parameter to select + lua instruction counts between samples. Default is ``'time'`` variant with + ``10*1000`` frequency. + + ``'call'`` variant has much higher runtime cost which will increase the + runtime of profiled code by factor of ten. For the extreme costs it provides + accurate function call counts that can help locate code which takes much time + in native calls. + +* ``obj:start()`` + + Resets collected statistics. Then it starts collecting new statistics. + +* ``obj:stop()`` + + Stops profile collection. + +* ``obj:report(outfile[, sort_by_total_time])`` + + Write a report from previous statistics collection to ``outfile``. + ``outfile`` should be writeable io file object (``io.open`` or + ``io.stdout``). Passing ``true`` as second parameter ``sort_by_total_time`` + switches sorting order to use total time instead of default self time order. + +* ``obj:prevent(function)`` + + Adds an ignore filter for a ``function``. It will ignore the pointed function + and all of it children. + +Examples +-------- + +:: + + local prof = profiler.newProfiler() + prof:start() + + profiledCode() + + prof:stop() + + local out = io.open( "lua-profile.txt", "w+") + prof:report(out) + out:close() + +class +===== + +Implements a trivial single-inheritance class system. + +* ``Foo = defclass(Foo[, ParentClass])`` + + Defines or updates class Foo. The ``Foo = defclass(Foo)`` syntax + is needed so that when the module or script is reloaded, the + class identity will be preserved through the preservation of + global variable values. + + The ``defclass`` function is defined as a stub in the global + namespace, and using it will auto-load the class module. + +* ``Class.super`` + + This class field is set by defclass to the parent class, and + allows a readable ``Class.super.method(self, ...)`` syntax for + calling superclass methods. + +* ``Class.ATTRS { foo = xxx, bar = yyy }`` + + Declares certain instance fields to be attributes, i.e., auto-initialized + from fields in the table used as the constructor argument. If omitted, + they are initialized with the default values specified in this declaration. + + If the default value should be *nil*, use ``ATTRS { foo = DEFAULT_NIL }``. + + Declaring an attribute is mostly the same as defining your ``init`` method + like this:: + + function Class.init(args) + self.attr1 = args.attr1 or default1 + self.attr2 = args.attr2 or default2 + ... + end + + The main difference is that attributes are processed as a separate + initialization step, before any ``init`` methods are called. They + also make the direct relation between instance fields and constructor + arguments more explicit. + +* ``new_obj = Class{ foo = arg, bar = arg, ... }`` + + Calling the class as a function creates and initializes a new instance. + Initialization happens in this order: + + 1. An empty instance table is created, and its metatable set. + 2. The ``preinit`` methods are called via ``invoke_before`` (see below) + with the table used as the argument to the class. These methods are + intended for validating and tweaking that argument table. + 3. Declared ATTRS are initialized from the argument table or their default values. + 4. The ``init`` methods are called via ``invoke_after`` with the argument table. + This is the main constructor method. + 5. The ``postinit`` methods are called via ``invoke_after`` with the argument table. + Place code that should be called after the object is fully constructed here. + +Predefined instance methods: + +* ``instance:assign{ foo = xxx }`` + + Assigns all values in the input table to the matching instance fields. + +* ``instance:callback(method_name, [args...])`` + + Returns a closure that invokes the specified method of the class, + properly passing in self, and optionally a number of initial arguments too. + The arguments given to the closure are appended to these. + +* ``instance:cb_getfield(field_name)`` + + Returns a closure that returns the specified field of the object when called. + +* ``instance:cb_setfield(field_name)`` + + Returns a closure that sets the specified field to its argument when called. + +* ``instance:invoke_before(method_name, args...)`` + + Navigates the inheritance chain of the instance starting from the most specific + class, and invokes the specified method with the arguments if it is defined in + that specific class. Equivalent to the following definition in every class:: + + function Class:invoke_before(method, ...) + if rawget(Class, method) then + rawget(Class, method)(self, ...) + end + Class.super.invoke_before(method, ...) + end + +* ``instance:invoke_after(method_name, args...)`` + + Like invoke_before, only the method is called after the recursive call to super, + i.e., invocations happen in the parent to child order. + + These two methods are inspired by the Common Lisp before and after methods, and + are intended for implementing similar protocols for certain things. The class + library itself uses them for constructors. + +To avoid confusion, these methods cannot be redefined. + +.. _custom-raw-tokens: + +custom-raw-tokens +================= + +A module for reading custom tokens added to the raws by mods. + +* ``customRawTokens.getToken(typeDefinition, token)`` + + Where ``typeDefinition`` is a type definition struct as seen in + ``df.global.world.raws`` (e.g.: ``dfhack.gui.getSelectedItem().subtype``) + and ``token`` is the name of the custom token you want read. The arguments + from the token will then be returned as strings using single or multiple + return values. If the token is not present, the result is false; if it is present + but has no arguments, the result is true. For ``creature_raw``, it checks against + no caste. For ``plant_raw``, it checks against no growth. + +* ``customRawTokens.getToken(typeInstance, token)`` + + Where ``typeInstance`` is a unit, entity, item, job, projectile, building, + plant, or interaction instance. Gets ``typeDefinition`` and then returns the same + as ``getToken(typeDefinition, token)``. For units, it gets the token from the race + or caste instead if applicable. For plant growth items, it gets the token from the + plant or plant growth instead if applicable. For plants it does the same but with + growth number -1. + +* ``customRawTokens.getToken(raceDefinition, casteNumber, token)`` + + The same as ``getToken(unit, token)`` but with a specified race and caste. + Caste number -1 is no caste. + +* ``customRawTokens.getToken(raceDefinition, casteName, token)`` + + The same as ``getToken(unit, token)`` but with a specified race and caste, using + caste name (e.g., "FEMALE") instead of number. + +* ``customRawTokens.getToken(plantDefinition, growthNumber, token)`` + + The same as ``getToken(plantGrowthItem, token)`` but with a specified plant and + growth. Growth number -1 is no growth. + +* ``customRawTokens.getToken(plantDefinition, growthName, token)`` + + The same as ``getToken(plantGrowthItem, token)`` but with a specified plant and + growth, using growth name (e.g., "LEAVES") instead of number. + +It is recommended to prefix custom raw tokens with the name of your mod to avoid +duplicate behaviour where two mods make callbacks that work on the same tag. + +Examples: + +* Using an eventful onReactionComplete hook, something for disturbing dwarven science:: + + if customRawTokens.getToken(reaction, "EXAMPLE_MOD_CAUSES_INSANITY") then + -- make unit who performed reaction go insane + +* Using an eventful onProjItemCheckMovement hook, a fast or slow-firing crossbow:: + + -- check projectile distance flown is zero, get firer, etc... + local multiplier = tonumber(customRawTokens.getToken(bow, "EXAMPLE_MOD_FIRE_RATE_MULTIPLIER")) or 1 + if firer.counters.think_counter > 0 then + firer.counters.think_counter = math.max(math.floor(firer.counters.think_counter * multiplier), 1) + end + +* Something for a script that prints help text about different types of units:: + + local unit = dfhack.gui.getSelectedUnit() + if not unit then return end + local helpText = customRawTokens.getToken(unit, "EXAMPLE_MOD_HELP_TEXT") + if helpText then print(helpText) end + +* Healing armour:: + + -- (per unit every tick) + local healAmount = 0 + for _, entry in ipairs(unit.inventory) do + if entry.mode == 2 then -- Worn + healAmount = healAmount + tonumber((customRawTokens.getToken(entry.item, "EXAMPLE_MOD_HEAL_AMOUNT")) or 0) + end + end + unit.body.blood_count = math.min(unit.body.blood_max, unit.body.blood_count + healAmount) + +.. _lua-ui-library: + +================== +In-game UI Library +================== + +.. contents:: + :local: + +A number of lua modules with names starting with ``gui`` are dedicated +to wrapping the natives of the ``dfhack.screen`` module in a way that +is easy to use. This allows relatively easily and naturally creating +dialogs that integrate in the main game UI window. + +These modules make extensive use of the ``class`` module, and define +things ranging from the basic ``Painter``, ``View`` and ``Screen`` +classes, to fully functional predefined dialogs. + +gui +=== + +This module defines the most important classes and functions for +implementing interfaces. This documents those of them that are +considered stable. + + +Misc +---- + +* ``CLEAR_PEN`` + + The black pen used to clear the screen. In graphics mode, it will clear the + foreground and set the background to the standard black tile. + +* ``TRANSPARENT_PEN`` + + A pen that will clear all textures from the UI layer, making the tile transparent. + +* ``KEEP_LOWER_PEN`` + + A pen that will write tiles over existing background tiles instead of clearing + them. + +* ``simulateInput(screen, keys...)`` + + This function wraps an undocumented native function that passes a set of + keycodes to a screen, and is the official way to do that. + + Every argument after the initial screen may be *nil*, a numeric keycode, + a string keycode, a sequence of numeric or string keycodes, or a mapping + of keycodes to *true* or *false*. For instance, it is possible to use the + table passed as argument to ``onInput``. The ``_STRING`` convenience field of + an ``onInput`` keys table will be ignored; the presence (or absence) of a + ``STRING_A???`` keycode will determine the text content of the simulated + input. + + You can send mouse clicks as well by setting the ``_MOUSE_L`` key or other + mouse-related pseudo-keys documented with the ``screen:onInput(keys)`` + function above. Note that if you are simulating a click at a specific spot on + the screen, you must set ``df.global.gps.mouse_x`` and + ``df.global.gps.mouse_y`` if you are clicking on the interface layer or + ``df.global.gps.precise_mouse_x`` and ``df.global.gps.precise_mouse_y`` if + you are clicking on the map. + +* ``mkdims_xy(x1,y1,x2,y2)`` + + Returns a table containing the arguments as fields, and also ``width`` and + ``height`` that contains the rectangle dimensions. + +* ``mkdims_wh(x1,y1,width,height)`` + + Returns the same kind of table as ``mkdims_xy``, only this time it computes + ``x2`` and ``y2``. + +* ``get_interface_rect()`` + + Returns the table rect (as per ``mkdims_xy``) for the interface area of the + screen, respecting the player's setting for ``max_interface_percentage``. + +* ``get_interface_frame()`` + + Returns the frame (as per `Widget class`_) for configuring a ``Widget`` with + a body that represents the interface area. + +* ``is_in_rect(rect,x,y)`` + + Checks if the given point is within a rectangle, represented by a table produced + by one of the ``mkdims`` functions. + +* ``blink_visible(delay)`` + + Returns *true* or *false*, with the value switching to the opposite every ``delay`` + msec. This is intended for rendering blinking interface objects. + +* ``getKeyDisplay(keycode)`` + + Wraps ``dfhack.screen.getKeyDisplay`` in order to allow using strings for + the keycode argument. + + +* ``invert_color(color, bold)`` + + This inverts the brightness of ``color``. If this color is coming from a pen's + foreground color, include ``pen.bold`` in ``bold`` for this to work properly. + + +ViewRect class +-------------- + +This class represents an on-screen rectangle with an associated independent +clip area rectangle. It is the base of the ``Painter`` class, and is used by +``Views`` to track their client area. + +* ``ViewRect{ rect = ..., clip_rect = ..., view_rect = ..., clip_view = ... }`` + + The constructor has the following arguments: + + :rect: The ``mkdims`` rectangle in screen coordinates of the logical viewport. + Defaults to the whole screen. + :clip_rect: The clip rectangle in screen coordinates. Defaults to ``rect``. + :view_rect: A ViewRect object to copy from; overrides both ``rect`` and ``clip_rect``. + :clip_view: A ViewRect object to intersect the specified clip area with. + +* ``rect:isDefunct()`` + + Returns *true* if the clip area is empty, i.e., no painting is possible. + +* ``rect:inClipGlobalXY(x,y)`` + + Checks if these global coordinates are within the clip rectangle. + +* ``rect:inClipLocalXY(x,y)`` + + Checks if these coordinates (specified relative to ``x1,y1``) are within the + clip rectangle. + +* ``rect:localXY(x,y)`` + + Converts a pair of global coordinates to local; returns *x_local,y_local*. + +* ``rect:globalXY(x,y)`` + + Converts a pair of local coordinates to global; returns *x_global,y_global*. + +* ``rect:viewport(x,y,w,h)`` or ``rect:viewport(subrect)`` + + Returns a ViewRect representing a sub-rectangle of the current one. + The arguments are specified in local coordinates; the ``subrect`` + argument must be a ``mkdims`` table. The returned object consists of + the exact specified rectangle, and a clip area produced by intersecting + it with the clip area of the original object. + + +Painter class +------------- + +The painting natives in ``dfhack.screen`` apply to the whole screen, are +completely stateless and don't implement clipping. + +The Painter class inherits from ViewRect to provide clipping and local +coordinates, and tracks current cursor position and current pen. It also +supports drawing to a separate map buffer if applicable (see ``map()`` below +for details). + +* ``Painter{ ..., pen = ..., key_pen = ... }`` + + In addition to ViewRect arguments, Painter accepts a suggestion of + the initial value for the main pen, and the keybinding pen. They + default to COLOR_GREY and COLOR_LIGHTGREEN otherwise. + + There are also some convenience functions that wrap this constructor: + + - ``Painter.new(rect,pen)`` + - ``Painter.new_view(view_rect,pen)`` + - ``Painter.new_xy(x1,y1,x2,y2,pen)`` + - ``Painter.new_wh(x1,y1,width,height,pen)`` + +* ``painter:isValidPos()`` + + Checks if the current cursor position is within the clip area. + +* ``painter:viewport(x,y,w,h)`` + + Like the superclass method, but returns a Painter object. + +* ``painter:cursor()`` + + Returns the current cursor *x,y* in screen coordinates. + +* ``painter:cursorX()`` + + Returns just the current *x* cursor coordinate + +* ``painter:cursorY()`` + + Returns just the current *y* cursor coordinate + +* ``painter:seek(x,y)`` + + Sets the current cursor position, and returns *self*. + Either of the arguments may be *nil* to keep the current value. + +* ``painter:advance(dx,dy)`` + + Adds the given offsets to the cursor position, and returns *self*. + Either of the arguments may be *nil* to keep the current value. + +* ``painter:newline([dx])`` + + Advances the cursor to the start of the next line plus the given x offset, + and returns *self*. + +* ``painter:pen(...)`` + + Sets the current pen to ``dfhack.pen.parse(old_pen,...)``, and returns *self*. + +* ``painter:color(fg[,bold[,bg]])`` + + Sets the specified colors of the current pen and returns *self*. + +* ``painter:key_pen(...)`` + + Sets the current keybinding pen to ``dfhack.pen.parse(old_pen,...)``, + and returns *self*. + +* ``painter:map(to_map)`` + + Enables or disables drawing to a separate map buffer. ``to_map`` is a boolean + that will be passed as the ``map`` parameter to any ``dfhack.screen`` functions + that accept it. Note that only third-party plugins like TWBT currently implement + a separate map buffer; if none are enabled, this function has no effect (but + should still be used to ensure proper support for such plugins). Returns *self*. + +* ``painter:clear()`` + + Fills the whole clip rectangle with ``CLEAR_PEN``, and returns *self*. + +* ``painter:fill(x1,y1,x2,y2[,...])`` or ``painter:fill(rect[,...])`` + + Fills the specified local coordinate rectangle with + ``dfhack.pen.parse(cur_pen,...)``, and returns *self*. + +* ``painter:char([char[, ...]])`` + + Paints one character using ``char`` and ``dfhack.pen.parse(cur_pen,...)``. + Returns *self*. The ``char`` argument, if not nil, is used to override the + ``ch`` property of the pen. + +* ``painter:tile([char, tile[, ...]])`` + + Like ``char()`` above, but also allows overriding the ``tile`` property on + ad-hoc basis. + +* ``painter:string(text[, ...])`` + + Paints the string with ``dfhack.pen.parse(cur_pen,...)``; returns *self*. + +* ``painter:key(keycode[, ...])`` + + Paints the description of the keycode using ``dfhack.pen.parse(cur_key_pen,...)``. + Returns *self*. + +* ``painter:key_string(keycode, text, ...)`` + + A convenience wrapper around both ``key()`` and ``string()`` that prints both + the specified keycode description and text, separated by ``:``. Any extra + arguments are passed directly to ``string()``. Returns *self*. + +Unless specified otherwise above, all Painter methods return *self*, in order to +allow chaining them like this:: + + painter:pen(foo):seek(x,y):char(1):advance(1):string('bar')... + + +View class +---------- + +This class is the common abstract base of both the stand-alone screens +and common widgets to be used inside them. It defines the basic layout, +rendering and event handling framework. + +The class defines the following attributes: + +:visible: Specifies that the view should be painted. This can be a boolean or + a function that returns a boolean. +:active: Specifies that the view should receive events, if also visible. This + can be a boolean or a function that returns a boolean. +:view_id: Specifies an identifier to easily identify the view among subviews. + This is reserved for use by script writers and should not be set by + library widgets for their internal subviews. +:on_focus: Called when the view gains keyboard focus; see ``setFocus()`` below. +:on_unfocus: Called when the view loses keyboard focus. + +It also always has the following fields: + +:subviews: Contains a table of all subviews. The sequence part of the + table is used for iteration. In addition, subviews are also + indexed under their ``view_id``, if any; see ``addviews()`` below. +:parent_view: A reference to the parent view. This field is ``nil`` until the + view is added as a subview to another view with ``addviews()``. +:focus_group: The list of widgets in a hierarchy. This table is unique and empty + when a view is initialized, but is replaced by a shared table when + the view is added to a parent via ``addviews()``. If a view in the + focus group has keyboard focus, that widget can be accessed via + ``focus_group.cur``. +:focus: A boolean indicating whether the view currently has keyboard focus. + +These fields are computed by the layout process: + +:frame_parent_rect: The ViewRect representing the client area of the parent view. +:frame_rect: The ``mkdims`` rect of the outer frame in parent-local coordinates. +:frame_body: The ViewRect representing the body part of the View's own frame. + +The class has the following methods: + +* ``view:addviews(list)`` + + Adds the views in the list to the ``subviews`` sequence. If any of the views + in the list have ``view_id`` attributes that don't conflict with existing keys + in ``subviews``, also stores them under the string keys. Finally, copies any + non-conflicting string keys from the ``subviews`` tables of the listed views. + + Thus, doing something like this:: + + self:addviews{ + Panel{ + view_id = 'panel', + subviews = { + Label{ view_id = 'label' } + } + } + } + + Would make the label accessible as both ``self.subviews.label`` and + ``self.subviews.panel.subviews.label``. + +* ``view:getWindowSize()`` + + Returns the dimensions of the ``frame_body`` rectangle. + +* ``view:getMousePos([view_rect])`` + + Returns the mouse *x,y* in coordinates local to the given ViewRect (or + ``frame_body`` if no ViewRect is passed) if it is within its clip area, or + nothing otherwise. + +* ``view:getMouseFramePos()`` + + Returns the mouse *x,y* in coordinates local to ``frame_rect`` if it is + within its clip area, or nothing otherwise. + +* ``view:updateLayout([parent_rect])`` + + Recomputes layout of the view and its subviews. If no argument is + given, re-uses the previous parent rect. The process goes as follows: + + 1. Calls ``preUpdateLayout(parent_rect)`` via ``invoke_before``. + 2. Uses ``computeFrame(parent_rect)`` to compute the desired frame. + 3. Calls ``postComputeFrame(frame_body)`` via ``invoke_after``. + 4. Calls ``updateSubviewLayout(frame_body)`` to update children. + 5. Calls ``postUpdateLayout(frame_body)`` via ``invoke_after``. + +* ``view:computeFrame(parent_rect)`` *(for overriding)* + + Called by ``updateLayout`` in order to compute the frame rectangle(s). + Should return the ``mkdims`` rectangle for the outer frame, and optionally + also for the body frame. If only one rectangle is returned, it is used + for both frames, and the margin becomes zero. + +* ``view:updateSubviewLayout(frame_body)`` + + Calls ``updateLayout`` on all children. + +* ``view:render(painter)`` + + Given the parent's painter, renders the view via the following process: + + 1. Calls ``onRenderFrame(painter, frame_rect)`` to paint the outer frame. + 2. Creates a new painter using the ``frame_body`` rect. + 3. Calls ``onRenderBody(new_painter)`` to paint the client area. + 4. Calls ``renderSubviews(new_painter)`` to paint visible children. + +* ``view:renderSubviews(painter)`` + + Calls ``render`` on all ``visible`` subviews in the order they + appear in the ``subviews`` sequence. + +* ``view:onRenderFrame(painter, rect)`` *(for overriding)* + + Called by ``render`` to paint the outer frame; by default does nothing. + +* ``view:onRenderBody(painter)`` *(for overriding)* + + Called by ``render`` to paint the client area; by default does nothing. + +* ``view:onInput(keys)`` *(for overriding)* + + Override this to handle events. By default directly calls ``inputToSubviews``. + Return a true value from this method to signal that the event has been handled + and should not be passed on to more views. + +* ``view:inputToSubviews(keys)`` + + Calls ``onInput`` on all visible active subviews, iterating the ``subviews`` + sequence in *reverse order*, so that topmost subviews get events first. + Returns ``true`` if any of the subviews handled the event. If a subview within + the view's ``focus_group`` has focus and it and all of its ancestors are + active and visible, that subview is offered the chance to handle the input + before any other subviews. + +* ``view:getPreferredFocusState()`` + + Returns ``false`` by default, but should be overridden by subclasses that may + want to take keyboard focus (if it is unclaimed) when they are added to a + parent view with ``addviews()``. + +* ``view:setFocus(focus)`` + + Sets the keyboard focus to the view if ``focus`` is ``true``, or relinquishes + keyboard focus if ``focus`` is ``false``. Views that newly acquire keyboard + focus will trigger the ``on_focus`` callback, and views that lose keyboard + focus will trigger the ``on_unfocus`` callback. While a view has focus, all + keyboard input is sent to that view before any of its siblings or parents. + Keyboard input is propagated as normal (see ``inputToSubviews()`` above) if + there is no view with focus or if the view with focus returns ``false`` from + its ``onInput()`` function. + +.. _lua-gui-screen: + +Screen class +------------ + +This is a View subclass intended for use as a stand-alone modal dialog or screen. +It adds the following methods: + +* ``screen:isShown()`` + + Returns *true* if the screen is currently in the game engine's display stack. + +* ``screen:isDismissed()`` + + Returns *true* if the screen is dismissed. + +* ``screen:isActive()`` + + Returns *true* if the screen is shown and not dismissed. + +* ``screen:invalidate()`` + + Requests a repaint. Note that currently using it is not necessary, because + repaints are constantly requested automatically, due to issues with native + screens happening otherwise. + +* ``screen:renderParent()`` + + Asks the parent native screen to render itself, or clears the screen + if impossible. + +* ``screen:sendInputToParent(...)`` + + Uses ``simulateInput`` to send keypresses to the native parent screen. + +* ``screen:show([parent])`` + + Adds the screen to the display stack with the given screen as the parent; + if parent is not specified, places this one one topmost. Before calling + ``dfhack.screen.show``, calls ``self:onAboutToShow(parent)``. Note that + ``onAboutToShow()`` can dismiss active screens, and therefore change the + potential parent. If parent is not specified, this function will re-detect + the current topmost window after ``self:onAboutToShow(parent)`` returns. + This function returns ``self`` as a convenience so you can write such code + as ``local view = MyScreen{params=val}:show()``. + +* ``screen:onAboutToShow(parent)`` *(for overriding)* + + Called when ``dfhack.screen.show`` is about to be called. + +* ``screen:onShow()`` + + Called by ``dfhack.screen.show`` once the screen is successfully shown. + +* ``screen:dismiss()`` + + Dismisses the screen. A dismissed screen does not receive any more + events or paint requests, but may remain in the display stack for + a short time until the game removes it. + +* ``screen:onDismiss()`` *(for overriding)* + + Called by ``dfhack.screen.dismiss()``. + +* ``screen:onDestroy()`` *(for overriding)* + + Called by the native code when the screen is fully destroyed and removed + from the display stack. Place code that absolutely must be called whenever + the screen is removed by any means here. + +* ``screen:onResize``, ``screen:onRender`` + + Defined as callbacks for native code. + +ZScreen class +------------- + +A screen subclass that allows multi-layer interactivity. For example, a DFHack +GUI tool implemented as a ZScreen can allow the player to interact with the +underlying map, or even other DFHack ZScreen windows! That is, even when the +DFHack tool window is visible, players will be able to use vanilla designation +tools, select units, and scan/drag the map around. + +At most one ZScreen can have input focus at a time. That ZScreen's widgets +will have a chance to handle the input before anything else. If unhandled, the +input skips all unfocused ZScreens under that ZScreen and is passed directly to +the first non-ZScreen viewscreen. There are class attributes that can be set to +control what kind of unhandled input is passed to the lower layers. + +If multiple ZScreens are visible and the player scrolls or left/right clicks on +a visible element of a non-focused ZScreen, that ZScreen will be given focus. +This allows multiple DFHack GUI tools to be usable at the same time. If the +mouse is clicked away from the ZScreen widgets, that ZScreen loses focus. If no +ZScreen has focus, all input is passed directly through to the first underlying +non-ZScreen viewscreen. + +For a ZScreen with keyboard focus, if :kbd:`Esc` or the right mouse button is +pressed, and the ZScreen widgets don't otherwise handle them, then the ZScreen +is dismissed. + +All this behavior is implemented in ``ZScreen:onInput()``, which subclasses +**must not override**. Instead, ZScreen subclasses should delegate all input +processing to subviews. Consider using a `Window class`_ widget subview as your +top level input processor. + +When rendering, the parent viewscreen is automatically rendered first, so +subclasses do not have to call ``self:renderParent()``. Calls to ``logic()`` +(a world "tick" when playing the game) are also passed through, so the game +progresses normally and can be paused/unpaused as normal by the player. Note +that passing ``logic()`` calls through to the underlying map is required for +allowing the player to drag the map with the mouse. ZScreen subclasses can set +attributes that control whether the game is paused when the ZScreen is shown and +whether the game is forced to continue being paused while the ZScreen is shown. +If pausing is forced, child ``Window`` widgets will show a force-pause indicator +to show which tool is forcing the pausing. + +ZScreen provides the following functions: + +* ``zscreen:raise()`` + + Raises the ZScreen to the top of the viewscreen stack, gives it keyboard + focus, and returns a reference to ``self``. A common pattern is to check if + a tool dialog is already active when the tool command is run and raise the + existing dialog if it exists or show a new dialog if it doesn't. See the + sample code below for an example. + +* ``zscreen:isMouseOver()`` + + The default implementation iterates over the direct subviews of the ZScreen + subclass (which usually only includes a single Window subview) and sees if + ``getMouseFramePos()`` returns a position for any of them. Subclasses can + override this function if that logic is not appropriate. + +* ``zscreen:hasFocus()`` + + Whether the ZScreen has keyboard focus. Subclasses will generally not need to + check this because they can assume if they are getting input, then they have + focus. + +ZScreen subclasses can set the following attributes: + +* ``defocusable`` (default: ``true``) + + Whether the ZScreen loses keyboard focus when the player clicks on an area + of the screen other than the tool window. If the player clicks on a different + ZScreen window, focus still transfers to that other ZScreen. + +* ``defocused`` (default: ``false``) + + Whether the ZScreen starts in a defocused state. + +* ``initial_pause`` (default: ``DEFAULT_INITIAL_PAUSE or not pass_mouse_clicks``) + + Whether to pause the game when the ZScreen is shown. If not explicitly set, + this attribute will be true if the system-wide ``DEFAULT_INITIAL_PAUSE`` is + ``true`` (which is its default value) or if the ``pass_mouse_clicks`` attribute + is ``false`` (see below). It depends on ``pass_mouse_clicks`` because if the + player normally pauses/unpauses the game with the mouse, they will not be able + to pause the game like they usually do while the ZScreen has focus. + ``DEFAULT_INITIAL_PAUSE`` can be customized permanently via `gui/control-panel` + or set for the session by running a command like:: + + :lua require('gui.widgets').DEFAULT_INITIAL_PAUSE = false + +* ``force_pause`` (default: ``false``) + + Whether to ensure the game *stays* paused while the ZScreen is shown, + regardless of whether it has input focus. + +* ``pass_pause`` (default: ``true``) + + Whether to pass the pause key to the lower viewscreens if it is not handled + by this ZScreen. + +* ``pass_movement_keys`` (default: ``false``) + + Whether to pass the map movement keys to the lower viewscreens if they are not + handled by this ZScreen. + +* ``pass_mouse_clicks`` (default: ``true``) + + Whether to pass mouse clicks to the lower viewscreens if they are not handled + by this ZScreen. + +Here is an example skeleton for a ZScreen tool window:: + + local gui = require('gui') + local widgets = require('gui.widgets') + + MyWindow = defclass(MyWindow, widgets.Window) + MyWindow.ATTRS { + frame_title='My Window', + frame={w=50, h=45}, + resizable=true, -- if resizing makes sense for your dialog + resize_min={w=50, h=20}, -- try to allow users to shrink your windows + } + + function MyWindow:init() + self:addviews{ + -- add subview widgets here + } + end + + -- implement if you need to handle custom input + --function MyWindow:onInput(keys) + -- return MyWindow.super.onInput(self, keys) + --end + + MyScreen = defclass(MyScreen, gui.ZScreen) + MyScreen.ATTRS { + focus_path='myscreen', + -- set pause and passthrough attributes as appropriate + -- (but most tools can use the defaults) + } + + function MyScreen:init() + self:addviews{MyWindow{}} + end + + function MyScreen:onDismiss() + view = nil + end + + view = view and view:raise() or MyScreen{}:show() + +ZScreenModal class +------------------ + +A ZScreen convenience subclass that sets the attributes to something +appropriate for modal dialogs. The game is force paused, and no input is passed +through to the underlying viewscreens. + +gui.widgets +=========== + +This module implements some basic widgets based on the View infrastructure. + +.. _widget: + +Widget class +------------ + +Base of all the widgets. Inherits from View and has the following attributes: + +* ``frame = {...}`` + + Specifies the constraints on the outer frame of the widget. + If omitted, the widget will occupy the whole parent rectangle. + + The frame is specified as a table with the following possible fields: + + :l: gap between the left edges of the frame and the parent. + :t: gap between the top edges of the frame and the parent. + :r: gap between the right edges of the frame and the parent. + :b: gap between the bottom edges of the frame and the parent. + :w: maximum width of the frame. + :h: maximum height of the frame. + :xalign: X alignment of the frame. + :yalign: Y alignment of the frame. + + First the ``l,t,r,b`` fields restrict the available area for + placing the frame. If ``w`` and ``h`` are not specified or + larger than the computed area, it becomes the frame. Otherwise + the smaller frame is placed within the are based on the + ``xalign/yalign`` fields. If the align hints are omitted, they + are assumed to be 0, 1, or 0.5 based on which of the ``l/r/t/b`` + fields are set. + +* ``frame_inset = {...}`` + + Specifies the gap between the outer frame, and the client area. + The attribute may be a simple integer value to specify a uniform + inset, or a table with the following fields: + + :l: left margin. + :t: top margin. + :r: right margin. + :b: bottom margin. + :x: left/right margin, if ``l`` and/or ``r`` are omitted. + :y: top/bottom margin, if ``t`` and/or ``b`` are omitted. + + Omitted fields are interpreted as having the value of 0. + +* ``frame_background = pen`` + + The pen to fill the outer frame with. Defaults to no fill. + +.. _panel: + +Panel class +----------- + +Inherits from Widget, and intended for framing and/or grouping subviews. Though +this can be used for your "main window", see the `Window class`_ below for a +more conveniently configured ``Panel`` subclass. + +Has attributes: + +* ``subviews = {}`` + + Used to initialize the subview list in the constructor. + +* ``on_render = function(painter)`` + + Called from ``onRenderBody``. + +* ``on_layout = function(frame_body)`` + + Called from ``postComputeFrame``. + +* ``draggable = bool`` (default: ``false``) +* ``drag_anchors = {}`` (default: ``{title=true, frame=false/true, body=true}``) +* ``drag_bound = 'frame' or 'body'`` (default: ``'frame'``) +* ``on_drag_begin = function()`` (default: ``nil``) +* ``on_drag_end = function(success, new_frame)`` (default: ``nil``) + + If ``draggable`` is set to ``true``, then the above attributes come into play + when the panel is dragged around the screen, either with the mouse or the + keyboard. ``drag_anchors`` sets which parts of the panel can be clicked on + with the left mouse button to start dragging. The frame is a drag anchor by + default only if ``resizable`` (below) is ``false``. ``drag_bound`` configures + whether the frame of the panel (if any) can be dragged outside the containing + parent's boundary. The body will never be draggable outside of the parent, + but you can allow the frame to cross the boundary by setting ``drag_bound`` to + ``'body'``. The boolean passed to the ``on_drag_end`` callback will be + ``true`` if the drag was "successful" (i.e., not canceled) and ``false`` + otherwise. Dragging can be canceled by right clicking while dragging with the + mouse, hitting :kbd:`Esc` (while dragging with the mouse or keyboard), or by + calling ``Panel:setKeyboardDragEnabled(false)`` (while dragging with the + keyboard). If it is more convenient to do so, you can choose to override the + ``panel:onDragBegin`` and/or the ``panel:onDragEnd`` methods instead of + setting the ``on_drag_begin`` and/or ``on_drag_end`` attributes. + +* ``resizable = bool`` (default: ``false``) +* ``resize_anchors = {}`` (default: ``{t=false, l=true, r=true, b=true}`` +* ``resize_min = {}`` (default: w and h from the ``frame``, or ``{w=5, h=5}``) +* ``on_resize_begin = function()`` (default: ``nil``) +* ``on_resize_end = function(success, new_frame)`` (default: ``nil``) + + If ``resizable`` is set to ``true``, then the player can click the mouse on + any edge specified in ``resize_anchors`` and drag the border to resize the + window. If two adjacent edges are enabled as anchors, then the tile where they + meet can be used to resize both edges at the same time. The minimum dimensions + specified in ``resize_min`` (or inherited from ``frame`` are respected when + resizing. The panel is also prevented from resizing beyond the boundaries of + its parent. When the player clicks on a valid anchor, ``on_resize_begin()`` is + called. The boolean passed to the ``on_resize_end`` callback will be ``true`` + if the drag was "successful" (i.e., not canceled) and ``false`` otherwise. + Dragging can be canceled by right clicking while resizing with the mouse, + hitting :kbd:`Esc` (while resizing with the mouse or keyboard), or by calling + ``Panel:setKeyboardResizeEnabled(false)`` (while resizing with the keyboard). + If it is more convenient to do so, you can choose to override the + ``panel:onResizeBegin`` and/or the ``panel:onResizeEnd`` methods instead of + setting the ``on_resize_begin`` and/or ``on_resize_end`` attributes. + +* ``autoarrange_subviews = bool`` (default: ``false``) +* ``autoarrange_gap = int`` (default: ``0``) + + If ``autoarrange_subviews`` is set to ``true``, the Panel will + automatically handle subview layout. Subviews are laid out vertically + according to their current height, with ``autoarrange_gap`` empty lines + between subviews. This allows you to have widgets dynamically change + height or become visible/hidden and you don't have to worry about + recalculating subview positions. + +* ``frame_style``, ``frame_title`` (default: ``nil``) + + If defined, a frame will be drawn around the panel and subviews will be + inset by 1. The following predefined frame styles are defined: + + * ``FRAME_WINDOW`` + + A frame suitable for a draggable, optionally resizable window. + + * ``FRAME_PANEL`` + + A frame suitable for a static (non-resizable) panel. + + * ``FRAME_MEDIUM`` + + A frame suitable for overlay widget panels. + + * ``FRAME_THIN`` + + A frame suitable for floating tooltip panels that need the DFHack signature. + + * ``FRAME_BOLD`` + + A frame suitable for a non-draggable panel meant to capture the user's + focus, like an important notification, confirmation dialog or error message. + + * ``FRAME_INTERIOR`` + + A frame suitable for light interior accent elements. This frame does *not* + have a visible ``DFHack`` signature on it, so it must not be used as the + external frame for a DFHack-owned UI. + + * ``FRAME_INTERIOR_MEDIUM`` + + A copy of ``FRAME_MEDIUM`` that lacks the ``DFHack`` signature. Suitable for + panels that are part of a larger widget cluster. Must *not* be used as the + external frame for a DFHack-owned UI. + + When using the predefined frame styles in the ``gui`` module, remember to + ``require`` the gui module and prefix the identifier with ``gui.``, e.g., + ``gui.FRAME_THIN``. + +* ``no_force_pause_badge`` (default: ``false``) + + If true, then don't display the PAUSE FORCED badge on the frame even if the + game has been force paused. + +Has functions: + +* ``panel:setKeyboardDragEnabled(bool)`` + + If called with ``true`` and the panel is not already in keyboard drag mode, + then any current drag or resize operations are halted where they are (not + canceled), the panel seizes input focus (see `View class`_ above for + information on the DFHack focus subsystem), and further keyboard cursor keys + move the window as if it were being dragged. Shift-cursor keys move by larger + amounts. Hit :kbd:`Enter` to commit the new window position or :kbd:`Esc` to + cancel. If dragging is canceled, then the window is moved back to its original + position. + +* ``panel:setKeyboardResizeEnabled(bool)`` + + If called with ``true`` and the panel is not already in keyboard resize mode, + then any current drag or resize operations are halted where they are (not + canceled), the panel seizes input focus (see `View class`_ above for + information on the DFHack focus subsystem), and further keyboard cursor keys + resize the window as if it were being dragged from the lower right corner. If + neither the bottom or right edge is a valid anchor, an appropriate corner will + be chosen. Shift-cursor keys move by larger amounts. Hit :kbd:`Enter` to + commit the new window size or :kbd:`Esc` to cancel. If resizing is canceled, + then the window size from before the resize operation is restored. + +* ``panel:onDragBegin()`` +* ``panel:onDragEnd(success, new_frame)`` +* ``panel:onResizeBegin()`` +* ``panel:onResizeEnd(success, new_frame)`` + +The default implementations of these methods call the associated attribute (if +set). You can override them in a subclass if that is more convenient than +setting the attributes. + +Double clicking: + +If the panel is resizable and the user double-clicks on the top edge (the frame +title, if the panel has a frame), then the panel will jump to its maximum size. +If the panel has already been maximized in this fashion, then it will jump to +its minimum size. Both jumps respect the resizable edges defined by the +``resize_anchors`` attribute. + +The time duration that a double click can span can be controlled via the +`control-panel` or `gui/control-panel` interfaces (``Mouse double click speed`` +option). It defaults to 500 ms. + +Window class +------------ + +Subclass of Panel; sets Panel attributes to useful defaults for a top-level +framed, draggable window. + +ResizingPanel class +------------------- + +Subclass of Panel; automatically adjusts its own frame height and width to the +minimum required to show its subviews. Pairs nicely with a parent Panel that has +``autoarrange_subviews`` enabled. + +It has the following attributes: + +:auto_height: Sets self.frame.h from the positions and height of its subviews + (default is ``true``). +:auto_width: Sets self.frame.w from the positions and width of its subviews + (default is ``false``). + +Pages class +----------- + +Subclass of Panel; keeps exactly one child visible. + +* ``Pages{ ..., selected = ... }`` + + Specifies which child to select initially; defaults to the first one. + +* ``pages:getSelected()`` + + Returns the selected *index, child*. + +* ``pages:setSelected(index)`` + + Selects the specified child, hiding the previous selected one. + It is permitted to use the subview object, or its ``view_id`` as index. + +Divider class +------------- + +Subclass of Widget; implements a divider line that can optionally connect to +existing frames via T-junction edges. A ``Divider`` instance is required to +have a ``frame`` that is either 1 unit tall or 1 unit wide. + +``Divider`` widgets should be a sibling with the framed ``Panel`` that they +are dividing, and they should be added to the common parent widget **after** +the ``Panel`` so that the ``Divider`` can overwrite the ``Panel`` frame with +the appropriate T-junction graphic. If the ``Divider`` will not have +T-junction edges, then it could potentially be a child of the ``Panel`` since +the ``Divider`` won't need to overwrite the ``Panel``'s frame. + +If two ``Divider`` widgets are set to cross, then you must have a third 1x1 +``Divider`` widget for the crossing tile so the other two ``Divider``\s can +be seamlessly connected. + +Attributes: + +* ``frame_style`` + + The ``gui`` ``FRAME`` instance to use for the graphical tiles. Defaults to + ``gui.FRAME_THIN``. + +* ``interior`` + + Whether the edge T-junction tiles should connect to interior lines (e.g., the + vertical or horizontal segment of another ``Divider`` instance) or the + exterior border of a ``Panel`` frame. Defaults to ``false``, meaning + exterior T-junctions will be chosen. + +* ``frame_style_t`` +* ``frame_style_b`` +* ``frame_style_l`` +* ``frame_style_r`` + + Overrides for the frame style for specific T-junctions. Note that there are + not currently any frame styles that allow borders of different weights to be + seamlessly connected. If set to ``false``, then the indicated edge will end + in a straight segment instead of a T-junction. + +* ``interior_t`` +* ``interior_b`` +* ``interior_l`` +* ``interior_r`` + + Overrides for the interior/exterior specification for specific T-junctions. + +EditField class +--------------- + +Subclass of Widget; implements a simple edit field. + +Attributes: + +:label_text: The optional text label displayed before the editable text. +:text: The current contents of the field. +:text_pen: The pen to draw the text with. +:on_char: Input validation callback; used as ``on_char(new_char,text)``. + If it returns false, the character is ignored. +:on_change: Change notification callback; used as ``on_change(new_text,old_text)``. +:on_submit: Enter key callback; if set the field will handle the key and call ``on_submit(text)``. +:key: If specified, the field is disabled until this key is pressed. Must be given as a string. +:key_sep: If specified, will be used to customize how the activation key is + displayed. See ``token.key_sep`` in the ``Label`` documentation below. +:modal: Whether the ``EditField`` should prevent input from propagating to other + widgets while it has focus. You can set this to ``true``, for example, + if you don't want a ``List`` widget to react to arrow keys while the + user is editing. +:ignore_keys: If specified, must be a list of key names that the edit field + should ignore. This is useful if you have plain string characters + that you want to use as hotkeys (like ``+``). + +An ``EditField`` will only read and process text input if it has keyboard focus. +It will automatically acquire keyboard focus when it is added as a subview to +a parent that has not already granted keyboard focus to another widget. If you +have more than one ``EditField`` on a screen, you can select which has focus by +calling ``setFocus(true)`` on the field object. + +If an activation ``key`` is specified, the ``EditField`` will manage its own +focus. It will start in the unfocused state, and pressing the activation key +will acquire keyboard focus. Pressing the Enter key will release keyboard focus +and then call the ``on_submit`` callback. Pressing the Escape key (or r-clicking +with the mouse) will also release keyboard focus, but first it will restore the +text that was displayed before the ``EditField`` gained focus and then call the +``on_change`` callback. + +The ``EditField`` cursor can be moved to where you want to insert/remove text. +You can click where you want the cursor to move or you can use any of the +following keyboard hotkeys: + +- Left/Right arrow: move the cursor one character to the left or right +- Ctrl-Left/Ctrl-Right: move the cursor one word back or forward +- Home/End: move the cursor to the beginning/end of the text + +The widget also supports integration with the system clipboard: + +- Ctrl-C: copy current text to the system clipboard +- Ctrl-X: copy current text to the system clipboard and clear text in widget +- Ctrl-V: paste text from the system clipboard (text is converted to cp437) + +The ``EditField`` class also provides the following functions: + +* ``editfield:setCursor([cursor_pos])`` + + Sets the text insert cursor to the specified position. If ``cursor_pos`` is + not specified or is past the end of the current text string, the cursor will + be set to the end of the current input (that is, ``#editfield.text + 1``). + +* ``editfield:setText(text[, cursor_pos])`` + + Sets the input text string and, optionally, the cursor position. If the + cursor position is not specified, it sets it to the end of the string. + +* ``editfield:insert(text)`` + + Inserts the given text at the current cursor position. + +TextArea class +-------------- + +Subclass of Panel; implements a multi-line text field with features such as +text wrapping, mouse control, text selection, clipboard support, history, +and typical text editor shortcuts. + +Cursor Behavior +~~~~~~~~~~~~~~~ + +The cursor in the ``TextArea`` class is index-based, starting from 1, +consistent with Lua's text indexing conventions. + +Each character, including newlines (``string.char(10)``), +occupies a single index in the text content. + +Cursor movement and position are fully aware of line breaks, +meaning they count as one unit in the offset. + +The cursor always points to the position between characters, +with 1 being the position before the first character and +``#text + 1`` representing the position after the last character. + +Cursor positions are preserved during text operations like insertion, +deletion, or replacement. If changes affect the cursor's position, +it will be adjusted to the nearest valid index. + +TextArea Attributes: + +* ``init_text``: The initial text content for the text area. + +* ``init_cursor``: The initial cursor position within the text content. + If not specified, defaults to end of the text (length of ``init_text`` + 1). + +* ``text_pen``: Optional pen used to draw the text. Default is ``COLOR_LIGHTCYAN``. + +* ``select_pen``: Optional pen used for text selection. Default is ``COLOR_CYAN``. + +* ``ignore_keys``: List of input keys to ignore. + Functions similarly to the ``ignore_keys`` attribute in the ``EditField`` class. + +* ``on_text_change``: Callback function called whenever the text changes. + The function signature should be ``on_text_change(new_text, old_text)``. + +* ``on_cursor_change``: Callback function called whenever the cursor position changes. + Expected function signature is ``on_cursor_change(new_cursor, old_cursor)``. + +* ``one_line_mode``: If set to ``true``, disables multi-line text features. + In this mode the :kbd:`Enter` key is not handled by the widget + as if it were included in ``ignore_keys``. + If multiline text (including ``\n`` chars) is pasted into the widget, newlines are removed. + +TextArea Functions: + +* ``textarea:getText()`` + + Returns the current text content of the ``TextArea`` widget as a string. + ``\n`` characters (``string.char(10)``) should be interpreted as new lines + +* ``textarea:setText(text)`` + + Sets the content of the ``TextArea`` to the specified string ``text``. + The cursor position will not be adjusted, so should be set separately. + +* ``textarea:getCursor()`` + + Returns the current cursor position within the text content. + The position is represented as a single integer, starting from 1. + +* ``textarea:setCursor(cursor)`` + + Sets the cursor position within the text content. + +* ``textarea:scrollToCursor()`` + + Scrolls the text area view to ensure that the current cursor position is visible. + This happens automatically when the user interactively moves the cursor or + pastes text into the widget, but may need to be called when ``setCursor`` is + called programmatically. + +* ``textarea:clearHistory()`` + + Clears undo/redo history of the widget. + +Functionality +~~~~~~~~~~~~~ + +The TextArea widget provides a familiar and intuitive text editing experience with baseline features such as: + +- Text Wrapping: Automatically fits text within the display area. +- Mouse and Keyboard Support: Standard keys like :kbd:`Home`, :kbd:`End`, :kbd:`Backspace`, and :kbd:`Delete` are supported, + along with gestures like double-click to select a word or triple-click to select a line. +- Clipboard Operations: copy, cut, and paste, + with intuitive defaults when no text is selected. +- Undo/Redo: :kbd:`Ctrl` + :kbd:`Z` and :kbd:`Ctrl` + :kbd:`Y` for quick changes. +- Additional features include advanced navigation, line management, + and smooth scrolling for handling long text efficiently. + +Detailed list: + +- Cursor Control: Navigate through text using arrow keys (Left, Right, Up, + and Down) for precise cursor placement. +- Mouse Control: Use the mouse to position the cursor within the text, + providing an alternative to keyboard navigation. +- Text Selection: Select text with the mouse, with support for replacing or + removing selected text. +- Select Word/Line: Use double click to select current word, or triple click to + select current line. +- Move By Word: Use :kbd:`Ctrl` + :kbd:`Left` and :kbd:`Ctrl` + :kbd:`Right` to + move the cursor one word back or forward. +- Line Navigation: :kbd:`Home` moves the cursor to the beginning of the current + line, and :kbd:`End` moves it to the end. +- Jump to Beginning/End: Quickly move the cursor to the beginning or end of the + text using :kbd:`Ctrl` + :kbd:`Home` and :kbd:`Ctrl` + :kbd:`End`. +- Longest X Position Memory: The cursor remembers the longest x position when + moving up or down, making vertical navigation more intuitive. +- New Lines: Easily insert new lines using the :kbd:`Enter` key, supporting + multiline text input. +- Text Wrapping: Text automatically wraps within the editor, ensuring lines fit + within the display without manual adjustments. +- Scrolling for long text entries. +- Backspace Support: Use the backspace key to delete characters to the left of + the cursor. +- Delete Character: :kbd:`Delete` deletes the character under the cursor. +- Delete Current Line: :kbd:`Ctrl` + :kbd:`U` deletes the entire current line + where the cursor is located. +- Delete Rest of Line: :kbd:`Ctrl` + :kbd:`K` deletes text from the cursor to + the end of the line. +- Delete Last Word: :kbd:`Ctrl` + :kbd:`W` removes the word immediately before + the cursor. +- Select All: Select entire text by :kbd:`Ctrl` + :kbd:`A`. +- Undo/Redo: Undo/Redo changes by :kbd:`Ctrl` + :kbd:`Z` / :kbd:`Ctrl` + + :kbd:`Y`. +- Clipboard Operations: Perform OS clipboard cut, copy, and paste operations on + selected text, allowing you to paste the copied content into other + applications. +- Copy Text: Use :kbd:`Ctrl` + :kbd:`C` to copy selected text. + - copy selected text, if available + - if no text is selected it copy the entire current line, including the + terminating newline if present +- Cut Text: Use :kbd:`Ctrl` + :kbd:`X` to cut selected text. + - cut selected text, if available + - if no text is selected it will cut the entire current line, including the + terminating newline if present +- Paste Text: Use :kbd:`Ctrl` + :kbd:`V` to paste text from the clipboard into + the editor. + - replace selected text, if available + - If no text is selected, paste text in the cursor position + +Scrollbar class +--------------- + +This Widget subclass implements mouse-interactive scrollbars whose bar sizes +represent the amount of content currently visible in an associated display +widget (like a `Label class`_ or a `List class`_). They are styled like scrollbars +used in vanilla DF. + +Scrollbars have the following attributes: + +:on_scroll: A callback called when the scrollbar is scrolled. If the scrollbar + is clicked, the callback will be called with one of the following string parameters: + "up_large", "down_large", "up_small", or "down_small". If the scrollbar is dragged, + the callback will be called with the value that ``top_elem`` should be set to on + the next call to ``update()`` (see below). + +The Scrollbar widget implements the following methods: + +* ``scrollbar:update(top_elem, elems_per_page, num_elems)`` + + Updates the info about the widget that the scrollbar is paired with. + The ``top_elem`` param is the (one-based) index of the first visible element. + The ``elems_per_page`` param is the maximum number of elements that can be + shown at one time. The ``num_elems`` param is the total number of elements + that the paired widget can scroll through. If ``elems_per_page`` or + ``num_elems`` is not specified, the most recently specified value for these + parameters is used. The scrollbar will adjust its scrollbar size and position + according to the values passed to this function. + +Clicking on the arrows at the top or the bottom of a scrollbar will scroll an +associated widget by a small amount. Clicking on the unfilled portion of the +scrollbar above or below the filled area will scroll by a larger amount in that +direction. The amount of scrolling done in each case in determined by the +associated widget, and after scrolling is complete, the associated widget must +call ``scrollbar:update()`` with updated new display info. + +If the mouse wheel is scrolled while the mouse is over the Scrollbar widget's +parent view, then the parent is scrolled accordingly. Holding :kbd:`Shift` +while scrolling will result in faster movement. + +You can click and drag the scrollbar to scroll to a specific spot, or you can +click and hold on the end arrows or in the unfilled portion of the scrollbar to +scroll multiple times, just like in a normal browser scrollbar. The speed of +scroll events when the mouse button is held down can be controlled +via the `control-panel` or `gui/control-panel` interfaces: + +1. The delay before the second scroll event is the ``Mouse initial scroll repeat + delay`` setting (default is 300 ms) + +2. The delay between further scroll events is the ``Mouse scroll repeat delay`` option + (default is 20 ms) + +Label class +----------- + +This Widget subclass implements flowing semi-static text. + +It has the following attributes: + +:text_pen: Specifies the pen for active text. +:text_dpen: Specifies the pen for disabled text. +:text_hpen: Specifies the pen for text hovered over by the mouse, if a click + handler is registered. By default, this will invert the foreground and + background colors. +:disabled: Boolean or a callback; if true, the label is disabled. +:enabled: Boolean or a callback; if false, the label is disabled. +:auto_height: Sets self.frame.h from the text height. +:auto_width: Sets self.frame.w from the text width. +:on_click: A callback called when the label is clicked (optional) +:on_rclick: A callback called when the label is right-clicked (optional) +:scroll_keys: Specifies which keys the label should react to as a table. The + table should map keys to the number of lines to scroll as positive or + negative integers or one of the keywords supported by the ``scroll`` + method. The default is up/down arrows scrolling by one line and page + up/down scrolling by one page. + +``text_pen``, ``text_dpen``, and ``text_hpen`` can either be a pen or a +function that dynamically returns a pen. + +The text itself is represented as a complex structure, and passed +to the object via the ``text`` argument of the constructor, or via +the ``setText`` method, as one of: + +* A simple string, possibly containing newlines. +* A sequence of tokens. + +Every token in the sequence in turn may be either a string, possibly +containing newlines (or equal to ``NEWLINE``), or a table with the following +possible fields: + +* ``token.text = ...`` + + Specifies the main text content of a token, and may be a string, or + a callback returning a string. + +* ``token.gap = ...`` + + Specifies the number of character positions to advance on the line + before rendering the token. + +* ``token.tile``, ``token.htile`` + + Specifies a pen or texture index (or a function that returns a pen or texture + index) to paint as one tile before the main part of the token. If ``htile`` + is specified, that is used instead of ``tile`` when the Label is hovered over + with the mouse. + +* ``token.width = ...`` + + If specified either as a value or a callback, the text (or tile) field is + padded or truncated to the specified number. + +* ``token.pad_char = '?'`` + + If specified together with ``width``, the padding area is filled with + this character instead of just being skipped over. + +* ``token.key = '...'`` + + Specifies the keycode associated with the token. The string description + of the key binding is added to the text content of the token. + +* ``token.key_sep = '...'`` + + Specifies the separator to place between the keybinding label produced + by ``token.key``, and the main text of the token. If the separator starts with + '()', the token is formatted as ``text..' ('..binding..sep:sub(2)``. Otherwise + it is simply ``binding..sep..text``. + +* ``token.enabled``, ``token.disabled`` + + Same as the attributes of the label itself, but applies only to the token. + +* ``token.pen``, ``token.dpen``, ``token.hpen`` + + Specify the pen, disabled pen, and hover pen to be used for the token's text. + The fields may be either the pen itself, or a callback that returns it. + +* ``token.on_activate`` + + If this field is not nil, and ``token.key`` is set, the token will actually + respond to that key binding unless disabled, and call this callback. Eventually + this may be extended with mouse click support. + +* ``token.id`` + + Specifies a unique identifier for the token. + +* ``token.line``, ``token.x1``, ``token.x2`` + + Reserved for internal use. + +The Label widget implements the following methods: + +* ``label:setText(new_text)`` + + Replaces the text currently contained in the widget. + +* ``label:itemById(id)`` + + Finds a token by its ``id`` field. + +* ``label:getTextHeight()`` + + Computes the height of the text. + +* ``label:getTextWidth()`` + + Computes the width of the text. + +* ``label:scroll(nlines)`` + + This method takes the number of lines to scroll as positive or negative + integers or one of the following keywords: ``+page``, ``-page``, + ``+halfpage``, ``-halfpage``, ``home``, or ``end``. It returns the number of + lines that were actually scrolled (negative for scrolling up). + +* ``label:shouldHover()`` + + This method returns whether or not this widget should show a hover effect, + generally you want to return ``true`` if there is some type of mouse handler + present. For example, for a ``HotKeyLabel``:: + + function HotkeyLabel:shouldHover() + -- When on_activate is set, text should also hover on mouseover + return HotkeyLabel.super.shouldHover(self) or self.on_activate + end + +The widgets module also provides the following methods for help in constructing +common text token lists that you can then pass as ``text`` to a ``Label``: + +* ``makeButtonLabelText(spec)`` + + Returns a list of ``Label`` text tokens that represent a button according + to the given ``spec``, which is a table with the following fields. Fields + that contain ``_hover`` are optional and specify alternate values to be + used when the mouse cursor is hovering over the button. + + - ``chars``, ``chars_hover``: A list of strings or a list of lists of + characters. These strings (or lists of characters) make up the ASCII + representation of the button. If a list of strings is passed, each + string must be the same length. ``chars`` is the only required element + in the spec. If ``chars_hover`` is not specified, it defaults to the + value of ``chars``. + + - ``pens``, ``pens_hover``: A color or a pen or a list of lists of colors + or pens. This controls what color and other pen properties should be + applied to the corresponding button tile position. If a single color or + pen is passed, then that color or pen will apply to all tiles of the + button. If not specified, ``pens`` defaults to ``COLOR_GRAY`` and + ``pens_hover`` defaults to ``COLOR_WHITE`` + + - ``tileset``, ``tileset_hover``: If specified, must be a tileset that was + returned from ``dfhack.textures.loadTileset``. + + - ``tileset_offset``, ``tileset_hover_offset``: The 1-based offset within + the tileset to the tile that represents the upper left corner of the + button. If not specified, defaults to ``1``. + + - ``tileset_stride``, ``tileset_hover_stride``: The number of tiles in one + row of the tileset. This is used to find the start position of + subsequent rows of tiles for the button. If not specified, defaults to + the width of a button row specified in ``chars``, which is appropriate + for a tileset that has only a single button image per logical row. + + - ``asset``, ``asset_hover``: If specified, must be a table defining a + graphic asset loaded by DF from the vanilla sprite sheets or a mod. The + table must indicate which sprite page to read and the x and y offsets + of the upper left corner of the target asset in the following format: + ``{page=pagename, x=x_offset, y=y_offset}``. + + - ``tiles_override``, ``tiles_hover_override``: A list of lists of integers + representing raw tile texpos values to be displayed at the + corresponding button position. Tiles specified here will override + corresponding tiles from ``tileset`` and ``asset``. The lists can be + sparse, so any unspecified values in the override array will fall + through to other specifiers. + + If no tile is set for a particular button position, the corresponding + pen is used without setting a ``tile`` value. + + Example 1: The civ-alert button - a text-only (no graphic tiles) button + that highlights the text on hover:: + + widgets.Label{ + text=widgets.makeButtonLabelText{ + chars={ + ' Activate ', + ' civilian ', + ' alert ', + }, + pens={fg=COLOR_BLACK, bg=COLOR_LIGHTRED}, + pens_hover={fg=COLOR_WHITE, bg=COLOR_RED}, + }, + on_click=sound_alarm, + }, + + Example 2: The DFHack logo - a graphical button in graphics mode and a text + button in ASCII mode. The ASCII colors use the default for hovering:: + + local logo_textures=dfhack.textures.loadTileset( + 'hack/data/art/logo.png', 8, 12, true), + widgets.Label{ + text=widgets.makeButtonLabelText{ + chars={ + {179, 'D', 'F', 179}, + {179, 'H', 'a', 179}, + {179, 'c', 'k', 179}, + }, + tileset=logo_textures, + tileset_offset=1, + tileset_stride=8, + tileset_hover=logo_textures, + tileset_hover_offset=5, + tileset_hover_stride=8, + }, + on_click=function() + dfhack.run_command{'hotkeys', 'menu', self.name} + end, + }, + + Example 3: One of the warm/damp toolbar buttons - similar to example 2, but + with custom colors throughout the button when in ASCII mode:: + + widgets.Label{ + text=widgets.makeButtonLabelText{ + chars={ + {218, 196, 196, 191}, + {179, '~', '~', 179}, + {192, 196, 196, 217}, + }, + pens={ + {COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE}, + {COLOR_WHITE, COLOR_RED, COLOR_GRAY, COLOR_WHITE}, + {COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE}, + }, + tileset=toolbar_textures, + tileset_offset=25, + tileset_stride=8, + }, + on_click=launch_warm_damp_dig_config, + }, + + Example 4: A copy of the mining toolbar button (except that it has a + highlight on hover), loaded from the DF assets:: + + widgets.Label{ + text=widgets.makeButtonLabelText{ + chars={ + {218, 196, 196, 191}, + {179, '-', ')', 179}, + {192, 196, 196, 217}, + }, + pens={ + {COLOR_GRAY, COLOR_GRAY, COLOR_GRAY, COLOR_GRAY}, + {COLOR_GRAY, COLOR_BROWN, COLOR_GRAY, COLOR_GRAY}, + {COLOR_GRAY, COLOR_GRAY, COLOR_GRAY, COLOR_GRAY}, + }, + pens_hover={ + {COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE}, + {COLOR_WHITE, COLOR_BROWN, COLOR_GRAY, COLOR_WHITE}, + {COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE}, + }, + asset={page='INTERFACE_BITS', x=0, y=22}, + }, + on_click=self:callback('mining_menu'), + }, + + Example 5: A copy of the mining toolbar button (except that it has a + custom hotkey hint in the upper corner), loaded from the DF assets and with + one tile overridden:: + + widgets.Label{ + text=widgets.makeButtonLabelText{ + chars={ + {218, 196, 196, self.hint_char}, + {179, '-', ')', 179}, + {192, 196, 196, 217}, + }, + pens={ + {COLOR_GRAY, COLOR_GRAY, COLOR_GRAY, COLOR_RED}, + {COLOR_GRAY, COLOR_BROWN, COLOR_GRAY, COLOR_GRAY}, + {COLOR_GRAY, COLOR_GRAY, COLOR_GRAY, COLOR_GRAY}, + }, + asset={page='INTERFACE_BITS', x=0, y=22}, + tiles_override={{[4]=string.byte(self.hint_char)}}, + }, + on_click=self:callback('mining_menu'), + }, + +WrappedLabel class +------------------ + +This Label subclass represents text that you want to be able to dynamically +wrap. This frees you from having to pre-split long strings into multiple lines +in the Label ``text`` list. + +It has the following attributes: + +:text_to_wrap: The string (or a table of strings or a function that returns a + string or a table of strings) to display. The text will be autowrapped to + the width of the widget, though any existing newlines will be kept. +:indent: The number of spaces to indent the text from the left margin. The + default is ``0``. + +The displayed text is refreshed and rewrapped whenever the widget bounds change. +To force a refresh (to pick up changes in the string that ``text_to_wrap`` +returns, for example), all ``updateLayout()`` on this widget or on a widget that +contains this widget. + +TooltipLabel class +------------------ + +This WrappedLabel subclass represents text that you want to be able to +dynamically hide, like help text in a tooltip. + +It has the following attributes: + +:show_tooltip: Boolean or a callback; if true, the widget is visible. + +The ``text_pen`` attribute of the ``Label`` class is overridden with a default +of ``COLOR_GREY`` and the ``indent`` attribute of the ``WrappedLabel`` class is +overridden with a default of ``2``. + +The text of the tooltip can be passed in the inherited ``text_to_wrap`` +attribute so it can be autowrapped, or in the basic ``text`` attribute if no +wrapping is required. + +HotkeyLabel class +----------------- + +This Label subclass is a convenience class for formatting text that responds to +a hotkey or mouse click. + +It has the following attributes: + +:key: The hotkey keycode to display, e.g., ``'CUSTOM_A'``. +:key_sep: If specified, will be used to customize how the activation key is + displayed. See ``token.key_sep`` in the ``Label`` documentation. +:label: The string (or a function that returns a string) to display after the + hotkey. +:on_activate: If specified, it is the callback that will be called whenever + the hotkey is pressed or the label is clicked. + +The HotkeyLabel widget implements the following methods: + +* ``hotkeylabel:setLabel(label)`` + + Updates the label without altering the hotkey text. + +* ``hotkeylabel:setOnActivate(on_activate)`` + + Updates the on_activate callback. + +CycleHotkeyLabel class +---------------------- + +This Label subclass represents a group of related options that the user can +cycle through by pressing a specified hotkey or clicking on the text. + +It has the following attributes: + +:key: The hotkey keycode to display, e.g., ``'CUSTOM_A'``. +:key_back: Similar to ``key``, but will cycle backwards (optional) +:key_sep: If specified, will be used to customize how the activation key is + displayed. See ``token.key_sep`` in the ``Label`` documentation. +:label: The string (or a function that returns a string) to display after the + hotkey. +:label_width: The number of spaces to allocate to the ``label`` (for use in + aligning a column of ``CycleHotkeyLabel`` labels). +:label_below: If ``true``, then the option value will appear below the label + instead of to the right of it. Defaults to ``false``. +:option_gap: The size of the gap between the label text and the option value. + Default is ``1``. If set to ``0``, there'll be no gap between the strings. + If ``label_below`` == ``true``, negative values will shift the value leftwards. +:options: A list of strings or tables of + ``{label=string or fn, value=val[, pen=pen]}``. String options use the same + string for the label and value and use the default pen. The optional ``pen`` + element could be a color like ``COLOR_RED``. +:initial_option: The value or numeric index of the initial option. +:on_change: The callback to call when the selected option changes. It is called + as ``on_change(new_option_value, old_option_value)``. + +The index of the currently selected option in the ``options`` list is kept in +the ``option_idx`` instance variable. + +The CycleHotkeyLabel widget implements the following methods: + +* ``cyclehotkeylabel:cycle([backwards])`` + + Cycles the selected option and triggers the ``on_change`` callback. + If ``backwards`` is defined and is truthy, the cycle direction will be reversed + +* ``cyclehotkeylabel:setOption(value_or_index, call_on_change)`` + + Sets the current option to the option with the specified value or + index. If ``call_on_change`` is set to ``true``, then the ``on_change`` + callback is triggered. + +* ``cyclehotkeylabel:getOptionLabel([option_idx])`` + + Retrieves the option label at the given index, or the label of the + currently selected option if no index is given. + +* ``cyclehotkeylabel:getOptionValue([option_idx])`` + + Retrieves the option value at the given index, or the value of the + currently selected option if no index is given. + +* ``cyclehotkeylabel:getOptionPen([option_idx])`` + + Retrieves the option pen at the given index, or the pen of the currently + selected option if no index is given. If an option was defined as just a + string, then this function will return ``nil`` for that option. + +ButtonGroup class +----------------- + +This is a specialized subclass of CycleHotkeyLabel that, in addition to the +regular clickable widget, displays a corresponding row of clickable graphical +buttons and synchronizes their selection state with the currently selected +option. + +It takes two additional required parameters to define the buttons: + +:button_specs: A list of specs to pass to ``makeButtonLabelText`` (defined in + `Label class`_ above). +:button_specs_selected: A list of specs that represent the buttons in their + selected state. + +ToggleHotkeyLabel class +----------------------- + +This is a specialized subclass of CycleHotkeyLabel that has two options: +``On`` (with a value of ``true``) and ``Off`` (with a value of ``false``). The +``On`` option is rendered in green. + +ConfigureButton class +--------------------- + +A 3x1 tile button with a gear symbol on it, intended to represent a configure +icon. Clicking on the icon will run the given callback. The graphics can also +be overridden to create custom buttons. + +It has the following attributes: + +:on_click: The function to run when the icon is clicked. +:pen_left: Pen or function returning a pen to overwrite the left tile of the button. +:pen_center: As above, but for the center tile (gear symbol). +:pen_right: As above, but for the right tile. + +HelpButton class +---------------- + +Subclass of ConfigureButton; a 3x1 tile button with a question mark on it, +intended to represent a help icon. Clicking on the icon will launch +`gui/launcher` with a given command string, showing the help text for that +command. + +It has the following attributes: + +:command: The command to load in `gui/launcher`. + +It also sets the ``frame`` attribute so the button appears in the upper right +corner of the parent, but you can override this to your liking if you want a +different position. + +RadioButton class +----------------- + +Subclass of ConfigureButton; a 3x1 tile button that resembles a radio button +(or check box in ASCII mode), identical to the ones found in +`gui/control-panel`. Clicking on the button will toggle its enabled state. + +It has the following attributes: + +:initial_state: Whether to start in the ``true`` or ``false`` state. Defaults to ``true``. +:on_change: Callback to call when state changes, including initialization. Called as ``on_change(val)``. + +It implements the following method: + +* ``RadioButton:setState(val)`` + + Sets the state to boolean ``val`` and calls ``on_change`` (if defined). + +BannerPanel class +----------------- + +This is a Panel subclass that prints a distinctive banner along the far left +and right columns of the widget frame. Note that this is not a "proper" frame +since it doesn't have top or bottom borders. Subviews of this panel should +inset their frames one tile from the left and right edges. + +TextButton class +---------------- + +This is a BannerPanel subclass that wraps a HotkeyLabel with some decorators on +the sides to make it look more like a button, suitable for both graphics and +ASCII modes. All HotkeyLabel parameters passed to the constructor are passed +through to the wrapped HotkeyLabel. + +List class +---------- + +The List widget implements a simple list with paging. You can click on a list +item to call the ``on_submit`` callback for that item. + +It has the following attributes: + +:text_pen: Specifies the pen for deselected list entries. +:text_hpen: Specifies the pen for entries that the mouse is hovered over. + Defaults to swapping the background/foreground colors. +:cursor_pen: Specifies the pen for the selected entry. +:inactive_pen: If specified, used for the cursor when the widget is not active. +:icon_pen: Default pen for icons. +:on_select: Selection change callback; called as ``on_select(index,choice)``. + This is also called with *nil* arguments if ``setChoices`` is called + with an empty list. +:on_submit: Enter key or mouse click callback; if specified, the list reacts to the + key/click and calls the callback as ``on_submit(index,choice)``. +:on_submit2: Shift-click callback; if specified, the list reacts to the click and + calls the callback as ``on_submit2(index,choice)``. +:on_double_click: Mouse double click callback; if specified, the list reacts to the + click and calls the callback as ``on_double_click(index,choice)``. +:on_double_click2: Shift-double click callback; if specified, the list reacts to the + click and calls the callback as ``on_double_click2(index,choice)``. +:row_height: Height of every row in text lines. +:icon_width: If not *nil*, the specified number of character columns + are reserved to the left of the list item for the icons. +:scroll_keys: Specifies which keys the list should react to as a table. + +Every list item may be specified either as a string, or as a lua table +with the following fields: + +:text: Specifies the label text in the same format as the Label text. +:text_*: Reserved for internal use. +:key: Specifies a keybinding that acts as a shortcut for the specified item. +:icon: Specifies an icon string, or a pen to paint a single character. May be a callback. +:icon_pen: When the icon is a string, used to paint it. + +The list supports the following methods: + +* ``List{ ..., choices = ..., selected = ... }`` + + Same as calling ``setChoices`` after construction. + +* ``list:setChoices(choices[, selected])`` + + Replaces the list of choices, possibly also setting the currently selected index. + +* ``list:setSelected(selected)`` + + Sets the currently selected index. Returns the index after validation. + +* ``list:getChoices()`` + + Returns the list of choices. + +* ``list:getSelected()`` + + Returns the selected *index, choice*, or nothing if the list is empty. + +* ``list:getIdxUnderMouse()`` + + Returns the index of the list item under the mouse cursor, or nothing if the + list is empty or the mouse is not over a list item. + +* ``list:getContentWidth()`` + + Returns the minimal width to draw all choices without clipping. + +* ``list:getContentHeight()`` + + Returns the minimal width to draw all choices without scrolling. + +* ``list:submit()`` + + Call the ``on_submit`` callback, as if the Enter key was handled. + +* ``list:submit2()`` + + Call the ``on_submit2`` callback, as if the Shift-Enter key was handled. + +FilteredList class +------------------ + +This widget combines List, EditField and Label into a combo-box like +construction that allows filtering the list. + +In addition to passing through all attributes supported by List, it +supports: + +:edit_pen: If specified, used instead of ``cursor_pen`` for the edit field. +:edit_below: If true, the edit field is placed below the list instead of above. +:edit_key: If specified, the edit field is disabled until this key is pressed. +:edit_ignore_keys: If specified, will be passed to the filter edit field as its ``ignore_keys`` attribute. +:edit_on_change: If specified, will be passed to the filter edit field as its ``on_change`` attribute. +:edit_on_char: If specified, will be passed to the filter edit field as its ``on_char`` attribute. +:not_found_label: Specifies the text of the label shown when no items match the filter. + +The list choices may include the following attributes: + +:search_key: If specified, used instead of **text** to match against the filter. + Can be a string or a function that returns a string. + +The widget implements: + +* ``list:setChoices(choices[, selected])`` + + Resets the filter, and passes through to the inner list. + +* ``list:getChoices()`` + + Returns the list of *all* choices. + +* ``list:getVisibleChoices()`` + + Returns the *filtered* list of choices. + +* ``list:getFilter()`` + + Returns the current filter string, and the *filtered* list of choices. + +* ``list:setFilter(filter[,pos])`` + + Sets the new filter string, filters the list, and selects the item at + index ``pos`` in the *unfiltered* list if possible. + +* ``list:canSubmit()`` + + Checks if there are currently any choices in the filtered list. + +* ``list:getSelected()``, ``list:getContentWidth()``, ``list:getContentHeight()``, ``list:submit()`` + + Same as with an ordinary list. + +Filter behavior: + +By default, the filter matches substrings that start at the beginning of a word +(or after any punctuation). You can instead configure filters to match any +substring across the full text by setting ``FILTER_FULL_TEXT`` in `gui/control-panel` +or set it for the session by running a command like:: + + :lua require('utils').FILTER_FULL_TEXT=true + +TabBar class +------------ + +This widget implements a set of one or more tabs to allow navigation between groups +of content. + +:wrap: If true, tabs automatically wrap on the width of the window and will + continue rendering on the next line(s) if all tabs cannot fit on a single line. + If false, tabs will be truncated and can be scrolled using ``scroll_key`` + and ``scroll_key_back``, mouse wheel or by clicking on the scroll labels + that will automatically appear on the left and right sides of the tab bar + as needed. When clicking on a tab or using ``key`` or ``key_back`` to switch tabs, + the selected tab will be scrolled into view if it is not already visible. + Defaults to true. +:key: Specifies a keybinding that can be used to switch to the next tab. + Defaults to ``CUSTOM_CTRL_T``. +:key_back: Specifies a keybinding that can be used to switch to the previous + tab. Defaults to ``CUSTOM_CTRL_Y``. +:labels: A table of strings; entry representing the label text for a single tab. + The order of the entries determines the order the tabs will appear in. +:on_select: Callback executed when a tab is selected. It receives the selected tab + index as an argument. The provided function should update the value of + whichever variable your script uses to keep track of the currently + selected tab. +:get_cur_page: The function used by the TabBar to determine which Tab is currently + selected. The function you provide should return an integer that + corresponds to the non-zero index of the currently selected Tab + (i.e., whatever variable you update in your ``on_select`` callback). +:active_tab_pens: A table of pens used to render active tabs. See the default + implementation in widgets.lua for an example of how to construct + the table. Leave unspecified to use the default pens. +:inactive_tab_pens: A table of pens used to render inactive tabs. See the default + implementation in widgets.lua for an example of how to + construct the table. Leave unspecified to use the default pens. +:get_pens: A function used to determine which pens should be used to render a tab. + Receives the index of the tab as the first argument and the TabBar widget + itself as the second. The default implementation, which will handle most + situations, returns ``self.active_tab_pens``, if ``self.get_cur_page() == idx``, + otherwise returns ``self.inactive_tab_pens``. +:scroll_key: Specifies a keybinding that can be used to scroll the tabs to the right. + Defaults to ``CUSTOM_ALT_T``. +:scroll_key_back: Specifies a keybinding that can be used to scroll the tabs to the left. + Defaults to ``CUSTOM_ALT_Y``. +:scroll_left_text: The text to display on the left scroll label. + Defaults to "<<<". +:scroll_right_text: The text to display on the right scroll label. + Defaults to ">>>". +:scroll_label_text_pen: The pen to use for the scroll label text. + Defaults to ``Label`` default. +:scroll_label_text_hpen: The pen to use for the scroll label text when hovered. + Defaults to ``scroll_label_text_pen`` with the background + and foreground colors swapped. +:scroll_step: The number of units to scroll tabs by. + Defaults to 10. +:fast_scroll_multiplier: The multiplier for fast scrolling (holding shift). + Defaults to 3. +:scroll_into_view_offset: After a selected tab is scrolled into view, this offset + is added to the scroll position to ensure the tab is + not flush against the edge of the tab bar, allowing + some space for the user to see the next tab. + Defaults to 5. + +Tab class +--------- + +This widget implements a single clickable tab and is the main component of the TabBar +widget. Usage of the ``TabBar`` widget does not require direct usage of ``Tab``. + +:id: The id of the tab. +:label: The text displayed on the tab. +:on_select: Callback executed when the tab is selected. +:get_pens: A function that is used during ``Tab:onRenderBody`` to determine the pens + that should be used for drawing. See the usage of ``Tab`` in + ``TabBar:init()`` for an example. See the default value of + ``active_tab_pens`` or ``inactive_tab_pens`` in ``TabBar`` + for an example of how to construct pens. + +RangeSlider class +----------------- + +This widget implements a mouse-interactable range-slider. The player can move its two +handles to set minimum and maximum values to define a range, or they can drag the bar +itself to move both handles at once. The parent widget owns the range values, and can +control them independently (e.g., with ``CycleHotkeyLabels``). If the range values +change, the ``RangeSlider`` appearance will adjust automatically. + +:num_stops: Used to specify the number of "notches" in the range slider, the places + where handles can stop. (This should match the parents' number of options.) +:get_left_idx_fn: The function used by the RangeSlider to get the notch index on which + to display the left handle. +:get_right_idx_fn: The function used by the RangeSlider to get the notch index on which + to display the right handle. +:on_left_change: Callback executed when moving the left handle. +:on_right_change: Callback executed when moving the right handle. + +Slider class +----------------- + +This widget implements a mouse-interactable slider. The player can move the handle to +set the value of the slider. The parent widget owns the slider value, and can control +it independently (e.g., with a ``CycleHotkeyLabel``). If the value changes, the ``Slider`` +appearance will adjust automatically. + +:num_stops: Used to specify the number of "notches" in the slider, the places + where the handle can stop. (This should match the parents' number of options.) +:get_idx_fn: The function used by the Slider to get the notch index on which + to display the handle. +:on_change: Callback executed when moving the handle. + +DimensionsTooltip class +----------------------- + +This widget follows the mouse cursor around and displays a string that +indicates selected 3d dimensions. It is intended to be a child widget of a +full-screen ``View``, such as a ``ZScreen``. + +:display_offset: the offset from the mouse cursor where the tooltip is + displayed. Positive offsets are down and to the right. Defaults to + ``{x=3, y=3}``. +:get_anchor_pos_fn: function that provides the other corner of the selected + area as a ``df.coord``-style table, that is, a table with ``x``, ``y``, and + ``z`` fields. Must return ``nil`` if there is no current selection. + +gui.textures +============ + +This module contains convenience methods for accessing default DFHack graphic assets. +Pass the ``offset`` in tiles (in row major position) to get a particular tile from the +asset. ``offset`` 0 is the first tile. + +* ``tp_green_pin(offset)`` tileset: ``hack/data/art/green-pin.png`` +* ``tp_red_pin(offset)`` tileset: ``hack/data/art/red-pin.png`` +* ``tp_icons(offset)`` tileset: ``hack/data/art/icons.png`` +* ``tp_on_off(offset)`` tileset: ``hack/data/art/on-off.png`` +* ``tp_control_panel(offset)`` tileset: ``hack/data/art/control-panel.png`` +* ``tp_border_thin(offset)`` tileset: ``hack/data/art/border-thin.png`` +* ``tp_border_medium(offset)`` tileset: ``hack/data/art/border-medium.png`` +* ``tp_border_bold(offset)`` tileset: ``hack/data/art/border-bold.png`` +* ``tp_border_panel(offset)`` tileset: ``hack/data/art/border-panel.png`` +* ``tp_border_window(offset)`` tileset: ``hack/data/art/order-window.png`` + +Example usage:: + + local textures = require('gui.textures') + local first_border_texpos = textures.tp_border_thin(1) + + +.. _lua-plugins: + +======= +Plugins +======= + +.. contents:: + :local: + +DFHack plugins may export native functions and events to Lua contexts. These are +exposed as ``plugins.`` modules, which can be imported with +``require('plugins.')``. The plugins listed in this section expose +functions and/or data to Lua in this way. + +In addition to any native functions documented here, plugins that can be +enabled (that is, plugins that support the `enable/disable API `) will +have the following functions defined: + +* ``isEnabled()`` returns whether the plugin is enabled. +* ``setEnabled(boolean)`` sets whether the plugin is enabled. + +For plugin developers, note that a Lua file in ``plugins/lua`` is required for +``require()`` to work, even if it contains no pure-Lua functions. This file must +contain ``mkmodule('plugins.')`` to import any native functions defined in +the plugin. See existing files in ``plugins/lua`` for examples. + +blueprint +========= + +Lua functions provided by the `blueprint` plugin to programmatically generate +blueprint files: + +* ``dig(start, end, name)`` +* ``build(start, end, name)`` +* ``place(start, end, name)`` +* ``query(start, end, name)`` + + ``start`` and ``end`` are tables containing positions (see ``xyz2pos``). + ``name`` is used as the basis for the generated filenames. + +The names of the functions are also available as the keys of the +``valid_phases`` table. + +.. _building-hacks-api: + +building-hacks +============== + +This plugin overwrites some methods in workshop df class so that mechanical workshops are +possible. Although plugin export a function it's recommended to use lua decorated function. + +.. contents:: + :local: + +Functions +--------- + +``registerBuilding(table)`` where table must contain name, as a workshop raw name, +the rest are optional: + + :name: + custom workshop id e.g., ``SOAPMAKER`` + + .. note:: this is the only mandatory field. + + :fix_impassible: + if true make impassable tiles impassable to liquids too + :consume: + how much machine power is needed to work. + Disables reactions if not supplied enough and ``needs_power==1`` + :produce: + how much machine power is produced. + :needs_power: + if produced in network < consumed stop working, default true + :gears: + a table or ``{x=?,y=?}`` of connection points for machines. + :action: + a table of number (how much ticks to skip) and a function which + gets called on shop update + :animate: + a table of frames which can be a table of: + + a. tables of 4 numbers ``{tile,fore,back,bright}`` OR + b. empty table (tile not modified) OR + c. ``{x= y= + 4 numbers like in first case}``, + this generates full frame useful for animations that change little (1-2 tiles) + + :canBeRoomSubset: + a flag if this building can be counted in room. 1 means it can, + 0 means it can't and -1 default building behaviour + :auto_gears: + a flag that automatically fills up gears and animations. + It looks over the building definition for gear icons and maps them. + + Animate table also might contain: + + :frameLength: + how many ticks does one frame take OR + :isMechanical: + a bool that says to try to match to mechanical system (i.e., how gears are turning) + +``getPower(building)`` returns two number - produced and consumed power if building can be +modified and returns nothing otherwise + +``setPower(building,produced,consumed)`` sets current power production and +consumption for a building. + +Examples +-------- + +Simple mechanical workshop:: + + require('plugins.building-hacks').registerBuilding{name="BONE_GRINDER", + consume=15, + gears={x=0,y=0}, --connection point + animate={ + isMechanical=true, --animate the same conn. point as vanilla gear + frames={ + {{x=0,y=0,42,7,0,0}}, --first frame, 1 changed tile + {{x=0,y=0,15,7,0,0}} -- second frame, same + } + } + +Or with auto_gears:: + + require('plugins.building-hacks').registerBuilding{name="BONE_GRINDER", + consume=15, + auto_gears=true + } + +buildingplan +============ + +Native functions provided by the `buildingplan` plugin: + +* ``bool isPlannableBuilding(df::building_type type, int16_t subtype, int32_t custom)`` + + Returns whether the building type is handled by buildingplan. + +* ``bool isPlanModeEnabled(df::building_type type, int16_t subtype, int32_t custom)`` + + Returns whether the buildingplan UI is enabled for the specified building type. + +* ``bool isPlannedBuilding(df::building *bld)`` + + Returns whether the given building is managed by buildingplan. + +* ``void addPlannedBuilding(df::building *bld)`` + + Suspends the building jobs and adds the building to the monitor list. + +* ``void doCycle()`` + + Runs a check for whether buildings in the monitor list can be assigned + items and unsuspended. This method runs automatically twice a game day, + so you only need to call it directly if you want buildingplan to do a + check right now. + +* ``void scheduleCycle()`` + + Schedules a cycle to be run during the next non-paused game frame. + Can be called multiple times while the game is paused and only one + cycle will be scheduled. + +.. _cxxrandom-api: + +cxxrandom +========= + +Exposes some features of the C++11 random number library to Lua. + +.. contents:: + :local: + +Native functions (exported to Lua) +---------------------------------- + +- ``GenerateEngine(seed)`` + + returns engine id + +- ``DestroyEngine(rngID)`` + + destroys corresponding engine + +- ``NewSeed(rngID, seed)`` + + re-seeds engine + +- ``rollInt(rngID, min, max)`` + + generates random integer + +- ``rollDouble(rngID, min, max)`` + + generates random double + +- ``rollNormal(rngID, avg, stddev)`` + + generates random double drawn from a normal (Gaussian) distribution + +- ``rollBool(rngID, chance)`` + + generates random boolean + +- ``MakeNumSequence(start, end)`` + + returns sequence id + +- ``AddToSequence(seqID, num)`` + + adds a number to the sequence + +- ``ShuffleSequence(seqID, rngID)`` + + shuffles the number sequence + +- ``NextInSequence(seqID)`` + + returns the next number in sequence + + +Lua plugin functions +-------------------- + +- ``MakeNewEngine(seed)`` + + returns engine id + +Lua plugin classes +------------------ + +crng +~~~~ + +- ``init(id, df, dist)``: constructor + + - ``id``: Reference ID of engine to use in RNGenerations. + - ``df`` (optional): bool indicating whether to destroy the Engine + when the crng object is garbage collected. + - ``dist`` (optional): lua number distribution to use. + +- ``changeSeed(seed)``: alters engine's seed value +- ``setNumDistrib(distrib)``: sets the number distribution crng object should use. + + - ``distrib``: number distribution object to use in RNGenerations. + +- ``next()``: returns the next number in the distribution. +- ``shuffle()``: effectively shuffles the number distribution. + +normal_distribution +~~~~~~~~~~~~~~~~~~~ + +- ``init(avg, stddev)``: constructor +- ``next(id)``: returns next number in the distribution + + - ``id``: engine ID to pass to native function + +real_distribution +~~~~~~~~~~~~~~~~~ + +- ``init(min, max)``: constructor +- ``next(id)``: returns next number in the distribution + + - ``id``: engine ID to pass to native function + +int_distribution +~~~~~~~~~~~~~~~~ + +- ``init(min, max)``: constructor +- ``next(id)``: returns next number in the distribution + + - ``id``: engine ID to pass to native function + +bool_distribution +~~~~~~~~~~~~~~~~~ + +- ``init(chance)``: constructor +- ``next(id)``: returns next boolean in the distribution + + - ``id``: engine ID to pass to native function + +num_sequence +~~~~~~~~~~~~ + +- ``init(a, b)``: constructor +- ``add(num)``: adds num to the end of the number sequence +- ``shuffle()``: shuffles the sequence of numbers +- ``next()``: returns next number in the sequence + +Usage +----- + +The randomization state is kept in an "engine". The distribution class turns +that engine state into random numbers. + +Example:: + + local rng = require('plugins.cxxrandom') + local norm_dist = rng.normal_distribution(6820, 116) -- avg, stddev + local engID = rng.MakeNewEngine(0) + print(norm_dist:next(engID)) + + -- alternate syntax + local cleanup = true -- delete engine on cleanup + local number_generator = rng.crng:new(engID, cleanup, norm_dist) + print(number_generator:next()) + + -- simplified + print(rng.rollNormal(engID, 6820, 116)) + +The number sequences are much simpler. They're intended for where you need to +randomly generate an index, perhaps in a loop for an array. You technically +don't need an engine to use it, if you don't mind never shuffling. + +Example:: + + local rng = require('plugins.cxxrandom') + local engID = rng.MakeNewEngine(0) + local g = rng.crng:new(engId, true, rng.num_sequence:new(0, table_size)) + g:shuffle() + for _ = 1, table_size do + func(array[g:next()]) + end + + +dig-now +======= + +The dig-now plugin exposes the following functions to Lua: + +* ``dig_now_tile(pos)`` or ``dig_now_tile(x,y,z)``: Runs dig-now for the + specified tile coordinate. Default options apply, as if you were running the + command ``dig-now ``. See the `dig-now` documentation for details + on default settings. + +.. _eventful-api: + +eventful +======== + +This plugin exports some events to lua thus allowing to run lua functions +on DF world events. + +.. contents:: + :local: + +List of events +-------------- + +1. ``onReactionCompleting(reaction,reaction_product,unit,input_items,input_reagents,output_items,call_native)`` + + Is called once per reaction product, before the reaction has a chance to + call native code for item creation. Setting ``call_native.value=false`` + cancels further processing: no items are created and ``onReactionComplete`` + is not called. + +2. ``onReactionComplete(reaction,reaction_product,unit,input_items,input_reagents,output_items)`` + + Is called once per reaction product, when reaction finishes and has + at least one product. + +3. ``onItemContaminateWound(item,unit,wound,number1,number2)`` + + Is called when item tries to contaminate wound (e.g., stuck in). + +4. ``onProjItemCheckMovement(projectile)`` + + Is called when projectile moves. + +5. ``onProjItemCheckImpact(projectile,somebool)`` + + Is called when projectile hits something. + +6. ``onProjUnitCheckMovement(projectile)`` + + Is called when projectile moves. + +7. ``onProjUnitCheckImpact(projectile,somebool)`` + + Is called when projectile hits something. + +8. ``onWorkshopFillSidebarMenu(workshop,callnative)`` + + Is called when viewing a workshop in 'q' mode, to populate + reactions, useful for custom viewscreens for shops. + +9. ``postWorkshopFillSidebarMenu(workshop)`` + + Is called after calling (or not) native fillSidebarMenu(). + Useful for job button tweaking (e.g., adding custom reactions) + +.. _EventManager: + +Events from EventManager +------------------------ +These events are straight from EventManager module. Each of them first needs +to be enabled. See functions for more info. If you register a listener before +the game is loaded, be aware that no events will be triggered immediately +after loading, so you might need to add another event listener for when the +game first loads in some cases. + +1. ``onBuildingCreatedDestroyed(building_id)`` + + Gets called when building is created or destroyed. + +2. ``onConstructionCreatedDestroyed(building_id)`` + + Gets called when construction is created or destroyed. + +3. ``onJobInitiated(job)`` + + Gets called when job is issued. + +4. ``onJobCompleted(job)`` + + Gets called when job is finished. The job that is passed to this function + is a copy. Requires a frequency of 0 in order to distinguish between + workshop jobs that were canceled by the user and workshop jobs that + completed successfully. + +5. ``onUnitDeath(unit_id)`` + + Gets called on unit death. + +6. ``onItemCreated(item_id)`` + + Gets called when item is created (except due to traders, migrants, + invaders, and spider webs). + +7. ``onSyndrome(unit_id,syndrome_index)`` + + Gets called when new syndrome appears on a unit. + +8. ``onInvasion(invasion_id)`` + + Gets called when new invasion happens. + +9. ``onInventoryChange(unit_id,item_id,old_equip,new_equip)`` + + Gets called when someone picks up an item, puts one down, + or changes the way they are holding it. If an item is picked up, + old_equip will be null. If an item is dropped, new_equip will be null. + If an item is re-equipped in a new way, then neither will be null. + You absolutely must NOT alter either old_equip or new_equip or you + might break other plugins. + +10. ``onReport(reportId)`` + + Gets called when a report happens. This happens more often than + you probably think, even if it doesn't show up in the announcements. + +11. ``onUnitAttack(attackerId, defenderId, woundId)`` + + Called when a unit wounds another with a weapon. + Is NOT called if blocked, dodged, deflected, or parried. + +12. ``onUnload()`` + + A convenience event in case you don't want to register for every onStateChange event. + +13. ``onInteraction(attackVerb, defendVerb, attackerId, defenderId, attackReportId, defendReportId)`` + + Called when a unit uses an interaction on another. + +Functions +--------- + +1. ``registerReaction(reaction_name,callback)`` + + Simplified way of using onReactionCompleting; the callback is function (same params as event). + +2. ``removeNative(shop_name)`` + + Removes native choice list from the building. + +3. ``addReactionToShop(reaction_name,shop_name)`` + + Add a custom reaction to the building. + +4. ``enableEvent(evType,frequency)`` + + Enable event checking for EventManager events. For event types use ``eventType`` table. + Note that different types of events require different frequencies to be effective. The + frequency is how many ticks EventManager will wait before checking if that type of event + has happened. If multiple scripts or plugins use the same event type, the smallest frequency + is the one that is used, so you might get events triggered more often than the frequency + you use here. + +5. ``registerSidebar(shop_name,callback)`` + + Enable callback when sidebar for ``shop_name`` is drawn. Useful for custom workshop views, + e.g., using gui.dwarfmode lib. Also accepts a ``class`` instead of function as callback. + Best used with ``gui.dwarfmode`` class ``WorkshopOverlay``. + +Examples +-------- +Spawn dragon breath on each item attempt to contaminate wound:: + + b=require "plugins.eventful" + b.onItemContaminateWound.one=function(item,unit,un_wound,x,y) + local flw=dfhack.maps.spawnFlow(unit.pos,6,0,0,50000) + end + +Reaction complete example:: + + b=require "plugins.eventful" + + b.registerReaction("LAY_BOMB",function(reaction,unit,in_items,in_reag,out_items,call_native) + local pos=copyall(unit.pos) + -- spawn dragonbreath after 100 ticks + dfhack.timeout(100,"ticks",function() dfhack.maps.spawnFlow(pos,6,0,0,50000) end) + --do not call real item creation code + call_native.value=false + end) + +Grenade example:: + + b=require "plugins.eventful" + b.onProjItemCheckImpact.one=function(projectile) + -- you can check if projectile.item e.g., has correct material + dfhack.maps.spawnFlow(projectile.cur_pos,6,0,0,50000) + end + +Integrated tannery:: + + b=require "plugins.eventful" + b.addReactionToShop("TAN_A_HIDE","LEATHERWORKS") + +.. _luasocket-api: + +luasocket +========= + +A way to access csocket from lua. The usage is made similar to luasocket in +vanilla lua distributions. Currently only a subset of the functions exist +and only TCP mode is implemented. + +.. contents:: + :local: + +Socket class +------------ + +This is a base class for ``client`` and ``server`` sockets. You can not create +it - it's like a virtual base class in c++. + +* ``socket:close()`` + + Closes the connection. + +* ``socket:setTimeout(sec,msec)`` + + Sets the operation timeout for this socket. It's possible to set timeout to 0. + Then it performs like a non-blocking socket. + +Client class +------------ + +Client is a connection socket to a server. You can get this object either from +``tcp:connect(address,port)`` or from ``server:accept()``. +It's a subclass of ``socket``. + +* ``client:receive(pattern)`` + + Receives data. Pattern is one of: + + :``*l``: read one line (default, if pattern is *nil*) + :: read specified number of bytes + :``*a``: read all available data + +* ``client:send(data)`` + + Sends data. Data is a string. + + +Server class +------------ + +Server is a socket that is waiting for clients. +You can get this object from ``tcp:bind(address,port)``. + +* ``server:accept()`` + + Accepts an incoming connection if it exists. + Returns a ``client`` object representing that socket. + +Tcp class +--------- + +A class with all the tcp functionality. + +* ``tcp:bind(address,port)`` + + Starts listening on that port for incoming connections. + Returns ``server`` object. + +* ``tcp:connect(address,port)`` + + Tries connecting to that address and port. Returns ``client`` object. + + +.. _map-render-api: + +map-render +========== + +A way to ask DF to render a section of the fortress mode map. +This uses a native DF rendering function so it's highly dependent +on DF settings (e.g., tileset, colors, etc.) + +Functions +--------- + +- ``render_map_rect(x,y,z,w,h)`` + + Returns a table with w*h*4 entries of rendered tiles. The format is + the same as ``df.global.gps.screen`` (tile,foreground,bright,background). + +.. _pathable-api: + +pathable +======== + +This plugin implements the back end of the `gui/pathable` script. It exports a +single Lua function, in ``hack/lua/plugins/pathable.lua``: + +* ``paintScreen(cursor[,skip_unrevealed])``: Paint each visible of the screen + green or red, depending on whether it can be pathed to from the tile at + ``cursor``. If ``skip_unrevealed`` is specified and true, do not draw + unrevealed tiles. + +reveal +====== + +Native functions provided by the `reveal` plugin: + +* ``void unhideFlood(pos)``: Unhides map tiles according to visibility rules, + starting from the given coordinates. This algorithm only processes adjacent + hidden tiles, so it must start on a hidden tile in order to have any effect. + It will not reveal hidden sections separated by already-unhidden tiles. + +Example of revealing a cavern that happens to have an open tile at the specified +coordinate:: + + unhideFlood({x=25, y=38, z=140}) + +sort +==== + +The `sort ` plugin does not export any native functions as of now. +Instead, it calls Lua code to perform the actual ordering of list items. + +tiletypes +========= + +* ``bool tiletypes_setTile(pos, shape, material, special, variant)`` where + the parameters are enum values from ``df.tiletype_shape``, + ``df.tiletype_material``, etc. Returns whether the conversion succeeded. + +* ``bool tiletypes_setTile(pos, tiletype_options)`` where + the ``tiletype_options`` parameter takes in a table, with any fields matching + the available tiletypes options. Any unspecified fields default to keeping + the value of the original tile. Returns whether the conversion succeeded. + - ``shape``: ``df.tiletype_shape`` + - ``material``: ``df.tiletype_material`` + - ``special``: ``df.tiletype_special`` + - ``variant``: ``df.tiletype_variant`` + - ``hidden``: -1, 0, or 1 + - ``light``: -1, 0, or 1 + - ``subterranean``: -1, 0, or 1 + - ``skyview``: -1, 0, or 1 + - ``aquifer``: -1, 0, 1, or 2 + - ``autocorrect``: 0 or 1 + - ``stone_material``: integer material id + - ``vein_type``: ``df.inclusion_type`` + +.. _xlsxreader-api: + +xlsxreader +========== + +Utility functions to facilitate reading .xlsx spreadsheets. It provides the +following low-level API methods: + +- ``open_xlsx_file(filename)`` returns a file_handle or nil on error +- ``close_xlsx_file(file_handle)`` closes the specified file_handle +- ``list_sheets(file_handle)`` returns a list of strings representing sheet + names +- ``open_sheet(file_handle, sheet_name)`` returns a sheet_handle. This call + always succeeds, even if the sheet doesn't exist. Non-existent sheets will + have no data, though. +- ``close_sheet(sheet_handle)`` closes the specified sheet_handle +- ``get_row(sheet_handle, max_tokens)`` returns a list of strings representing + the contents of the cells in the next row. The ``max_tokens`` parameter is + optional. If set to a number > 0, it limits the number of cells read and + returned for the row. + +The plugin also provides Lua class wrappers for ease of use: + +- ``XlsxioReader`` provides access to .xlsx files +- ``XlsxioSheetReader`` provides access to sheets within .xlsx files +- ``open(filepath)`` initializes and returns an ``XlsxioReader`` object + +The ``XlsxioReader`` class has the following methods: + +- ``XlsxioReader:close()`` closes the file. Be sure to close any open child + sheet handles first! +- ``XlsxioReader:list_sheets()`` returns a list of strings representing sheet + names +- ``XlsxioReader:open_sheet(sheet_name)`` returns an initialized + ``XlsxioSheetReader`` object + +The ``XlsxioSheetReader`` class has the following methods: + +- ``XlsxioSheetReader:close()`` closes the sheet +- ``XlsxioSheetReader:get_row(max_tokens)`` reads the next row from the sheet. + If ``max_tokens`` is specified and is a positive integer, only the first + ``max_tokens`` elements of the row are returned. + +Here is an end-to-end example:: + + local xlsxreader = require('plugins.xlsxreader') + + local function dump_sheet(reader, sheet_name) + print('reading sheet: ' .. sheet_name) + local sheet_reader = reader:open_sheet(sheet_name) + dfhack.with_finalize( + function() sheet_reader:close() end, + function() + local row_cells = sheet_reader:get_row() + while row_cells do + printall(row_cells) + row_cells = sheet_reader:get_row() + end + end + ) + end + + local filepath = 'path/to/some_file.xlsx' + local reader = xlsxreader.open(filepath) + dfhack.with_finalize( + function() reader:close() end, + function() + for _,sheet_name in ipairs(reader:list_sheets()) do + dump_sheet(reader, sheet_name) + end + end + ) + +======= +Scripts +======= + +.. contents:: + :local: + +Any files with the ``.lua`` extension placed into the :file:`hack/scripts` folder +(or any other folder in your `script-paths`) are automatically made available as +DFHack commands. The command corresponding to a script is simply the script's +filename, relative to the scripts folder, with the extension omitted. For example: + +* :file:`dfhack-config/scripts/startup.lua` is invoked as ``startup`` +* :file:`hack/scripts/gui/teleport.lua` is invoked as ``gui/teleport`` + +.. note:: + In general, scripts should be placed in subfolders in the following + situations: + + * ``devel``: scripts that are intended exclusively for DFHack development, + including examples, or scripts that are experimental and unstable + * ``fix``: fixes for specific DF issues + * ``gui``: GUI front-ends for existing tools (for example, see the + relationship between `teleport` and `gui/teleport`) + * ``modtools``: scripts that are intended to be run exclusively as part of + mods, not directly by end-users (as a rule of thumb: if someone other than + a mod developer would want to run a script from the console, it should + not be placed in this folder) + +Scripts are read from disk when run for the first time, or if they have changed +since the last time they were run. + +Each script has an isolated environment where global variables set by the script +are stored. Values of globals persist across script runs in the same DF session. +See `devel/lua-example` for an example of this behavior. Note that ``local`` +variables do *not* persist. + +Arguments are passed in to the scripts via the ``...`` built-in quasi-variable; +when the script is called by the DFHack core, they are all guaranteed to be +non-nil strings. + +Additional data about how a script is invoked is passed to the script as a +special ``dfhack_flags`` global, which is unique to each script. This table +is guaranteed to exist, but individual entries may be present or absent +depending on how the script was invoked. Flags that are present are described +in the subsections below. + +DFHack invokes the scripts in the `core context `; however it +is possible to call them from any lua code (including from other scripts) in any +context with ``dfhack.run_script()`` below. + +General script API +================== + +* ``dfhack.run_script(name[,args...])`` + + Run a Lua script in your `script-paths`, as if it were started from the + DFHack command-line. The ``name`` argument should be the name of the script + without its extension, as it would be used on the command line. + + Example: + + In DFHack prompt:: + + repeat -time 14 -timeUnits days -command [ workorder ShearCreature ] -name autoShearCreature + + In Lua script:: + + dfhack.run_script("repeat", "-time", "14", "-timeUnits", "days", "-command", "[", "workorder", "ShearCreature", "]", "-name", "autoShearCreature") + + Note that the ``dfhack.run_script()`` function allows Lua errors to propagate to the caller. + + To run other types of commands (i.e., built-in commands or commands provided by plugins), + see ``dfhack.run_command()``. Note that this is slightly slower than ``dfhack.run_script()`` + when running Lua scripts. + +* ``dfhack.script_help([name, [extension]])`` + + Returns the contents of the rendered (or embedded) `documentation` for the + specified script. ``extension`` defaults to "lua", and ``name`` defaults to + the name of the script where this function was called. For example, the + following can be used to print the current script's help text:: + + local args = {...} + if args[1] == 'help' then + print(script_help()) + return + end + +.. _reqscript: + +Importing scripts +================= + +* ``dfhack.reqscript(name)`` or ``reqscript(name)`` + + Loads a Lua script and returns its environment (i.e., a table of all global + functions and variables). This is similar to the built-in ``require()``, but + searches all `script-paths` for the first matching ``name.lua`` file instead + of searching the Lua library paths (like ``hack/lua/``). + + Most scripts can be made to support ``reqscript()`` without significant + changes (in contrast, ``require()`` requires the use of ``mkmodule()`` and + some additional boilerplate). However, because scripts can have side effects + when they are loaded (such as printing messages or modifying the game state), + scripts that intend to support being imported must satisfy some criteria to + ensure that they can be imported safely: + + 1. Include the following line - ``reqscript()`` will fail if this line is + not present:: + + --@ module = true + + In order to be recognized, this line **must** begin with ``--@`` with no + whitespace characters before it:: + + --@ module = true OK + --@module = true OK + -- @module = true NOT OK (no --@ found due to space after --) + --@module = true NOT OK (leading space, --@ is not at the beginning of the line) + ---@module = true NOT OK (leading dash, --@ is not at the beginning of the line) + + 2. Include a check for ``dfhack_flags.module``, and avoid running any code + that has side-effects if this flag is true. For instance:: + + -- (function definitions) + if dfhack_flags.module then + return + end + -- (main script code with side-effects) + + or:: + + -- (function definitions) + function main() + -- (main script code with side-effects) + end + if not dfhack_flags.module then + main() + end + + Example usage:: + + local addThought = reqscript('add-thought') + addThought.addEmotionToUnit(unit, ...) + + Circular dependencies between scripts are supported, as long as the scripts + have no side-effects at load time (which should already be the case per + the above criteria). + + .. warning:: + + Avoid caching the table returned by ``reqscript()`` beyond storing it in + a local variable as in the example above. ``reqscript()`` is fast for + scripts that have previously been loaded and haven't changed. If you retain + a reference to a table returned by an old ``reqscript()`` call, this may + lead to unintended behavior if the location of the script changes (e.g., if a + save is loaded or unloaded, or if a `script path ` is added in + some other way). + + .. admonition:: Tip + + Mods that include custom Lua modules can write these modules to support + ``reqscript()`` and distribute them as scripts in ``raw/scripts``. Since the + entire ``raw`` folder is copied into new saves, this will allow saves to be + successfully transferred to other users who do not have the mod installed + (as long as they have DFHack installed). + + .. admonition:: Backwards compatibility notes + + For backwards compatibility, ``moduleMode`` is also defined if + ``dfhack_flags.module`` is defined, and is set to the same value. + Support for this may be removed in a future version. + +* ``dfhack.script_environment(name)`` + + Similar to ``reqscript()`` but does not enforce the check for module support. + This can be used to import scripts that support being used as a module but do + not declare support as described above, although it is preferred to update + such scripts so that ``reqscript()`` can be used instead. + +.. _script-enable-api: + +Enabling and disabling scripts +============================== + +Scripts can choose to recognize the built-in ``enable`` and ``disable`` commands +by including the following line near the top of their file:: + + --@enable = true + --@module = true + +Note that enableable scripts must also be `modules ` so their +``isEnabled()`` functions can be called from outside the script. + +When the ``enable`` and ``disable`` commands are invoked, the ``dfhack_flags`` +table passed to the script will have the following fields set: + +* ``enable``: Always ``true`` if the script is being enabled *or* disabled +* ``enable_state``: ``true`` if the script is being enabled, ``false`` otherwise + +If you declare a global function named ``isEnabled`` that returns a boolean +indicating whether your script is enabled, then your script will be listed among +the other enableable scripts and plugins when the player runs the `enable` +command. + +Example usage:: + + --@enable = true + --@module = true + + enabled = enabled or false + function isEnabled() + return enabled + end + + -- (function definitions...) + + if dfhack_flags.enable then + if dfhack_flags.enable_state then + start() + enabled = true + else + stop() + enabled = false + end + end + +If the state of your script can be tied to an active savegame, then your script +should hook the appropriate events to load persisted state when a savegame is +loaded. For example:: + + local utils = require('utils') + + local GLOBAL_KEY = 'my-script-name' + + local function get_default_state() + return { + -- add default config here, e.g., + -- enabled=false, + } + end + + state = state or get_default_state() + + dfhack.onStateChange[GLOBAL_KEY] = function(sc) + if sc ~= SC_MAP_LOADED or df.global.gamemode ~= df.game_mode.DWARF then + return + end + -- retrieve state saved in game. merge with default state so config + -- saved from previous versions can pick up newer defaults. + state = get_default_state() + utils.assign(state, dfhack.persistent.getSiteData(GLOBAL_KEY, state)) + end + + -- to be called when global state changes that needs to be persisted + local function persist_state() + dfhack.persistent.saveSiteData(GLOBAL_KEY, state) + end + +The attachment to ``dfhack.onStateChange`` should appear in your script code +outside of any function. DFHack will load your script as a module just before +the ``SC_DFHACK_INITIALIZED`` state change event is sent, giving your code an +opportunity to run and attach hooks before the game is loaded. + +If an enableable script is added to a DFHack `script path ` while +DF is running, then it will miss the initial sweep that loads all the module +scripts and any ``onStateChange`` handlers the script may want to register will +not be registered until the script is loaded via some means, either by running +it or loading it as a module. If you just added new scripts that you want to +load so they can attach their ``onStateChange`` handlers, run ``enable`` without +parameters or call ``:lua require('script-manager').reload()`` to scan and load +all script modules. + +Save init script +================ + +If a save directory contains a file called ``init.lua``, it is +automatically loaded and executed every time the save is loaded. +The same applies to any files called ``init.d/*.lua``. Every +such script can define the following functions to be called by dfhack: + +* ``function onStateChange(op) ... end`` + + Automatically called from the regular onStateChange event as long + as the save is still loaded. This avoids the need to install a hook + into the global ``dfhack.onStateChange`` table, with associated + cleanup concerns. + +* ``function onUnload() ... end`` + + Called when the save containing the script is unloaded. This function + should clean up any global hooks installed by the script. Note that + when this is called, the world is already completely unloaded. + +Within the init script, the path to the save directory is available as ``SAVE_PATH``. diff --git a/docs/Memory-research.rst b/docs/dev/Memory-research.rst similarity index 96% rename from docs/Memory-research.rst rename to docs/dev/Memory-research.rst index 9729072f51..2ee47bb05b 100644 --- a/docs/Memory-research.rst +++ b/docs/dev/Memory-research.rst @@ -50,7 +50,7 @@ Plugins There are a few development plugins useful for low-level memory research. They are not built by default, but can be built by setting the ``BUILD_DEVEL`` -`CMake option `. These include: +`CMake option `. These include: - ``check-structures-sanity``, which performs sanity checks on the given DF object. Note that this will crash in several cases, some intentional, so using @@ -63,7 +63,7 @@ are not built by default, but can be built by setting the ``BUILD_DEVEL`` Scripts ~~~~~~~ -Several `development scripts ` can be useful for memory research. +Several `development tools ` can be useful for memory research. These include (but are not limited to): - `devel/dump-offsets` @@ -85,7 +85,7 @@ You should not count on DF being stable when using this. DFHack's implementation of sizecheck is currently only tested on Linux, although it probably also works on macOS. It can be built with the ``BUILD_SIZECHECK`` -`CMake option `, which produces a ``libsizecheck`` +`CMake option `, which produces a ``libsizecheck`` library installed in the ``hack`` folder. On Linux, passing ``--sc`` as the first argument to the ``dfhack`` launcher script will load this library on startup. On other platforms, or when passing a different argument to the diff --git a/docs/Remote.rst b/docs/dev/Remote.rst similarity index 97% rename from docs/Remote.rst rename to docs/dev/Remote.rst index c41a14058b..c98d6ae520 100644 --- a/docs/Remote.rst +++ b/docs/dev/Remote.rst @@ -1,7 +1,7 @@ .. _remote: ======================= -DFHack Remote Interface +DFHack remote interface ======================= DFHack provides a remote access interface that external tools can connect to and @@ -55,7 +55,6 @@ Plugins that implement RPC methods include: - `rename` - `remotefortressreader` -- `isoworldremote` Plugins that use the RPC API include: @@ -75,10 +74,11 @@ from other (non-C++) languages, including: - `RemoteClientDF-Net `_ for C# - `dfhackrpc `_ for Go -- `dfhack-remote `_ for JavaScript +- `dfhack-remote `__ for JavaScript - `dfhack-client-qt `_ for C++ with Qt - `dfhack-client-python `_ for Python (adapted from :forums:`"Blendwarf" <178089>`) - `dfhack-client-java `_ for Java +- `dfhack-remote `__ for Rust Protocol description @@ -102,8 +102,6 @@ ID Method Input Output 1 RunCommand dfproto.CoreRunCommandRequest dfproto.EmptyMessage === ============ =============================== ======================= - - Conversation flow ----------------- diff --git a/docs/Structures-intro.rst b/docs/dev/Structures-intro.rst similarity index 87% rename from docs/Structures-intro.rst rename to docs/dev/Structures-intro.rst index c45d03eaf0..8fe8d6e99b 100644 --- a/docs/Structures-intro.rst +++ b/docs/dev/Structures-intro.rst @@ -18,17 +18,15 @@ layout changes, and will need to be recompiled for every new DF version. Addresses of DF global objects and vtables are stored in a separate file, :file:`symbols.xml`. Since these are only absolute addresses, they do not need -to be compiled in to DFHack code, and are instead loaded at runtime. This makes +to be compiled into DFHack code, and are instead loaded at runtime. This makes fixes and additions to global addresses possible without recompiling DFHack. In an installed copy of DFHack, this file can be found at the root of the ``hack`` folder. -The following pages contain more detailed information about various aspects -of DF-structures: +Please see the following page for detailed information about the syntax of the +df-structures XML files: .. toctree:: :titlesonly: /library/xml/SYNTAX - /library/xml/how-to-update - diff --git a/docs/dev/compile/Compile.rst b/docs/dev/compile/Compile.rst new file mode 100644 index 0000000000..2ad2c52efb --- /dev/null +++ b/docs/dev/compile/Compile.rst @@ -0,0 +1,455 @@ +.. highlight:: shell + +.. _compile: + +########### +Compilation +########### + +DFHack builds are available for all supported platforms; see `installing` for +installation instructions. If you are a DFHack end-user, modder, or plan on +writing scripts [lua] (not plugins), it is generally recommended (and easier) to use +these `builds `_ instead of compiling DFHack from source. + +However, if you are looking to develop plugins, work on the DFHack core, make +complex changes to DF-structures, or anything else that requires compiling +DFHack from source, this document will walk you through the build process. Note +that some steps may be unconventional compared to other projects, so be sure to +pay close attention if this is your first time compiling DFHack. + +.. contents:: Contents + :local: + :depth: 2 + +.. _compile-how-to-get-the-code: + +How to get the code +=================== +DFHack uses Git for source control; instructions for installing Git can be found +in the platform-specific sections below. The code is hosted on +`GitHub `_, and can be downloaded with:: + + git clone --recursive https://github.com/DFHack/dfhack + cd dfhack + +If your version of Git does not support the ``--recursive`` flag, you will need +to omit it and run ``git submodule update --init`` after entering the dfhack +directory. + +This will check out the code on the default branch of the GitHub repo, currently +``develop``, which may be unstable. If you want code for the latest stable +release, you can check out the ``master`` branch instead:: + + git checkout master + git submodule update + +In general, a single DFHack clone is suitable for development - most Git +operations such as switching branches can be done on an existing clone. If you +find yourself cloning DFHack frequently as part of your development process, or +getting stuck on anything else Git-related, feel free to reach out to us for +assistance. + +.. admonition:: Offline builds + + If you plan to build DFHack on a machine without an internet connection (or + with an unreliable connection), see `note-offline-builds` for additional + instructions. + +.. admonition:: Working with submodules + + DFHack uses submodules extensively to manage its subprojects (including the + ``scripts`` folder and DF-structures in ``library/xml``). Failing to keep + submodules in sync when switching between branches can result in build errors + or scripts that don't work. In general, you should always update submodules + whenever you switch between branches in the main DFHack repo with + ``git submodule update``. (If you are working on bleeding-edge DFHack and + have checked out the master branch of some submodules, running ``git pull`` + in those submodules is also an option.) + + Rarely, we add or remove submodules. If there are any changes to the existence + of submodules when you switch between branches, you should run + ``git submodule update --init`` instead (adding ``--init`` to the above + command). + + Some common errors that can arise when failing to update submodules include: + + * ``fatal: does not exist`` when performing Git operations + * Build errors, particularly referring to structures in the ``df::`` namespace + or the ``library/include/df`` folder + * ``Not a known DF version`` when starting DF + * ``Run 'git submodule update --init'`` when running CMake + + Submodules are a particularly confusing feature of Git. The + `Git Book `_ has a + thorough explanation of them (as well as of many other aspects of Git) and + is a recommended resource if you run into any issues. Other DFHack developers + are also able to help with any submodule-related (or Git-related) issues + you may encounter. + +All Platforms +============= +Before you can compile the code you'll need to configure your build with cmake. Some IDEs can do this +for you, but it's more common to do it from the command line. Windows developers can refer to the +Windows section below for batch files that can be used to avoid opening a terminal/command-prompt. + +You should seek cmake's documentation online or via ``cmake --help`` to see how the command works. See +the `build-options` page for help finding the DFHack build options relevant to you. + +Before compiling code, you'll of course need code to compile. This **will include** the submodules, so +be sure you've read the section about getting the code. + +.. _compile-linux: + +Linux +===== + +Building is fairly straightforward. Enter the ``build`` folder (or create an +empty folder in the DFHack directory to use instead) and start the build like this:: + + cd build + cmake .. -G Ninja -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX= + ninja install # or ninja -jX install to specify the number of cores (X) to use + + should be a path to a copy of Dwarf Fortress, of the appropriate +version for the DFHack you are building. This will build the library along +with the normal set of plugins and install them into your DF folder. + +Alternatively, you can use ccmake instead of cmake:: + + cd build + ccmake .. -G Ninja + ninja install + +This will show a curses-based interface that lets you set all of the +extra options. You can also use a cmake-friendly IDE like KDevelop 4 +or the cmake-gui program. + +.. _compile-windows: + +Windows +======= +There are several different batch files in the ``win32`` and ``win64`` +subfolders in the ``build`` folder, along with a script that's used for picking +the DF path. Use the subfolder corresponding to the architecture that you want +to build for. + +First, run ``set_df_path.vbs`` and point the dialog that pops up at +a suitable DF installation which is of the appropriate version for the DFHack +you are compiling. The result is the creation of the file ``DF_PATH.txt`` in +the build directory. It contains the full path to the destination directory. +You could therefore also create this file manually - or copy in a pre-prepared +version - if you prefer. + +Next, run one of the scripts with ``generate`` prefix. These create the MSVC +solution file(s): + +* ``all`` will create a solution with everything enabled (and the kitchen sink). +* ``gui`` will pop up the CMake GUI and let you choose what to build. + This is probably what you want most of the time. Set the options you are interested + in, then hit configure, then generate. More options can appear after the configure step. +* ``minimal`` will create a minimal solution with just the bare necessities - + the main library and standard plugins. +* ``release`` will create a solution with everything that should be included in + release builds of DFHack. Note that this includes documentation, which requires + Python. + +Then you can either open the solution with MSVC or use one of the msbuild scripts. + +Visual Studio IDE +----------------- +After running the CMake generate script you will have a new folder called VC2022 +or VC2022_32, depending on the architecture you specified. Open the file +``dfhack.sln`` inside that folder. If you have multiple versions of Visual +Studio installed, make sure you open with Visual Studio 2022. + +The first thing you must then do is ensure the build type is not Debug, which +cannot be used on Windows. Debug is not binary-compatible with DF. +If you try to use a debug build with DF, you'll only get crashes and for this +reason the Windows "debug" scripts actually do RelWithDebInfo builds. +After loading the Solution, change the Build Type to either ``Release`` +or ``RelWithDebInfo``. + +Then build the ``INSTALL`` target listed under ``CMakePredefinedTargets``. + +Command Line +------------ +In the build directory you will find several ``.bat`` files: + +* Scripts with ``build`` prefix will only build DFHack. +* Scripts with ``install`` prefix will build DFHack and install it to the previously selected DF path. +* Scripts with ``package`` prefix will build and create a .zip package of DFHack. + +Compiling from the command line is generally the quickest and easiest option. +Modern Windows terminal emulators such as `Cmder `_ or +`Windows Terminal `_ provide a better +experience by providing more scrollback and larger window sizes. + +.. _compile-macos: + +macOS +===== + +NOTE: this section is currently outdated. Once DF itself can build on macOS +again, we will match DF's build environment and update the instructions here. + +DFHack functions similarly on macOS and Linux, and the majority of the +information above regarding the build process (CMake and Ninja) applies here +as well. + +DFHack can officially be built on macOS only with GCC 4.8 or 7. Anything newer than 7 +will require you to perform extra steps to get DFHack to run (see `osx-new-gcc-notes`), +and your build will likely not be redistributable. + +Building +-------- + +* Get the DFHack source as per section `compile-how-to-get-the-code`, above. +* Set environment variables + + Homebrew (if installed elsewhere, replace /usr/local with ``$(brew --prefix)``):: + + export CC=/usr/local/bin/gcc-7 + export CXX=/usr/local/bin/g++-7 + + Macports:: + + export CC=/opt/local/bin/gcc-mp-7 + export CXX=/opt/local/bin/g++-mp-7 + + Change the version numbers appropriately if you installed a different version of GCC. + + If you are confident that you have GCC in your path, you can omit the absolute paths:: + + export CC=gcc-7 + export CXX=g++-7 + + (adjust as needed for different GCC installations) + +* Build DFHack:: + + mkdir build-osx + cd build-osx + cmake .. -G Ninja -DCMAKE_BUILD_TYPE:string=Release -DCMAKE_INSTALL_PREFIX= + ninja install # or ninja -jX install to specify the number of cores (X) to use + + should be a path to a copy of Dwarf Fortress, of the appropriate + version for the DFHack you are building. + +.. _osx-new-gcc-notes: + +Notes for GCC 8+ or OS X 10.10+ users +------------------------------------- + +If you have issues building on OS X 10.10 (Yosemite) or above, try defining +the following environment variable:: + + export MACOSX_DEPLOYMENT_TARGET=10.9 + +If you build with a GCC version newer than 7, DFHack will probably crash +immediately on startup, or soon after. To fix this, you will need to replace +``hack/libstdc++.6.dylib`` with a symlink to the ``libstdc++.6.dylib`` included +in your version of GCC:: + + cd /hack && mv libstdc++.6.dylib libstdc++.6.dylib.orig && + ln -s [PATH_TO_LIBSTDC++] . + +For example, with GCC 6.3.0, ``PATH_TO_LIBSTDC++`` would be:: + + /usr/local/Cellar/gcc@6/6.3.0/lib/gcc/6/libstdc++.6.dylib # for 64-bit DFHack + /usr/local/Cellar/gcc@6/6.3.0/lib/gcc/6/i386/libstdc++.6.dylib # for 32-bit DFHack + +**Note:** If you build with a version of GCC that requires this, your DFHack +build will *not* be redistributable. (Even if you copy the ``libstdc++.6.dylib`` +from your GCC version and distribute that too, it will fail on older OS X +versions.) For this reason, if you plan on distributing DFHack, it is highly +recommended to use GCC 4.8 or 7. + +.. _osx-m1-notes: + +Notes for M1 users +------------------ + +Alongside the above, you will need to follow these additional steps to get it +running on Apple silicon. + +Install an x86 copy of ``homebrew`` alongside your existing one. `This +stackoverflow answer `__ describes the +process. + +Follow the normal macOS steps to install ``cmake`` and ``gcc`` via your x86 copy of +``homebrew``. Note that this will install a GCC version newer than 7, so see +`osx-new-gcc-notes`. + +In your terminal, ensure you have your path set to the correct homebrew in +addition to the normal ``CC`` and ``CXX`` flags above:: + + export PATH=/usr/local/bin:$PATH + +Windows cross compiling from Linux (running DF inside docker) +============================================================= + +.. highlight:: bash + +You can use docker to build DFHack for Windows. These instructions were developed +on a Linux host system. + +.. contents:: + :local: + :depth: 1 + +Step 1: prepare a build container +--------------------------------- + +On your Linux host, install and run the docker daemon and then run these commands:: + + xhost +local:root + docker run -it --env="DISPLAY" --env="QT_X11_NO_MITSHM=1" --volume=/tmp/.X11-unix:/tmp/.X11-unix --user buildmaster --name dfhack-win ghcr.io/dfhack/build-env:master + +The ``xhost`` command and ``--env`` parameters are there so you can eventually +run Dwarf Fortress from the container and have it display on your host. + +Step 2: build DFHack +-------------------- + +The ``docker run`` command above will give you a shell prompt (as the ``buildmaster`` user) in the +container. Inside the container, run the following commands:: + + git clone https://github.com/DFHack/dfhack.git + cd dfhack + git submodule update --init + cd build + dfhack-configure windows 64 Release + dfhack-make + +Inside the ``dfhack-*`` scripts there are several commands that set up the wine +server. Each invocation of a Windows tool will cause wine to run in the container. +Preloading the wineserver and telling it not to exit will speed configuration and +compilation up considerably (approx. 10x). You can configure and build DFHack +with regular ``cmake`` and ``ninja`` commands, but your build will go much slower. + +Step 3: copy Dwarf Fortress to the container +-------------------------------------------- + +First, create a directory in the container to house the Dwarf Fortress binary and +assets:: + + mkdir ~/df + +If you can just download Dwarf Fortress directly into the container, then that's fine. +Otherwise, you can do something like this in your host Linux environment to copy an +installed version to the container:: + + cd ~/.steam/steam/steamapps/common/Dwarf\ Fortress/ + docker cp . dfhack-win:df/ + +Step 4: install DFHack and run DF +--------------------------------- + +Back in the container, run the following commands:: + + cd dfhack/build + cmake .. -DCMAKE_INSTALL_PREFIX=/home/buildmaster/df + ninja install + cd ~/df + wine64 "Dwarf Fortress.exe" + +Other notes +----------- + +Closing your shell will kick you out of the container. Run this command on your Linux +host when you want to reattach:: + + docker start -ai dfhack-win + +If you edit code and need to rebuild, run ``dfhack-make`` and then ``ninja install``. +That will handle all the wineserver management for you. + +Cross-compiling windows files for running DF in Steam for Linux +=============================================================== + +.. highlight:: bash + +If you wish, you can use Docker to build just the Windows files to copy to your +existing Steam installation on Linux. + +.. contents:: + :local: + :depth: 1 + +Step 1: Get dfhack, and run the build script +-------------------------------------------- + +Check out ``dfhack`` into another directory, and run the build script:: + + git clone https://github.com/DFHack/dfhack.git + cd dfhack + git submodule update --init --recursive + cd build + ./build-win64-from-linux.sh + +The script will mount your host's ``dfhack`` directory to docker, use it to +build the artifacts in ``build/win64-cross``, and put all the files needed to +install in ``build/win64-cross/output``. + +If you need to run ``docker`` using ``sudo``, run the script using ``sudo`` +rather than directly:: + + sudo ./build-win64-from-linux.sh + +Step 2: install dfhack to your Steam DF install +----------------------------------------------- +As the script will tell you, you can then copy the files into your DF folder:: + + # Optional -- remove the old hack directory in case we leave files behind + rm ~/.local/share/Steam/steamapps/common/"Dwarf Fortress"/hack + cp -r win64-cross/output/* ~/.local/share/Steam/steamapps/common/"Dwarf Fortress"/ + +Afterward, just run DF as normal. + +.. _note-offline-builds: + +Building DFHack Offline +======================= +As of 0.43.05, DFHack downloads several files during the build process, depending +on your target OS and architecture. If your build machine's internet connection +is unreliable, or nonexistent, you can download these files in advance. + +First, you must locate the files you will need. These can be found in the +`dfhack-bin repo `_. Look for the +most recent version number *before or equal to* the DF version which you are +building for. For example, suppose "0.43.05" and "0.43.07" are listed. You should +choose "0.43.05" if you are building for 0.43.05 or 0.43.06, and "0.43.07" if +you are building for 0.43.07 or 0.43.08. + +Then, download all of the files you need, and save them to ``/CMake/downloads/``. The destination filename you choose +does not matter, as long as the files end up in the ``CMake/downloads`` folder. +You need to download all of the files for the architecture(s) you are building +for. For example, if you are building for 32-bit Linux and 64-bit Windows, +download all files starting with ``linux32`` and ``win64``. GitHub should sort +files alphabetically, so all the files you need should be next to each other. + +.. note:: + + * Any files containing "allegro" in their filename are only necessary for + building `stonesense`. If you are not building Stonesense, you don't have to + download these, as they are larger than any other listed files. + +It is recommended that you create a build folder and run CMake to verify that +you have downloaded everything at this point, assuming your download machine has +CMake installed. This involves running a "generate" batch script on Windows, or +a command starting with ``cmake .. -G Ninja`` on Linux and macOS, following the +instructions in the sections above. CMake should automatically locate files that +you placed in ``CMake/downloads``, and use them instead of attempting to +download them. + +In addition, some packages used by DFHack are managed using CMake's ``FetchContent`` +feature, which requires an online connection during builds. The simplest way to address +this is to have a connection during the first build (during which CMake will download the +dependencies), and then to use CMake's ``FETCHCONTENT_FULLY_DISCONNECTED`` or +``FETCHCONTENT_UPDATES_DISCONNECTED`` defines to control how CMake manages cached +dependencies. If you need even the first-time build be an offline build, you will need +to provide a CMake dependency provider. We do not provide one, but CMake's own documentation +includes a simple provider. For more information about CMake's ``FetchContent`` feature +and how to use it in offline builds, see the +`CMake documentation `_. diff --git a/docs/dev/compile/Dependencies.rst b/docs/dev/compile/Dependencies.rst new file mode 100644 index 0000000000..b42a833785 --- /dev/null +++ b/docs/dev/compile/Dependencies.rst @@ -0,0 +1,303 @@ +.. _build-dependencies: + +############ +Dependencies +############ + +DFHack is meant to be installed into an **existing DF folder**, so ensure that +one is ready. + +.. contents:: Contents + :local: + :depth: 2 + +Overview of Dependencies +======================== + +This section provides an overview of system dependencies that DFHack relies on. +See the platform-specific sections later in this document for specifics on how +to install these dependencies. + +DFHack also has several dependencies on libraries that are included in the +repository as Git submodules, which require no further action to install. + +System dependencies +------------------- + + +* CMake (v3.21 or newer is recommended) +* build system (e.g. gcc & ninja, or Visual Studio) +* Perl 5 (for code generation) + * XML::LibXML + * XML::LibXSLT +* Python 3 (for `documentation `) + * Sphinx +* Git (required for `contributions `_) +* ccache (**optional**, but strongly recommended to improve build times) +* OpenGL headers (**optional**: to build `stonesense`) +* zlib (compression library used for `xlsxreader-api` -> `quickfort`) + +Perl packages +------------- + +* XML::LibXML +* XML::LibXSLT + +The Perl packages are used in code generation. DF memory structures are +represented as XML in DFHack's source tree. During the configuration process +(cmake) the xml files are converted into C++ headers and Lua wrappers for use +by plugins and scripts. + +Python packages +--------------- + +* Sphinx (required to build the `documentation `) + +Installing Dependencies +======================= + +.. contents:: + :local: + :depth: 2 + +.. _linux-dependency-instructions: + +Linux +----- + +Here are some package install commands for various distributions: + +* On Arch Linux:: + + pacman -Sy gcc cmake ccache ninja git dwarffortress zlib perl-xml-libxml perl-xml-libxslt + + * The ``dwarffortress`` package provides the necessary SDL packages. + * For the required Perl modules: ``perl-xml-libxml`` and ``perl-xml-libxslt`` (or through ``cpan``) + +* On Ubuntu:: + + apt-get install gcc cmake ccache ninja-build git zlib1g-dev libsdl2-dev libxml-libxml-perl libxml-libxslt-perl + + * Other Debian-based distributions should have similar requirements. + +* On Fedora:: + + yum install gcc-c++ cmake ccache ninja-build git zlib-devel SDL2-devel perl-core perl-XML-LibXML perl-XML-LibXSLT ruby + +To build DFHack, you need GCC 10 or newer. Note that extremely new GCC versions +may not have been used to build DFHack yet, so if you run into issues with +these, please let us know (e.g. by opening a GitHub issue). + +Distributing binaries compiled with newer GCC versions may result in +compatibility issues for players with older GCC versions. This is why DFHack +builds distributables with GCC 10, which is the same GCC version that DF itself +is compiled with. + +Before you can build anything, you'll also need ``cmake``. It is advisable to +also get ``ccmake`` (the interactive configuration interface) on distributions +that split the cmake package into multiple parts. As mentioned above, ``ninja`` +is recommended as the build system (many distributions call this package +``ninja-build``), but ``make`` also works. + +You will need pthread; most systems should have this already. Note that older +CMake versions may have trouble detecting pthread, so if you run into +pthread-related errors and pthread is installed, you may need to upgrade CMake, +either by downloading it from `cmake.org `_ or +through your package manager, if possible. + +.. _windows-dependency-instructions: + +Windows +------- + +DFHack must be built with the Microsoft Visual C++ 2022 toolchain (aka MSVC v143) +for ABI compatibility with Dwarf Fortress v50. + +.. contents:: + :local: + :depth: 1 + +With Chocolatey +~~~~~~~~~~~~~~~ +Many of the dependencies are simple enough to download and install via the +`chocolatey`_ package manager on the command line. + +Here are some package install commands:: + + choco install cmake + choco install ccache + choco install strawberryperl + choco install python + choco install sphinx + + # Visual Studio + choco install visualstudio2022community --params "--add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended" + # OR + # Build Tools for Visual Studio + choco install visualstudio2022buildtools --params "--add Microsoft.VisualStudio.Workload.NativeDesktop --includeRecommended" + +If you already have Visual Studio 2022 or the Build Tools installed, you may +need to modify the installed version to include the workload components +listed in the manual installation section, as chocolatey will not amend +the existing install. + +.. _chocolatey: https://chocolatey.org/install + +Manually +~~~~~~~~ +If you prefer to install manually rather than using Chocolatey, details and +requirements are as below. If you do install manually, **ensure that your PATH +variable is updated** to include the install locations for all tools. This can +be edited from ``Control Panel -> System -> Advanced System Settings -> +Environment Variables``. + +.. contents:: + :local: + :depth: 1 + +CMake +^^^^^ +You can get the Windows installer from `the official site `_. +It has the usual installer wizard. Make sure you let it add its binary folder +to your binary search PATH so the tool can be later run from anywhere. + +Perl / Strawberry Perl +^^^^^^^^^^^^^^^^^^^^^^ +For the code generation stage of the build process, you'll need Perl 5 with the +``XML::LibXML`` and ``XML::LibXSLT`` packages installed. +`Strawberry Perl `_ is recommended as it includes all +of the required packages in a single easy install. + +After install, ensure Perl is in your user's PATH. The following directories must be in your PATH, in this order: + +* ``\c\bin`` +* ``\perl\site\bin`` +* ``\perl\bin`` +* ``\perl\vendor\lib\auto\XML\LibXML`` (path may only be required on some systems) + +Be sure to close and re-open any existing ``cmd.exe`` windows after updating +your PATH. + +If you already have a different version of Perl installed (for example, from Cygwin), +you can run into some trouble. Either remove the other Perl install from PATH, or +install XML::LibXML and XML::LibXSLT for it using CPAN. + +Python +^^^^^^ +See the `Python`_ website. Any supported version of Python 3 will work. + +.. _Python: https://www.python.org/downloads/ + +Sphinx +^^^^^^ +See the `Sphinx`_ website. + +.. _Sphinx: https://www.sphinx-doc.org/en/master/usage/installation.html + +.. _install-visual-studio: + +Visual Studio +^^^^^^^^^^^^^ +The required toolchain can be installed as a part of either the `Visual Studio 2022 IDE`_ +or the `Build Tools for Visual Studio 2022`_. If you already have a preferred code +editor, the Build Tools will be a smaller install. You may need to log into (or create) +a Microsoft account in order to download Visual Studio. + +.. _Visual Studio 2022 IDE: https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community&channel=Release&version=VS2022&source=VSLandingPage&cid=2030&passive=false +.. _Build Tools for Visual Studio 2022: https://my.visualstudio.com/Downloads?q=Build%20Tools%20for%20Visual%20Studio%202022 + + +Build Tools [Without Visual Studio] +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Click `Build Tools for Visual Studio 2022`_ and you will be prompted to login to your Microsoft account. +Then you should be redirected to a page with various download options with 2022 +in their name. If this redirect doesn't occur, just copy, paste, and enter the +download link again and you should see the options. + +You want to select the most up-to-date version -- as of writing this is +"Build Tools for Visual Studio 2022 (version 17.4)". "LTSC" is an extended +support variant and is not required for our purposes. + +When installing, select the "Desktop Development with C++" workload and ensure that the following are checked: + +- MSVC v143 - VS 2022 C++ x64/x86 build tools +- C++ CMake tools for Windows +- At least one Windows SDK (for example, Windows 11 SDK 10.0.22621). + +.. _mac-dependency-instructions: + +macOS +----- + +NOTE: this section is currently outdated. Once DF itself can build on macOS +again, we will match DF's build environment and update the instructions here. + +DFHack is easiest to build on macOS with exactly GCC 4.8 or 7. Anything newer than 7 +will require you to perform extra steps to get DFHack to run (see `osx-new-gcc-notes`), +and your build will likely not be redistributable. + +#. Download and unpack a copy of the latest DF +#. Install Xcode from the Mac App Store + +#. Install the XCode Command Line Tools by running the following command:: + + xcode-select --install + +#. Install dependencies + + It is recommended to use Homebrew instead of MacPorts, as it is generally + cleaner, quicker, and smarter. For example, installing MacPort's GCC will + install more than twice as many dependencies as Homebrew's will, and all in + both 32-bit and 64-bit variants. Homebrew also doesn't require constant use + of ``sudo``. + + Using `Homebrew `_ (recommended):: + + brew tap homebrew/versions + brew install git + brew install cmake + brew install ninja + brew install gcc@7 + + Using `MacPorts `_:: + + sudo port install gcc7 +universal cmake +universal git-core +universal ninja +universal + + Macports will take some time - maybe hours. At some point it may ask + you to install a Java environment; let it do so. + +#. Install Perl dependencies + + * Using system Perl + + * ``sudo cpan`` + + If this is the first time you've run cpan, you will need to go through the setup + process. Just stick with the defaults for everything and you'll be fine. + + If you are running OS X 10.6 (Snow Leopard) or earlier, good luck! + You'll need to open a separate Terminal window and run:: + + sudo ln -s /usr/include/libxml2/libxml /usr/include/libxml + + * ``install XML::LibXML`` + * ``install XML::LibXSLT`` + + * In a separate, local Perl install + + Rather than using system Perl, you might also want to consider + the Perl manager, `Perlbrew `_. + + This manages Perl 5 locally under ``~/perl5/``, providing an easy + way to install Perl and run CPAN against it without ``sudo``. + It can maintain multiple Perl installs and being local has the + benefit of easy migration and insulation from OS issues and upgrades. + + See https://perlbrew.pl/ for more details. + +#. Install Python dependencies + + * You can choose to use a system Python 3 installation or any supported + version of Python 3 from `python.org `__. + + * Install `Sphinx`_ diff --git a/docs/dev/compile/Options.rst b/docs/dev/compile/Options.rst new file mode 100644 index 0000000000..462fd1f1ca --- /dev/null +++ b/docs/dev/compile/Options.rst @@ -0,0 +1,163 @@ +.. _build-options: + +############# +Build Options +############# + +.. contents:: Typical Options + :local: + :depth: 1 + +There are a variety of other settings which you can find in CMakeCache.txt in +your build folder or by running ``ccmake`` (or another CMake GUI). Most +DFHack-specific settings begin with ``BUILD_`` and control which parts of DFHack +are built. + +Typical usage may look like:: + + # Plugin development with updated documentation + cmake ./ -G Ninja -B builds/debug-info/ -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE:string=RelWithDebInfo -DBUILD_DOCS:bool=ON -DBUILD_PLUGINS=1 + # Core DFHack only + cmake ../ -G Ninja -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE:string=RelWithDebInfo -DBUILD_TESTS -DBUILD_DOCS:0 -DBUILD_PLUGINS=0 + +.. admonition:: Modifying Build Options + + You can typically run new cmake commands from your build directory to turn on/off options. + Of course the generator selection is not something you can change, but the rest are. + + Additionally, you can edit the build settings in CMakeCache.txt. You also have cmake's + configuration utility ``ccmake``. + +Generator +========= +For the uninitiated, the generator is what allows cmake to, of course, generate +visual studio solution & project files, a makefile, or anything else. +Your selection of generator comes down to preference and availability. + +Visual Studio +------------- +To generate visual studio project files, you'll need to select a particular version of +visual studio, and match that to your system's generator list viewed with ``cmake --help`` + +example:: + + cmake .. -G "Visual Studio 17 2022" + +Ninja +----- +The generally preferred build system where available. + +example:: + + cmake .. -G Ninja + +Install Location +================ +This is the location where DFHack will be installed. + +Variable: ``CMAKE_INSTALL_PREFIX`` + +Usage:: + + cmake .. -DCMAKE_INSTALL_PREFIX= + +The path to df will of course depend on your system. If the directory exists it is +recommended to use ``~/.dwarffortress`` to avoid permission troubles. + +Build type +========== +This is the type of build you want. This controls what information about symbols and +line numbers the debugger will have available to it. + +Variable: ``CMAKE_BUILD_TYPE`` + +Usage:: + + cmake .. -DCMAKE_BUILD_TYPE:string=RelWithDebInfo + +Options: + +* Release +* RelWithDebInfo + +Target architecture (32/64-bit) +=============================== +You can set this if you need 32-bit binaries or are looking to be explicit about +building 64-bit. + +Variable: ``DFHACK_BUILD_ARCH`` + +Usage:: + + cmake .. -DDFHACK_BUILD_ARCH=32 + +Options: + +* '32' +* '64' (default option) + +Library +======= +This will only be useful if you're looking to avoid building the library core, as it builds by default. + +Variable: ``BUILD_LIBRARY`` + +Usage:: + + cmake .. -DBUILD_LIBRARY:bool=OFF + cmake .. -DBUILD_LIBRARY=0 + +Testing +======= +Regression testing will be arriving in the future, but for now there are only tests written in lua. + +Variables: + +* ``BUILD_TESTING`` (will build unit tests, in the future) +* ``BUILD_TESTS`` (installs lua tests) + +Usage:: + + cmake .. -DBUILD_TESTS:bool=ON + cmake .. -DBUILD_TESTS=1 + +Plugins +======= +If you're doing plugin development. + +Variable: ``BUILD_PLUGINS`` + +Usage:: + + cmake .. -DBUILD_PLUGINS:bool=ON + cmake .. -DBUILD_PLUGINS=1 + +.. _building-documentation: + +Documentation +============= +If you need to build `documentation `. + +.. note:: + + These options are primarily useful for verifying that the end-to-end process + for building and packaging the documentation is working as expected. For + iterating on documentation changes, `faster alternatives ` are + available. + +Variables: + +* ``BUILD_DOCS``: enables the default documentation build +* ``BUILD_DOCS_NO_HTML``: disables the HTML documentation build (only builds the text documentation used in-game) + +Usage:: + + cmake .. -DBUILD_DOCS:bool=ON + cmake .. -DBUILD_DOCS=1 + cmake .. -DBUILD_DOCS_NO_HTML:bool=ON + cmake .. -DBUILD_DOCS_NO_HTML=1 + +The generated documentation is stored in ``docs/html`` and ``docs/text`` (respectively) +in the root DFHack folder, and they will both be installed to ``hack/docs`` when you +install DFHack. The html and txt files will intermingle, but will not interfere with +one another. diff --git a/docs/dev/compile/index.rst b/docs/dev/compile/index.rst new file mode 100644 index 0000000000..f9f6105ff6 --- /dev/null +++ b/docs/dev/compile/index.rst @@ -0,0 +1,15 @@ +.. _building-dfhack-index: + +=============== +Building DFHack +=============== + +Those seeking to compile the source code for DFHack, including core and plugins, +can refer to the following help pages. + +.. toctree:: + :maxdepth: 2 + + /docs/dev/compile/Dependencies + /docs/dev/compile/Compile + /docs/dev/compile/Options diff --git a/docs/dev/data-identity.rst b/docs/dev/data-identity.rst new file mode 100644 index 0000000000..ae7076941d --- /dev/null +++ b/docs/dev/data-identity.rst @@ -0,0 +1,246 @@ +.. _data_identity: + +########################### +DFHack Data Identity System +########################### + +This article is an attempt to describe DFHack's data identity system. +DFHack internally has a collection of C++ classes that provide metadata about the data in DF itself as well as data used +by various components of DFHack. This metadata is used primarily to enable the Lua scripting system to access data +held by Dwarf Fortress in a transparent manner, but is also used for several other purposes within DFHack, such as rerouting virtual method calls. + +The base class of the identity system is the class ``type_identity``, defined in :source:`DataDefs.h `. A ``type_identity`` object +provides information about one *type* of data object, in either Dwarf Fortress or DFHack, that can be manipulated as a discrete entity in Lua. +With one specific exception (``global_identity``, covered below), there is a one-to-one relationship between C++ types and ``type_identity`` objects. +In Lua, objects that are being managed via the data identity system are represented as a Lua userdata object. The userdata object +contains both a pointer to the C++ object itself and a pointer to a ``type_identity`` object that describes the data pointed +by that pointer. Note that the userdata object does not own the objects pointed to by these pointers, and the Lua engine is +never responsible for managing their lifetimes. + +``type_identity`` defines the following public methods: + +- ``byte_size``: returns the size, in bytes, of the object held + +- ``type``: returns an enum (of type ``identity_type``) classifying the object held. + +- ``getFullName``: returns a string that describes the type. This will usually be similar to a C++ ``typedef``, although this is not guaranteed. + +- ``lua_read``: Used by the Lua engine to "read" the data from a C++ object into the Lua state. + +- ``lua_write``: Used by the Lua engine to "write" a value from the Lua state into a C++ data object. + +- ``build_metatable``: Create a Lua metatable in the specified Lua state corresponding to this type identity. + +- ``is_primitive``: indicates that ``lua_read`` will store a *copy* of the object on the Lua stack instead of a non-owning reference to it. Used for types that have direct representations in Lua: numbers, booleans, simple strings + +- ``is_constructed``: indicates that creating a C++ instance of this type requires the use of a possibly nontrivial constructor. A type identity that is both primitive and constructed cannot be inserted into a container. At the moment the only type identity that is both primitive and constructed is ``stl_string_identity``, which wraps the C++ ``std::string`` type. + +- ``is_container``: indicates that the type is a container and thus implements the methods specific to ``container_identity`` + +- ``allocate``: allocate, and construct if necessary, a C++ instance of this type. This may fail if the type does not support construction. + +- ``copy``: copy the object at ``src`` onto ``tgt``. This uses ``memmove`` for primitive types, and C++ copy-assignment (when possible) for other types + +There are plethora of subclasses of ``type_identity``: + +* ``type_identity`` the abstract base class of all type identities + + * ``constructed_identity`` anything with an internal structure (not primitive) + + * ``compound_identity`` anything with fields + + * ``bitfield_identity`` a structure defined with fields at bit rather than byte boundaries + + * ``enum_identity`` C++ ``enum`` + + * ``struct_identity`` C++ ``class`` or ``structure`` + + * ``global_identity`` holds, as a quasiobject, handles for all of the known Dwarf Fortress program-scope static objects as if they were fields of an object called ``global`` + + * ``union_identity`` C++ ``union`` + + * ``other_vectors_identity`` special-case identity for the categorized subvectors of objects that appears in many of Dwarf Fortress's "handler" classes + + * ``virtual_identity`` polymorphic C++ ``class`` or ``structure`` having a virtual table to handle virtual dispatch + + * ``stl_string_identity`` ``std::string`` + + * ``xlsx_file_handle_identity`` special case + + * ``xlsx_sheet_handle_identity`` special case + + * ``container_identity`` "containers" generally. note that all container types are homogeneous (that is, the elements of the container must all be of the same type). abstract base class + + * ``bit_container_identity`` for containers that contain bools stored one element per *bit* (rather than per byte) + + * ``bit_array_identity`` Dwarf Fortress's ``BitArray`` type + + * ``stl_bit_vector_identity`` ``std::vector`` + + * ``buffer_container_identity`` C++ static arrays and raw C++ pointers acting as arrays of unspecified bound + + * ``enum_list_attr_identity`` (template) metaobject with metadata about a C++ enumeration; may also include additional metadata + + * ``ptr_container_identity`` containers that contain pointers + + * ``stl_ptr_container_identity`` containers that are of the form ``std::vector`` for some ``T`` + + * ``ro_stl_container_identity`` (template) "read only containers" + + * ``ro_stl_assoc_container_identity`` (template) ``std::map`` and ``std::unordered_map`` + + * ``stl_container_identity`` (template) ``std::vector`` where ``T`` is *not* a pointer (and not ``bool``) + + * ``opaque_identity`` opaque wrapper around any type, provides no functionality + + * ``stl_string_identity`` ``std::string`` + + * ``function_identity_base`` abstract base class for ``function_identity`` + + * ``function_identity`` (template) wrapper around a C++ function that can be invoked from Lua + + * ``primitive_identity`` wrapper around a primitive type. primitive types are fixed-length objects with no internal structure + + * ``bool_identity`` ``bool`` + + * ``number_identity_base`` abstract base for numeric types + + * ``float_identity_base`` abstract base for floating point types + + * ``float_identity`` (template) ``double`` and ``float`` + + * ``integer_identity_base`` abstract base for integral types + + * ``integer_identity`` (template) ``int8_t``, ``int16_t``, ``int32_t``, ``size_t``, etc. lots of these + + * ``pointer_identity`` any arbitrary C++ pointer (other than ``char*``) + + * ``ptr_string_identity`` C-style (``char *``) string + +Types marked with "(template)" are C++ template types, all parameterized by a single typename. + +Type identity object lifetime and mutability +============================================ + +*Most* instances of ``type_identity`` are statically constructed and immutable and are thus ``const static`` when constructed. +All ``type_identity`` pointers should be declared ``const``. Due to ``virtual_identity``'s role in implementing +DFHack's vmethod interpose system, it is important that there be at most one ``virtual_identity`` object per virtual class. +Having more than one ``struct_identity`` object for the same type might also potentially lead to misoperation. + +In general, there should be a one to one correspondence between ``type_identity`` objects and C++ types +(with the special case that ``global_identity`` has no corresponding type). As far as we know, for any type other than ``virtual_identity``, +violations of this constraint will not lead to misoperation, but this constraint should not be lightly violated. +The Lua/C++ interface does, in a handful of places, assume that it can compare ``type_identity`` +pointers to determine if they reference the same type, but as far as we know all of these instances will fall +back to correct behavior as long as the shadow copies are indistinguishable from one another; +that is, two copies having the same values will compare equal in all known such comparisons. +Therefore, if two ``type_identity`` objects do exist (for any reason) for the same underlying C++ type, +those objects must be indistinguishable from one another by anything other than their address. + +The ``type_identity`` object for a given C++ type can be obtained by using the ``get`` method of the ``df::identity_trait`` +trait class. +More specifically, ``identity_traits::get()`` will return a pointer to a ``type_identity`` object for the type ``T``. +Developers who create new type identities must *either* provide an specialization of ``identity_traits`` that implements +a ``get`` method that returns the correct ``type_identity`` +*or* ensure that a static instance of ``T::_identity`` exists for the type ``T`` +(which will result in a template in :source:`DataDefs.h ` providing +an implementation of ``get`` for that type). +Note that this is only possible for compound types, and is the way that the *vast* majority of +compound types have their identities specified (including all of those defined via codegen). + +Because objects in the Lua environment are constructed as a pointer to the data and +a pointer to the data's ``type_identity`` object, it is necessary for ``type_identity`` objects to have a lifetime +that exceeds the lifetime in the Lua environment of any object that exists anywhere in the Lua environment. +It is therefore advised to avoid creating ``type_identity`` objects that do *not* have program lifetime, since +predicting the lifetime of objects in the Lua environment can be difficult. +If it is necessary to create a ``type_identity`` object that will not have program lifetime, +it is incumbent on the developer to ensure that no references to that type identity object persist beyond its lifetime. + +Due to the way template types are implemented in the C++ compilers we use for Dwarf Fortress, any specialization of one +of the type identity classes noted above as a template must at present be statically constructed in the DFHack core. +This is because we export the statically constructed instances from the core library to plugins, which then imports them +from the core library instead of instantiating them locally. As a result, referencing an instance in a plugin that has +not been instantiated in the core will result in linkage errors when linking the plugin to the core library. + +We could instead *not* export the templated types, and thus their statically constructed identity objects, +and instead allow the compiler to instantiate a local copy of these instances while compiling a plugin, +but this would definitely result in a violation of the current requirement that there be at most one instance of the +type identity object for a given C++ type across the entire program (including plugins loaded as a shared library). + +For primitive and opaque types the static constructors of the identity types +are generally found in :source:`DataIdentity.h ` +or :source:`DataIdentity.cpp `. +Types defined by Dwarf Fortress are constructed in the header files and the related ``static*.inc`` files created by codegen, +which are included into DFHack via :source:`DataStatics.cpp `. + +Some plugins (e.g. :source:`blueprint `) also define their own type identities. Type identities in plugins should be used with caution, +because the DFHack plugin model allows plugins to be unloaded on request. +Since the ``type_identity`` object is constructed within the the plugin's address space, and Lua objects that reference +this ``type_identity`` object will hold a (borrowed) pointer to that object, +unloading the plugin will result in a dangling pointer reference within the Lua environment. +It is, at present, incumbent on plugin authors to ensure that they do not use plugin defined type identities on objects +that may persist in the Lua environment beyond the lifetime of the plugin. +Declaring a ``struct_identity`` in a plugin that is the child of another ``struct_identity`` will also result in +a potentially dangling reference to that identity in the ``child`` vector of the parent identity, which means this +must also be approached with caution. + +A final note: because most instances of ``type_identity`` are statically constructed +and their construction is scattered across multiple translation units, it is, in general, *not* safe to cross-reference +the contents of one statically-defined ``type_identity`` instance during the static instantiation of another, +because the order in which statically constructed objects are instantiated in C++ is unspecified for objects defined in different translation units. +Specifically, this means that the constructor for a ``type_identity`` instance must use care in using +``df::identity_traits::get`` to use values from the identity object +of some other type, because that type's identity object may not have been constructed yet. +The ``get`` operation itself is safe, but the pointer returned by ``get`` may point to not-yet-initialized data +until at-start static data initialization is fully complete. + +Namespaces +========== + +The type identity system formally lives in the ``DFHack`` namespace. +However, because the types created by the codegen process live in the ``df`` namespace, +the identities needed to describe types coming from Dwarf Fortress are also imported into the ``df`` namespace. +When defining a new ``type_identity`` class for the purposes of supporting a new category of types coming from codegen, +remember to add an appropriate ``using`` clause to the list in :source:`DataDefs.h `. + +The ``identity_traits``, ``enum_traits``, ``bitfield_traits``, and ``enum_fields`` type traits +are defined in the ``df`` namespace. + +Type traits +=========== + +``identity_traits`` +------------------- +This type trait has two members: + +* ``static const type_identity * get()``: This function returns a pointer to the ``type_identity`` for the type ``T``. +* ``is_primitive``: true if the type is a "primitive type" (except false for enums) + +While not a type trait *per se*, the ``allocate`` template function is defined for all types +as ``return (T*)identity_traits::get()->allocate()`` and provides a convenient way to +reference the allocator in a type's ``type_identity``. + +An additional note: Conceptually, ``Lua::Push`` and ``identity_traits::get->lua_read`` are equivalent, but this is aspirational rather than actual. +There are several types for which ``Lua::Push`` has specializations that do something different than what ``type_identity::lua_read`` does for the same type. + + +``enum_traits`` +--------------- +This type trait has the following members: + +* ``is_complex``: enum is a "complex enum" +* ``enum_type`` (type): the type of the enum +* ``base_type`` (type): the underlying integral type of the enum +* ``complex``: (complex enums only) an ``DFHack::enum_identity::ComplexData`` that describes the enum +* ``is_valid(base_type value)``: (simple enums only) a function that returns a bool indicating whether ``value`` is "in range" for the enum +* ``first_item``: (simple enums only) the least valid value of the enum +* ``last_item``: (simple enums only) the greatest valid value of the enum +* ``key_table``: (simple enums only) a static array of ``const char *`` strings that correspond to the possible values of the enum + +``bitfield_traits`` +------------------- +(TODO) + +``enum_fields`` +--------------- +(TODO) diff --git a/docs/dev/github-workflows.rst b/docs/dev/github-workflows.rst new file mode 100644 index 0000000000..ea71e1a2b6 --- /dev/null +++ b/docs/dev/github-workflows.rst @@ -0,0 +1,204 @@ +GitHub workflows +================ + +We run our continuous integration (CI) validation and our release automation +via GitHub workflows. This allows us to merge PRs with confidence that they +won't catastrophically break DFHack functionality. GitHub workflows also allow +us to quickly produce stable release builds with fewer manual steps. Reducing +manual steps for releases is important since it is easy for a person to forget +a small but impactful step and therefore produce a bad release that causes +trouble for our users. + +Background +---------- + +`GitHub workflows `_ run +on provisioned VMs in the cloud with stable environments that we specify. They +are free to use since DFHack is an open source project. They have proven to be +reliably available within a few seconds when our workflows are triggered. The +logic for the workflows is written in yaml, and the files that control our +workflows are stored in the :file:`.github/workflows/` directory in each of our +repos. Example: :source:`.github/workflows`. + +Each workflow contains metadata that specifies: +- when it `triggers `_ +- what `base environment `_ it uses (OS, pre-installed dependencies, etc.) +- what additional dependencies should be installed (if any) +- custom business logic + +Workflows run in the context of a single repo, but workflows defined in one +repo can inherit logic from workflows in other repos. All our common CI logic +is in the main DFHack/dfhack repo, but our submodules, like our ``scripts`` and +``df-structures`` repos, have CI workflows defined that inherit from the logic +in DFHack/dfhack. That way we can fix bugs and extend functionality in one +place and have it benefit the entire org tree. + +Caches +~~~~~~ + +GitHub also provides 10GB per repository for `caches `_. +We utilize the cache system to keep state between workflow runs, cache +downloads, and keep compiler output to speed up subsequent builds. Efficient +use of the cache system is a critical part of our workflow design. It allows us +to iterate on test failures in PRs in one minute instead of 20. It allows us to +put out an entire emergency release build in 5 minutes instead of 45. We have +tuned our build and test workflows to minimize spurious cache misses and keep +the fast path fast. + +Caches are namespaced by key prefixes, and we have one key prefix per build +context. For example, release builds on gcc-11 are kept in one cache namespace, +whereas test builds on gcc-11 are kept separate. MSVC release and test builds +similarly have their own namespaces. Each cache has a maximum size that is +enforced by the business logic that writes the cache data. + +In order to maintain consistency in a distributed environment, caches are +versioned. A workflow will read the latest version of the cache with its key +prefix, maybe modify the cache with new data, then write back a new version. +Caches that are not used for 2 weeks are purged from GitHub storage, but if a +repo goes over the 10GB limit, caches are deleted in LRU order until the repo +is under the storage limit again. + +CI workflows +------------ + +Build +~~~~~ + +The Build workflow is the main CI workflow. It runs on every PR and push to a +branch. The ``build.yml`` file is essentially an orchestration layer for the +logic in several other .yml files: + +- ``test.yml`` builds DFHack with the test suite enabled (but stonesense and + windows pdb files disabled) and runs the test suite. It is optimized for + speed and is intended to give PR authors quick feedback on their changes. + The test suite is executed in a real running DF game on both Linux and + Windows. The ``test`` job populates the ``test`` cache, which is used by many + other workflows for non-distributed builds. +- ``package.yml`` builds DFHack as it would be released: test suite disabled + but stonesense and windows pdb files enabled. The ``package`` job populates the ``release`` cache, which is used to build all distributed binaries. +- The ``docs`` target does a docs-only build of DFHack and reports any errors. + Doc errors would show up in the ``test`` and ``package`` builds anyway, but + the ``docs`` target runs very fast and can identify doc errors in less than + 1m. +- ``lint.yml`` runs the verification scripts in the ``ci`` directory. These + scripts check for common errors in the codebase that are not caught by the + compiler. The lint scripts are written in Python and shell script and are + intended to be run quickly and catch common errors. + +Check type sizes +~~~~~~~~~~~~~~~~ + +``check-type-sizes.yml`` is a df-structures-only workflow that checks for +changes in the sizes of types in the xml structures. It builds the +``xml-dump-type-sizes`` binary on both Linux and Windows for both the +structures in this PR and for the structures in the target merge branch. It +then runs the built binary on its native OS and compares the output. If any +type sizes have changed, the workflow generates a PR comment (via the +``comment-pr.yml`` workflow) with details. + +.. _workflows-release-automation: + +Release automation workflows +---------------------------- + +Watch DF Releases +~~~~~~~~~~~~~~~~~ + +This workflow runs every 8 minutes and checks the Steam metadata, the Itch +website, and the Bay 12 website for evidence of new releases. If a new release +is found, it generates an announcement in a private channel on the DFHack +Discord server. + +Inside the ``watch-df-releases.yml`` workflow, there are separate jobs for +watching Steam branches and watching the websites. For the Steam watcher, it +takes configuration for: + +- which branches to watch +- whether to kick off the Generate symbols workflow when a new release is found +- whether to autodeploy to Steam when the Generate symbols workflow completes + +The workflow has protections against concurrent runs, so if you suspect a new +release is out, you can manually trigger the workflow to check. If the cron +trigger happens to run the workflow at the same time, the second run will be +paused while the first run completes. + +Generate symbols +~~~~~~~~~~~~~~~~ + +This workflow can be triggered manually or by the Watch DF Releases workflow. +It downloads the specified DF version for the selected distribution platform(s) +and OS target(s), then updates the ``symbol-table`` entries in ``symbols.xml``. +If the distribution platform is Steam, it can also autodetect the DF version by +extracting the version string from the DF title screen data. + +For Linux, it always builds DFHack -- just the core library (no plugins) -- and +generates symbols via the `devel/dump-offsets` and `devel/scan-vtables` scripts. + +For Windows, we extract symbol data via static analysis, so the workflow only +builds DFHack if it needs to autodetect the DF version. + +Once the symbols.xml file is updated, the workflow commits the changes to the +specified df-structures branch and updates the xml submodule ref in the +specified DFHack/dfhack branch. If a deploy Steam branch is specified, it also +launches the Deploy to Steam workflow. + +Deploy to GitHub +~~~~~~~~~~~~~~~~ + +`github-release.yml `_ +can be triggered manually or automatically by creating a new release version +tag in git. It builds DFHack with the release configuration, packages the +aritifacts for GitHub, creates a new GitHub release, and uploads the packages +to the GitHub release page. + +It uses text in :source:`.github/release_template.md` to generate the release +notes, and appends the changelog contents for the tagged version. + +If you need to re-tag the release to fix a mistake, it will automatically run +again and replace the binaries attached to the GitHub release for the tagged +version. It will not overwrite the release notes, though, to preserve any edits +you may have made in the GitHub UI. If you *want* it to completely regenerate +the release notes, you can delete the release before you re-tag the version. + +GitHub releases end up here: https://github.com/DFHack/dfhack/releases. + +Deploy to Steam +~~~~~~~~~~~~~~~ + +`steam-deploy.yml `_ +can be triggered manually or automatically by creating a new release version +tag in git. It builds DFHack with the release configuration, packages the +aritifacts for Steam, and uploads them to the specified Steam branch. + +The workflow caches steamcmd to speed the deployment up by 30s or so. +Otherwise, steamcmd would have to be downloaded and updated every time the +workflow runs. + +Steam releases end up here: +https://partner.steamgames.com/apps/builds/2346660. The "version" you +specified for the workflow is used as the "description" for the build. + +Maintenance workflows +--------------------- + +Update submodules +~~~~~~~~~~~~~~~~~ + +`update-submodules.yml `_ +runs daily, or can be run manually as needed. It checks DFHack submodules for +new commits on the main branches and updates the submodule refs in the DFHack +develop branch. + +You generally should not run this workflow for anything other than the develop +branch, as it will overwrite any changes you have made to the submodule refs in +other branches. + +Clean up PR caches +~~~~~~~~~~~~~~~~~~ + +This workflow runs automatically whenever a PR is closed or merged. It removes +caches created for the PR so they don't take up quota. + +Note that if you merge a PR before all the workflows have completed, the caches +may be created after this workflow runs. In that case, the caches will be +orphaned and will be purged by GitHub's cache eviction policy after 2 weeks. diff --git a/docs/dev/index.rst b/docs/dev/index.rst new file mode 100644 index 0000000000..931b9bb006 --- /dev/null +++ b/docs/dev/index.rst @@ -0,0 +1,26 @@ + + +======================== +DFHack development guide +======================== + +These are pages relevant to people developing for DFHack. + +.. toctree:: + :maxdepth: 1 + + /docs/dev/Dev-intro + /docs/dev/compile/index + /docs/dev/Contributing + /docs/dev/Documentation + /docs/api/index + /docs/dev/Lua API + /docs/dev/overlay-dev-guide + /docs/dev/Structures-intro + /docs/dev/data-identity + /docs/dev/github-workflows + /docs/dev/release-process + /docs/dev/Memory-research + /docs/dev/Binpatches + /docs/dev/Remote + /docs/NEWS-dev diff --git a/docs/dev/overlay-dev-guide.rst b/docs/dev/overlay-dev-guide.rst new file mode 100644 index 0000000000..d87178bfff --- /dev/null +++ b/docs/dev/overlay-dev-guide.rst @@ -0,0 +1,461 @@ +.. _overlay-dev-guide: + +DFHack overlay dev guide +========================= + +.. highlight:: lua + +This guide walks you through how to build overlay widgets and register them with +the `overlay` framework for injection into Dwarf Fortress viewscreens. + +Why would I want to create an overlay widget? +--------------------------------------------- + +There are both C++ and Lua APIs for creating viewscreens and drawing to the +screen. If you need very specific low-level control, those APIs might be the +right choice for you. However, here are some reasons you might want to implement +an overlay widget instead: + +#. You can draw directly to an existing viewscreen instead of creating an + entirely new screen on the viewscreen stack. This allows the original + viewscreen to continue processing uninterrupted and keybindings bound to + that viewscreen will continue to function. This was previously only + achievable by C++ plugins. +#. You'll get a free UI for enabling/disabling your widget and repositioning it + on the screen. Widget state is saved for you and is automatically restored + when the game is restarted. +#. You don't have to manage the C++ interposing logic yourself and can focus on + the business logic, writing purely in Lua if desired. + +In general, if you are writing a plugin or script and have anything you'd like +to add to an existing screen (including live updates of map tiles while the game +is unpaused), an overlay widget is probably your easiest path to get it done. If +your plugin or script doesn't otherwise need to be enabled to function, using +the overlay allows you to avoid writing any of the enable or lifecycle +management code that would normally be required for you to show info in the UI. + +Overlay widget API +------------------ + +Overlay widgets are Lua classes that inherit from ``overlay.OverlayWidget`` +(which itself inherits from `widgets.Panel `). The regular +``onInput(keys)``, ``onRenderFrame(dc, frame_rect)``, and ``onRenderBody(dc)`` +functions work as normal, and they are called when the viewscreen that the +widget is associated with does its usual input and render processing. The widget +gets first dibs on input processing. If a widget returns ``true`` from its +``onInput()`` function, the viewscreen will not receive the input. + +Overlay widgets can contain other Widgets and be as simple or complex as you +need them to be, just like you're building a regular UI element. + +There are a few extra capabilities that overlay widgets have that take them +beyond your everyday `widgets.Widget `: + +- If an ``overlay_onupdate(viewscreen)`` function is defined, it will be called + just after the associated viewscreen's ``logic()`` function is called (i.e. + a "tick" or a (non-graphical) "frame"). For hotspot widgets, this function + will also get called after the top viewscreen's ``logic()`` function is + called, regardless of whether the widget is associated with that viewscreen. + If this function returns ``true``, then the widget's ``overlay_trigger()`` + function is immediately called. Note that the ``viewscreen`` parameter will + be ``nil`` for hotspot widgets that are not also associated with the current + viewscreen. +- If an ``overlay_trigger()`` function is defined, will be called when the + widget's ``overlay_onupdate`` callback returns true or when the player uses + the CLI (or a keybinding calling the CLI) to trigger the widget. The + function must return either ``nil`` or the ``gui.Screen`` object that the + widget code has allocated, shown, and now owns. Hotspot widgets will receive + no callbacks from unassociated viewscreens until the returned screen is + dismissed. Unbound hotspot widgets **must** allocate a Screen with this + function if they want to react to the ``onInput()`` feed or be rendered. The + widgets owned by the overlay framework must not be attached to that new + screen, but the returned screen can instantiate and configure any new views + that it wants to. See the `hotkeys` DFHack logo widget for an example. + + The ``overlay_trigger()`` function enables the activation of overlay widgets + via the command line interface (CLI) or keybindings. + For example, executing ``overlay trigger notes.map_notes add Kitchen``:: + + function MyOverlayWidget:overlay_trigger(arg1, arg2) + if arg1 == 'add' then + -- Add a new note to the map + self:addSomething(arg2) + elseif arg1 == 'delete' then + self:deleteSomething(arg2) + end + end + + This allows for dynamic updates to UI overlays directly from the CLI. +- If an ``overlay_onenable()`` function is defined, it is called when the + overlay is enabled (including when the persisted state is reloaded at DF + startup). +- If an ``overlay_ondisable()`` function is defined, it is called when the + overlay is disabled. + +If the widget can take up a variable amount of space on the screen, and you want +the widget to adjust its position according to the size of its contents, you can +modify ``self.frame.w`` and ``self.frame.h`` at any time -- in ``init()`` or in +any of the callbacks -- to indicate a new size. The overlay framework will +detect the size change and adjust the widget position and layout. + +If you don't need to dynamically resize, just set ``self.frame.w`` and +``self.frame.h`` once in ``init()`` (or just leave them at the defaults). If +you don't need to render a widget on the screen at all, set your frame width +and/or height to 0. Your ``render`` function will still be called, but no +repositioning frame will be shown for the overlay in `gui/overlay`. + +Widget attributes +***************** + +The ``overlay.OverlayWidget`` superclass defines the following class attributes: + +- ``name`` + This will be filled in with the display name of your widget, in case you + have multiple widgets with the same implementation but different + configurations. You should not set this property yourself. +- ``version`` + You can set this to any string. If the version string of a loaded widget + does not match the saved settings for that widget, then the configuration + for the widget (position, enabled status) will be reset to defaults. +- ``desc`` + A short (<100 character) description of what the overlay does. This text + will be displayed in `gui/control-panel` on the "Overlays" tab. +- ``default_pos`` (default: ``{x=-2, y=-2}``) + Override this attribute with your desired default widget position. See + the `overlay` docs for information on what positive and negative numbers + mean for the position. Players can change the widget position at any time + via the `overlay position ` command, so don't assume that your + widget will always be at the default position. +- ``default_enabled`` (default: ``false``) + Override this attribute if the overlay should be enabled by default if it + does not already have a state stored in ``dfhack-config/overlay.json``. +- ``viewscreens`` (default: ``{}``) + The list of viewscreens that this widget should be associated with. When + one of these viewscreens is on top of the viewscreen stack, your widget's + callback functions for update, input, and render will be interposed into the + viewscreen's call path. The name of the viewscreen is the name of the DFHack + class that represents the viewscreen, minus the ``viewscreen_`` prefix and + ``st`` suffix. For example, the fort mode main map viewscreen would be + ``dwarfmode`` and the adventure mode map viewscreen would be + ``dungeonmode``. If there is only one viewscreen that this widget is + associated with, it can be specified as a string instead of a list of + strings with a single element. If you only want your widget to appear in + certain contexts, you can specify a focus path, in the same syntax as the + `keybinding` command. For example, ``dwarfmode/Info/CREATURES/CITIZEN`` will + ensure the overlay widget is only displayed when the "Citizens" subtab under + the "Units" panel is active. +- ``hotspot`` (default: ``false``) + If set to ``true``, your widget's ``overlay_onupdate`` function will be + called whenever the `overlay` plugin's ``plugin_onupdate()`` function is + called (which corresponds to one call per call to the current top + viewscreen's ``logic()`` function). This call to ``overlay_onupdate`` is in + addition to any calls initiated from associated interposed viewscreens and + will come after calls from associated viewscreens. +- ``fullscreen`` (default: ``false``) + If set to ``true``, no widget frame will be drawn in `gui/overlay` for drag + and drop repositioning. Overlay widgets that need their frame positioned + relative to the screen and not just the scaled interface area should set + this to ``true``. +- ``full_interface`` (default: ``false``) + If set to ``true``, no widget frame will be drawn in `gui/overlay` for drag + and drop repositioning. Overlay widgets that need access to the whole + scaled interface area should set this to ``true``. +- ``overlay_onupdate_max_freq_seconds`` (default: ``5``) + This throttles how often a widget's ``overlay_onupdate`` function can be + called (from any source). Set this to the largest amount of time (in + seconds) that your widget can take to react to changes in information and + not annoy the player. Set to 0 to be called at the maximum rate. Be aware + that running more often than you really need to will impact game FPS, + especially if your widget can run while the game is unpaused. If you change + the value of this attribute dynamically, it may not be noticed until the + previous timeout expires. However, if you need a burst of high-frequency + updates, set it to ``0`` and it will be noticed immediately. + +Common widget attributes such as ``active`` and ``visible`` are also respected. +Note that those properties are checked *after* matching ``viewscreens`` focus +string(s), so you can assume they are evaluated in an consistent context. For +example, if your widget has ``viewscreens='dwarfmode/Trade/Default'``, then you +can assume your ``visible=function() ... end`` function will be executing while +the trade screen is active. + +Registering a widget with the overlay framework +*********************************************** + +Anywhere in your code after the widget classes are declared, define a table +named ``OVERLAY_WIDGETS``. The keys are the display names for your widgets and +the values are the widget classes. For example, the `dwarfmonitor` widgets are +declared like this:: + + OVERLAY_WIDGETS = { + cursor=CursorWidget, + date=DateWidget, + misery=MiseryWidget, + weather=WeatherWidget, + } + +When the `overlay` plugin is enabled, it scans all plugins and scripts for +this table and registers the widgets on your behalf. Plugin lua code is loaded +with ``require()`` and script lua code is loaded with ``reqscript()``. +If your widget is in a script, ensure your script can be +`loaded as a module `, or else the widget will not be discoverable. +Whether the widget is enabled and the widget's position is restored according +to the state saved in the :file:`dfhack-config/overlay.json` file. + +The overlay framework will instantiate widgets from the named classes and own +the resulting objects. The instantiated widgets must not be added as subviews to +any other View, including the Screen views that can be returned from the +``overlay_trigger()`` function. + +Performance considerations +************************** + +Overlays that do any processing or rendering during unpaused gameplay (that is, +nearly all of them) must be developed with performance in mind. DFHack has an +overall service level objective of no more than 10% performance impact during +unpaused gameplay with all overlays and background tools enabled. A single +overlay should seek to take up no more than a fraction of 1% of elapsed +gameplay time. + +Please see the Core `performance-monitoring` section for details on how to get +a perf report while testing your overlay. The metric that you will be +interested in is the percentage of elapsed time that your overlay accounts for. + +If you need to improve performance, here are some potential options: + +1. Shard scanning over multiple passes. For example, instead of checking every + item on the map in every update in your overlay, only check every Nth item + and change the start offset every time you scan. + +2. Reduce the frequency of state updates by moving calcuations to + ``overlay_onupdate`` and setting the value of the + ``overlay_onupdate_max_freq_seconds`` attribute appropriately + +3. Move hotspots into C++ code, either in a new core library function or in a + dedicated plugin + +Overlay framework API +--------------------- + +The overlay plugin Lua interface provides a few functions for interacting with +the framework. You can get a reference to the API via:: + + local overlay = require('plugins.overlay') + +* ``overlay.rescan()`` + + Rescans all module-loadable Lua scripts for registered overlays and loads + updated widget definitions. + +* ``overlay.isOverlayEnabled(name)`` + + Returns whether the overlay with the given name is enabled. + +Development workflows +--------------------- + +When you are developing an overlay widget, you will likely need to reload your +widget many times as you make changes. The process for this differs slightly +depending on whether your widget is attached to a plugin or is implemented in a +script. + +Note that reloading a script does not clear its global environment. This is fine +if you are changing existing functions or adding new ones. If you remove a +global function or other variable from the source, though, it will stick around +in your script's global environment until you restart DF or run +`devel/clear-script-env`. + +Scripts +******* + +#. Edit the widget source +#. If the script is not in your `script-paths`, install your script (see the + `modding-guide` for help setting up a dev environment so that you don't need + to reinstall your scripts after every edit). +#. Call ``:lua require('plugins.overlay').rescan()`` to reload your overlay + widget + +Plugins +******* + +#. Edit the widget source +#. Install the plugin so that the updated code is available in + :file:`hack/lua/plugins/` +#. If you have changed the compiled plugin, `reload` it +#. If you have changed the lua code, run ``:lua reload('plugins.mypluginname')`` +#. Call ``:lua require('plugins.overlay').rescan()`` to reload your overlay + widget + +Troubleshooting +--------------- + +You can check that your widget is getting discovered by the overlay framework +by running ``overlay list`` or by launching `gui/control-panel` and checking +the ``Overlays`` tab. + +**If your widget is not listed, double check that:** + +#. ``OVERLAY_WIDGETS`` is declared, is global (not ``local``), and references + your widget class +#. (if a script) your script is `declared as a module ` + (``--@ module = true``) and it does not have side effects when loaded as a + module (i.e. you check ``dfhack_flags.module`` and return before executing + any statements if the value is ``true``) +#. your code does not have syntax errors -- run + ``:lua ~reqscript('myscriptname')`` (if a script) or + ``:lua ~require('plugins.mypluginname')`` (if a plugin) and make sure there + are no errors and the global environment contains what you expect. + +**If your widget is not running when you expect it to be running,** run +`gui/overlay` when on the target screen and check to see if your widget is +listed when showing overlays for the current screen. If it's not there, verify +that this screen is included in the ``viewscreens`` list in the widget class +attributes. Also, load `gui/control-panel` and make sure your widget is enabled. + +Widget example 1: adding text to a DF screen +-------------------------------------------- + +This is a simple widget that displays a message at its position. The message +text is retrieved from the host script or plugin every ~20 seconds or when +the :kbd:`Alt`:kbd:`Z` hotkey is hit:: + + local overlay = require('plugins.overlay') + local widgets = require('gui.widgets') + + MessageWidget = defclass(MessageWidget, overlay.OverlayWidget) + MessageWidget.ATTRS{ + desc='Sample widget that displays a message on the screen.', + default_pos={x=5,y=-2}, + default_enabled=true, + viewscreens={'dwarfmode', 'dungeonmode'}, + overlay_onupdate_max_freq_seconds=20, + } + + function MessageWidget:init() + self:addviews{ + widgets.Label{ + view_id='label', + text='', + }, + } + end + + function MessageWidget:overlay_onupdate() + local text = getImportantMessage() -- defined in the host script/plugin + self.subviews.label:setText(text) + self.frame.w = #text + end + + function MessageWidget:onInput(keys) + if keys.CUSTOM_ALT_Z then + self:overlay_onupdate() + return true + end + return MessageWidget.super.onInput(self, keys) + end + + OVERLAY_WIDGETS = {message=MessageWidget} + +Widget example 2: highlighting artifacts on the live game map +------------------------------------------------------------- + +This widget is not rendered at its "position" at all, but instead monitors the +map and overlays information about where artifacts are located. Scanning for +which artifacts are visible on the map can slow, so that is only done every 10 +seconds to avoid slowing down the entire game on every frame. + +:: + + local overlay = require('plugins.overlay') + local widgets = require('gui.widgets') + + ArtifactRadarWidget = defclass(ArtifactRadarWidget, overlay.OverlayWidget) + ArtifactRadarWidget.ATTRS{ + desc='Sample widget that highlights artifacts on the game map.', + default_enabled=true, + viewscreens={'dwarfmode', 'dungeonmode'}, + frame={w=0, h=0}, + overlay_onupdate_max_freq_seconds=10, + } + + function ArtifactRadarWidget:overlay_onupdate() + self.visible_artifacts_coords = getVisibleArtifactCoords() + end + + function ArtifactRadarWidget:onRenderFrame() + for _,pos in ipairs(self.visible_artifacts_coords) do + -- highlight tile at given coordinates + end + end + + OVERLAY_WIDGETS = {radar=ArtifactRadarWidget} + +Widget example 3: corner hotspot +-------------------------------- + +This hotspot reacts to mouseover events and launches a screen that can react to +input events. The hotspot area is a 2x2 block near the lower right corner of the +screen (by default, but the player can move it wherever). + +:: + + local overlay = require('plugins.overlay') + local widgets = require('gui.widgets') + + HotspotMenuWidget = defclass(HotspotMenuWidget, overlay.OverlayWidget) + HotspotMenuWidget.ATTRS{ + desc='Sample widget that reacts to mouse hover.', + default_pos={x=-3,y=-3}, + default_enabled=true, + frame={w=2, h=2}, + hotspot=true, + viewscreens='dwarfmode', + overlay_onupdate_max_freq_seconds=0, -- check for mouseover every tick + } + + function HotspotMenuWidget:init() + -- note this label only gets rendered on the associated viewscreen + -- (dwarfmode), but the hotspot is active on all screens + self:addviews{widgets.Label{text={'!!', NEWLINE, '!!'}}} + self.mouseover = false + end + + function HotspotMenuWidget:overlay_onupdate() + local hasMouse = self:getMousePos() + if hasMouse and not self.mouseover then -- only trigger on mouse entry + self.mouseover = true + return true + end + self.mouseover = hasMouse + end + + function HotspotMenuWidget:overlay_trigger() + return MenuScreen{hotspot_frame=self.frame}:show() + end + + OVERLAY_WIDGETS = {menu=HotspotMenuWidget} + + MenuScreen = defclass(MenuScreen, gui.ZScreen) + MenuScreen.ATTRS{ + focus_path='hotspot/menu', + hotspot_frame=DEFAULT_NIL, + } + + function MenuScreen:init() + self.mouseover = false + + -- derive the menu frame from the hotspot frame so it + -- can appear in a nearby location + local frame = copyall(self.hotspot_frame) + -- ... + + self:addviews{ + widgets.Window{ + frame=frame, + autoarrange_subviews=true, + subviews={ + -- ... + }, + }, + }, + } + end diff --git a/docs/dev/release-process.rst b/docs/dev/release-process.rst new file mode 100644 index 0000000000..bef09be412 --- /dev/null +++ b/docs/dev/release-process.rst @@ -0,0 +1,209 @@ +Release process +=============== + +This page details the process we follow for beta and stable releases. + +For documentation on the related GitHub workflows, see +`workflows-release-automation`. + +Beta release +------------ + +This process pushes a pre-release build to GitHub and Steam. It is intended to +be lower-toil than the stable release process and allows us to facilitate +frequent public testing and feedback without compromising the stability of our +"stable" releases. + +1. Run the `Update submodules `_ GitHub action on the ``develop`` branch to ensure that all submodules are up to date. + +2. Update version strings in :source:`CMakeLists.txt` as appropriate. Set ``DFHACK_RELEASE`` to the *next* stable release version with an "rc#" suffix. For example, if the last stable release was "r1" then set the string to "r2rc1". If we do a second beta release before the final stable "r2" then the string would be "r2rc2". + + - Ensure the ``DFHACK_PRERELEASE`` flag is set to ``TRUE``. + - Commit and push to ``develop`` + - Set ``RELEASE`` in your environment for the commands below (e.g. ``RELEASE=51.07-r2rc1`` for bash) + +3. Tag ``develop`` (no need to tag the submodules) and push: ``git tag -a $RELEASE -m "Bump to $RELEASE"; git push --tags origin`` + + - This will automatically trigger `Deploy to Steam `_ and `Deploy to GitHub `_ build workflows. + +4. Write release notes highlights and any requests for feedback in the `draft GitHub release `_ and publish the draft. + +5. Associate release notes with the build on Steam + + - Go to the `announcement creation page `_ + - Select "A game update" + - Select "Small update / Patch notes" + - Set the "Event title" to the release version (e.g. "DFHack 51.07-r2rc1") + - Set the "Subtitle" to "DFHack pre-release (beta channel)" + - Mention release highlights in the "Summary" field + - Transcode release notes from the GitHub release into the "Event description" field + - patch notes must be in BBcode; see `converting-markdown-to-bbcode` below for how to convert our release notes to BBcode + - Click "Link to build" and select the staging branch (be sure the build has been deployed to the branch first. By the time you're done with the patch notes the build will likely be ready for you) + - Go to the Artwork tab, select "Previously uploaded images", and search for and double-click on dfhack_logo.png. Click "Upload" (even though it has already been uploaded). + - Switch to the "Publish" tab and publish! + - `Promote `_ the build to the "beta" branch (and the "testing" branch if it's newer than what is on the "testing" branch) + +6. Monitor for beta channel subscriber feedback on the Steam `community page `_ + +7. *Maybe* also post to Reddit and other announcement channels if we feel like we need to recruit more beta testers into the pool, but we should avoid posting so often that it is annoying for those who don't use Steam or just want announcements for stable releases. + +Stable release +-------------- + +This process creates a stable DFHack release meant for widespread distribution. +Stable releases come in two forms: straight from ``develop`` or from a point +release branch. + +During "normal" times, we will test out new features in beta releases until we +reach a point of stability. Then, after the ``develop`` branch is feature frozen +while we polish and fix bugs, we tag a release directly from ``develop`` +``HEAD``. + +However, if we have already started committing beta features to ``develop`` and +it becomes necessary to put out a bugfix release for a problem in an +already-released stable release, then we will create a new branch from the +stable tag, cherry-pick fixes from ``develop`` onto that branch, and spin a +release from there. After the point release is published, we'll merge the +branch back into ``develop`` and remove the release branch to clean up. + +1. Triage remaining issues/PRs in the `release project `_ + + - Don't feel pressure to merge anything risky just before a stable release. That's what beta releases are for. + +2. In your local clone of the ``DFHack/develop`` branch, make sure your checkout and all submodules (listed in :source:`.gitmodules`) are up to date with their latest public commits and have no uncommitted/unpushed local changes. + +3. Ensure that CI has not failed unexpectedly on the latest online changes: + + - https://github.com/DFHack/dfhack/commits/develop + - https://github.com/DFHack/scripts/commits/master + - https://github.com/DFHack/df-structures/commits/master + +4. Update version strings in :source:`CMakeLists.txt` as appropriate + + - Ensure the ``DFHACK_PRERELEASE`` flag is set to ``FALSE``. + - Set ``RELEASE`` in your environment for the commands below (e.g. ``RELEASE=51.07-r1``) + +5. Replace "Future" with the version number and clean up changelog entries; add new "Future" section (with headers pre-populated from the template at the top of the file): + + - ``docs/changelog.txt`` + - ``scripts/changelog.txt`` + - ``library/xml/changelog.txt`` + - ``plugins/stonesense/docs/changelog.txt`` + +6. Do a top-level build to ensure the docs build cleanly + +7. Commit/push changes to submodules and tag (``git tag -a $RELEASE -m "Bump to $RELEASE"; git push --tags origin master``) + + - ``scripts`` + - ``library/xml`` + - ``plugins/stonesense`` + +8. Commit and push changes to ``develop`` + + - Ensure that any updates you pushed to submodules are tracked in the commit to ``DFHack/develop`` + +9. Tag ``dfhack``: ``git tag -a $RELEASE -m "Bump to $RELEASE"; git push --tags origin develop`` + + - This will automatically trigger a `Deploy to Steam `_ GitHub action to the "staging" Steam branch and a `Deploy to GitHub `_ GitHub action to create a draft `release `_ from a template and attach the built artifacts. + +10. Switch to the Steam ``staging`` release channel in the Steam client (password: ``stagingstagingstaging``) and download/test the update. + + - Ensure DFHack starts DF when run from the Steam client + - Ensure the DFHack version string is accurate on the title page (should just be the release number, e.g. ``DFHack 51.07-r1``, with no git hash or warnings) + - Run `devel/check-release` + - If something goes wrong with this step, fix it, delete the tag (both from `GitHub `_ and locally (``git tag -d $RELEASE``)), re-tag, re-push, and re-test. Note that you do *not* need to remove the GitHub draft release -- the existing one will just get updated with the new tag and binaries. You *can* remove the draft release, though, if you want the release notes to get regenerated. + +11. Prep release on GitHub + + - Go to the draft `release `_ on GitHub + - Add announcements, highlights (with demo videos), etc. to the description + +12. Push develop to master (``git push origin develop:master``) + + - This will start the documentation build process and update the published "stable" docs + - Note that if this is a -r1 release, you won't be able to complete this step until a classic build is available on the Bay 12 website so the DFHack Test workflow can pass, which is a prerequisite for being able to push to ``master``. + +13. Post release notes on Steam + + - Go to the `announcement creation page `_ + - Select "A game update" + - Select "Regular update" + - Set the "Event title" to the release version (e.g. "DFHack 51.07-r1") + - Set the "Subtitle" to "DFHack stable release" + - Add list of highlights (and maybe announcements, if significant) to the "Summary" field + - Upload screenshots and demo videos via the button at the bottom of the "Previously uploaded videos" area + - Add release notes to the "Event description" field (must be in BBcode; see `converting-markdown-to-bbcode` below for how to convert our release notes to BBcode) + - Drag uploaded images/videos into their appropriate places in the announcement text (replace the GitHub URL tags, which won't work from Steam) + - If the generated release notes exceed the announcement length limits, add a link to the GitHub release page at the bottom of the announcement instead + - Click "Link to build" and select the staging branch (be sure the build has been deployed to the branch first. by the time you're done with the patch notes the build will likely be ready for you) + - the release notes will travel with the build when we promote it to other branches + - Go to the Artwork tab, select "Previously uploaded images", and search for and double-click on STABLEannouncement6.png. Click "Upload" (even though it has already been uploaded). + - Switch to the "Publish" tab and publish! + +14. Go to the `Steam builds page `_ and promote the build to the "default" branch + + - For the build that you just pushed to "staging", click the "-- Select an app branch --" drop-down and select "default" + - Click on "Preview Change" + - Commit the change (you may need to verify with 2FA) + - If the release is newer than what's on the ``beta`` and/or ``testing`` branches, set it live on those branches as well + +15. Publish the prepped GitHub release + +16. Send out release announcements + + - Announce new version in r/dwarffortress. Example: https://www.reddit.com/r/dwarffortress/comments/1i3l5xl/dfhack_5015r2_released_highlights_stonesense/ + - Create the post in the Reddit web interface; the mobile app is extremely painful to use for posting + - Do an "Images & Video" post, sample title: "DFHack 51.07-r1 released! Hilights: Open legends mode directly from an active fort, Dig through warm or damp tiles without interruption, Unlink buildings from levers" + - Add the animated gifs to the post (with appropriate captions naming the relevant tool and what is being demonstrated) + - Add the "DFHack Official" flair to the post. If you're not a r/dwarffortress mod, ask Myk to do this after posting. + - After posting, add each section of the release notes as its own comment, splitting out individual announcements and highlights. This gives people the opportunity to respond directly to the portion of the release notes that interests them; it also helps us avoid size limits for comments. You can include a single still shot (.png file) per comment, but you have to switch to "Fancy Pants Editor" to do it. You can only switch editors once, or the image will get messed up (that is, the image will turn into a hyperlink to an image). Suggested procedure is to prepare the comment in markdown, switch to Fancy Pants Editor, and add images just before submitting the comment. + - Announce new version in forum thread. Example: http://www.bay12forums.com/smf/index.php?topic=164123.msg8567134#msg8567134 + - Update latest version text and link in `first post `_ (if you are not Lethosor, ping Lethosor for this) + - Announce in `#announcements `_ on DFHack Discord + - Announce in `#mod-releases `_ on Kitfox Discord + - Change the name of the release thread on Kitfox Discord to match the release version (if you are not Myk, ping Myk for this) + +17. Monitor all announcement channels for feedback and respond to questions/complaints + +18. Create a `project `_ on GitHub in the DFHack org for the next release + + - Open the `project template `_ + - Click "Use this template" + - Name the project according to the version, e.g. "51.07-r2" and click "Use template" + - In the new project, select settings and set the visibility to Public + - Move any remaining To Do or In Progress items from last release project to next release project + - Close project for last release + +19. If this is a -r2 release or later, go to https://readthedocs.org/projects/dfhack/versions/ and "Edit" previous DFHack releases for the same DF version and mark them "Hidden" (keep the "Active" flag set) so they no longer appear on the docs version selector. + +.. _converting-markdown-to-bbcode: + +Converting Markdown to BBcode +----------------------------- + +Hopefully we can `automate `_ this in the future, but for now, here is the procedure: + +1. Get the markdown that you want to convert into some field on GitHub (can be a temporary text field that you then preview without saving) + +2. View the rendered release notes in your browser (these instructions are for Chrome, but other browsers probably have similar capabilities) + +3. Right click on the rendered text and inspect the DOM + +4. Copy the HTML element that contains the release notes + +5. Click on the "Import HTML" button on the Steam announcement form; paste in the HTML and click "Overwrite" + +6. Copy the generated BBCode out from the description field and into a text editor + +7. Fix it up: + + - Remove the "How do I download DFHack?" section -- people on Steam don't need it + - Some ``

`` elements aren't converted properly and need to be rewritten with square brackets + - Any monospaced text gets HTML tags instead of BBCode ``[code]`` tags, but you can't use them either since they force newlines. ``[tt]`` isn't supported. Any ```` tags just need to be removed entirely. + - Any ``
`` and ```` tags need to be removed + +8. Copy it all back into the description field for the announcement + +9. Click on "Preview event" to double check that it renders sanely + +10. You're done. diff --git a/docs/guides/examples-guide.rst b/docs/guides/examples-guide.rst deleted file mode 100644 index 4300f412de..0000000000 --- a/docs/guides/examples-guide.rst +++ /dev/null @@ -1,272 +0,0 @@ -.. _dfhack-examples-guide: - -DFHack Example Configuration File Guide -======================================= - -The :source:`hack/examples ` folder contains ready-to-use -examples of various DFHack configuration files. You can use them by copying them -to appropriate folders where DFHack and its plugins can find them (details -below). You can use them unmodified, or you can customize them to better suit -your preferences. - -The ``init/`` subfolder ------------------------ - -The :source:`init/ ` subfolder contains useful DFHack -`init-files` that you can copy into your main Dwarf Fortress folder -- the same -directory as ``dfhack.init``. - -.. _onMapLoad-dreamfort-init: - -:source:`onMapLoad_dreamfort.init ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This is the config file that comes with the `dreamfort` set of blueprints, but -it is useful (and customizable) for any fort. It includes the following config: - -- Calls `ban-cooking` for items that have important alternate uses and should - not be cooked. This configuration is only set when a fortress is first - started, so later manual changes will not be overridden. -- Automates calling of various fort maintenance and `scripts-fix`, like - `cleanowned` and `fix/stuckdoors`. -- Keeps your manager orders intelligently ordered with `orders` ``sort`` so no - orders block other orders from ever getting completed. -- Periodically enqueues orders to shear and milk shearable and milkable pets. -- Sets up `autofarm` to grow 30 units of every crop, except for pig tails, which - is set to 150 units to support the textile industry. -- Sets up `seedwatch` to keep 30 of every type of seed. -- Configures `prioritize` to automatically boost the priority of important and - time-sensitive tasks that could otherwise get ignored in busy forts, like - hauling food, tanning hides, storing items in vehicles, pulling levers, and - removing constructions. -- Optimizes `autobutcher` settings for raising geese, alpacas, sheep, llamas, - and pigs. Adds sensible defaults for all other animals, including dogs and - cats. There are instructions in the file for customizing the settings for - other combinations of animals. These settings are also only set when a - fortress is first started, so any later changes you make to autobutcher - settings won't be overridden. -- Enables `automelt`, `tailor`, `zone`, `nestboxes`, and `autonestbox`. - -The ``orders/`` subfolder -------------------------- - -The :source:`orders/ ` subfolder contains manager orders -that, along with the ``onMapLoad_dreamfort.init`` file above, allow a fort to be -self-sustaining. Copy them to your ``dfhack-config/orders/`` folder and import -as required with the `orders` DFHack plugin. - -:source:`basic.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This collection of orders handles basic fort necessities: - -- prepared meals and food products (and by-products like oil) -- booze/mead -- thread/cloth/dye -- pots/jugs/buckets -- bags of leather, cloth, silk, and yarn -- crafts and totems from otherwise unusable by-products -- mechanisms/cages -- splints/crutches -- lye/soap -- ash/potash -- beds/wheelbarrows/minecarts -- scrolls - -You should import it as soon as you have enough dwarves to perform the tasks. -Right after the first migration wave is usually a good time. - -:source:`furnace.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This collection creates basic items that require heat. It is separated out from -``basic.json`` to give players the opportunity to set up magma furnaces first in -order to save resources. It handles: - -- charcoal (including smelting of bituminous coal and lignite) -- pearlash -- sand -- green/clear/crystal glass -- adamantine processing -- item melting - -Orders are missing for plaster powder until DF `bug 11803 -`_ is fixed. - -:source:`military.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This collection adds high-volume smelting jobs for military-grade metal ores and -produces weapons and armor: - -- leather backpacks/waterskins/cloaks/quivers/armor -- bone/wooden bolts -- smelting for platinum, silver, steel, bronze, bismuth bronze, and copper (and - their dependencies) -- bronze/bismuth bronze/copper bolts -- platinum/silver/steel/iron/bismuth bronze/bronze/copper weapons and armor, - with checks to ensure only the best available materials are being used - -If you set a stockpile to take weapons and armor of less than masterwork quality -and turn on `automelt` (like what `dreamfort` provides on its industry level), -these orders will automatically upgrade your military equipment to masterwork. -Make sure you have a lot of fuel (or magma forges and furnaces) before you turn -``automelt`` on, though! - -This file should only be imported, of course, if you need to equip a military. - -:source:`smelting.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This collection adds smelting jobs for all ores. It includes handling the ores -already managed by ``military.json``, but has lower limits. This ensures all -ores will be covered if a player imports ``smelting`` but not ``military``, but -the higher-volume ``military`` orders will take priority if both are imported. - -:source:`rockstock.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This collection of orders keeps a small stock of all types of rock furniture. -This allows you to do ad-hoc furnishings of guildhalls, libraries, temples, or -other rooms with `buildingplan` and your masons will make sure there is always -stock on hand to fulfill the plans. - -:source:`glassstock.json ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Similar to ``rockstock`` above, this collection keeps a small stock of all types -of glass furniture. If you have a functioning glass industry, this is more -sustainable than ``rockstock`` since you can never run out of sand. If you have -plenty of rock and just want the variety, you can import both ``rockstock`` and -``glassstock`` to get a mixture of rock and glass furnishings in your fort. - -There are a few items that ``glassstock`` produces that ``rockstock`` does not, -since there are some items that can not be made out of rock, for example: - -- tubes and corkscrews for building magma-safe screw pumps -- windows -- terrariums (as an alternative to wooden cages) - -The ``professions/`` subfolder ------------------------------- - -The :source:`professions/ ` subfolder contains -professions, or sets of related labors, that you can assign to your dwarves with -the DFHack `manipulator` plugin. Copy them into the ``professions/`` -subdirectory under the main Dwarf Fortress folder (you may have to create this -subdirectory) and assign them to your dwarves in the manipulator UI, accessible -from the ``units`` screen via the :kbd:`l` hotkey. Make sure that the -``manipulator`` plugin is enabled in your ``dfhack.init`` file! You can assign a -profession to a dwarf by selecting the dwarf in the ``manipulator`` UI and -hitting :kbd:`p`. The list of professions that you copied into the -``professions/`` folder will show up for you to choose from. This is very useful -for assigning roles to new migrants to ensure that all the tasks in your fort -have adequate numbers of dwarves attending to them. - -If you'd rather use Dwarf Therapist to manage your labors, it is easy to import -these professions to DT and use them there. Simply assign the professions you -want to import to a dwarf. Once you have assigned a profession to at least one -dwarf, you can select "Import Professions from DF" in the DT "File" menu. The -professions will then be available for use in DT. - -In the charts below, the "At Start" and "Max" columns indicate the approximate -number of dwarves of each profession that you are likely to need at the start of -the game and how many you are likely to need in a mature fort. - -============= ======== ===== ================================================= -Profession At Start Max Description -============= ======== ===== ================================================= -Chef 0 3 Buchery, Tanning, and Cooking. It is important to - focus just a few dwarves on cooking since - well-crafted meals make dwarves very happy. They - are also an excellent trade good. -Craftsdwarf 0 4-6 All labors used at Craftsdwarf's workshops, - Glassmaker's workshops, and kilns. -Doctor 0 2-4 The full suite of medical labors, plus Animal - Caretaking for those using the dwarfvet plugin. -Farmer 1 4 Food- and animal product-related labors. This - profession also has the ``Alchemist`` labor - enabled since they need to focus on food-related - jobs, though you might want to disable - ``Alchemist`` for your first farmer until there - are actual farming duties to perform. -Fisherdwarf 0 0-1 Fishing and fish cleaning. If you assign this - profession to any dwarf, be prepared to be - inundated with fish. Fisherdwarves *never stop - fishing*. Be sure to also run ``prioritize -a - PrepareRawFish ExtractFromRawFish`` (or use the - ``onMapLoad_dreamfort.init`` file above) or else - caught fish will just be left to rot. -Hauler 0 >20 All hauling labors plus Siege Operating, Mechanic - (so haulers can assist in reloading traps) and - Architecture (so haulers can help build massive - windmill farms and pump stacks). As you - accumulate enough Haulers, you can turn off - hauling labors for other dwarves so they can - focus on their skilled tasks. You may also want - to restrict your Mechanic's workshops to only - skilled mechanics so your haulers don't make - low-quality mechanisms. -Laborer 0 10-12 All labors that don't improve quality with skill, - such as Soapmaking and furnace labors. -Marksdwarf 0 10-30 Similar to Hauler. See the description for - Meleedwarf below for more details. -Mason 2 2-4 Masonry, Gem Cutting/Encrusting, and - Architecture. In the early game, you may need to - run "`prioritize` ConstructBuilding" to get your - masons to build wells and bridges if they are too - busy crafting stone furniture. Late game, you can - turn off their Architecture labor since that will - be better handled by your Haulers. -Meleedwarf 0 20-50 Similar to Hauler, but without most civilian - labors. This profession is separate from Hauler - so you can find your military dwarves easily. - Meleedwarves and Marksdwarves have Mechanics and - hauling labors enabled so you can temporarily - deactivate your military after sieges and allow - your military dwarves to help clean up. -Migrant 0 0 You can assign this profession to new migrants - temporarily while you sort them into professions. - Like Marksdwarf and Meleedwarf, the purpose of - this profession is so you can find your new - dwarves more easily. -Miner 2 2-10 Mining and Engraving. This profession also has - the ``Alchemist`` labor enabled, which disables - hauling for those using the `autohauler` plugin. - Once the need for Miners tapers off in the late - game, dwarves with this profession make good - military dwarves, wielding their picks as - weapons. -Outdoorsdwarf 1 2-4 Carpentry, Bowyery, Woodcutting, Animal Training, - Trapping, Plant Gathering, Beekeeping, and Siege - Engineering. -Smith 0 2-4 Smithing labors. You may want to specialize your - Smiths to focus on a single smithing skill to - maximize equipment quality. -StartManager 1 0 All skills not covered by the other starting - professions (Miner, Mason, Outdoorsdwarf, and - Farmer), plus a few overlapping skills to - assist in critical tasks at the beginning of the - game. Individual labors should be turned off as - migrants are assigned more specialized - professions that cover them, and the StartManager - dwarf can eventually convert to some other - profession. -Tailor 0 2 Textile industry labors: Dying, Leatherworking, - Weaving, and Clothesmaking. -============= ======== ===== ================================================= - -A note on autohauler -~~~~~~~~~~~~~~~~~~~~ - -These profession definitions are designed to work well with or without the -`autohauler` plugin (which helps to keep your dwarves focused on skilled labors -instead of constantly being distracted by hauling). If you do want to use -autohauler, adding the following lines to your ``onMapLoad.init`` file will -configure it to let the professions manage the "Feed water to civilians" and -"Recover wounded" labors instead of enabling those labors for all hauling -dwarves:: - - on-new-fortress enable autohauler - on-new-fortress autohauler FEED_WATER_CIVILIANS allow - on-new-fortress autohauler RECOVER_WOUNDED allow diff --git a/docs/guides/index.rst b/docs/guides/index.rst index 7208b52766..f47f9565ce 100644 --- a/docs/guides/index.rst +++ b/docs/guides/index.rst @@ -1,11 +1,13 @@ =========== -User Guides +User guides =========== These pages are detailed guides covering DFHack tools. .. toctree:: :maxdepth: 1 - :glob: - * + /docs/guides/modding-guide + /docs/guides/quickfort-library-guide + /docs/guides/quickfort-user-guide + /docs/guides/stonesense-art-guide diff --git a/docs/guides/modding-guide.rst b/docs/guides/modding-guide.rst new file mode 100644 index 0000000000..e93051d41a --- /dev/null +++ b/docs/guides/modding-guide.rst @@ -0,0 +1,743 @@ +.. _modding-guide: + +DFHack modding guide +==================== + +.. highlight:: lua + +What is the difference between a script and a mod? +-------------------------------------------------- + +Well, sometimes there is no difference. A mod is anything you add to the game, +which can be graphics overrides, content in the raws, DFHack scripts, or all of +the above. There are already resources out there for +`raws modding `__, so this +guide will focus more on scripts, both standalone and as an extension to +raws-based mods. + +A DFHack script is a Lua file that can be run as a command in +DFHack. Scripts can do pretty much anything, from displaying information to +enforcing new game mechanics. If you don't already know Lua, there's a great +primer at `lua.org `__. + +Why not just mod the raws? +-------------------------- + +It depends on what you want to do. Some mods *are* better to do in just the +raws. You don't need DFHack to add a new race or modify attributes. However, +DFHack scripts can do many things that you just can't do in the raws, like make +a creature that trails smoke or launch a unit into the air when they are hit +with a certain type of projectile. Some things *could* be done in the raws, but +a script is better (e.g. easier to maintain, easier to extend, and/or not prone +to side-effects). A great example is adding a syndrome when a reaction +is performed. If done in the raws, you have to create an exploding boulder as +an intermediary to apply the syndrome. DFHack scripts can add the syndrome +directly and with much more flexibility. In the end, complex mods will likely +require a mix of raw modding and DFHack scripting. + +The structure of a mod +---------------------- + +In the example below, we'll use a mod name of ``example-mod``. I'm sure your +mods will have more creative names! Mods have a basic structure that looks like +this:: + + info.txt + graphics/... + objects/... + blueprints/... + scripts_modactive/example-mod.lua + scripts_modactive/internal/example-mod/... + scripts_modinstalled/... + README.md (optional) + +Let's go through that line by line. + +- The :file:`info.txt` file contains metadata about your mod that DF will + display in-game. You can read more about this file in the + `Official DF Modding Guide `__. + It would be a good idea to give your mod a ``dfhack`` tag so players can + indentify it as requiring DFHack when they subscribe to it on the DF Steam + workshop. +- Modifications to the game raws (potentially with + `custom raw tokens `) go in the :file:`graphics/` and + :file:`objects/` folders. You can read more about the files that go in + these directories on the :wiki:`Modding` wiki page. +- Any `quickfort` blueprints included with your mod go in the + :file:`blueprints` folder. Note that your mod can *just* be blueprints and + the :file:`info.txt` file if you like. See the next section for an example. +- A control script in :file:`scripts_modactive/` directory that handles + system-level event hooks (e.g. reloading state when a world is loaded), + registering `overlays `, and + `enabling/disabling ` your mod. You can put other + scripts in this directory as well if you want them to appear as runnable + DFHack commands when your mod is active for the current world. Lua modules + that your main scripts use, but which don't need to be directly runnable by + the player, should go in a subdirectory under + :file:`scripts_modactive/internal/` so they don't show up in the DFHack + `launcher ` command autocomplete lists. +- Scripts that you want to be available before a world is loaded (i.e. on the + DF title screen) or that you want to be runnable in any world, regardless + of whether your mod is active, should go in the + :file:`scripts_modinstalled/` folder. You can also have an :file:`internal/` + subfolder in here for private modules if you like. +- Finally, a :file:`README.md` file that has more information about your mod. + If you develop your mod using version control (recommended!), that + :file:`README.md` file can also serve as your git repository documentation. + +These files end up in a subdirectory under :file:`mods/` when players copy them +in or install them from the +`Steam Workshop `__, and in +:file:`data/installed_mods/` when the mod is selected as "active" for the first +time. + +DFHack will discover scripts in your mod's ``scripts_modinstalled/`` directory +and other DFHack-relevant data files (like blueprints) regardless of whether +the mod has been marked "active" for any player world. + +What if I just want to distribute quickfort blueprints? +------------------------------------------------------- + +For this, all you need is :file:`info.txt` and your blueprints. + +.. highlight:: none + +Your :file:`info.txt` could look something like this:: + + [ID:drooble_blueprints] + [NUMERIC_VERSION:1] + [DISPLAYED_VERSION:1.0.0] + [EARLIEST_COMPATIBLE_NUMERIC_VERSION:1] + [EARLIEST_COMPATIBLE_DISPLAYED_VERSION:1.0.0] + [AUTHOR:Drooble] + [NAME:Drooble's blueprints] + [DESCRIPTION:Useful quickfort blueprints for any occasion.] + [STEAM_TITLE:Drooble's blueprints] + [STEAM_DESCRIPTION:Useful quickfort blueprints for any occasion.] + [STEAM_TAG:dfhack] + [STEAM_TAG:quickfort] + [STEAM_TAG:blueprints] + +and your blueprints, which could be .csv or .xlsx files, would go in the +``blueprints/`` subdirectory. If you add blueprint file named +``blueprints/bedrooms.csv``, then it will be shown to players as +``drooble_blueprints/bedrooms.csv`` in `quickfort` and `gui/quickfort`. The +"drooble_blueprints" prefix comes from the mod ID specified in ``info.txt``. + +What if I just want to distribute a simple standalone script? +------------------------------------------------------------- + +If your mod is just a script with no raws modifications, all you need is:: + + info.txt + scripts_modinstalled/yourscript.lua + README.md (optional) + +Adding your script to the :file:`scripts_modinstalled/` folder will allow +DFHack to find it and add your mod to the `script-paths`. Your script will be +runnable from the title screen and in any loaded world, regardless of whether +your mod is explicitly "active". + +A mod-maker's development environment +------------------------------------- + +Create a folder for development somewhere outside your Dwarf Fortress +installation directory (e.g. ``/path/to/mymods/``). If you work on multiple +mods, you might want to make a subdirectory for each mod. + +If you have changes to the raws, you'll still have to copy them into DF's +``data/installed_mods/`` folder to have them take effect, but you can set +things up so that scripts are run directly from your dev directory. You can +edit your scripts in your dev directory and have the changes available in the +game immediately: no copying, no restarting. + +How does this magic work? Just add a line like this to your +``dfhack-config/script-paths.txt`` file:: + + +/path/to/mymods/example-mod/scripts_modinstalled + +Then that directory will be searched when you run DFHack commands from inside +the game. The ``+`` at the front of the path means to search that directory +first, before any other script directory (like :file:`hack/scripts` or other +versions of your mod in the DF mod folders). + +The structure of the game +------------------------- + +"The game", that is, all the Dwarf Fortress state, is in the global variable +`df `. Most of the information relevant to a script is found in +``df.global.world``, which contains data like the lists of active items and +units, whether to reindex pathfinding, et cetera. Also relevant to us are the +various data types found in the game, e.g. ``df.pronoun_type`` which we will be +using in this guide. We'll explore more of the game structures below. + +Your first script +----------------- + +So! It's time to write your first script. This section will walk you through how +to make a script that will get the pronoun type of the currently selected unit. +If you're not familiar with Lua script syntax, maybe skim through some topics +in the `manual `__ first. + +.. highlight:: lua + +First line, we get a reference to an in-game unit:: + + local unit = dfhack.gui.getSelectedUnit() + +If no unit is selected by the player in the DF UI, ``unit`` will be ``nil`` and +an error message will be printed. + +If ``unit`` is ``nil``, we don't want the script to run anymore:: + + if not unit then + return + end + +Now, the field ``unit.sex`` is an integer, but each integer corresponds to a +string value ("it", "she", or "he"). We get this value by indexing the +bidirectional map ``df.pronoun_type``. Indexing the other way, with one of the +strings, will yield its corresponding number. So:: + + local pronounTypeString = df.pronoun_type[unit.sex] + print(pronounTypeString) + +Simple. The entire script altogether looks like this:: + + local unit = dfhack.gui.getSelectedUnit() + if not unit then + return + end + local pronounTypeString = df.pronoun_type[unit.sex] + print(pronounTypeString) + +Save the text as a ``.lua`` file in your own scripts directory and run it from +`gui/launcher` when a unit is selected in the Dwarf Fortress UI. + +DFHack provides a vast library of functionality that make it easier to interact +with the game state. When you start asking yourself "How do I get/do X", search +through the `lua-api` for relevant functions and look through existing scripts +for examples. + +Exploring DF state +------------------ + +So how could you have known about the field and type we just used? Well, there +are two main tools for discovering the various fields in the game's data +structures. The first is the ``df-structures`` +`repository `__ that contains XML files +describing the layouts of the game's structures. These are complete, but +difficult to read (for a human). The second option is the `gui/gm-editor` +interface, an interactive data explorer. You can run the script while objects +like units are selected to view the data within them. Press :kbd:`?` while the +script is active to view help. + +Familiarising yourself with the many structs of the game will help with ideas +immensely, and you can always ask for help in the `right places `. + +Reading and writing files and other persistent state +---------------------------------------------------- + +There are several locations and APIs that a mod might need to read or store +data: + +Global state that is not world-specific should be stored in the directory +returned by the ``scriptmanager.getModStatePath()`` function. JSON is a +convenient format for this kind of stored state, and DFHack provides facilities +for reading and writing JSON data. For example:: + + local json = require('json') + local scriptmanager = require('script-manager') + local path = scriptmanager.getModStatePath('mymodname') + config = config or json.open(path .. 'settings.json') + + -- modify state in the config.data table and persist it when it changes with + -- config:write() + +State that should be saved with a world or a specific fort within that world +should use `persistent-api` API. You can attach a state change hook for new +world loaded where you can load the state, which often includes whether the mod +itself is enabled (if the mod can be dynamically enabled/disabled -- see the +`script-enable-api` for more details). For example:: + + --@ enable=true + --@ module=true + + local utils = require('utils') + + local GLOBAL_KEY = 'mymodname' + + local function get_default_state() + return { + enabled=false, + somevar=0, + somesubtable={ + someothervar=0, + }, + } + end + state = state or get_default_state() + + -- implement the enabled API so DFHack can read this script's status + function isEnabled() + return state.enabled + end + + local function persist_state() + dfhack.persistent.saveSiteData(GLOBAL_KEY, state) + end + + local function do_enable() + -- initialization tasks, such as hooking events + end + + local function do_disable() + -- cleanup tasks, such as removing event hooks + end + + dfhack.onStateChange[GLOBAL_KEY] = function(sc) + if sc == SC_MAP_UNLOADED then + do_disable() + + -- ensure our mod doesn't run when a different + -- world is loaded where we are *not* active + dfhack.onStateChange[GLOBAL_KEY] = nil + + return + end + + if sc ~= SC_MAP_LOADED or not dfhack.world.isFortressMode() then + return + end + + -- retrieve state saved in game. merge with default state so config + -- saved from previous versions can pick up newer defaults. + state = get_default_state() + utils.assign(state, dfhack.persistent.getSiteData(GLOBAL_KEY, state)) + if state.enabled then + do_enable() + end + end + +Finally, you may have distributed data files with your mod that you need to +read at runtime. Your mod directory should be treated as read-only since data +there is not backed up. Use the `script-manager` API to get the path to your +mod data and the ``json`` (or any other file I/O) API as needed. For example:: + + local scriptmanager = require('script-manager') + + local GLOBAL_KEY = 'mymodname' + + local function read_bulk_data_db() + local mod_source_path = scriptmanager.getModSourcePath(GLOBAL_KEY) + -- read data from files in the mod directory + return ... + end + + bulk_data_db = bulk_data_db or read_bulk_data_db() + +If you want to store state in the savegame so that it is associated with the +current world/fort/adventure, use the `persistent-api` API. or in the fuller example later in this +guide. + +Reacting to events +------------------ + +The common method for injecting new behaviour into the game is to define a +callback function and get it called when something interesting happens. DFHack +provides two libraries for this, ``repeat-util`` and `eventful `. +``repeat-util`` is used to run a function once per a configurable number of +frames (paused or unpaused), ticks (unpaused), in-game days, months, or years. +If you need to be aware the instant something happens, you'll need to run a +check once a tick. Be careful not to do this gratuitously, though, since +running callbacks too often can significantly slow down the game! + +``eventful``, on the other hand, is much more performance-friendly since it will +only call your callback when a relevant event happens, like a reaction +occuring, a job being completed, or a projectile moving to a new tile. + +To get something to run once every 1000 ticks, we can call +``repeat-util.scheduleEvery()``. First, we load the module:: + + local repeatUtil = require('repeat-util') + +Both ``repeat-util`` and ``eventful`` require keys for registered callbacks. You +should use something unique, like your mod id:: + + local GLOBAL_KEY = 'mymodname' + +Then, we pass the key, amount of time units between function calls, what the +time units are, and finally the callback function itself:: + + repeatUtil.scheduleEvery(GLOBAL_KEY, 1000, 'ticks', function() + -- Do something like iterating over all active units and + -- check for something interesting + for _, unit in ipairs(df.global.world.units.active) do + ... + end + end) + +``eventful`` is slightly more involved. First get the module:: + + local eventful = require('plugins.eventful') + +``eventful`` contains a table for each event which you populate with functions. +Each function in the table is then called with the appropriate arguments when +the event occurs. So, for example, to print the position of a moving (item) +projectile:: + + eventful.onProjItemCheckMovement[GLOBAL_KEY] = function(projectile) + print(projectile.cur_pos.x, projectile.cur_pos.y, + projectile.cur_pos.z) + end + +Check out the `full list of supported events ` to see what else +you can react to with ``eventful``. + +Now, you may have noticed that you won't be able to register multiple callbacks +with a single key named after your mod. You can, of course, call all the +functions you want from a single registered callback. Alternately, you can +create multiple callbacks using different keys, using your mod ID as a key name +prefix. If you do register multiple callbacks, though, there are no guarantees +about the call order. + +Custom raw tokens +----------------- + +.. highlight:: none + +In this section, we are going to use `custom raw tokens ` +applied to a reaction to transfer the material of a reagent to a product as a +handle improvement (like on artifact buckets). As a second example, we are +going to make boots that make units go faster when worn. + +First, let's define raws for a custom crossbow with its own custom reaction. The +crossbow:: + + [ITEM_WEAPON:ITEM_WEAPON_CROSSBOW_SIEGE] + [NAME:crossbow:crossbows] + [SIZE:600] + [SKILL:HAMMER] + [RANGED:CROSSBOW:BOLT] + [SHOOT_FORCE:4000] + [SHOOT_MAXVEL:800] + [TWO_HANDED:0] + [MINIMUM_SIZE:17500] + [MATERIAL_SIZE:4] + [ATTACK:BLUNT:10000:4000:bash:bashes:NO_SUB:1250] + [ATTACK_PREPARE_AND_RECOVER:3:3] + [SIEGE_CROSSBOW_MOD_FIRE_RATE_MULTIPLIER:2] custom token (you'll see) + +The reaction to make it (you would add the reaction and not the weapon to an +entity raw):: + + [REACTION:MAKE_SIEGE_CROSSBOW] + [NAME:make siege crossbow] + [BUILDING:BOWYER:NONE] + [SKILL:BOWYER] + [REAGENT:mechanism 1:2:TRAPPARTS:NONE:NONE:NONE] + [REAGENT:bar:150:BAR:NONE:NONE:NONE] + [METAL_ITEM_MATERIAL] + [REAGENT:handle 1:1:BLOCKS:NONE:NONE:NONE] wooden handles + [ANY_PLANT_MATERIAL] + [REAGENT:handle 2:1:BLOCKS:NONE:NONE:NONE] + [ANY_PLANT_MATERIAL] + [SIEGE_CROSSBOW_MOD_TRANSFER_HANDLE_MATERIAL_TO_PRODUCT_IMPROVEMENT:1] + another custom token + [PRODUCT:100:1:WEAPON:ITEM_WEAPON_CROSSBOW_SIEGE:GET_MATERIAL_FROM_REAGENT:bar:NONE] + +So, we are going to use the ``eventful`` module to react when this crossbow is +crafted, allowing us to inject the logic that will add the handle improvement. + +.. highlight:: lua + +First, require the modules we are going to use:: + + local eventful = require('plugins.eventful') + local customRawTokens = require('custom-raw-tokens') + +and attach a callback to the event:: + + local GLOBAL_KEY = 'mymodname' + + local function reaction_handler(reaction, reactionProduct, unit, + inputItems, inputReagents, outputItems) + -- we'll be defining the body of this function below + end + + eventful.onReactionComplete[GLOBAL_KEY] = reaction_handler + +Now let's look at the ``reaction_handler`` function and give it some logic. +First, we check to see if it the reaction that just happened is relevant to this +callback:: + + if not customRawTokens.getToken(reaction, + 'SIEGE_CROSSBOW_MOD_TRANSFER_HANDLE_MATERIAL_TO_PRODUCT_IMPROVEMENT') + then + return + end + +Then, we check the reagents for names that start with "handle". For those +reagents, we get the corresponding item and add a handle improvement:: + + for i, reagent in ipairs(inputReagents) do + if reagent.code:startswith('handle') then + -- Found handle reagent + local item = inputItems[i] + local improv = df.itemimprovement_itemspecificst:new() + improv.mat_type, improv.mat_index = item.mat_type, item.mat_index + improv.type = df.itemimprovement_specific_type.HANDLE + outputItems[1].improvements:insert('#', improv) + end + end + +Let's also modify the fire rate of our siege crossbow according to the custom +token we added to the item definition in the raws:: + + eventful.onProjItemCheckMovement[GLOBAL_KEY] = function(projectile) + if projectile.distance_flown > 0 then + -- don't make this adjustment more than once + return + end + + local firer = projectile.firer + if not firer then + return + end + + local weapon = df.item.find(projectile.bow_id) + if not weapon then + return + end + + local multiplier = tonumber(customRawTokens.getToken( + weapon.subtype, + 'SIEGE_CROSSBOW_MOD_FIRE_RATE_MULTIPLIER')) or 1 + firer.counters.think_counter = math.floor( + firer.counters.think_counter * multiplier) + end + +.. highlight:: none + +Now, let's see how we could make some "pegasus boots". First, let's define the +item in the raws:: + + [ITEM_SHOES:ITEM_SHOES_BOOTS_PEGASUS] + [NAME:pegasus boot:pegasus boots] + [ARMORLEVEL:1] + [UPSTEP:1] + [METAL_ARMOR_LEVELS] + [LAYER:OVER] + [COVERAGE:100] + [LAYER_SIZE:25] + [LAYER_PERMIT:15] + [MATERIAL_SIZE:2] + [METAL] + [LEATHER] + [HARD] + [PEGASUS_BOOTS_MOD_FOOT_MOVEMENT_TIMER_REDUCTION_PER_TICK:2] custom raw token + (you don't have to comment the custom token every time, + but it does clarify what it is) + +.. highlight:: lua + +Then, let's define a function that will implement the logic associated with the +boots:: + + local function do_pegasus() + for _,unit in ipairs(df.global.world.units.active) do + local amount = 0 + for _,inv_entry in ipairs(unit.inventory) do + if inv_entry.mode == df.unit_inventory_item.T_mode.Worn then + local reduction = customRawTokens.getToken( + inv_entry.item, + 'PEGASUS_BOOTS_MOD_FOOT_MOVEMENT_TIMER_REDUCTION_PER_TICK') + amount = amount + (tonumber(reduction) or 0) + end + end + -- Subtract amount from on-foot movement timers if not on ground + if not unit.flags1.on_ground then + dfhack.units.subtractActionTimers(unit, amount, + df.unit_action_type_group.MovementFeet) + end + end + end + +Finally, we can schedule the callback to be run once a tick using the +``repeat-util`` module:: + + repeatUtil.scheduleEvery(GLOBAL_KEY, 1, 'ticks', do_pegasus) + +Note that the ``do_pegasus`` function as written here is **extremely +inefficient**. In a real mod, you would likely want to cache which units are +equipping pegasus boots so you don't have to scan every inventory item of every +active unit on every tick. + +Putting it all together +----------------------- + +Ok, you're all set up! Now, let's take a look at an example +``scripts_modinstalled/example-mod.lua`` file:: + + -- main file for the example-mod mod + + -- these lines indicate that the script supports the "enable" + -- API so you can start it by running "enable example-mod" and + -- stop it by running "disable example-mod" + --@ module=true + --@ enable=true + + -- this is the help text that will appear in `help` and + -- `gui/launcher`. see possible tags here: + -- https://docs.dfhack.org/en/stable/docs/Tags.html + --[====[ + example-mod + =========== + + Tags: fort | gameplay + + Short one-sentence description. + + Longer description ... + + Usage + ----- + + enable example-mod + disable example-mod + ]====] + + local eventful = require('plugins.eventful') + local repeatUtil = require('repeat-util') + local utils = require('utils') + + -- you can reference global values or functions declared in any of + -- your internal modules + local moduleA = reqscript('internal/example-mod/module-a') + local moduleB = reqscript('internal/example-mod/module-b') + + local GLOBAL_KEY = 'example-mod' + + local function get_default_state() + return { + enabled=false, + somevar=0, + somesubtable={ + someothervar=0, + }, + } + end + state = state or get_default_state() + + -- implement the enabled API so DFHack can read this script's status + function isEnabled() + return state.enabled + end + + -- call this whenever the contents of the state table changes + local function persist_state() + dfhack.persistent.saveSiteData(GLOBAL_KEY, state) + end + + local function do_enable() + -- do any initialization your internal scripts might require + moduleA.onEnable() + moduleB.onEnable() + + repeatUtil.scheduleEvery(GLOBAL_KEY, 1000, 'ticks', function() + moduleA.cycle() + moduleB.cycle() + end) + + eventful.onProjItemCheckMovement[GLOBAL_KEY] = + moduleB.onProjItemCheckMovement + eventful.onProjUnitCheckImpact[GLOBAL_KEY] = + moduleB.onProjUnitCheckImpact + end + + local function do_disable() + -- call any shutdown functions your internal scripts might require + moduleA.onDisable() + moduleB.onDisable() + + repeatUtil.cancel(GLOBAL_KEY) + + eventful.onProjItemCheckMovement[GLOBAL_KEY] = nil + eventful.onProjUnitCheckImpact[GLOBAL_KEY] = nil + end + + dfhack.onStateChange[GLOBAL_KEY] = function(sc) + if sc == SC_MAP_UNLOADED then + do_disable() + + -- ensure our mod doesn't run when a different + -- world is loaded where we are *not* active + dfhack.onStateChange[GLOBAL_KEY] = nil + + return + end + + if sc ~= SC_MAP_LOADED or not dfhack.world.isFortressMode() then + return + end + + -- retrieve state saved in game. merge with default state so config + -- saved from previous versions can pick up newer defaults. + state = get_default_state() + utils.assign(state, dfhack.persistent.getSiteData(GLOBAL_KEY, state)) + if state.enabled then + do_enable() + end + end + + if dfhack_flags.module then + return + end + + if not dfhack_flags.enable then + print(dfhack.script_help()) + print() + print(('Example mod is currently '):format( + enabled and 'enabled' or 'disabled')) + return + end + + if dfhack_flags.enable_state then + state.enabled = true + do_enable() + else + state.enabled = false + do_disable() + end + + persist_state() + +The ``scripts_modinstalled/internal/example-mod/module-a.lua`` file could look +something like this:: + + --@ module=true + + -- global (non-local) variables and functions are exported + function onEnable() + -- ... + end + + function onDisable() + -- ... + end + + -- this is a local function: local functions/variables + -- are not accessible to other scripts. + local function usedByCycle(unit) + -- ... + end + + function cycle() -- exported + for _,unit in ipairs(df.global.world.units.active) do + usedByCycle(unit) + end + end + +The `reqscript ` function reloads scripts that have changed, so you +can modify your scripts while DF is running and just disable/enable your mod to +load the changes into your running game! diff --git a/docs/guides/quickfort-alias-guide.rst b/docs/guides/quickfort-alias-guide.rst deleted file mode 100644 index 8d5f830d3c..0000000000 --- a/docs/guides/quickfort-alias-guide.rst +++ /dev/null @@ -1,860 +0,0 @@ -.. _quickfort-alias-guide: - -Quickfort Alias Guide -===================== - -Aliases allow you to use simple words to represent complicated key sequences -when configuring buildings and stockpiles in quickfort ``#query`` blueprints. - -For example, say you have the following ``#build`` and ``#place`` blueprints:: - - #build masonry workshop - ~, ~,~,`,`,` - ~,wm,~,`,`,` - ~, ~,~,`,`,` - - #place stockpile for mason - ~,~,~,s,s,s - ~,~,~,s,s,s - ~,~,~,s,s,s - -and you want to configure the stockpile to hold only non-economic ("other") -stone and to give to the adjacent mason workshop. You could write the -key sequences directly:: - - #query configure stockpile with expanded key sequences - ~,~,~,s{Down 5}deb{Right}{Down 2}p^,`,` - ~,~,~,g{Left 2}&, `,` - ~,~,~,`, `,` - -or you could use aliases:: - - #query configure stockpile with aliases - ~,~,~,otherstone,`,` - ~,~,~,give2left, `,` - ~,~,~,`, `,` - -If the stockpile had only a single tile, you could also replay both aliases in -a single cell:: - - #query configure mason with multiple aliases in one cell - ~,~,~,{otherstone}{give2left},`,` - ~,~,~,`, `,` - ~,~,~,`, `,` - -With aliases, blueprints are much easier to read and understand. They also -save you from having to copy the same long key sequences everywhere. - -Alias definition files ----------------------- - -DFHack comes with a library of aliases for you to use that are always -available when you run a ``#query`` blueprint. Many blueprints can be built -with just those aliases. This "standard alias library" is stored in -:source:`data/quickfort/aliases-common.txt` (installed under the ``hack`` folder -in your DFHack installation). The aliases in that file are described at the -`bottom of this document `. - -Please do not edit the aliases in the standard library directly. The file will -get overwritten when DFHack is updated and you'll lose your changes. Instead, -add your custom aliases to :source:`dfhack-config/quickfort/aliases.txt` or -directly to your blueprints in an `#aliases ` -section. Your custom alias definitions take precedence over any definitions in -the standard library. - -Alias syntax and usage ----------------------- - -The syntax for defining aliases is:: - - aliasname: expansion - -Where ``aliasname`` is at least two letters or digits long (dashes and -underscores are also allowed) and ``expansion`` is whatever you would type -into the DF UI. - -You use an alias by typing its name into a ``#query`` blueprint cell where you -want it to be applied. You can use an alias by itself or as part of a larger -sequence, potentially with other aliases. If the alias is the only text in the -cell, the alias name is matched and its expansion is used. If the alias has -other keys before or after it, the alias name must be surrounded in curly -brackets (:kbd:`{` and :kbd:`}`). An alias can be surrounded in curly brackets -even if it is the only text in the cell, it just isn't necesary. For example, -the following blueprint uses the ``aliasname`` alias by itself in the first -two rows and uses it as part of a longer sequence in the third row:: - - #query apply alias 'aliasname' in three different ways - aliasname - {aliasname} - literaltext{aliasname}literaltext - -For a more concrete example of an alias definition, a simple alias that -configures a stockpile to have no bins (:kbd:`C`) and no barrels (:kbd:`E`) -assigned to it would look like this:: - - nocontainers: CE - -The alias definition can also contain references to other aliases by including -the alias names in curly brackets. For example, ``nocontainers`` could be -equivalently defined like this:: - - nobins: C - nobarrels: E - nocontainers: {nobins}{nobarrels} - -Aliases used in alias definitions *must* be surrounded by curly brackets, even -if they are the only text in the definition:: - - alias1: text1 - alias2: alias1 - alias3: {alias1} - -Here, ``alias1`` and ``alias3`` expand to ``text1``, but ``alias2`` expands to -the literal text ``alias1``. - -Keycodes -~~~~~~~~ - -Non-printable characters, like the arrow keys, are represented by their -keycode name and are also surrounded by curly brackets, like ``{Right}`` or -``{Enter}``. Keycodes are used exactly like aliases -- they just have special -expansions that you wouldn't be able to write yourself. In order to avoid -naming conflicts between aliases and keycodes, the convention is to start -aliases with a lowercase letter. - -Any keycode name from the DF interface definition file -(data/init/interface.txt) is valid, but only a few keycodes are actually -useful for blueprints:: - - Up - Down - Left - Right - Enter - ESC - Backspace - Space - Tab - -There is also one pseudo-keycode that quickfort recognizes:: - - Empty - -which has an empty expansion. It is primarily useful for defining blank default values for `Sub-aliases`_. - -Repetitions -~~~~~~~~~~~ - -Anything enclosed within curly brackets can also have a number, indicating how -many times that alias or keycode should be repeated. For example: -``{togglesequence 9}`` or ``{Down 5}`` will repeat the ``togglesequence`` -alias nine times and the ``Down`` keycode five times, respectively. - -Modifier keys -~~~~~~~~~~~~~ - -Ctrl, Alt, and Shift modifiers can be specified for the next key by adding -them into the key sequence. For example, Alt-h is written as ``{Alt}h``. - -Shorthand characters -~~~~~~~~~~~~~~~~~~~~ - -Some frequently-used keycodes are assigned shorthand characters. Think of them -as single-character aliases that don't need to be surrounded in curly -brackets:: - - & expands to {Enter} - @ expands to {Shift}{Enter} - ~ expands to {Alt} - ! expands to {Ctrl} - ^ expands to {ESC} - -If you need literal versions of the shorthand characters, surround them in -curly brackets, for example: use ``{!}`` for a literal exclamation point. - -Built-in aliases -~~~~~~~~~~~~~~~~ - -Most aliases that come with DFHack are in ``aliases-common.txt``, but there is -one alias built into the code for the common shorthand for "make room":: - - r+ expands to r+{Enter} - -This needs special code support since ``+`` can't normally be used in alias -names. You can use it just like any other alias, either by itself in a cell -(``r+``) or surrounded in curly brackets (``{r+}``). - -Sub-aliases -~~~~~~~~~~~ - -You can specify sub-aliases that will only be defined while the current alias -is being resolved. This is useful for "injecting" custom behavior into the -middle of a larger alias. As a simple example, the ``givename`` alias is defined -like this:: - - givename: !n{name}& - -Note the use of the ``name`` alias inside of the ``givename`` expansion. In your -``#query`` blueprint, you could write something like this, say, while over your -main drawbridge:: - - {givename name="Front Gate"} - -The value that you give the sub-alias ``name`` will be used when the -``givename`` alias is expanded. Without sub-aliases, we'd have to define -``givename`` like this:: - - givenameprefix: !n - givenamesuffix: & - -and use it like this:: - - {givenameprefix}Front Gate{givenamesuffix} - -which is more difficult to write and more difficult to understand. - -A handy technique is to define an alias with some sort of default -behavior and then use sub-aliases to override that behavior as necessary. For -example, here is a simplified version of the standard ``quantum`` alias that -sets up quantum stockpiles:: - - quantum_enable: {enableanimals}{enablefood}{enablefurniture}... - quantum: {linksonly}{nocontainers}{quantum_enable} - -You can use the default behavior of ``quantum_enable`` by just using the -``quantum`` alias by itself. But you can override ``quantum_enable`` to just -enable furniture for some specific stockpile like this:: - - {quantum quantum_enable={enablefurniture}} - -If an alias uses a sub-alias in its expansion, but the sub-alias is not defined -when the alias is used, quickfort will halt the ``#query`` blueprint with an -error. If you want your aliases to work regardless of whether sub-aliases are -defined, then you must define them with default values like ``quantum_enable`` -above. If a default value should be blank, like the ``name`` sub-alias used by -the ``givename`` alias above, define it with the ``{Empty}`` pesudo-keycode:: - - name: {Empty} - -Sub-aliases must be in one of the following formats:: - - subaliasname=keyswithnospaces - subaliasname="keys with spaces or {aliases}" - subaliasname={singlealias} - -If you specify both a sub-alias and a number of repetitions, the number for -repetitions goes last, right before the :kbd:`}`:: - - {alias subaliasname=value repetitions} - -Beyond query mode ------------------ -``#query`` blueprints normally do things in DF :kbd:`q`\uery mode, but nobody -said that we have to *stay* in query mode. ``#query`` blueprints send -arbitrary key sequences to Dwarf Fortress. Anything you can do by typing keys -into DF, you can do in a ``#query`` blueprint. It is absolutely fine to -temporarily exit out of query mode, go into, say, hauling or zone or hotkey -mode, and do whatever needs to be done. - -You just have to make certain to exit out of that alternate mode and get back -into :kbd:`q`\uery mode at the end of the key sequence. That way quickfort can -continue on configuring the next tile -- a tile configuration that assumes the -game is still in query mode. - -For example, here is the standard library alias for giving a name to a zone:: - - namezone: ^i{givename}^q - -The first :kbd:`\^` exits out of query mode. Then :kbd:`i` enters zones mode. -We then reuse the standard alias for giving something a name. Finally, we exit -out of zones mode with another :kbd:`\^` and return to :kbd:`q`\uery mode. - -.. _quickfort-alias-library: - -The DFHack standard alias library ---------------------------------- - -DFHack comes with many useful aliases for you to use in your blueprints. Many -blueprints can be built with just these aliases alone, with no custom aliases -required. - -This section goes through all aliases provided by the DFHack standard alias -library, discussing their intended usage and detailing sub-aliases that you -can define to customize their behavior. - -If you do define your own custom aliases in -``dfhack-config/quickfort/aliases.txt``, try to build on library alias -components. For example, if you create an alias to modify particular furniture -stockpile settings, start your alias with ``{furnitureprefix}`` instead of -``s{Down 2}``. Using library prefixes will allow library sub-aliases to work -with your aliases just like they do with library aliases. In this case, using -``{furnitureprefix}`` will allow your stockpile customization alias to work -with both stockpiles and hauling routes. - -Note that some aliases use the DFHack-provided search prompts. If you get errors -while running ``#query`` blueprints, ensure the DFHack `search-plugin` plugin is -enabled. - -Naming aliases -~~~~~~~~~~~~~~ - -These aliases give descriptive names to workshops, levers, stockpiles, zones, -etc. Dwarf Fortress building, stockpile, and zone names have a maximum length -of 20 characters. - -======== =========== -Alias Sub-aliases -======== =========== -givename name -namezone name -======== =========== - -``givename`` works anywhere you can hit Ctrl-n to customize a name, like when -the cursor is over buildings and stockpiles. Example:: - - #place - f(10x2) - - #query - {booze}{givename name=booze} - -``namezone`` is intended to be used when over an activity zone. It includes -commands to get into zones mode, set the zone name, and get back to query -mode. Example:: - - #zone - n(2x2) - - #query - {namezone name="guard dog pen"} - -Quantum stockpile aliases -~~~~~~~~~~~~~~~~~~~~~~~~~ - -These aliases make it easy to create :wiki:`minecart stop-based quantum stockpiles `. - -+----------------------+------------------+ -| Alias | Sub-aliases | -+======================+==================+ -| quantum | | name | -| | | quantum_enable | -+----------------------+------------------+ -| quantumstopfromnorth | | name | -+----------------------+ | stop_name | -| quantumstopfromsouth | | route_enable | -+----------------------+ | -| quantumstopfromeast | | -+----------------------+ | -| quantumstopfromwest | | -+----------------------+------------------+ -| sp_link | | move | -| | | move_back | -+----------------------+------------------+ -| quantumstop | | name | -| | | stop_name | -| | | route_enable | -| | | move | -| | | move_back | -| | | sp_links | -+----------------------+------------------+ - -The idea is to use a minecart on a track stop to dump an infinite number of -items into a receiving "quantum" stockpile, which significantly simplifies -stockpile management. These aliases configure the quantum stockpile and -hauling route that make it all work. Here is a complete example for quantum -stockpiling weapons, armor, and ammunition. It has a 3x1 feeder stockpile on -the bottom (South), the trackstop in the center, and the quantum stockpile on -the top (North). Note that the feeder stockpile is the only stockpile that -needs to be configured to control which types of items end up in the quantum -stockpile. By default, the hauling route and quantum stockpile itself simply -accept whatever is put into them. - -:: - - #place - ,c - , - pdz(3x1) - - #build - , - ,trackstopN - - #query message(remember to assign a minecart to the new route) - ,quantum - ,quantumstopfromsouth - nocontainers - -The ``quantum`` alias configures a 1x1 stockpile to be a quantum stockpile. It -bans all containers and prevents the stockpile from being manually filled. By -default, it also enables storage of all item categories (except corpses and -refuse), so it doesn't really matter what letter you use to place the -stockpile. :wiki:`Refuse` is excluded by default since otherwise clothes and -armor in the quantum stockpile would rot away. If you want corpses or bones in -your quantum stockpile, use :kbd:`y` and/or :kbd:`r` to place the stockpile -and the ``quantum`` alias will just enable the remaining types. If you *do* -enable refuse in your quantum stockpile, be sure you avoid putting useful -clothes or armor in there! - -The ``quantumstopfromsouth`` alias is run over the track stop and configures -the hauling route, again, allowing all item categories into the minecart by -default so any item that can go into the feeder stockpile can then be placed -in the minecart. It also links the hauling route with the feeder stockpile to -the South.The track stop does not need to be fully constructed before the -``#query`` blueprint is run, but the feeder stockpile needs to exist so we can -link to it. This means that the three blueprints above can be run one right -after another, without any dwarven labor in between them, and the quantum -stockpile will work properly. - -Finally, the ``nocontainers`` alias simply configures the feeder stockpile to -not have any containers (which would just get in the way here). If we wanted -to be more specific about what item types we want in the quantum stockpile, we -could configure the feeder stockpile further, for example with standard -`stockpile adjustment aliases `. - -After the blueprints are run, the last step is to manually assign a minecart -to the newly-defined hauling route. - -You can define sub-aliases to customize how these aliases work, for example to -have fine-grained control over what item types are enabled for the route and -quantum stockpile. We'll go over those options below, but first, here is an -example for how to just give names to everything:: - - #query message(remember to assign a minecart to the new route) - ,{quantum name="armory quantum"} - ,{quantumstopfromsouth name="Armory quantum" stop_name="Armory quantum stop"}{givename name="armory dumper"} - {givename name="armory feeder"} - -All ``name`` sub-aliases are completely optional, of course. Keep in mind that -hauling route names have a maximum length of 22 characters, hauling route stop -names have a maximum length of 21 characters, and all other names have a -maximum length of 20 characters. - -If you want to be absolutely certain that nothing ends up in your quantum -stockpile other than what you've configured in the feeder stockpile, you can -set the ``quantum_enable`` sub-alias for the ``quantum`` alias. This can -prevent, for example, somebody's knocked-out tooth from being considered part -of your furniture quantum stockpile when it happened to land on it during a -fistfight:: - - #query - {quantum name="furniture quantum" quantum_enable={enablefurniture}} - -You can have similar control over the hauling route if you need to be more -selective about what item types are allowed into the minecart. If you have -multiple specialized quantum stockpiles that use a common feeder pile, for -example, you can set the ``route_enable`` sub-alias:: - - #query - {quantumstopfromsouth name="Steel bar quantum" route_enable="{enablebars}{steelbars}"} - -Any of the `stockpile configuration aliases ` can -be used for either the ``quantum_enable`` or ``route_enable`` sub-aliases. -Experienced Dwarf Fortress players may be wondering how the same aliases can -work in both contexts since the keys for entering the configuration screen -differ. Fear not! There is some sub-alias magic at work here. If you define -your own stockpile configuraiton aliases, you can use the magic yourself by -building your aliases on the ``*prefix`` aliases described later in this -guide. - -Finally, the ``quantumstop`` alias is a more general version of the simpler -``quantumstopfrom*`` aliases. The ``quantumstopfrom*`` aliases assume that a -single feeder stockpile is orthogonally adjacent to your track stop (which is -how most people set them up). If your feeder stockpile is somewhere further -away, or you have multiple feeder stockpiles to link, you can use the -``quantumstop`` alias directly. In addition to the sub-aliases used in the -``quantumstopfrom*`` alias, you can define the ``move`` and ``move_back`` -sub-aliases, which let you specify the cursor keys required to move from the -track stop to the (single) feeder stockpile and back again, respectively:: - - #query - {quantumstop move="{Right 2}{Up}" move_back="{Down}{Left 2}"} - -If you have multiple stockpiles to link, define the ``sp_links`` sub-alias, -which can chain several ``sp_link`` aliases together, each with their own -movement configuration:: - - #query - {quantumstop sp_links="{sp_link move=""{Right}{Up}"" move_back=""{Down}{Left}""}{sp_link move=""{Right}{Down}"" move_back=""{Up}{Left}""}"} - -Note the doubled quotes for quoted elements that are within the outer quotes. - -Farm plots -~~~~~~~~~~ - -Sets a farm plot to grow the first or last type of seed in the list of -available seeds for all four seasons. The last seed is usually Plump helmet -spawn, suitable for post-embark. But if you only have one seed type, that'll -be grown instead. - -+------------------+ -| Alias | -+==================+ -| growlastcropall | -+------------------+ -| growfirstcropall | -+------------------+ - -Instead of these aliases, though, it might be more useful to use the DFHack -`autofarm` plugin. - -Stockpile configuration utility aliases -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -================ =========== -Alias Sub-aliases -================ =========== -linksonly -maxbins -maxbarrels -nobins -nobarrels -nocontainers -give2up -give2down -give2left -give2right -give10up -give10down -give10left -give10right -give move -togglesequence -togglesequence2 -masterworkonly prefix -artifactonly prefix -togglemasterwork prefix -toggleartifact prefix -================ =========== - -``linksonly``, ``maxbins``, ``maxbarrels``, ``nobins``, ``nobarrels``, and -``nocontainers`` set the named basic properties on stockpiles. ``nocontainers`` -sets bins and barrels to 0, but does not affect wheelbarrows since the hotkeys -for changing the number of wheelbarrows depend on whether you have DFHack's -``tweak max-wheelbarrow`` enabled. It is better to set the number of -wheelbarrows via the `quickfort` ``stockpiles_max_wheelbarrows`` setting (set to -``0`` by default), or explicitly when you define the stockpile in the ``#place`` -blueprint. - -The ``give*`` aliases set a stockpile to give to a workshop or another -stockpile located at the indicated number of tiles in the indicated direction -from the current tile. For example, here we use the ``give2down`` alias to -connect an ``otherstone`` stockpile with a mason workshop:: - - #place - s,s,s,s,s - s, , , ,s - s, , , ,s - s, , , ,s - s,s,s,s,s - - #build - `,`,`,`,` - `, , , ,` - `, ,wm,,` - `, , , ,` - `,`,`,`,` - - #query - , ,give2down - otherstone - -and here is a generic stone stockpile that gives to a stockpile that only -takes flux:: - - #place - s(10x1) - s(10x10) - - #query - flux - , - give2up - -If you want to give to some other tile that is not already covered by the -``give2*`` or ``give10*`` aliases, you can use the generic ``give`` alias and -specify the movement keys yourself in the ``move`` sub-alias. Here is how to -give to a stockpile or workshop one z-level above, 9 tiles to the left, and 14 -tiles down:: - - #query - {give move="<{Left 9}{Down 14}"} - -``togglesequence`` and ``togglesequence2`` send ``{Down}{Enter}`` or -``{Down 2}{Enter}`` to toggle adjacent (or alternating) items in a list. This -is useful when toggling a bunch of related item types in the stockpile config. -For example, the ``dye`` alias in the standard alias library needs to select -four adjacent items:: - - dye: {foodprefix}b{Right}{Down 11}{Right}{Down 28}{togglesequence 4}^ - -Finally, the ``masterwork`` and ``artifact`` group of aliases configure the -corresponding allowable core quality for the stockpile categories that have -them. This alias is used to implement category-specific aliases below, like -``artifactweapons`` and ``forbidartifactweapons``. - -.. _quickfort-stockpile-aliases: - -Stockpile adjustment aliases -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -For each stockpile item category, there are three standard aliases: - -* ``*prefix`` aliases enter the stockpile configuration screen and position - the cursor at a particular item category in the left-most column, ready for - further keys that configure the elements within that category. All other - stockpile adjustment aliases are built on these prefixes. You can use them - yourself to create stockpile adjustment aliases that aren't already covered - by the standard library aliases. Using the library prefix instead of - creating your own also allows your stockpile configuration aliases to be - used for both stockpiles and hauling routes. For example, here is the - library definition for ``booze``:: - - booze: {foodprefix}b{Right}{Down 5}p{Down}p^ - -* ``enable*`` aliases enter the stockpile configuration screen, enable all - subtypes of the named category, and exit the stockpile configuration screen -* ``disable*`` aliases enter the stockpile configuration screen, disable all - subtypes of the named category, and exit the stockpile configuration screen - -==================== ==================== ===================== -Prefix Enable Disable -==================== ==================== ===================== -animalsprefix enableanimals disableanimals -foodprefix enablefood disablefood -furnitureprefix enablefurniture disablefurniture -corpsesprefix enablecorpses disablecorpses -refuseprefix enablerefuse disablerefuse -stoneprefix enablestone disablestone -ammoprefix enableammo disableammo -coinsprefix enablecoins disablecoins -barsprefix enablebars disablebars -gemsprefix enablegems disablegems -finishedgoodsprefix enablefinishedgoods disablefinishedgoods -leatherprefix enableleather disableleather -clothprefix enablecloth disablecloth -woodprefix enablewood disablewood -weaponsprefix enableweapons disableweapons -armorprefix enablearmor disablearmor -sheetprefix enablesheet disablesheet -==================== ==================== ===================== - -Then, for each item category, there are aliases that manipulate interesting -subsets of that category: - -* Exclusive aliases forbid everthing within a category and then enable only - the named item type (or named class of items) -* ``forbid*`` aliases forbid the named type and leave the rest of the - stockpile untouched. -* ``permit*`` aliases permit the named type and leave the rest of the - stockpile untouched. - -Note that for specific item types (items in the third stockpile configuration -column), you can only toggle the item type on and off. Aliases can't know -whether sending the ``{Enter}`` key will enable or disable the type. The -``forbid*`` aliases that affect these item types assume the item type was -enabled and toggle it off. Likewise, the ``permit*`` aliases assume the item -type was disabled and toggle it on. If the item type is not in the expected -enabled/disabled state when the alias is run, the aliases will not behave -properly. - -Animal stockpile adjustments -```````````````````````````` - -=========== =========== ============ -Exclusive Forbid Permit -=========== =========== ============ -cages forbidcages permitcages -traps forbidtraps permittraps -=========== =========== ============ - -Food stockpile adjustments -`````````````````````````` - -=============== ==================== ==================== -Exclusive Forbid Permit -=============== ==================== ==================== -preparedfood forbidpreparedfood permitpreparedfood -unpreparedfish forbidunpreparedfish permitunpreparedfish -plants forbidplants permitplants -booze forbidbooze permitbooze -seeds forbidseeds permitseeds -dye forbiddye permitdye -tallow forbidtallow permittallow -miscliquid forbidmiscliquid permitmiscliquid -wax forbidwax permitwax -=============== ==================== ==================== - -Furniture stockpile adjustments -``````````````````````````````` - -=================== ========================= ========================= -Exclusive Forbid Permit -=================== ========================= ========================= -pots forbidpots permitpots -bags -buckets forbidbuckets permitbuckets -sand forbidsand permitsand -masterworkfurniture forbidmasterworkfurniture permitmasterworkfurniture -artifactfurniture forbidartifactfurniture permitartifactfurniture -=================== ========================= ========================= - -Notes: - -* The ``bags`` alias excludes coffers and other boxes by forbidding all - materials other than cloth, yarn, silk, and leather. Therefore, it is - difficult to create ``forbidbags`` and ``permitbags`` without affecting other - types of furniture stored in the same stockpile. - -* Because of the limitations of Dwarf Fortress, ``bags`` cannot distinguish - between empty bags and bags filled with gypsum powder. - -Refuse stockpile adjustments -```````````````````````````` - -=========== ================== ================== -Exclusive Forbid Permit -=========== ================== ================== -corpses forbidcorpses permitcorpses -rawhides forbidrawhides permitrawhides -tannedhides forbidtannedhides permittannedhides -skulls forbidskulls permitskulls -bones forbidbones permitbones -shells forbidshells permitshells -teeth forbidteeth permitteeth -horns forbidhorns permithorns -hair forbidhair permithair -craftrefuse forbidcraftrefuse permitcraftrefuse -=========== ================== ================== - -Notes: - -* ``craftrefuse`` includes everything a craftsdwarf can use: skulls, bones, - shells, teeth, horns, and hair. - -Stone stockpile adjustments -``````````````````````````` - -============= ==================== ==================== -Exclusive Forbid Permit -============= ==================== ==================== -metal forbidmetal permitmetal -iron forbidiron permitiron -economic forbideconomic permiteconomic -flux forbidflux permitflux -plaster forbidplaster permitplaster -coalproducing forbidcoalproducing permitcoalproducing -otherstone forbidotherstone permitotherstone -bauxite forbidbauxite permitbauxite -clay forbidclay permitclay -============= ==================== ==================== - -Ammo stockpile adjustments -`````````````````````````` - -============== ==================== ==================== -Exclusive Forbid Permit -============== ==================== ==================== -bolts -\ forbidmetalbolts -\ forbidwoodenbolts -\ forbidbonebolts -masterworkammo forbidmasterworkammo permitmasterworkammo -artifactammo forbidartifactammo permitartifactammo -============== ==================== ==================== - -Bar stockpile adjustments -````````````````````````` - -=========== ================== -Exclusive Forbid -=========== ================== -bars forbidbars -metalbars forbidmetalbars -ironbars forbidironbars -steelbars forbidsteelbars -pigironbars forbidpigironbars -otherbars forbidotherbars -coal forbidcoal -potash forbidpotash -ash forbidash -pearlash forbidpearlash -soap forbidsoap -blocks forbidblocks -=========== ================== - -Gem stockpile adjustments -````````````````````````` - -=========== ================ -Exclusive Forbid -=========== ================ -roughgems forbidroughgems -roughglass forbidroughglass -cutgems forbidcutgems -cutglass forbidcutglass -cutstone forbidcutstone -=========== ================ - -Finished goods stockpile adjustments -```````````````````````````````````` - -======================= ============================= ============================= -Exclusive Forbid Permit -======================= ============================= ============================= -jugs -crafts forbidcrafts permitcrafts -goblets forbidgoblets permitgoblets -masterworkfinishedgoods forbidmasterworkfinishedgoods permitmasterworkfinishedgoods -artifactfinishedgoods forbidartifactfinishedgoods permitartifactfinishedgoods -======================= ============================= ============================= - -Cloth stockpile adjustments -``````````````````````````` - -+------------------+ -| Exclusive | -+==================+ -| thread | -+------------------+ -| adamantinethread | -+------------------+ -| cloth | -+------------------+ -| adamantinecloth | -+------------------+ - -Weapon stockpile adjustments -```````````````````````````` - -================= ======================== ======================= -Exclusive Forbid Permit -================= ======================== ======================= -\ forbidweapons permitweapons -\ forbidtrapcomponents permittrapcomponents -metalweapons forbidmetalweapons permitmetalweapons -\ forbidstoneweapons permitstoneweapons -\ forbidotherweapons permitotherweapons -ironweapons forbidironweapons permitironweapons -bronzeweapons forbidbronzeweapons permitbronzeweapons -copperweapons forbidcopperweapons permitcopperweapons -steelweapons forbidsteelweapons permitsteelweapons -masterworkweapons forbidmasterworkweapons permitmasterworkweapons -artifactweapons forbidartifactweapons permitartifactweapons -================= ======================== ======================= - -Armor stockpile adjustments -``````````````````````````` - -=============== ====================== ===================== -Exclusive Forbid Permit -=============== ====================== ===================== -metalarmor forbidmetalarmor permitmetalarmor -otherarmor forbidotherarmor permitotherarmor -ironarmor forbidironarmor permitironarmor -bronzearmor forbidbronzearmor permitbronzearmor -copperarmor forbidcopperarmor permitcopperarmor -steelarmor forbidsteelarmor permitsteelarmor -masterworkarmor forbidmasterworkarmor permitmasterworkarmor -artifactarmor forbidartifactarmor permitartifactarmor -=============== ====================== ===================== diff --git a/docs/guides/quickfort-library-guide.rst b/docs/guides/quickfort-library-guide.rst index 74823fa7e4..e363fe0987 100644 --- a/docs/guides/quickfort-library-guide.rst +++ b/docs/guides/quickfort-library-guide.rst @@ -1,15 +1,16 @@ +.. _blueprint-library-guide: .. _quickfort-library-guide: -Quickfort Library Guide -======================= +Quickfort blueprint library +=========================== This guide contains a high-level overview of the blueprints available in the -:source:`quickfort blueprint library `. You can list -library blueprints by running ``quickfort list --library`` or by hitting -:kbd:`Alt`:kbd:`l` in the ``quickfort gui`` interactive dialog. +:source:`quickfort blueprint library `. Each file is hyperlinked to its online version so you can see exactly what the -blueprints do. +blueprints do before you run them. Also, if you use `gui/quickfort`, you will +get a live preview of which tiles will be modified by the blueprint before you +apply it to your map. Whole fort blueprint sets ------------------------- @@ -17,8 +18,7 @@ Whole fort blueprint sets These files contain the plans for entire fortresses. Each file has one or more help sections that walk you through how to build the fort, step by step. -- :source:`library/dreamfort.csv ` -- :source:`library/quickfortress.csv ` +- :source:`library/dreamfort.csv ` .. _dreamfort: @@ -27,112 +27,112 @@ Dreamfort Dreamfort is a fully functional, self-sustaining fortress with defenses, farming, a complete set of workshops, self-managing quantum stockpiles, a grand -dining hall, hospital, jail, fresh water well system, guildhalls, noble suites, -and bedrooms for hundreds of dwarves. It also comes with manager work orders to -automate basic fort needs, such as food, booze, and item production. It can -function by itself or as the core of a larger, more ambitious fortress. Read the -high-level walkthrough by running ``quickfort run library/dreamfort.csv`` and -list the walkthroughs for the individual levels by running ``quickfort list -l -dreamfort -m notes`` or ``quickfort gui -l dreamfort notes``. +dining hall, hospital (werecreature-ready), library, temple, jail, fresh water +well system, guildhalls, noble suites, and bedrooms for hundreds of dwarves. It +also comes with manager work orders to automate basic fort needs, such as food, +booze, and item production. It can function by itself or as the core of a +larger, more ambitious fortress. Read the walkthrough by running +`gui/quickfort`, searching for ``dreamfort help``, and selecting the blueprints. Dreamfort blueprints are available for easy viewing and copying `online -`__. +`__. The online spreadsheets also include `embark profile suggestions -`__, +`__, a complete `example embark profile -`__, +`__, and a convenient `checklist -`__ -from which you can copy the ``quickfort`` commands. +`__ +that you can use to track your progress. -You can download a fully built Dreamfort-based fort from `dffd -`__, load it, and explore it -interactively. +If you'd like a visual demonstration, there is a `series of videos on YouTube `__ +that walk you through the entire process of building a Dreamfort-based +fortress. You can also download a fully built Dreamfort-based fort from +:dffd:`dffd <15434>`, load it, and explore it interactively. -Visual overview -``````````````` - -Here are some annotated screenshots of the major levels (or click `here -`__ +Here are annotated screenshots of the major Dreamfort levels (or click `here +`__ for a slideshow). Surface level -\\\\\\\\\\\\\ +````````````` -.. image:: https://drive.google.com/uc?export=download&id=1YL_vQJLB2YnUEFrAg9y3HEdFq3Wpw9WP +.. image:: https://lh3.googleusercontent.com/d/1dlu3nmwQszav-ZaTx-ac28wrcaYBQc_t :alt: Annotated screenshot of the dreamfort surface level - :target: https://drive.google.com/file/d/1YL_vQJLB2YnUEFrAg9y3HEdFq3Wpw9WP + :target: https://drive.google.com/file/d/1dlu3nmwQszav-ZaTx-ac28wrcaYBQc_t :align: center Farming level -\\\\\\\\\\\\\ +````````````` -.. image:: https://drive.google.com/uc?export=download&id=1fBC3G5Y888l4tVe5REAyAd_zeojADVme +.. image:: https://lh3.googleusercontent.com/d/1vDaedLcgoexUdKREUz75ZXQi0ZSdwWwj :alt: Annotated screenshot of the dreamfort farming level - :target: https://drive.google.com/file/d/1fBC3G5Y888l4tVe5REAyAd_zeojADVme + :target: https://drive.google.com/file/d/1vDaedLcgoexUdKREUz75ZXQi0ZSdwWwj :align: center Industry level -\\\\\\\\\\\\\\ +`````````````` -.. image:: https://drive.google.com/uc?export=download&id=1emMaHHCaUPcdRbkLQqvr-0ZCs2tdM5X7 +.. image:: https://lh3.googleusercontent.com/d/1c8YTHxTgJY5tUII-BOWdLhmDFAHwIOEs :alt: Annotated screenshot of the dreamfort industry level - :target: https://drive.google.com/file/d/1emMaHHCaUPcdRbkLQqvr-0ZCs2tdM5X7 + :target: https://drive.google.com/file/d/1c8YTHxTgJY5tUII-BOWdLhmDFAHwIOEs + :align: center -Services level -\\\\\\\\\\\\\\ +Services levels (4 deep) +```````````````````````` -.. image:: https://drive.google.com/uc?export=download&id=13vDIkTVOZGkM84tYf4O5nmRs4VZdE1gh +.. image:: https://lh3.googleusercontent.com/d/1RQMy_zYQWM5GN7-zjn6LoLWmnrJjkxPM :alt: Annotated screenshot of the dreamfort services level - :target: https://drive.google.com/file/d/13vDIkTVOZGkM84tYf4O5nmRs4VZdE1gh + :target: https://drive.google.com/file/d/1RQMy_zYQWM5GN7-zjn6LoLWmnrJjkxPM :align: center -.. image:: https://drive.google.com/uc?export=download&id=1jlGr6tAhS8i-XFTz8gowTZBhXcfjfL_L - :alt: Annotated screenshot of the dreamfort cistern - :target: https://drive.google.com/file/d/1jlGr6tAhS8i-XFTz8gowTZBhXcfjfL_L + +**Example plumbing to fill cisterns** + +If you are routing water to fill the cisterns, you can do it like this: + +.. image:: https://lh3.googleusercontent.com/d/1paXqPJ-7h9_jG_eNXU1z5GGvR0J8C0uJ + :alt: Annotated screenshot of an example plumbing for the dreamfort cisterns + :target: https://drive.google.com/file/d/1paXqPJ-7h9_jG_eNXU1z5GGvR0J8C0uJ :align: center -Example plumbing to fill cisterns -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +Cistern drain (keep open while you're digging out the aquifer tap): -.. image:: https://drive.google.com/uc?export=download&id=1GvhX_pVDOlmqTi2OujoBqCG_qX36ExAv - :alt: Annotated screenshot of an example aqueduct addition to the dreamfort cistern - :target: https://drive.google.com/file/d/1GvhX_pVDOlmqTi2OujoBqCG_qX36ExAv +.. image:: https://lh3.googleusercontent.com/d/1SwSluJcN_kOrCYPdcFOfJ13wEDvZGcJe + :alt: Annotated screenshot of an example drainage for the dreamfort cisterns + :target: https://drive.google.com/file/d/1SwSluJcN_kOrCYPdcFOfJ13wEDvZGcJe :align: center Guildhall level -\\\\\\\\\\\\\\\ +``````````````` -.. image:: https://drive.google.com/uc?export=download&id=17jHiCKeZm6FSS-CI4V0r0GJZh09nzcO_ +.. image:: https://lh3.googleusercontent.com/d/1mt66QOkfBqFLtw6AJKU6GNYmhB72XSJG :alt: Annotated screenshot of the dreamfort guildhall level - :target: https://drive.google.com/file/d/17jHiCKeZm6FSS-CI4V0r0GJZh09nzcO_ + :target: https://drive.google.com/file/d/1mt66QOkfBqFLtw6AJKU6GNYmhB72XSJG :align: center Noble suites -\\\\\\\\\\\\ +```````````` -.. image:: https://drive.google.com/uc?export=download&id=1IBqCf6fF3lw7sHiBE_15Euubysl5AAiS +.. image:: https://lh3.googleusercontent.com/d/16XRb1w5zFoyVq2LBMx_aCwOyjFq7GULc :alt: Annotated screenshot of the dreamfort noble suites - :target: https://drive.google.com/file/d/1IBqCf6fF3lw7sHiBE_15Euubysl5AAiS + :target: https://drive.google.com/file/d/16XRb1w5zFoyVq2LBMx_aCwOyjFq7GULc :align: center Apartments -\\\\\\\\\\ +`````````` -.. image:: https://drive.google.com/uc?export=download&id=1mDQQXG8BnXqasRGFC9R5N6xNALiswEyr +.. image:: https://lh3.googleusercontent.com/d/16-NXlodLIQjeZUMSmsWRafeytwU2dXQo :alt: Annotated screenshot of the dreamfort apartments - :target: https://drive.google.com/file/d/1mDQQXG8BnXqasRGFC9R5N6xNALiswEyr + :target: https://drive.google.com/file/d/16-NXlodLIQjeZUMSmsWRafeytwU2dXQo :align: center -The Quick Fortress -~~~~~~~~~~~~~~~~~~ +Crypt +````` -The Quick Fortress is an updated version of the example fortress that came with -`Python Quickfort 2.0 `__ (the program -DFHack quickfort was inspired by). While it is not a complete fortress by -itself, it is much simpler than Dreamfort and is good for a first introduction -to `quickfort` blueprints. Read its walkthrough with ``quickfort run -library/quickfortress.csv``. +.. image:: https://lh3.googleusercontent.com/d/16iT_ho7BIRPD_eofuxdlVQ4FunR1Li23 + :alt: Annotated screenshot of the dreamfort crypt + :target: https://drive.google.com/file/d/16iT_ho7BIRPD_eofuxdlVQ4FunR1Li23 + :align: center Layout helpers -------------- @@ -145,21 +145,21 @@ these ``#dig`` blueprints can only mark undug wall tiles for mining, they are best used underground. They won't do much on the surface, where there aren't many walls. -- :source:`library/layout-helpers/mark_up_left.csv ` -- :source:`library/layout-helpers/mark_up_right.csv ` -- :source:`library/layout-helpers/mark_down_right.csv ` -- :source:`library/layout-helpers/mark_down_left.csv ` +- :source:`library/layout-helpers/mark_up_left.csv ` +- :source:`library/layout-helpers/mark_up_right.csv ` +- :source:`library/layout-helpers/mark_down_right.csv ` +- :source:`library/layout-helpers/mark_down_left.csv ` Bedrooms -------- These are popular bedroom layouts from the :wiki:`Bedroom design` page on the -wiki. Each file has ``#dig``, ``#build``, and ``#query`` blueprints to dig the -rooms, build the furniture, and configure the beds as bedrooms, respectively. +wiki. Each file has blueprints to dig the rooms, zone them as bedrooms, and +build the furniture. -- :source:`library/bedrooms/48-4-Raynard_Whirlpool_Housing.csv ` -- :source:`library/bedrooms/95-9-Hactar1_3_Branch_Tree.csv ` -- :source:`library/bedrooms/28-3-Modified_Windmill_Villas.csv ` +- :source:`library/bedrooms/48-4-Raynard_Whirlpool_Housing.csv ` +- :source:`library/bedrooms/95-9-Hactar1_3_Branch_Tree.csv ` +- :source:`library/bedrooms/28-3-Modified_Windmill_Villas.csv ` Tombs ----- @@ -167,27 +167,66 @@ Tombs These blueprints have burial plot layouts for fortress that expect a lot of casualties. -- :source:`library/tombs/Mini_Saracen.csv ` -- :source:`library/tombs/The_Saracen_Crypts.csv ` +- :source:`library/tombs/Mini_Saracen.csv ` +- :source:`library/tombs/The_Saracen_Crypts.csv ` Exploratory mining ------------------ Several mining patterns to choose from when searching for gems or ores. The -patterns can be repeated up or down z-levels for exploring through the depths. +patterns can be repeated up or down z-levels (via `gui/quickfort`\'s +:kbd:`r`\epeat functionality) for exploring through the depths. -- :source:`library/exploratory-mining/tunnels.csv ` -- :source:`library/exploratory-mining/vertical-mineshafts.csv ` -- :source:`library/exploratory-mining/connected-mineshafts.csv ` +- :source:`library/exploratory-mining/tunnels.csv ` +- :source:`library/exploratory-mining/vertical-mineshafts.csv ` +- :source:`library/exploratory-mining/connected-mineshafts.csv ` Miscellaneous ------------- Extra blueprints that are useful in specific situations. -- :source:`library/embark.csv ` +- :source:`library/aquifer_tap.csv ` +- :source:`library/embark.csv ` +- :source:`library/pump_stack.csv ` + +Light aquifer tap +~~~~~~~~~~~~~~~~~ + +The aquifer tap helps you create a safe, everlasting source of fresh water from +a light aquifer. See the step-by-step guide, including information on how to +create a drainage system so your dwarves don't drown when digging the tap, by +running the ``library/aquifer_tap.csv`` ``/help`` blueprint. Alternately, view +the demo video below. + +You can see how to nullify the water pressure (so you don't flood your fort) in +the Dreamfort cistern screenshot above: `Services levels (4 deep)`_. + +.. raw:: html + + + +The blueprint spreadsheet is also available +`online `__. + +Post-embark +~~~~~~~~~~~ The embark blueprints are useful directly after embark. It contains a ``#build`` blueprint that builds important starting workshops (mason, carpenter, mechanic, and craftsdwarf) and a ``#place`` blueprint that lays down a pattern of useful starting stockpiles. + +Pump stack +~~~~~~~~~~ + +The pump stack blueprints help you move water and magma up to more convenient +locations in your fort. See the step-by-step guide for using it by running the +``library/pump_stack.csv`` ``/help`` blueprint or by viewing the demo video: + +.. raw:: html + + + +The blueprint spreadsheet is also available +`online `__. diff --git a/docs/guides/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst index 1b10eefe85..dae03c3aba 100644 --- a/docs/guides/quickfort-user-guide.rst +++ b/docs/guides/quickfort-user-guide.rst @@ -1,132 +1,119 @@ -.. _quickfort-user-guide: .. _quickfort-blueprint-guide: +.. _quickfort-user-guide: +.. _quickfort-alias-guide: -Quickfort Blueprint Guide -========================= +Quickfort blueprint creation guide +================================== -`Quickfort ` is a DFHack script that helps you build fortresses from +`Quickfort ` is a DFHack tool that helps you build fortresses from "blueprint" .csv and .xlsx files. Many applications exist to edit these files, such as MS Excel and `Google Sheets `__. Most layout and -building-oriented DF commands are supported through the use of multiple files or -spreadsheets, each describing a different phase of DF construction: designation, -building, placing stockpiles/zones, and setting configuration. +building-oriented DF actions are supported through the use of multiple files or +spreadsheets, each describing a different phase of DF construction: designating +digging, defining zones, placing stockpiles, and building. The original idea came from :wiki:`Valdemar's ` auto-designation macro. Joel Thornton reimplemented the core logic in Python and extended its functionality with `Quickfort 2.0 `__. This DFHack-native implementation, called "DFHack Quickfort" or just "quickfort", -builds upon Quickfort 2.0's formats and features. Any blueprint that worked in -Python Quickfort 2.0 should work with DFHack Quickfort. DFHack Quickfort -interacts with Dwarf Fortress memory structures directly, allowing for +builds upon Quickfort 2.0's formats and features, preserving compatibility with +existing blueprints (where possible -- DF itself has changed since then). In +contrast with the earlier quickfort implementations, which interacted with DF +by simulating keyboard input, DFHack Quickfort calls lower-level API functions +to designate tiles and configure buildings. This allows for nearly instantaneous blueprint application, error checking and recovery, and many other advanced features. -This guide focuses on DFHack Quickfort's capabilities and teaches players how -to understand and create blueprint files. Some of the text was originally -written by Joel Thornton, reused here with his permission. +This guide focuses on DFHack Quickfort's capabilities and blueprint syntax, and +teaches players how to understand and create blueprint files. Some of the text +was originally written by Joel Thornton, reused here with his permission. -For those just looking to apply existing blueprints, check out the `quickfort -command's documentation ` for syntax. There are many ready-to-use -blueprints available in the ``blueprints/library`` subfolder in your DFHack -installation. Browse them on your computer or -:source:`online `, or run ``quickfort list -l`` at the -``[DFHack]#`` prompt to list them, and then ``quickfort run`` to apply them to -your fort! +If you are just looking to apply existing blueprints to your fort, check out +`gui/quickfort` (or `quickfort` for the commandline version). There are many +ready-to-use blueprints available in the `quickfort-library-guide` distributed +with DFHack. Before you become an expert at writing blueprints, though, you should know that the easiest way to make a quickfort blueprint is to build your plan "for real" -in Dwarf Fortress and then export your map using the DFHack `blueprint` plugin. -You can apply those blueprints as-is in your next fort, or you can fine-tune -them with additional features from this guide. +in Dwarf Fortress and then export that section of your map using +`gui/blueprint`. You can apply those blueprints as-is in your next fort, or you +can fine-tune them with additional features from this guide. See the `Links`_ section for more information and online resources. - .. contents:: Table of Contents :local: :depth: 2 +Feature summary +--------------- -Features --------- - -- General +- General - - Manages blueprints to handle all phases of DF construction - - Supports .csv and multi-worksheet .xlsx blueprint files - - Near-instant application, even for very large and complex blueprints - - Blueprints can span multiple z-levels - - You can package all blueprints and aliases needed for an entire fortress - in a single file for easy sharing - - "meta" blueprints that simplify the application of sequences of blueprints - - Undo functionality for dig, build, place, and zone blueprints - - Automatic cropping of blueprints so you don't get errors if the blueprint - extends off the map - - Can generate manager orders for everything required by a build blueprint - - Includes a library of ready-to-use blueprints - - Verbose output mode for blueprint debugging + - Blueprint modes for all phases of fort design + - Read blueprints from .csv or multi-worksheet .xlsx files + - Near-instant application, even for very large and complex blueprints + - Blueprints can span multiple z-levels + - Easy sharing of blueprints with multi-blueprint files + - Scripted application of sequences of blueprints + - Undo applied blueprints + - Rotate blueprints or flip them around + - Automatic cropping of blueprints that extend off the map + - Generate manager orders for items required by a blueprint + - Includes a library of ready-to-use blueprints + - Blueprint debugging -- Dig mode +- Dig mode - - Supports all types of designations, including dumping/forbidding items and + - Supports all types of designations, including dumping/forbidding items and setting traffic settings - - Supports setting dig priorities - - Supports applying dig blueprints in marker mode - - Handles carving arbitrarily complex minecart tracks, including tracks that + - Supports setting dig priorities + - Supports applying dig blueprints in marker mode + - Handles carving arbitrarily complex minecart tracks, including tracks that cross other tracks -- Build mode +- Zone and place modes - - Fully integrated with DFHack buildingplan: you can place buildings before - manufacturing building materials and you can use the buildingplan UI for - setting materials preferences - - Designate entire constructions in mid-air without having to wait for each + - Define zones and stockpiles of any shape, not just rectangles + - Configurable numbers of bins, barrels and wheelbarrows assigned to created + stockpiles + - Automatic splitting of stockpiles that exceed maximum dimension limits + - Create and attach locations to zones + - Full control over stockpile configuration based on the `stockpiles` + settings library + - Configurable zone/location settings, such as the pit/pond toggle or + hospital supply quantities + +- Build mode + + - Integrated with DFHack `buildingplan`: you can place buildings before + manufacturing building materials and you can use the `buildingplan` UI + for setting materials and quality preferences + - Designate entire constructions in mid-air without having to wait for each tile to become supported - - Automatic expansion of building footprints to their minimum dimensions, so + - Automatic expansion of building footprints to their minimum dimensions, so only the center tile of a multi-tile building needs to be recorded in the blueprint - - Tile occupancy and validity checking so, for example, buildings that - cannot be placed on a target tile will be skipped instead of messing up - the blueprint. Blueprints that are only partially applied for any reason - (e.g. you need to dig out some more tiles) can be safely reapplied to - build the remaining buildings. - - Relaxed rules for farm plot and road placement: you can still place the + - Tile occupancy and validity checking so, for example, buildings that + cannot be placed on a target tile will be skipped instead of causing + errors and interrupting the blueprint. Blueprints that are only partially + applied for any reason (e.g. you need to dig out some more tiles) can be + safely reapplied to build the remaining buildings. + - Relaxed rules for farm plot and road placement: you can still place the building even if an invalid tile (e.g. stone tiles for farm plots) splits the designated area into two disconnected parts - - Intelligent boundary detection for adjacent buildings of the same type + - Intelligent boundary detection for adjacent buildings of the same type (e.g. a 6x6 block of ``wj`` cells will be correctly split into 4 jeweler's workshops) + - Set building properties (such as a name) + - Can attach and configure track stops as part of hauling routes -- Place and zone modes +- Burrow mode - - Define stockpiles and zones of shape, not just rectangles - - Configurable numbers of bins, barrels and wheelbarrows assigned to created - stockpiles - - Automatic splitting of stockpiles and zones that exceed maximum dimension - limits - - Fully configurable zone settings, such as pit/pond and hospital supply - counts - -- Query mode - - - Send arbitrary keystroke sequences to the UI -- *anything* you can do - through the UI is supported - - Supports aliases to simplify frequent keystroke combos - - Includes a library of pre-made and tested aliases to simplify most common - tasks, such as configuring stockpiles for important item types or creating - named hauling routes for quantum stockpiles. - - Supports including aliases in other aliases for easy management of common - subsequences - - Supports repeating key sequences a specified number of times - - Skips sending keys when the cursor is over a tile that does not have a - stockpile or building, so missing buildings won't desynchronize your - blueprint - - Instant halting of query blueprint application when keystroke errors are - detected, such as when a mistake in a key sequence leaves us stuck in a - submenu, to make query blueprints easier to debug + - Supports creating, adding to, and subtracting from burrows. -Editing blueprints ------------------- +Introduction to blueprints +-------------------------- We recommend using a spreadsheet editor such as Excel, `Google Sheets `__, or `LibreOffice `__ @@ -135,76 +122,100 @@ to edit blueprint files, but any text editor will do. The format of Quickfort-compatible blueprint files is straightforward. The first line (or upper-left cell) of the spreadsheet should look like this:: - #dig + #dig -The keyword ``dig`` tells Quickfort we are going to be using the Designations -menu in DF. The following "mode" keywords are understood: +The keyword ``dig`` tells Quickfort we are going to be specifying designations. +The following "mode" keywords are understood: ============== =========== Blueprint mode Description ============== =========== -dig Designations menu (:kbd:`d`) -build Build menu (:kbd:`b`) -place Place stockpiles menu (:kbd:`p`) -zone Activity zones menu (:kbd:`i`) -query Set building tasks/prefs menu (:kbd:`q`) +dig Designations (digging, traffic, dumping, etc.) +build Constructions, buildings, and furniture +place Stockpiles +zone Activity zones ============== =========== If no modeline appears in the first cell, Quickfort assumes that it's looking at a ``#dig`` blueprint. There are also other modes that don't directly correspond to Dwarf Fortress -menus, but we'll talk about those `later `. +design operations, but we'll talk about those `later `. If you like, you may enter a comment after the mode keyword. This comment will -appear in the output of ``quickfort list`` when run from the ``DFHack#`` prompt. -You can use this space for explanations, attribution, etc. +appear in the output of ``quickfort list`` or in the dialog window when running +`gui/quickfort`. You can use this space for explanations, attribution, etc.:: -:: + #dig grand dining room - #dig grand dining room - -Below this line begin entering keys in each spreadsheet cell that represent what -you want designated in the corresponding game map tile. For example, we could -dig out a 4x4 room like so (spaces are used as column separators here for +Below this line, begin entering keys in each spreadsheet cell that represent +what you want designated in the corresponding game map tile. For example, we +could dig out a 4x4 room like so (spaces are used as column separators here for readability, but a real .csv file would have commas):: - #dig - d d d d # - d d d d # - d d d d # - d d d d # - # # # # # + #dig + d d d d # + d d d d # + d d d d # + d d d d # + # # # # # + +The letter ``d`` here stands for "dig". The character sequences in these +blueprints are based on the old (pre-v50) keyboard shortcuts for the various DF +menus. Please see the `quickfort_guide_appendix` below for a full reference. Note the :kbd:`#` symbols at the right end of each row and below the last row. These are completely optional, but can be helpful to make the row and column positions clear. -Once the dwarves have that dug out, let's build a walled-in bedroom within our -dug-out area:: - - #build - Cw Cw Cw Cw # - Cw b h Cw # - Cw Cw # - Cw Cw Cw # - # # # # # - -Note my generosity - in addition to the bed (:kbd:`b`) I've built a chest -(:kbd:`c`) here for the dwarf as well. You must use the full series of keys -needed to build something in each cell, e.g. :kbd:`C`:kbd:`w` indicates we -should enter DF's constructions submenu (:kbd:`C`) and select walls (:kbd:`w`). - -I'd also like to place a booze stockpile in the 2 unoccupied tiles in the room. - -:: - - #place Place a food stockpile - ` ` ` ` # - ` ~ ~ ` # - ` f f ` # - ` ` ` # - # # # # # +In general, any cell that contains text that starts with a :kbd:`#` is +interpreted as a comment and is ignored by `quickfort`. You can use this to +leave notes for yourself inside of a blueprint. Take care to start your comment +with a space after the ``#`` to avoid accidentally starting a modeline if your +comment happens to be in the first column and happens to start with a modeline +keyword. For example, ``#dig this area out`` is an accidental modeline that +will cause problems. However, ``# dig this area out`` is a safe comment. + +Once the dwarves have that dug out, let's zone it as a bedroom:: + + #zone + b b b b # + b b b b # + b b b b # + b b b b # + # # # # # + +This looks very similar to the ``#dig`` blueprint above, but with ``b``\s +instead of ``d``\s. The ``b``\s mark the area for a ``b``\edroom zone just like +the ``#dig`` blueprint marked the area for digging. It's important to wait +until after the area is completely dug out before applying further blueprints +since zones can't be applied to hidden tiles and furniture can't be built in +undug walls. + +Now, let's add some walls and furniture:: + + #build + Cw Cw Cw Cw # + Cw b h Cw # + Cw Cw # + Cw Cw Cw # + # # # # # + +The :kbd:`C`:kbd:`w` cells represent the constructed walls, leaving space for a +door that we might want to add later. Quickfort uses `buildingplan` for +managing buildings, so the walls will be built out of whatever matches the +current buildingplan filter set for walls. Also note my generosity -- in +addition to the bed (:kbd:`b`) I've built a container (:kbd:`h`) for this lucky +dwarf. + +Finally, let's place a booze stockpile in the 2 unoccupied tiles in the room:: + + #place personal booze stockpile + ` ` ` ` # + ` ~ ~ ` # + ` f f{name="bedroom booze"}:=booze + ` ` ` # + # # # # # This illustration may be a little hard to understand. The two :kbd:`f` characters are in row 3, columns 2 and 3. All the other cells are empty. QF @@ -215,99 +226,74 @@ multilayer or fortress-wide blueprint layouts as "chalk lines". QF is smart enough to recognize this as a 2x1 food stockpile, and creates it as such rather than as two 1x1 food stockpiles. Quickfort treats any connected region of identical designations as a single entity. The tiles can be connected -orthogonally or diagonally, just as long as they are touching. - -Lastly, let's turn the bed into a bedroom and set the food stockpile to hold -only booze. +orthogonally or diagonally, just as long as they are touching. You can also +treat disconnected segments as belonging to the same stockpile, but we'll get +into `Label syntax`_ later. -:: +Now what's all that business attached to the second ``f``? The part between the +curly brackets specifies properties, in this case the name that we want to give +the stockpile. The remaining part, from the colon (``:``) onward, applies the +``booze`` preset from the `stockpiles` library. That will configure the +stockpile to accept only booze. You can use presets (along with other options +that we'll go over later) to configure stockpiles however you want, directly +from the ``#place`` blueprint. - #query - ` ` ` ` # - ` r& ` # - ` booze # - ` ` ` ` # - # # # # # - -In row 2, column 2 we have ``r&``. This sends the :kbd:`r` key to DF when the -cursor is over the bed, causing us to "make room" and :kbd:`Enter`, represented -by special ``&`` alias, to indicate that we're done setting the size (the -default room size is fine here). - -In column 2, row 3 we have ``booze``. This is one of many alias keywords defined -in the included :source:`aliases library `. -This particular alias sets a food stockpile to accept only booze. It sends the -keys needed to navigate DF's stockpile settings menu, and then it sends an -Escape character to exit back to the map. It is important to exit out of any -menus that you enter while in query mode so that the cursor can move to the next -tile when it is done with the current tile. - -If there weren't an alias named ``booze`` then the literal characters -:kbd:`b`:kbd:`o`:kbd:`o`:kbd:`z`:kbd:`e` would have been sent, so be sure to -spell those aliases correctly! - -You can save a lot of time and effort by using aliases instead of adding all -key seqences directly to your blueprints. For more details, check out the -`Quickfort Alias Guide `. You can also see examples of -aliases being used in the query blueprints in the -:source:`DFHack blueprint library `. You can create -your own aliases by adding them to :source:`dfhack-config/quickfort/aliases.txt` -in your DFHack folder or you can add them -`directly to your blueprint files `. +And that's it! You now have a series of blueprints that you can "stamp" across +your fort to quickly build new bedrooms. Area expansion syntax ~~~~~~~~~~~~~~~~~~~~~ In Quickfort, the following blueprints are equivalent:: - #dig a 3x3 area - d d d # - d d d # - d d d # - # # # # + #dig a 3x3 area + d d d # + d d d # + d d d # + # # # # - #dig the same area with d(3x3) specified in row 1, col 1 - d(3x3)# - ` ` ` # - ` ` ` # - # # # # + #dig the same area with d(3x3) specified in row 1, col 1 + d(3x3)# + ` ` ` # + ` ` ` # + # # # # The second example uses Quickfort's "area expansion syntax", which takes the form:: - keys(WxH) + text(WxH) Note that area expansion syntax can only specify rectangular areas. If you want to create extent-based structures (e.g. farm plots or stockpiles) in different shapes, use the first format above. For example:: - #place L shaped food stockpile - f f ` ` # - f f ` ` # - f f f f # - f f f f # - # # # # # + #place A single L shaped food stockpile + f f ` ` # + f f ` ` # + f f f f # + f f f f # + # # # # # Area expansion syntax also sets boundaries, which can be useful if you want adjacent, but separate, stockpiles of the same type:: - #place Two touching but separate food stockpiles - f(4x2) # - ~ ~ ~ ~ # - f(4x2) # - ~ ~ ~ ~ # - # # # # # + #place Two touching but separate food stockpiles + f(2x2) # + ~ ~ ` ` # + f(4x2) # + ~ ~ ~ ~ # + # # # # # As mentioned previously, :kbd:`~` characters are ignored as comment characters and can be used for visualizing the blueprint layout. This blueprint can be equivalently written as:: - #place Two touching but separate food stockpiles - f(4x2) # - ~ ~ ~ ~ # - f f f f # - f f f f # - # # # # # + #place Two touching but separate food stockpiles + f(2x2) # + ~ ~ ` ` # + f f f f # + f f f f # + # # # # # since the area expansion syntax of the upper stockpile prevents it from combining with the lower, freeform syntax stockpile. @@ -315,15 +301,77 @@ combining with the lower, freeform syntax stockpile. Area expansion syntax can also be used for buildings which have an adjustable size, like bridges. The following blueprints are equivalent:: - #build a 4x2 bridge from row 1, col 1 - ga(4x2) ` # - ` ` ` ` # - # # # # # + #build a 4x2 bridge from row 1, col 1 + ga(4x2) ` # + ` ` ` ` # + # # # # # + + #build a 4x2 bridge from row 1, col 1 + ga ga ga ga # + ga ga ga ga # + # # # # # + +If it is convenient to do so, you can place the cell with the expansion syntax +in any corner of the resulting rectangle. Just use negative numbers to indicate +which direction the designation should expand in. For example, the previous +blueprint could also be written as:: - #build a 4x2 bridge from row 1, col 1 - ga ga ga ga # - ga ga ga ga # - # # # # # + #build a 4x2 bridge from row 2, col 4 + ` ` ` ` # + ga(4x-2) ` # + # # # # # + +Property syntax +~~~~~~~~~~~~~~~ + +Many things you can designate with `quickfort` are configurable. All buildings, +stockpiles, and zones, for example, can be named. These configuration elements +are expressed as properties. + +Properties are written between curly brackets (``{}``). There can be multiple +properties defined between those brackets, separated by spaces. Each property +has a name and a value, with an equal sign to connect them. If a property value +has a space within it, it should be surrounded by double quotes (``"``). + +If you have defined the area of something over multiple spreadsheet cells, you +can specify properties in just one of those cells and they will apply to the +whole object. You can even split properties up among multiple cells if that is +more convenient. If you are using expansion syntax, the expansion part always +goes last. + +Here's an example of a seed stockpile that is configured to take from a seed +feeder stockpile:: + + #place + f{name=Seeds links_only=true}:=seeds(3x2) + + f + f{name="Seeds feeder" give_to=Seeds}:=seeds + f{containers=0} + +Different modes and different types may have different properties that you can +configure. See the `quickfort_guide_appendix` for a full list. + +Label syntax +~~~~~~~~~~~~ + +Labels are different from the ``name`` property. They are only used internally +by Quickfort to associate tiles with a particular zones or stockpiles. This is +useful for when you want to define two touching zones or stockpiles of the same +type(s), but you can't use expansion syntax because they are non-rectangular. +It is also useful for marking two *disconnected* regions as belonging to the +same zone or stockpile. Note that every tile in the zone or stockpile must be +marked with the same label:: + + #place two touching stockpiles of the same type + f/feed f/feed f/feed{name="Seeds feeder" containers=0}:=seeds + f/feed f f/feed + f f f{name=Seeds links_only=true take_from="Seeds feeder"}:=seeds + + #zone one pasture in two disconnected regions + n/slots n/slots n/slots + + n/slots{name="Pasture slots"}(3x1) Automatic area expansion ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -332,38 +380,38 @@ Buildings larger than 1x1, like workshops, can be represented in any of three ways. You can designate just their center tile with empty cells around it to leave room for the footprint, like this:: - #build a mason workshop in row 2, col 2 that will occupy the 3x3 area - ` ` ` # - ` wm ` # - ` ` ` # - # # # # + #build a stonecutter workshop in row 2, col 2 that will occupy the 3x3 area + ` ` ` # + ` wm ` # + ` ` ` # + # # # # Or you can fill out the entire footprint like this:: - #build a mason workshop - wm wm wm # - wm wm wm # - wm wm wm # - # # # # + #build a stonecutter workshop + wm wm wm # + wm wm wm # + wm wm wm # + # # # # This format may be verbose for regular workshops, but it can be very helpful for laying out structures like screw pump towers and waterwheels, whose "center point" can be non-obvious. -Finally, you can use area expansion syntax to represent the workshop:: +Or you can use area expansion syntax:: - #build a mason workshop - wm(3x3) # - ` ` ` # - ` ` ` # - # # # # + #build a stonecutter workshop + wm(3x3) # + ` ` ` # + ` ` ` # + # # # # This style can be convenient for laying out multiple buildings of the same type. If you are building a large-scale block factory, for example, this will create -20 mason workshops all in a row:: +20 stonecutter workshops all in a row:: - #build line of 20 mason workshops - wm(60x3) + #build line of 20 stonecutter workshops + wm(60x3) Quickfort will intelligently break large areas of the same designation into appropriately-sized chunks. @@ -377,123 +425,365 @@ each floor. :: - #dig Stairs leading down to a small room below - j ` ` # - ` ` ` # - ` ` ` # - #> # # # - u d d # - d d d # - d d d # - # # # # + #dig Stairs leading down to a small room below + j ` ` # + ` ` ` # + ` ` ` # + #> # # # + u d d # + d d d # + d d d # + # # # # The marker must appear in the first column of the row to be recognized, just like a modeline. +You can go up or down multiple levels by adding a number after the ``<`` or +``>``. For example:: + + #dig Two double-level quarries + r(10x10) + #>2 + r(10x10) + +#dig mode +--------- + +``#dig`` blueprints are normally the first step in any design. They define the +boundaries and layouts for the blueprints for later stages of construction. +Despite their name, ``#dig`` blueprints are for more than just digging. They +also handle smoothing, carving, traffic designations, and marking items on the +ground for dumping, forbidding, or other similar tags. See the full list of +supported designations in the `#dig mode reference`_. + .. _quickfort-dig-priorities: Dig priorities ~~~~~~~~~~~~~~ -DF designation priorities are supported for ``#dig`` blueprints. The full syntax -is ``[letter][number][expansion]``, where if the ``letter`` is not specified, -``d`` is assumed, and if ``number`` is not specified, ``4`` is assumed (the -default priority). So each of these blueprints is equivalent:: - - #dig dig the interior of the room at high priority - d d d d d # - d d1 d1 d1 d # - d d1 d1 d1 d # - d d1 d1 d1 d # - d d d d d # - # # # # # # - - #dig dig the interior of the room at high priority - d d d d d # - d d1(3x3) d # - d ` ` ` d # - d ` ` ` d # - d d d d d # - # # # # # # - - #dig dig the interior of the room at high priority - 4 4 4 4 4 # - 4 1 1 1 4 # - 4 1 1 1 4 # - 4 1 1 1 4 # - 4 4 4 4 4 # - # # # # # # - -Marker mode +DF designation priorities are supported in ``#dig`` blueprints. The full syntax +is ``[markers][symbol][number][expansion]``, where if the ``symbol`` is not +specified, ``d`` is assumed, and if ``number`` is not specified, ``4`` is +assumed (the default priority). So all of these blueprints are equivalent:: + + #dig dig the interior of the room at high priority + d d d d d # + d d1 d1 d1 d # + d d1 d1 d1 d # + d d1 d1 d1 d # + d d d d d # + # # # # # # + + #dig dig the interior of the room at high priority + d d d d d # + d d1(3x3) d # + d ` ` ` d # + d ` ` ` d # + d d d d d # + # # # # # # + + #dig dig the interior of the room at high priority + 4 4 4 4 4 # + 4 1 1 1 4 # + 4 1 1 1 4 # + 4 1 1 1 4 # + 4 4 4 4 4 # + # # # # # # + +At least one of the symbol and the priority number must be specified. + +Dig markers ~~~~~~~~~~~ -Marker mode is useful for when you want to plan out your digging, but you don't -want to dig everything just yet. In ``#dig`` mode, you can add a :kbd:`m` before -any other designation letter to indicate that the tile should be designated in -marker mode. For example, to dig out the perimeter of a room, but leave the -center of the room marked for digging later:: +There are three types of markers you can apply to dig designated tiles. You can +apply multiple markers to the same tile by including multiple marker prefixes. +For example, a tile that is in blueprint mode and that is also marked for warm +and damp dig would be written as:: + + #dig + mbmwmdd - #dig - d d d d d # - d md md md d # - d md md md d # - d md md md d # - d d d d d # - # # # # # # +Blueprint marker +```````````````` -Then you can use "Toggle Standard/Marking" (:kbd:`d`:kbd:`M`) to convert the -center tiles to regular designations at your leisure. +"Blueprint" markers are useful for when you want to plan out your digging, but +you don't want to dig everything just yet. Here, "blueprint" refers to the +vanilla UI "blueprint mode" vs. "standard mode" buttons. You can use DF's +"Change blueprints to standard selections" button to convert the "blueprint" +marked tiles to regular designations. -To apply an entire dig blueprint in marker mode, regardless of what the -blueprint itself says, you can set the global quickfort setting -``force_marker_mode`` to ``true`` before you apply the blueprint. +For example, to dig out the perimeter of a room, but leave the center of the +room marked for digging later:: -Note that the in-game UI setting "Standard/Marker Only" (:kbd:`d`:kbd:`m`) does -not have any effect on quickfort. + #dig + d d d d d # + d mbd mbd mbd d # + d mbd mbd mbd d # + d mbd mbd mbd d # + d d d d d # + # # # # # # -Stockpiles and zones -~~~~~~~~~~~~~~~~~~~~ +To apply an entire dig blueprint in blueprint marker mode, regardless of what +the blueprint itself says, you can set the global quickfort setting +``force_marker_mode`` to ``true`` before you apply the blueprint by running +``quickfort set force_marker_mode true``. + +Note that the state of the in-game vanilla button that you use to draw +designations in either Standard or "Blueprint" mode does not have any effect on +`quickfort`. + +Warm and damp dig markers +````````````````````````` + +Warm and damp dig markers allow digging to continue uninterrupted through warm +or damp tiles. These markers are useful to include in blueprints that are +expected to be applied near magma or in damp/aquifer layers. See the `dig` tool +for more info on warm and damp dig. + +The prefix for warm dig is ``mw`` and the prefix for damp dig is ``md``. + +Carved minecart tracks +~~~~~~~~~~~~~~~~~~~~~~ + +In the game, you carve a minecart track by specifying a beginning and ending +tile, and the game "adds" the designation to the tiles in between. You cannot +designate single tiles because DF needs a multi-tile track to figure out which +direction the track should go on each tile. For example to carve two track +segments that cross each other, you might use the cursor to designate a line of +three vertical tiles like this:: + + ` start here ` # + ` ` ` # + ` end here ` # + # # # # + +Then to carve the cross, you'd do a horizontal segment:: + + ` ` ` # + start here ` end here # + ` ` ` # + # # # # + +This will result in a carved track that would be equivalent to a constructed +track of the form:: + + #build + ` trackS ` # + trackE trackNSEW trackW # + ` trackN ` # + # # # # + +Quickfort supports both styles of specification for carving tracks with ``#dig`` +blueprints. You can use the "additive" style to carve tracks in segments or you +can use the ``track`` aliases to specify the track tile by tile. To designate +track segments, use area expansion syntax with a height or width of 1:: + + #dig + ` T(1x3) ` # + T(3x1) ` ` # + ` ` ` # + # # # # + +"But wait!", I can hear you say, "How do you designate a track corner that opens +to the South and East? You can't put both T(1xH) and T(Wx1) in the same cell!" +This is true, but you can specify both width and height greater than 1, and for +tracks, QF interprets it as an upper-left corner extending to the right W tiles +and down H tiles. For example, to carve a track in a closed ring, you'd write:: + + #dig + T(3x3) ` T(1x3) # + ` ` ` # + T(3x1) ` ` # + # # # # + +You can also use negative numbers in the expansion syntax to indicate corners +that are not upper-left corners. This blueprint will also carve a closed ring:: + + #dig + T(3x3) ` ` # + ` ` ` # + ` ` T(-3x-3) # + # # # # + +Or you could use the aliases to specify tile by tile:: + + #dig + trackSE trackEW trackSW # + trackNS ` trackNS # + trackNE trackEW trackNW # + # # # # + +The aliases can also be used to designate a solid block of track. This is +especially useful for obliterating low-quality engravings so you can re-smooth +and re-engrave with higher quality. For example, you could use the following +sequence of blueprints to ensure a 10x10 floor area contains only masterwork +engravings:: + + #dig smooth floor + s(10x10) + #dig engrave floor + e(10x10) + #dig erase low-quality engravings + trackNSEW(10x10) + +The tracks only remove low-quality engravings since quickfort won't designate +masterwork engravings for destruction (unless forced to by a commandline +parameter). You would run (and let your dwarves complete the jobs for) the +sequence of blueprints until no tiles are designated by the "erase" blueprint. + +#zone mode +---------- + +Zones define how regions of your fort should be treated. They are also the +anchor point for "locations" like taverns and hospitals. Unlike stockpiles or +buildings, zones can overlap, which can lead to some interesting layouts. See +the full list of zone symbols in the `#zone mode reference`_. + +Zone designation syntax +~~~~~~~~~~~~~~~~~~~~~~~ + +A zone is declared with a symbol followed by optional properties:: + + #zone a single tile garbage dump zone + d + + #zone a single tile garbage dump zone named "The Dump" + d{name="The Dump"} + + #zone interrogation room + o{name=Interrogation assigned_unit=sheriff} + + #zone a small inactive pond zone + p{name="Fill me" pond=true active=false}(3x3) + +If you want multiple zones that have the same footprint, they can be declared +from the same cell:: + + #zone pasture and training area + n{name="Main pasture"}t{name="Pet training area"}(14x10) + +or from different corners of the same rectangle:: + + #zone pasture and training area + n{name="Main pasture"}(10x2) + t{name="Pet training area"}(10x-2) -It is very common to have stockpiles that accept multiple categories of items or -zones that permit more than one activity. Although it is perfectly valid to -declare a single-purpose stockpile or zone and then modify it with a ``#query`` -blueprint, quickfort also supports directly declaring all the types in the -``#place`` and ``#zone`` blueprints. For example, to declare a 20x10 stockpile -that accepts both corpses and refuse, you could write:: +and you can use this technique to achieve partial overlap, of course. The only +configuration that can't be specified in a single blueprint is multiple +non-rectangular zones that are partially overlapping. You will have to use +multiple ``#zone`` blueprints to achieve that. - #place refuse heap - yr(20x10) +You can also use labels (see `Label syntax`_ above) to separate adjacent +non-rectangular zones that happen to be of the same type or to combine +disconnected regions into a single zone. -And similarly, to declare a zone that is a pasture, a fruit picking area, and a -meeting area all at once:: +Locations, locations, locations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - #zone main pasture and picnic area - nmg(10x10) +Hospitals, guildhalls, taverns, libraries, and temples are locations. You can +declare a location in the properties for a zone:: + + #zone metalcrafter hall + m{location=guildhall profession=metalcrafter}(7x7) + +You can attach multiple zones to a single location by giving the location a +label (not a name -- you can name zones, but you can't directly name locations) +and then using that label for each of the zones you want to attach:: + + #zone tavern and rented room + b{location=tavern/bigpub name="Rent me"}(3x1) + h{location=tavern/bigpub name="Central pub" allow=residents}(25x40) + +Note that the label ("bigpub" in this case) will never appear in-game. It is +only used in the context of the blueprint to identify a common location. + +#place mode +----------- + +``#place`` mode is dedicated to stockpiles, which are a major design element in +any fortress. + +Stockpile designation syntax +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Just like zones, stockpiles can have properties like names or lists of other +stockpiles to take from. Unlike zones, stockpiles can have configuration +specifiers for exactly what types of items to accept. The full syntax looks +like this:: + + types/label{properties}:configuration(expansion) + +with every component other than the type being optional. You're already +familiar with `Property syntax`_, `Label syntax`_, and +`Area expansion syntax`_, so let's focus in on the remaining elements. + +Stockpile types +~~~~~~~~~~~~~~~ + +The type of stockpile corresponds to the category of items it accepts. Some +types will cause the stockpile to accept bins or barrels. See the full list in +the `#place mode reference`_. + +It is very common to have stockpiles that accept multiple categories of items. +Although it is perfectly valid to declare a single-purpose stockpile, +`quickfort` also supports directly declaring all the categories at once. For +example, to declare a 20x10 stockpile that accepts both corpses and refuse, you +could write:: + + #place refuse heap + yr(20x10) The order of the individual letters doesn't matter. If you want to configure the -stockpile from scratch in a ``#query`` blueprint, you can place unconfigured -"custom" stockpiles with (:kbd:`c`). It is more efficient, though, to place -stockpiles using the keys that represent the categories of items that you want -to store, and then only use a ``#query`` blueprint if you need fine-grained -customization. +stockpile from scratch, you can place unconfigured "custom" stockpiles with +(:kbd:`c`). .. _quickfort-place-containers: -Stockpile bins, barrels, and wheelbarrows -````````````````````````````````````````` +Bins, barrels, and wheelbarrows +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Quickfort has global settings for default values for the number of bins, barrels, and wheelbarrows assigned to stockpiles, but these numbers can be set -for individual stockpiles as well. +for individual stockpiles as well in the properties. -To set the number of bins, barrels, or wheelbarrows, just add a number after the -letter that indicates what type of stockpile it is. For example:: +Individual properties for ``bins``, ``barrels``, and ``wheelbarrows`` are +supported. You can also set them all at once with the ``containers`` alias (it +usually just makes sense to set this to 0 when you don't want any containers of +any type). For example:: - #place a stone stockpile with 5 wheelbarrows - s5(3x3) + #place a stone stockpile with five wheelbarrows + s{wheelbarrows=5}(3x3) #place a bar, ammo, weapon, and armor stockpile with 20 bins - bzpd20(5x5) + bzpd{bins=20}(5x5) + + #place a weapon stockpile with no bins + p{containers=0}(9x2) + +That last one could have equivalently used ``bins=0``, but sometimes you just +don't want to have to think about which stockpile types take which type of +container. + +The container settings also have a shorthand form. If you add a number after a +type symbol, you can set the relevant container count. The first example above +could equivalently be written as:: + + #place a stone stockpile with five wheelbarrows + s5(3x3) + +It sets the count for wheelbarrows specifically because the container +associated with stone stockpiles is wheelbarrows. + +If a stockpile has multiple types, it is the just the previous type symbol that +matters. ``s5e`` (stone and gems) would still set wheelbarrows only since the +``5`` comes directly after the ``s``. ``se5`` would set bins and not +wheelbarrows since the ``5`` would affect the container type associated with +gem stockpiles: bins. + +If the number follows a type symbol that does not have a specific container +type associated with it, then the container type defaults to wheelbarrows. This +allows you to easily add wheelbarrows to furniture and corpse stockpiles, where +having wheelbarrows is useful, but not added by default by the game. If the specified number exceeds the number of available stockpile tiles, the number of available tiles is used. For wheelbarrows, that limit is reduced by 1 @@ -501,254 +791,207 @@ to ensure there is at least one non-wheelbarrow tile available in the stockpile. Otherwise no stone would ever be brought to the stockpile since all tiles would be occupied by wheelbarrows! -Quickfort figures out which container type is being set by looking at the letter -that comes just before the number. For example ``zf10`` means 10 barrels in a -stockpile that accepts both ammo and food, whereas ``z10f`` means 10 bins. If -the stockpile category doesn't usually use any container type, like refuse or -corpses, wheelbarrows are assumed:: +Generating manager orders for a ``#place`` blueprint with explicitly set +container/wheelbarrow counts will enqueue manager orders for the specified +number of containers or wheelbarrows, even if that number exceeds the in-game +size of the stockpile. For example, the following blueprint will enqueue orders +for 10 rock pots, even though the stockpile only has 9 tiles:: - #place a corpse stockpile with 3 wheelbarrows - y3(3x3) + #place + f{barrels=10}(3x3) -Note that if you are not using expansion syntax, each tile of the stockpile must -have the same text. Otherwise the stockpile boundaries will not be detected -properly:: +Stockpile configuration +~~~~~~~~~~~~~~~~~~~~~~~ - #place a non-rectangular animal stockpile with 5 wheelbarrows - a5,a5,a5,a5 - a5, , ,a5 - a5, , ,a5 - a5,a5,a5,a5 +Quickfort uses the `stockpiles` plugin and `stockpiles-library` to configure +stockpile settings, and provides a syntax that is easy to write in a blueprint +yet still allows you to access the full power of the `stockpiles` command. -Running ``quickfort orders`` on a ``#place`` blueprint with explicitly set -container/wheelbarrow counts will enqueue manager orders for the specified -number of containers or wheelbarrows, even if that number exceeds the in-game -size of the stockpile. For example, ``quickfort orders`` on the following -blueprint will enqueue 10 rock pots, even though the stockpile only has 9 -tiles:: +The syntax is:: + + : [/] [ [/]...] + +```` is one of ``=``, ``-``, or ``+``, representing the three `stockpiles` +import modes: ``set``, ``disable``, or ``enable``, respectively. Note that if +you are using an ``=`` op, then it should go first in the list. Any ``=`` +configuration segment will override anything that comes before it. + +For example, a blueprint like:: #place - f10(3x3) + f:=booze(5x4) -Zone detailed configuration -``````````````````````````` +would be equivalent to creating a 5x4 food stockpile in the UI, then selecting +it and running this command:: -Detailed configuration for zones, such as the pit/pond toggle, can also be set -by mimicking the hotkeys used to set them. Note that gather flags default to -true, so specifying them in a blueprint will turn the toggles off. If you need -to set configuration from multiple zone subscreens, separate the key sections -with :kbd:`^`. Note the special syntax for setting hospital supply levels, which -have no in-game hotkeys:: + stockpiles import --mode=set booze - #zone a combination hospital and shrub (but not fruit) gathering zone - gGtf^hH{hospital buckets=5 splints=20}(10x10) +you can also add a slash (``/``) and a comma-separated list of filter strings +to customize the settings further:: -The valid hospital settings (and their maximum values) are:: + #place + p{name="Metal weapons"}:-cat_weapons/other/(7x3) - thread (1500000) - cloth (1000000) - splints (100) - crutches (100) - plaster (15000) - buckets (100) - soap (15000) +Note that the "op" in this case lets us disable the matched preset, which in +this case is the "Other materials" types in the Weapons category. This +configuration is equivalent to the `stockpiles` command:: -To toggle the ``active`` flag for zones, add an :kbd:`a` character to the -string. For example, to create a *disabled* pond zone (that you later intend to -carefully fill with 3-depth water for a dwarven bathtub):: + stockpiles import --mode=disable cat_weapons --filter=other/ - #zone disabled pond zone - apPf(1x3) +And we can chain multiple `stockpiles` commands together by adding another "op" +character and another preset:: -Minecart tracks -~~~~~~~~~~~~~~~ + #place + p{name="Steel weapons"}:-cat_weapons/mats/,other/+steelweapons(7x3) -There are two ways to produce minecart tracks, and they are handled very -differently by the game. You can carve them into hard natural floors or you can -construct them out of building materials. Constructed tracks are conceptually -simpler, so we'll start with them. - -Constructed tracks -`````````````````` - -Quickfort supports the designation of track stops and rollers in ``#build`` -blueprints. You can build a track stop with :kbd:`C`:kbd:`S` and some number of -:kbd:`d` and :kbd:`a` characters for selecting dump direction and friction. You -can build a roller with :kbd:`M`:kbd:`r` and some number of :kbd:`s` and -:kbd:`q` characters for direction and speed. However, this can get confusing -very quickly and is very difficult to read in a blueprint. Moreover, constructed -track segments don't even have keys associated with them at all! - -To solve this problem, Quickfort provides the following keywords for use in -build blueprints:: - - -- Track segments -- - trackN - trackS - trackE - trackW - trackNS - trackNE - trackNW - trackSE - trackSW - trackEW - trackNSE - trackNSW - trackNEW - trackSEW - trackNSEW - - -- Track/ramp segments -- - trackrampN - trackrampS - trackrampE - trackrampW - trackrampNS - trackrampNE - trackrampNW - trackrampSE - trackrampSW - trackrampEW - trackrampNSE - trackrampNSW - trackrampNEW - trackrampSEW - trackrampNSEW - - -- Horizontal and vertical roller segments -- - rollerH - rollerV - rollerNS - rollerSN - rollerEW - rollerWE - - Note: append up to four 'q' characters to roller keywords to set roller - speed. E.g. a roller that propels from East to West at the slowest speed can - be specified with 'rollerEWqqqq'. - - -- Track stops that (optionally) dump to the N/S/E/W -- - trackstop - trackstopN - trackstopS - trackstopE - trackstopW - - Note: append up to four 'a' characters to trackstop keywords to set friction - amount. E.g. a stop that applies the smallest amount of friction can be - specified with 'trackstopaaaa'. - -As an example, you can create an E-W track with stops at each end that dump to -their outside directions with the following blueprint:: - - #build Example track - trackstopW trackEW trackEW trackEW trackstopE - -Note that the **only** way to build track and track/ramp segments is with the -keywords. The UI method of using :kbd:`+` and :kbd:`-` keys to select the track -type from a list does not work since DFHack Quickfort doesn't actually send keys -to the UI to build buildings. The text in your spreadsheet cells is mapped -directly onto DFHack API calls. Only ``#query`` blueprints send actual keycodes -to the UI. - -Carved tracks -````````````` +which corresponds to running these two commands:: -In the game, you carve a minecart track by specifying a beginning and ending -tile and the game "adds" the designation to the tiles in between. You cannot -designate single tiles because DF needs a multi-tile track to figure out which -direction the track should go on each tile. For example to carve two track -segments that cross each other, you might use the cursor to designate a line of -three vertical tiles like this:: + stockpiles import --mode=disable cat_weapons --filter=mats/,other/ + stockpiles import --mode=enable steelweapons - ` start here ` # - ` ` ` # - ` end here ` # - # # # # +With the combination of the library presets and custom filter strings, you can +configure any stockpile any way you like! -Then to carve the cross, you'd do a horizonal segment:: +#build mode +----------- - ` ` ` # - start here ` end here # - ` ` ` # - # # # # +``#build`` mode handles buildings, furniture (which are also "buildings" +according to DF), constructions (including constructed tracks), and hauling +routes. -This will result in a carved track that would be equivalent to a constructed -track of the form:: +Building designation syntax +~~~~~~~~~~~~~~~~~~~~~~~~~~~ - #build - ` trackS ` # - trackE trackNSEW trackW # - ` trackN ` # - # # # # +The syntax is very similar to the syntax for stockpiles, except that it only +makes sense to have a single symbol to indicate what to build on that tile:: -Quickfort supports both styles of specification for carving tracks with ``#dig`` -blueprints. You can use the "additive" style to carve tracks in segments or you -can use the aliases to specify the track tile by tile. To designate track -segments, use area expansion syntax with a height or width of 1:: + symbol{properties}:configuration(expansion) - #dig - ` T(1x3) ` # - T(3x1) ` ` # - ` ` ` # - # # # # +See the `#build mode reference`_ for properties that you can specify for each +building type. -"But wait!", I can hear you say, "How do you designate a track corner that opens -to the South and East? You can't put both T(1xH) and T(Wx1) in the same cell!" -This is true, but you can specify both width and height greater than 1, and for -tracks, QF interprets it as an upper-left corner extending to the right W tiles -and down H tiles. For example, to carve a track in a closed ring, you'd write:: +Here's an example of a simple 5x5 square of flooring:: - #dig - T(3x3) ` T(1x3) # - ` ` ` # - T(3x1) ` ` # - # # # # + #build + Cf(5x5) -Or, using the aliases:: +or a named Jeweler's workshop that takes from specific stockpiles:: - #dig - trackSE trackEW trackSW # - trackNS ` trackNS # - trackNE trackEW trackNW # - # # # # + #build + wj{name="Encrusting center" take_from="Furniture,Gem storage"} -The aliases can also be used to designate a solid block of track. This is -epecially useful for obliterating low-quality engravings so you can re-smooth -and re-engrave with higher quality. For example, you could use the following -sequence of blueprints to ensure a 10x10 floor area contains only masterwork -engravings:: +or a forge that specializes in high-quality armor:: - #dig smooth floor - s(10x10) - #dig engrave floor - e(10x10) - #dig erase low-quality engravings - trackNSEW(10x10) + #build + wf{name=Armorer labors=Armoring min_skill=Master} -The tracks only remove low-quality engravings since quickfort won't designate -masterwork engravings for destruction unless forced by a commandline -parameter. You would run (and let your dwarves complete the jobs for) the -sequence of blueprints until no tiles are designated by the "erase" blueprint. +The ``:configuration`` part is only relevant for hauling routes, which we'll go +over in the next section. + +Hauling route definitions +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Hauling routes are defined by properties and configuration attached to track +stops. You can define a single-stop hauling route for a quantum stockpile as +easily as a multi-stop stone quarry transportation line. The stockpile-like +``:configuration`` part of the syntax controls which item types are considered +"desired" for the hauling route stop. If it's not specified, then all item +types are accepted. This is the most common case since most hauling route +contents are filtered by the stockpiles that the stops take from, but the +flexibility is there for when multiple stops take different items from the same +stockpile, or when a stop only wants a subset of items from a stockpile. + +Here is a common setup for a quantum stone stockpile:: + + #place + s{name="Stone quantum" quantum=true} ~ s5{name="Stone feeder"}(3x3) + #build + ~ trackstopW{take_from="Stone feeder" route="Stone dumper"} + +This sets up the quantum stockpile and the feeder stockpile in the ``#place`` +blueprint, followed by the trackstop and the hauling route configuration in the +``#build`` blueprint. The ``route`` property is the name of the hauling route +to create (or attach to if it already exists). If you are applying a quantum +stockpile blueprint more than once in a fort, be sure to *avoid* defining the +``route`` property so that each application of the blueprint creates a unique +hauling route. Two quantum stockpiles on the same route will not function +properly (since one of the stops will be missing a minecart). + +Let's look at a slightly more complicated setup where we sort the stone into +different output quantum stockpiles:: + + #place + s{name="Other stone quantum" quantum=true} ~ s5e{name="Rock feeder"}(3x3) + s{name="Ore/clay stone quantum" quantum=true} ~ + s{name="Gem quantum" quantum=true} ~ + #build + ~ trackstopW{take_from="Rock feeder" route="Other stone"}:=otherstone + ~ trackstopW{take_from="Rock feeder" route="Ore/clay"}:=cat_stone-otherstone + ~ trackstopW{take_from="Rock feeder" route="Gems"}:=cat_gems + +You can see how we make use of the stockpile-style configuration syntax to +fine-tune the items desired by the hauling route stop. + +Finally, let's make a series of stops on a common hauling route. There is +nothing particularly special about this example. If the ``route`` property +names an existing route, the stop will be added to that route:: + + #dig + trackE trackEW trackEW trackW + #build + trackstop{route="Tick tock"} ~ ~ trackstop{route="Tick tock"} + +These two track stops (which do not dump their contents) simply exist on a +common route at the ends of a connected carved track. + +#burrow mode +------------ + +``#burrow`` mode can create, extend, and remove tiles from burrows. + +Burrow designation syntax +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The syntax should look familiar by now:: + + symbol{properties}(expansion) + +See the `#burrow mode reference`_ for symbol and property definitions. + +Here's how to create (or add to, if a burrow by that name already exists) a +5x5 burrow named ``Inside+``. It will also register this burrow with +`gui/civ-alert` if no burrow has yet been registered:: + + #burrow + a{create=true name=Inside+ civalert=true}(5x5) + +Why the trailing ``+``? That's to indicate to the `burrow` plugin that the +burrow should grow as adjacent tiles are dug out. + +Similarly, here is how to erase a tile from all burrows that currently include +it:: + + #burrow + e .. _quickfort-modeline: Modeline markers -~~~~~~~~~~~~~~~~ +---------------- The modeline has some additional optional components that we haven't talked about yet. You can: -- give a blueprint a label by adding a ``label()`` marker -- set a cursor offset and/or start hint by adding a ``start()`` marker -- hide a blueprint from being listed with a ``hidden()`` marker -- register a message to be displayed after the blueprint is successfully - applied +- give a blueprint a label by adding a ``label()`` marker +- set a cursor offset and/or cursor placement hint by adding a ``start()`` + marker +- hide a blueprint from being listed with a ``hidden()`` marker +- register a message to be displayed after the blueprint is successfully + applied with a ``message()`` marker The full modeline syntax, when all optional elements are specified, is:: - #mode label(mylabel) start(X;Y;STARTCOMMENT) hidden() message(mymessage) comment + #mode label(mylabel) start(X;Y;startcomment) hidden() message(mymessage) comment Note that all elements are optional except for the initial ``#mode`` (though, as mentioned in the first section, if a modeline doesn't appear at all in the first @@ -756,247 +999,220 @@ cell of a spreadsheet, the blueprint is interpreted as a ``#dig`` blueprint with no optional markers). Here are a few examples of modelines with optional elements before we discuss them in more detail:: - #dig start(3; 3; Center tile of a 5-tile square) Regular blueprint comment - #build label(noblebedroom) start(10;15) - #query label(configstockpiles) No explicit start() means cursor is at upper left corner - #meta label(digwholefort) start(center of stairs on surface) - #dig label(digdining) hidden() managed by the digwholefort meta blueprint - #zone label(pastures) message(remember to assign animals to the new pastures) + #dig start(3; 3; Center tile of a 5-tile square) Regular blueprint comment + #build label(noblebedroom) No explicit 'start()' so cursor is in upper left + #meta label(digwholefort) start(center of stairs on surface) + #dig label(dig_dining) hidden() called by the digwholefort meta blueprint + #zone label(pastures) message(remember to assign animals to the pastures) .. _quickfort-label: Blueprint labels -```````````````` +~~~~~~~~~~~~~~~~ -Labels are displayed in the ``quickfort list`` output and are used for -addressing specific blueprints when there are multiple blueprints in a single -file or spreadsheet sheet (see `Packaging a set of blueprints`_ below). If a -blueprint has no label, the label becomes the ordinal of the blueprint's -position in the file or sheet. For example, the label of the first blueprint -will be "1" if it is not otherwise set, the label of the second blueprint will -be "2" if it is not otherwise set, etc. Labels that are explicitly defined must -start with a letter to ensure the auto-generated labels don't conflict with -user-defined labels. +Labels are displayed in the blueprint selection dialog and the output of +``quickfort list`` and are used for addressing specific blueprints when there +are multiple blueprints in a single file or spreadsheet sheet (see +`Packaging a set of blueprints`_ below). If a blueprint has no label, the label +becomes the ordinal of the blueprint's position in the file or sheet. For +example, the label of the first blueprint will be "1" if it is not otherwise +set, the label of the second blueprint will be "2" if it is not otherwise set, +etc. Labels that are explicitly defined must start with a letter to ensure the +auto-generated labels don't conflict with user-defined labels. .. _quickfort-start: Start positions -``````````````` +~~~~~~~~~~~~~~~ Start positions specify a cursor offset for a particular blueprint, simplifying the task of blueprint alignment. This is very helpful for blueprints that are -based on a central staircase, but it helps whenever a blueprint has an obvious -"center". For example:: +based on a central staircase, but it comes in handy whenever a blueprint has an +obvious "center". For example:: - #build start(2;2;center of workshop) label(masonw) a mason workshop - wm wm wm # - wm wm wm # - wm wm wm # - # # # # + #build start(2;2;center of workshop) label(stonew) a stonecutter workshop + wm wm wm # + wm wm wm # + wm wm wm # + # # # # will build the workshop *centered* on the cursor, not down and to the right of the cursor. -The two numbers specify the column and row (or X and Y offset) where the cursor -is expected to be when you apply the blueprint. Position ``1;1`` is the top left -cell. The optional comment will show up in the ``quickfort list`` output and +The two numbers specify the column and row (or 1-based X and Y offset) where the +cursor is expected to be when you apply the blueprint. Position ``1;1`` is the +top left cell. The optional comment will show up in the blueprint listings and should contain information about where to position the cursor. If the start position is ``1;1``, you can omit the numbers and just add a comment describing where to put the cursor. This is also useful for meta blueprints that don't actually care where the cursor is, but that refer to other blueprints that have fully-specified ``start()`` markers. For example, a meta blueprint that refers -to the ``masonw`` blueprint above could look like this:: +to the ``stonew`` blueprint above could look like this:: - #meta start(center of workshop) a mason workshop - /masonw + #meta start(center of workshop) a stonecutter workshop + /stonew You can use semicolons, commas, or spaces to separate the elements of the -``start()`` marker, whatever is most convenient. +``start()`` marker, whichever you prefer. .. _quickfort-hidden: Hiding blueprints -````````````````` +~~~~~~~~~~~~~~~~~ -A blueprint with a ``hidden()`` marker won't appear in ``quickfort list`` output -unless the ``--hidden`` flag is specified. The primary reason for hiding a -blueprint (rather than, say, deleting it or moving it out of the ``blueprints/`` -folder) is if a blueprint is intended to be run as part of a larger sequence -managed by a `meta blueprint `. +A blueprint with a ``hidden()`` marker won't appear in the blueprint listings +unless hidden blueprints are specifically requested. The primary reason for +hiding a blueprint (rather than, say, deleting it or moving it out of the +``blueprints/`` folder) is if a blueprint is intended to be run as part of a +larger sequence managed by a `meta blueprint `. .. _quickfort-message: Messages -```````` +~~~~~~~~ A blueprint with a ``message()`` marker will display a message after the -blueprint is applied with ``quickfort run``. This is useful for reminding -players to take manual steps that cannot be automated, like assigning minecarts -to a route, or listing the next step in a series of blueprints. For long or -multi-part messages, you can embed newlines:: +blueprint is applied. This is useful for reminding players to take manual steps +that cannot be automated, like assigning minecarts to a route, or listing the +next step in a series of blueprints. For long or multi-part messages, you can +embed newlines:: - "#meta label(surface1) message(This would be a good time to start digging the industry level. - Once the area is clear, continue with /surface2.) clear the embark site and set up pastures" + "#meta label(surface1) message(This would be a good time to start digging the industry level. + Once the area is clear, continue with /surface2.) clear the embark site and set up pastures" The quotes surrounding the cell text are only necessary if you are writing a .csv file by hand. Spreadsheet applications will surround multi-line text with quotes automatically when they save/export the file. -.. _quickfort-packaging: - -Packaging a set of blueprints -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -A complete specification for a section of your fortress may contain 5 or more -separate blueprints, one for each "phase" of construction (dig, build, place -stockpiles, designate zones, and query adjustments). - -To manage all the separate blueprints, it is often convenient to keep related -blueprints in a single file. For .xlsx spreadsheets, you can keep each blueprint -in a separate sheet. Online spreadsheet applications like `Google -Sheets `__ make it easy to work with multiple related -blueprints, and, as a bonus, they retain any formatting you've set, like column -sizes and coloring. - -For both .csv files and .xlsx spreadsheets you can also add as many blueprints -as you want in a single file or sheet. Just add a modeline in the first column -to indicate the start of a new blueprint. Instead of multiple .csv files, you -can concatenate them into one single file. This is especially useful when you -are sharing your blueprints with others. A single file is much easier to manage -than a directory of files. - -For example, you can store multiple blueprints together like this:: - - #dig label(bed1) - d d d d # - d d d d # - d d d d # - d d d d # - # # # # # - #build label(bed2) - b f h # - # - # - n # - # # # # # - #place label(bed3) - # - f(2x2) # - # - # - # # # # # - #query label(bed4) - # - booze # - # - # - # # # # # - #query label(bed5) - r{+ 3}& # - # - # - # - # # # # # - -Of course, you could still choose to keep your blueprints in single-sheet .csv -files and just give related blueprints similar names:: - - bedroom.1.dig.csv - bedroom.2.build.csv - bedroom.3.place.csv - bedroom.4.query.csv - bedroom.5.query2.csv - -The naming and organization is completely up to you. - .. _quickfort-other-modes: Other blueprint modes -~~~~~~~~~~~~~~~~~~~~~ +--------------------- There are a few additional blueprint modes that become useful when you are sharing your blueprints with others or managing complex blueprint sets. Instead -of mapping tile positions to keystroke sequences like the basic modes do, these +of mapping tile positions to map modifications like the basic modes do, these "blueprints" have specialized, higher-level uses: ============== =========== Blueprint mode Description ============== =========== -meta Link sequences of blueprints together notes Display long messages, such as help text or blueprint walkthroughs -aliases Define aliases that are visible only in the current file -ignore Hide a section from quickfort, useful for scratch space or - personal notes +ignore Hide a section of your spreadsheet from quickfort, useful for + scratch space or personal notes +meta Script sequences of blueprints together, transform them, and/or + repeat them across multiple z-levels ============== =========== +.. _quickfort-notes: + +#notes mode +~~~~~~~~~~~ + +Sometimes you just want to record some information about your blueprints, such +as when to apply them, what preparations you need to make, or what the +blueprints contain. The `message() ` modeline marker is +useful for small, single-line messages, but a ``#notes`` blueprint is more +convenient for long messages or messages that span many lines. The lines in a +``#notes`` blueprint are output as if they were contained within one large +multi-line ``message()`` marker. For example, the following (empty) ``#meta`` +blueprint:: + + "#meta label(help) message(This is the help text for the blueprint set + contained in this file. + + First, make sure that you embark in...) blueprint set walkthrough" + +could more naturally be written as a ``#notes`` blueprint:: + + #notes label(help) blueprint set walkthrough + This is the help text for the blueprint set + contained in this file + + First, make sure that you embark in... + +The ``#meta`` blueprint is all squashed into a single spreadsheet cell, using +embedded newlines. Each line of the ``#notes`` "blueprint", however, is in a +separate cell, allowing for much easier viewing and editing. + +#ignore mode +~~~~~~~~~~~~ + +If you don't want some data to be visible to quickfort at all, use an +``#ignore`` blueprint. All lines until the next modeline in the file or sheet +will be completely ignored. This can be useful for personal notes, scratch +space, or temporarily "commented out" blueprints. + .. _quickfort-meta: -Meta blueprints -``````````````` +#meta mode +~~~~~~~~~~ + +``#meta`` blueprints are blueprints that control how other blueprints are +applied. For example, meta blueprints can bundle a group of other blueprints so +that they can be run with a single command. They can also encode logic, like +rotating the blueprint or duplicating it across a specified number of z-levels. + +Scripting blueprints together +````````````````````````````` -Meta blueprints are blueprints that script a series of other blueprints. For -example, many blueprint sets follow this pattern: +A common scenario where meta blueprints are useful is when you have several +phases to link together. For example you might: -1. Apply dig blueprint to designate dig areas +1. Apply a dig blueprint to designate dig areas #. Wait for miners to dig -#. **Apply build buildprint** to designate buildings -#. **Apply place buildprint** to designate stockpiles -#. **Apply query blueprint** to configure stockpiles -#. Wait for buildings to get built -#. Apply a different query blueprint to configure rooms - -Those three "apply"s in the middle might as well get done in one command instead -of three. A ``#meta`` blueprint can encode that sequence. A meta blueprint -refers to other blueprints in the same file by their label (see the -`Modeline markers`_ section above) in the same format used by the `quickfort` -command: ``/