Merge branch 'develop' into world-module-docs

develop
vallode 2023-11-13 08:25:19 +01:00
commit 8fc232aba0
400 changed files with 23026 additions and 22491 deletions

@ -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
----------------------------------
<details>
<summary>Highlight 1, Highlight 2</summary>
### Highlight 1
Demo screenshot/vidcap
Text
### Highlight 2
Demo screenshot/vidcap
Text
</details>
Announcements
----------------------------------
<details>
<summary>Annc 1, PSAs</summary>
### 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.
Many 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 do not compile yet and are not available 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.
</details>
Generated release notes
====================
<details>
<summary>New tools, fixes, and improvements</summary>
%RELEASE_NOTES%
</details>

@ -0,0 +1,168 @@
name: Build linux64
on:
workflow_call:
inputs:
dfhack_ref:
type: string
scripts_ref:
type: string
structures_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
common-files:
type: boolean
default: true
docs:
type: boolean
default: false
html:
type: boolean
default: true
stonesense:
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: "10"
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<4.4.0'
- name: Clone DFHack
uses: actions/checkout@v3
with:
repository: ${{ inputs.dfhack_ref && github.repository || 'DFHack/dfhack' }}
ref: ${{ inputs.dfhack_ref }}
submodules: true
fetch-depth: ${{ !inputs.platform-files && 1 || 0 }}
- name: Clone scripts
if: inputs.scripts_ref
uses: actions/checkout@v3
with:
repository: ${{ inputs.scripts_ref && github.repository || 'DFHack/scripts' }}
ref: ${{ inputs.scripts_ref }}
path: scripts
- name: Clone structures
if: inputs.structures_ref
uses: actions/checkout@v3
with:
repository: ${{ inputs.structures_ref && github.repository || 'DFHack/df-structures' }}
ref: ${{ inputs.structures_ref }}
path: library/xml
- name: Fetch ccache
if: inputs.platform-files
uses: actions/cache/restore@v3
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 \
${{ 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 }} \
-DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} \
-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 cache
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@v3
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@v3
with:
name: ${{ steps.artifactname.outputs.name }}
path: ${{ steps.artifactname.outputs.name }}.tar.bz2

@ -0,0 +1,135 @@
name: Build win64
on:
workflow_call:
inputs:
dfhack_ref:
type: string
scripts_ref:
type: string
structures_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
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: ubuntu-22.04
steps:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install ccache
- name: Clone DFHack
uses: actions/checkout@v3
with:
repository: ${{ inputs.dfhack_ref && github.repository || 'DFHack/dfhack' }}
ref: ${{ inputs.dfhack_ref }}
submodules: true
fetch-depth: 0
- name: Clone scripts
if: inputs.scripts_ref
uses: actions/checkout@v3
with:
repository: ${{ inputs.scripts_ref && github.repository || 'DFHack/scripts' }}
ref: ${{ inputs.scripts_ref }}
path: scripts
- name: Clone structures
if: inputs.structures_ref
uses: actions/checkout@v3
with:
repository: ${{ inputs.structures_ref && github.repository || 'DFHack/df-structures' }}
ref: ${{ inputs.structures_ref }}
path: library/xml
- name: Get 3rd party SDKs
if: inputs.launchdf
uses: actions/checkout@v3
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@v3
with:
path: build/win64-cross/ccache
key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }}
restore-keys: |
win-msvc-${{ inputs.cache-id }}
win-msvc
- name: Cross-compile
env:
CMAKE_EXTRA_ARGS: -DBUILD_LIBRARY=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS: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' || '' }}
run: |
cd build
bash -x build-win64-from-linux.sh
- name: Finalize cache
run: |
cd build
ccache -d win64-cross/ccache --show-stats --verbose
ccache -d win64-cross/ccache --max-size 150M
ccache -d win64-cross/ccache --cleanup
ccache -d win64-cross/ccache --max-size 500M
ccache -d win64-cross/ccache --zero-stats
- name: Save ccache
if: inputs.platform-files && !inputs.cache-readonly
uses: actions/cache/save@v3
with:
path: build/win64-cross/ccache
key: win-msvc-${{ 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/win64-cross/output
tar cjf ../../../${{ steps.artifactname.outputs.name }}.tar.bz2 .
- name: Upload artifact
if: inputs.artifact-name
uses: actions/upload-artifact@v3
with:
name: ${{ steps.artifactname.outputs.name }}
path: ${{ steps.artifactname.outputs.name }}.tar.bz2

@ -3,222 +3,32 @@ name: Build
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
build: test:
runs-on: ${{ matrix.os }} uses: ./.github/workflows/test.yml
name: build (Linux, GCC ${{ matrix.gcc }}, ${{ matrix.plugins }} plugins) with:
strategy: dfhack_ref: ${{ github.ref }}
fail-fast: false secrets: inherit
matrix:
os:
- ubuntu-22.04
gcc:
- 10
plugins:
- default
include:
- os: ubuntu-22.04
gcc: 12
plugins: all
steps:
- name: Set up Python 3
uses: actions/setup-python@v4
with:
python-version: 3
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install \
ccache \
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<4.4.0'
- 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 "df_version=${DF_VERSION}" >> $GITHUB_OUTPUT
echo "DF_VERSION=${DF_VERSION}" >> $GITHUB_ENV
echo "DF_FOLDER=${HOME}/DF/${DF_VERSION}/df_linux" >> $GITHUB_ENV
echo "CCACHE_DIR=${HOME}/.ccache" >> $GITHUB_ENV
# - name: Fetch DF cache
# uses: actions/cache@v3
# with:
# path: ~/DF
# key: dfcache-${{ steps.env_setup.outputs.df_version }}-${{ hashFiles('ci/download-df.sh') }}
- name: Fetch ccache
uses: actions/cache@v3
with:
path: ~/.ccache
key: ccache-v2-${{ matrix.os }}-gcc-${{ matrix.gcc }}-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
ccache-v2-${{ matrix.os }}-gcc-${{ matrix.gcc }}-${{ github.ref_name }}
ccache-v2-${{ matrix.os }}-gcc-${{ matrix.gcc }}
# - name: Download DF
# run: |
# sh ci/download-df.sh
- name: Configure 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_SKELETON:BOOL=${{ matrix.plugins == 'all' }} \
-DBUILD_STONESENSE:BOOL=${{ matrix.plugins == 'all' }} \
-DBUILD_SUPPORTED:BOOL=1 \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_INSTALL_PREFIX="$DF_FOLDER"
- name: Build DFHack
run: |
ninja -C build-ci install
ccache --show-stats
- name: Run cpp unit tests
id: run_tests_cpp
run: |
ninja -C build-ci test
exit $?
# - name: Run lua tests
# id: run_tests_lua
# run: |
# export TERM=dumb
# status=0
# 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"
build-cross-win64: package:
name: Build MSVC win64 uses: ./.github/workflows/package.yml
runs-on: ubuntu-22.04 with:
steps: dfhack_ref: ${{ github.ref }}
- name: Clone DFHack secrets: inherit
uses: actions/checkout@v3
with:
submodules: true
fetch-depth: 0
- name: Fetch ccache
uses: actions/cache@v3
with:
path: build/win64-cross/ccache
key: ccache-win64-cross-msvc-${{ github.ref_name }}-${{ github.sha }}
restore-keys: |
ccache-win64-cross-msvc-${{ github.ref_name }}
ccache-win64-cross-msvc
- name: Cross-compile win64 artifacts
env:
CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1'
run: |
cd build
bash -x build-win64-from-linux.sh
- name: Format artifact name
id: artifactname
run: |
echo name=$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT
- name: Upload win64 artifacts
uses: actions/upload-artifact@v3
with:
name: dfhack-win64-build-${{ steps.artifactname.outputs.name }}
path: build/win64-cross/output/*
docs: docs:
runs-on: ubuntu-22.04 uses: ./.github/workflows/build-linux.yml
steps: with:
- name: Set up Python 3 dfhack_ref: ${{ github.ref }}
uses: actions/setup-python@v4 platform-files: false
with: common-files: false
python-version: 3 docs: true
- name: Install dependencies secrets: inherit
run: |
pip install 'sphinx'
- name: Clone DFHack
uses: actions/checkout@v1
with:
submodules: true
- name: Build docs
run: |
sphinx-build -W --keep-going -j auto --color . docs/html
- name: Upload docs
uses: actions/upload-artifact@v1
with:
name: docs
path: docs/html
lint: lint:
runs-on: ubuntu-22.04 uses: ./.github/workflows/lint.yml
steps: with:
- name: Set up Python 3 dfhack_ref: ${{ github.ref }}
uses: actions/setup-python@v4 secrets: inherit
with:
python-version: 3
- name: Set up Ruby 2.7
uses: ruby/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
check-pr: check-pr:
runs-on: ubuntu-latest runs-on: ubuntu-latest

@ -1,35 +0,0 @@
name: Buildmaster rebuild
on:
workflow_dispatch:
inputs:
pull_request:
description: Pull request ID
type: string
required: true # remove if we support commit rebuilds later
jobs:
rebuild:
runs-on: ubuntu-latest
name: Trigger Buildmaster
steps:
- name: Set up Python 3
uses: actions/setup-python@v4
with:
python-version: 3
- name: Install dependencies
run: |
pip install requests
- name: Clone DFHack
uses: actions/checkout@v1
with:
fetch-depth: 1
submodules: false
- name: Run
env:
DFHACK_BUILDMASTER_WEBHOOK_URL: ${{ secrets.DFHACK_BUILDMASTER_WEBHOOK_URL }}
DFHACK_BUILDMASTER_WEBHOOK_SECRET: ${{ secrets.DFHACK_BUILDMASTER_WEBHOOK_SECRET }}
GITHUB_REPO: ${{ github.repository }}
GITHUB_TOKEN: ${{ github.token }}
run: |
python ci/buildmaster-rebuild-pr.py --pull-request ${{ github.event.inputs.pull_request }}

@ -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@v3
- name: Cleanup
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"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

@ -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<4.4.0'
- name: Clone DFHack
uses: actions/checkout@v3
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 - 4)) $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@v3
- 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 }}

@ -0,0 +1,44 @@
name: Lint
on:
workflow_call:
inputs:
dfhack_ref:
type: string
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@v3
with:
repository: ${{ inputs.dfhack_ref && github.repository || 'DFHack/dfhack' }}
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@v3
with:
repository: ${{ inputs.scripts_ref && github.repository || 'DFHack/scripts' }}
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

@ -0,0 +1,52 @@
name: Package
on:
workflow_call:
inputs:
dfhack_ref:
type: string
scripts_ref:
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
jobs:
package-win64:
name: Windows
uses: ./.github/workflows/build-windows.yml
with:
dfhack_ref: ${{ inputs.dfhack_ref }}
scripts_ref: ${{ inputs.scripts_ref }}
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
launchdf: ${{ inputs.launchdf }}
secrets: inherit
package-linux:
name: Linux
uses: ./.github/workflows/build-linux.yml
with:
dfhack_ref: ${{ inputs.dfhack_ref }}
scripts_ref: ${{ inputs.scripts_ref }}
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
secrets: inherit

@ -0,0 +1,92 @@
name: Deploy to Steam
on:
push:
tags:
- '*-r*'
workflow_dispatch:
inputs:
ref:
description: Branch or commit hash
type: string
required: true
default: develop
version:
description: Version or build description
type: string
required: true
release_channel:
description: Steam release channel
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.event.inputs && github.event.inputs.ref || github.event.ref }}
platform-files: false
docs: true
stonesense: true
secrets: inherit
depot-win64:
name: Windows depot files
uses: ./.github/workflows/build-windows.yml
with:
artifact-name: win64-depot
dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.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.event.inputs && github.event.inputs.ref || github.event.ref }}
cache-id: release
cache-readonly: true
common-files: false
stonesense: true
secrets: inherit
deploy-to-steam:
name: Deploy to Steam
needs:
- depot-common
- depot-win64
- depot-linux64
runs-on: ubuntu-latest
concurrency: steam
steps:
- name: Download depot files
uses: actions/download-artifact@v3
- 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: 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 }}
rootPath: .
depot1Path: common-depot
depot2Path: win64-depot
depot3Path: linux64-depot
releaseBranch: ${{ github.event.inputs && github.event.inputs.release_channel || 'staging' }}

@ -1,57 +0,0 @@
name: Deploy to Steam
on:
workflow_dispatch:
inputs:
commit_hash:
description: Commit hash
type: string
required: true
version:
description: Version
type: string
required: true
release_channel:
description: Release channel
type: string
required: true
default: beta
jobs:
deploy-to-steam:
name: Deploy to Steam
runs-on: ubuntu-22.04
steps:
- name: Clone DFHack
uses: actions/checkout@v3
with:
submodules: true
fetch-depth: 0
ref: ${{ github.event.inputs.commit_hash }}
- name: Fetch ccache
uses: actions/cache@v3
with:
path: build/win64-cross/ccache
key: ccache-win64-cross-msvc-${{ github.event.inputs.commit_hash }}
restore-keys: |
ccache-win64-cross-msvc-develop-${{ github.event.inputs.commit_hash }}
ccache-win64-cross-msvc
- name: Cross-compile win64 artifacts
env:
CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1'
run: |
cd build
bash -x build-win64-from-linux.sh
- name: Steam deploy
uses: game-ci/steam-deploy@v2
with:
username: ${{ secrets.STEAM_USERNAME }}
password: ${{ secrets.STEAM_PASSWORD }}
configVdf: ${{ secrets.STEAM_CONFIG_VDF}}
ssfnFileName: ${{ secrets.STEAM_SSFN_FILE_NAME }}
ssfnFileContents: ${{ secrets.STEAM_SSFN_FILE_CONTENTS }}
appId: 2346660
buildDescription: ${{ github.event.inputs.version }}
rootPath: build
depot1Path: win64-cross/output
releaseBranch: ${{ github.event.inputs.release_channel }}

@ -0,0 +1,146 @@
name: Test
on:
workflow_call:
inputs:
dfhack_ref:
type: string
scripts_ref:
type: string
structures_ref:
type: string
jobs:
build-windows:
name: Windows MSVC
uses: ./.github/workflows/build-windows.yml
with:
dfhack_ref: ${{ inputs.dfhack_ref }}
scripts_ref: ${{ inputs.scripts_ref }}
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_ref: ${{ inputs.dfhack_ref }}
scripts_ref: ${{ inputs.scripts_ref }}
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: 10
plugins: "default"
- gcc: 12
plugins: "all"
run-tests:
name: Test (${{ matrix.os }}, ${{ matrix.compiler }}, ${{ matrix.plugins }} plugins, ${{ matrix.config }} config)
needs:
- build-windows
- build-linux
runs-on: ${{ matrix.os }}-latest
strategy:
fail-fast: false
matrix:
include:
- os: windows
compiler: msvc
plugins: "default"
config: "default"
- os: windows
compiler: msvc
plugins: "default"
config: "empty"
- os: ubuntu
compiler: gcc-10
plugins: "default"
config: "default"
- os: ubuntu
compiler: gcc-12
plugins: "all"
config: "default"
steps:
- name: Set env
shell: bash
run: echo "DF_FOLDER=DF" >> $GITHUB_ENV
- name: Install dependencies
if: matrix.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@v3
with:
repository: ${{ inputs.dfhack_ref && github.repository || 'DFHack/dfhack' }}
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@v3
with:
path: ${{ env.DF_FOLDER }}
key: df-${{ matrix.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 }} ${{ matrix.os }} ${{ env.DF_VERSION }}
- name: Save DF cache
if: steps.restore-df.outputs.cache-hit != 'true'
uses: actions/cache/save@v3
with:
path: ${{ env.DF_FOLDER }}
key: df-${{ matrix.os }}-${{ env.DF_VERSION }}-${{ hashFiles('ci/download-df.sh') }}
- name: Install blank DFHack init scripts
if: matrix.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@v3
with:
name: test-${{ matrix.compiler }}
- name: Install DFHack
shell: bash
run: tar xjf test-${{ matrix.compiler }}.tar.bz2 -C ${{ env.DF_FOLDER }}
- name: Start X server
if: matrix.os == 'ubuntu'
run: Xvfb :0 -screen 0 1600x1200x24 &
- name: Run lua tests
timeout-minutes: 10
env:
DISPLAY: :0
TERM: xterm-256color
run: 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@v3
if: always()
continue-on-error: true
with:
name: test-output-${{ matrix.compiler }}-${{ matrix.plugins }}_plugins-${{ matrix.config }}_config
path: |
${{ env.DF_FOLDER }}/dfhack-rpc.txt
${{ env.DF_FOLDER }}/test*.json
${{ env.DF_FOLDER }}/*.log

8
.gitignore vendored

@ -1,7 +1,7 @@
# linux backup files # linux backup files
*~ *~
#Kdevelop project files # Kdevelop project files
*.kdev4 *.kdev4
.kdev4 .kdev4
@ -70,7 +70,7 @@ tags
# Mac OS X .DS_Store files # Mac OS X .DS_Store files
.DS_Store .DS_Store
#VS is annoying about this one. # VS is annoying about this one.
/build/win64/DF_PATH.txt /build/win64/DF_PATH.txt
/build/win32/DF_PATH.txt /build/win32/DF_PATH.txt
/.vs /.vs
@ -80,3 +80,7 @@ tags
# external plugins # external plugins
/plugins/CMakeLists.custom.txt /plugins/CMakeLists.custom.txt
# 3rd party downloads
depends/steam
depends/SDL2

@ -4,7 +4,7 @@ ci:
repos: repos:
# shared across repos: # shared across repos:
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0 rev: v4.5.0
hooks: hooks:
- id: check-added-large-files - id: check-added-large-files
- id: check-case-conflict - id: check-case-conflict
@ -20,11 +20,11 @@ repos:
args: ['--fix=lf'] args: ['--fix=lf']
- id: trailing-whitespace - id: trailing-whitespace
- repo: https://github.com/python-jsonschema/check-jsonschema - repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.22.0 rev: 0.27.1
hooks: hooks:
- id: check-github-workflows - id: check-github-workflows
- repo: https://github.com/Lucas-C/pre-commit-hooks - repo: https://github.com/Lucas-C/pre-commit-hooks
rev: v1.5.1 rev: v1.5.4
hooks: hooks:
- id: forbid-tabs - id: forbid-tabs
exclude_types: exclude_types:

@ -1,21 +1,19 @@
# main project file. use it from a build sub-folder, see COMPILE for details # main project file. use it from a build sub-folder, see COMPILE for details
## some generic CMake magic ## some generic CMake magic
cmake_minimum_required(VERSION 3.6 FATAL_ERROR) cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
cmake_policy(SET CMP0048 NEW) cmake_policy(SET CMP0048 NEW)
cmake_policy(SET CMP0074 NEW)
project(dfhack) project(dfhack)
if("${CMAKE_GENERATOR}" STREQUAL Ninja) # set up versioning.
if("${CMAKE_VERSION}" VERSION_LESS 3.9) set(DF_VERSION "50.11")
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.") set(DFHACK_RELEASE "r2")
endif() set(DFHACK_PRERELEASE FALSE)
endif()
if(NOT("${CMAKE_VERSION}" VERSION_LESS 3.12)) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")
# make ZLIB_ROOT work in CMake >= 3.12 set(DFHACK_ABI_VERSION 1)
# https://cmake.org/cmake/help/git-stage/policy/CMP0074.html set(DFHACK_BUILD_ID "" CACHE STRING "Build ID (should be specified on command line)")
cmake_policy(SET CMP0074 NEW)
endif()
# Set up build types # Set up build types
if(CMAKE_CONFIGURATION_TYPES) if(CMAKE_CONFIGURATION_TYPES)
@ -32,14 +30,16 @@ else(CMAKE_CONFIGURATION_TYPES)
endif(CMAKE_CONFIGURATION_TYPES) endif(CMAKE_CONFIGURATION_TYPES)
option(BUILD_DOCS "Choose whether to build the documentation (requires python and Sphinx)." OFF) 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) 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) macro(CHECK_GCC compiler_path)
execute_process(COMMAND ${compiler_path} -dumpversion OUTPUT_VARIABLE GCC_VERSION_OUT) execute_process(COMMAND ${compiler_path} -dumpversion OUTPUT_VARIABLE GCC_VERSION_OUT)
string(STRIP "${GCC_VERSION_OUT}" GCC_VERSION_OUT) string(STRIP "${GCC_VERSION_OUT}" GCC_VERSION_OUT)
if(${GCC_VERSION_OUT} VERSION_LESS "4.8") if(${GCC_VERSION_OUT} VERSION_LESS "10")
message(SEND_ERROR "${compiler_path} version ${GCC_VERSION_OUT} cannot be used - use GCC 4.8 or later") message(SEND_ERROR "${compiler_path} version ${GCC_VERSION_OUT} cannot be used - use GCC 10 or later")
elseif(${GCC_VERSION_OUT} VERSION_GREATER "4.9.9") # TODO: this may need to be removed when DF linux actually comes out
# TODO: and we can test
# GCC 5 changes ABI name mangling to enable C++11 changes. # GCC 5 changes ABI name mangling to enable C++11 changes.
# This must be disabled to enable linking against DF. # This must be disabled to enable linking against DF.
# http://developerblog.redhat.com/2015/02/05/gcc5-and-the-c11-abi/ # http://developerblog.redhat.com/2015/02/05/gcc5-and-the-c11-abi/
@ -62,14 +62,14 @@ endif()
if(WIN32) if(WIN32)
if(NOT MSVC) if(NOT MSVC)
message(SEND_ERROR "No MSVC found! MSVC 2022 version 1930 to 1935 is required.") message(SEND_ERROR "No MSVC found! MSVC 2022 version 1930 to 1937 is required.")
elseif((MSVC_VERSION LESS 1930) OR (MSVC_VERSION GREATER 1935)) elseif((MSVC_VERSION LESS 1930) OR (MSVC_VERSION GREATER 1937))
message(SEND_ERROR "MSVC 2022 version 1930 to 1935 is required, Version Found: ${MSVC_VERSION}") message(SEND_ERROR "MSVC 2022 version 1930 to 1937 is required, Version Found: ${MSVC_VERSION}")
endif() endif()
endif() endif()
# Ask for C++11 standard from compilers # Ask for C++-20 standard from compilers
set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD 20)
# Require the standard support from compilers. # Require the standard support from compilers.
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Use only standard c++ to keep code portable # Use only standard c++ to keep code portable
@ -105,7 +105,7 @@ endif()
# Automatically detect architecture based on Visual Studio generator # Automatically detect architecture based on Visual Studio generator
if(MSVC AND NOT DEFINED DFHACK_BUILD_ARCH) if(MSVC AND NOT DEFINED DFHACK_BUILD_ARCH)
if ((${CMAKE_GENERATOR} MATCHES "Win32") OR (${CMAKE_GENERATOR} MATCHES "x86")) if ((${CMAKE_GENERATOR} MATCHES "Win32") OR (${CMAKE_GENERATOR} MATCHES "x86"))
set(DFHACK_BUILD_ARCH "32") message(SEND_ERROR "DF v50 does not support 32-bit")
else() else()
set(DFHACK_BUILD_ARCH "64") set(DFHACK_BUILD_ARCH "64")
endif() endif()
@ -123,7 +123,7 @@ elseif("${DFHACK_BUILD_ARCH}" STREQUAL "64")
set(DFHACK_SETARCH "x86_64") set(DFHACK_SETARCH "x86_64")
add_definitions(-DDFHACK64) add_definitions(-DDFHACK64)
else() 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() endif()
if(CMAKE_CROSSCOMPILING) if(CMAKE_CROSSCOMPILING)
@ -182,30 +182,24 @@ endif()
if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl 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}/scripts/CMakeLists.txt
OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/clsocket/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/libexpat/expat/CMakeLists.txt
OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/libzip/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/xlsxio/CMakeLists.txt
OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/googletest/CMakeLists.txt
OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/luacov/src 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() endif()
# set up versioning. # dfhack data goes here:
set(DF_VERSION "50.07") set(DFHACK_DATA_DESTINATION hack)
set(DFHACK_RELEASE "beta2")
set(DFHACK_PRERELEASE TRUE)
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)")
## where to install things (after the build is done, classic 'make install' or package structure) ## where to install things (after the build is done, classic 'make install' or package structure)
# the dfhack libraries will be installed here: # the dfhack libraries will be installed here:
if(UNIX) if(UNIX)
# put the lib into DF/hack # put the lib into DF/hack
set(DFHACK_LIBRARY_DESTINATION hack) set(DFHACK_LIBRARY_DESTINATION ${DFHACK_DATA_DESTINATION})
else() else()
# windows is crap, therefore we can't do nice things with it. leave the libs on a nasty pile... # 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_LIBRARY_DESTINATION .)
@ -213,37 +207,27 @@ endif()
# external tools will be installed here: # external tools will be installed here:
set(DFHACK_BINARY_DESTINATION .) set(DFHACK_BINARY_DESTINATION .)
# dfhack data goes here:
set(DFHACK_DATA_DESTINATION hack)
# plugin libs go here: # plugin libs go here:
set(DFHACK_PLUGIN_DESTINATION hack/plugins) set(DFHACK_PLUGIN_DESTINATION ${DFHACK_DATA_DESTINATION}/plugins)
# dfhack header files go here:
set(DFHACK_INCLUDES_DESTINATION hack/include)
# dfhack lua files go here: # dfhack lua files go here:
set(DFHACK_LUA_DESTINATION hack/lua) set(DFHACK_LUA_DESTINATION ${DFHACK_DATA_DESTINATION}/lua)
# the windows .lib file goes here:
set(DFHACK_DEVLIB_DESTINATION hack)
# user documentation goes here: # user documentation goes here:
set(DFHACK_USERDOC_DESTINATION hack) set(DFHACK_USERDOC_DESTINATION ${DFHACK_DATA_DESTINATION})
# developer documentation goes here:
set(DFHACK_DEVDOC_DESTINATION hack)
# some options for the user/developer to play with # some options for the user/developer to play with
option(BUILD_LIBRARY "Build the library that goes into DF." ON) option(BUILD_LIBRARY "Build the DFHack library." ON)
option(BUILD_PLUGINS "Build the plugins." 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) set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
if(UNIX) if(UNIX)
## flags for GCC ## flags for GCC
# default to hidden symbols # default to hidden symbols
# build 32bit
# ensure compatibility with older CPUs # ensure compatibility with older CPUs
# enable C++11 features
add_definitions(-DLINUX_BUILD) add_definitions(-DLINUX_BUILD)
add_definitions(-D_GLIBCXX_USE_C99) set(GCC_COMMON_FLAGS "-fvisibility=hidden -mtune=generic -Wall -Werror -Wl,--disable-new-dtags")
set(GCC_COMMON_FLAGS "-fvisibility=hidden -mtune=generic -Wall -Werror")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COMMON_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COMMON_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_COMMON_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_COMMON_FLAGS}")
if(DFHACK_BUILD_64) if(DFHACK_BUILD_64)
@ -254,7 +238,7 @@ if(UNIX)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -march=i686") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -march=i686")
endif() endif()
string(REPLACE "-DNDEBUG" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") string(REPLACE "-DNDEBUG" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
set(CMAKE_INSTALL_RPATH "hack") set(CMAKE_INSTALL_RPATH ${DFHACK_LIBRARY_DESTINATION})
elseif(MSVC) elseif(MSVC)
# for msvc, tell it to always use 8-byte pointers to member functions to avoid confusion # 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 "${CMAKE_CXX_FLAGS} /vmg /vmm /MP")
@ -276,43 +260,51 @@ elseif(WIN32)
add_definitions(-DWIN32) add_definitions(-DWIN32)
endif() endif()
#### download depends #### #### dependencies ####
# fix for pyenv: default to `python3` before `python3.x`
set(Python_FIND_UNVERSIONED_NAMES FIRST)
include(CMake/DownloadFile.cmake) include(CMake/DownloadFile.cmake)
if(WIN32) if(WIN32)
# Download zlib on Windows set(ZLIB_FILE zlib.lib)
set(ZLIB_DOWNLOAD_DIR ${dfhack_SOURCE_DIR}/depends/zlib/lib/win${DFHACK_BUILD_ARCH}) set(ZLIB_PATH ${dfhack_SOURCE_DIR}/depends/zlib/)
if(${DFHACK_BUILD_ARCH} STREQUAL "64") set(ZLIB_MD5 a3b2fc6b68efafa89b0882e354fc8418)
download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-zlib.lib" download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-${ZLIB_FILE}"
${ZLIB_DOWNLOAD_DIR}/zlib.lib ${ZLIB_PATH}lib/${ZLIB_FILE}
"a3b2fc6b68efafa89b0882e354fc8418") ${ZLIB_MD5})
else() set(ZLIB_ROOT ${ZLIB_PATH})
download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win32-zlib.lib" else()
${ZLIB_DOWNLOAD_DIR}/zlib.lib # Rescan for pthread and zlib if the build arch changed
"f4ebaa21d9de28566e88b1edfcdff901") if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_BUILD_ARCH_PREV}")
unset(ZLIB_LIBRARY CACHE)
unset(CMAKE_HAVE_PTHREAD_H CACHE)
endif() endif()
# Move zlib to the build folder so possible 32 and 64-bit builds if(NOT APPLE AND DFHACK_BUILD_32)
# in the same source tree don't conflict set(ZLIB_ROOT /usr/lib/i386-linux-gnu)
file(COPY ${dfhack_SOURCE_DIR}/depends/zlib
DESTINATION ${CMAKE_BINARY_DIR}/depends/)
file(COPY ${ZLIB_DOWNLOAD_DIR}/zlib.lib
DESTINATION ${CMAKE_BINARY_DIR}/depends/zlib/lib/)
# 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 ${dfhack_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")
else()
download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win32-SDL.dll"
${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll
"5a09604daca6b2b5ce049d79af935d6a")
endif() endif()
endif() endif()
find_package(ZLIB REQUIRED)
include_directories(${ZLIB_INCLUDE_DIRS})
if(BUILD_LIBRARY)
# 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})
include_directories(${SDL_ZIP_PATH}/SDL2-${SDL_VERSION}/include)
endif()
if(APPLE) if(APPLE)
# libstdc++ (GCC 4.8.5 for OS X 10.6) # libstdc++ (GCC 4.8.5 for OS X 10.6)
@ -372,26 +364,6 @@ endif()
#### expose depends #### #### 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/protobuf)
include_directories(depends/lua/include) include_directories(depends/lua/include)
include_directories(depends/md5) include_directories(depends/md5)
@ -413,17 +385,19 @@ endif()
include_directories(depends/lodepng) include_directories(depends/lodepng)
include_directories(depends/tthread) include_directories(depends/tthread)
include_directories(${ZLIB_INCLUDE_DIRS})
include_directories(depends/clsocket/src) include_directories(depends/clsocket/src)
include_directories(depends/xlsxio/include) include_directories(depends/xlsxio/include)
add_subdirectory(depends)
if(BUILD_LIBRARY)
add_subdirectory(depends)
endif()
# Testing with CTest # Testing with CTest
macro(dfhack_test name files) macro(dfhack_test name files)
if(UNIX AND NOT APPLE) # remove this once our MSVC build env has been updated if(BUILD_LIBRARY AND UNIX AND NOT APPLE) # remove this once our MSVC build env has been updated
add_executable(${name} ${files}) add_executable(${name} ${files})
target_include_directories(${name} PUBLIC depends/googletest/googletest/include) target_include_directories(${name} PUBLIC depends/googletest/googletest/include)
target_link_libraries(${name} dfhack gtest SDL) target_link_libraries(${name} dfhack gtest)
add_test(NAME ${name} COMMAND ${name}) add_test(NAME ${name} COMMAND ${name})
endif() endif()
endmacro() endmacro()
@ -435,22 +409,25 @@ if(NOT GIT_FOUND)
endif() endif()
# build the lib itself # build the lib itself
add_subdirectory(library)
if(BUILD_LIBRARY) if(BUILD_LIBRARY)
add_subdirectory(library) file(WRITE ${CMAKE_BINARY_DIR}/dfhack_setarch.txt ${DFHACK_SETARCH})
install(FILES LICENSE.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) install(FILES ${CMAKE_BINARY_DIR}/dfhack_setarch.txt DESTINATION ${DFHACK_DATA_DESTINATION})
install(FILES docs/changelog-placeholder.txt DESTINATION ${DFHACK_USERDOC_DESTINATION} RENAME changelog.txt)
endif() endif()
file(WRITE "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" ${DFHACK_SETARCH})
install(FILES "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" DESTINATION "${DFHACK_DATA_DESTINATION}")
# build the plugins # 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() endif()
add_subdirectory(data) if(INSTALL_SCRIPTS)
add_subdirectory(scripts) add_subdirectory(scripts)
endif()
if(BUILD_DOCS) if(BUILD_DOCS)
find_package(Python3) find_package(Python3)
@ -491,7 +468,14 @@ if(BUILD_DOCS)
"${CMAKE_CURRENT_SOURCE_DIR}/conf.py" "${CMAKE_CURRENT_SOURCE_DIR}/conf.py"
) )
set(SPHINX_OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/docs/html/.buildinfo") 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( set_property(
DIRECTORY PROPERTY ADDITIONAL_CLEAN_FILES TRUE DIRECTORY PROPERTY ADDITIONAL_CLEAN_FILES TRUE
"${CMAKE_CURRENT_SOURCE_DIR}/docs/changelogs" "${CMAKE_CURRENT_SOURCE_DIR}/docs/changelogs"
@ -508,9 +492,10 @@ if(BUILD_DOCS)
"${CMAKE_BINARY_DIR}/docs/text" "${CMAKE_BINARY_DIR}/docs/text"
"${CMAKE_BINARY_DIR}/docs/xml" "${CMAKE_BINARY_DIR}/docs/xml"
) )
add_custom_command(OUTPUT ${SPHINX_OUTPUT} add_custom_command(OUTPUT ${SPHINX_OUTPUT}
COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/docs/build.py" COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/docs/build.py"
html text --sphinx="${SPHINX_EXECUTABLE}" -- -q ${SPHINX_BUILD_TARGETS} --sphinx="${SPHINX_EXECUTABLE}" -- -q -W
DEPENDS ${SPHINX_DEPS} DEPENDS ${SPHINX_DEPS}
COMMENT "Building documentation with Sphinx" COMMENT "Building documentation with Sphinx"
) )
@ -523,10 +508,12 @@ if(BUILD_DOCS)
add_custom_command(TARGET dfhack_docs POST_BUILD add_custom_command(TARGET dfhack_docs POST_BUILD
COMMAND ${CMAKE_COMMAND} -E touch ${SPHINX_OUTPUT}) COMMAND ${CMAKE_COMMAND} -E touch ${SPHINX_OUTPUT})
install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/html/ if(NOT BUILD_DOCS_NO_HTML)
DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/html/
FILES_MATCHING PATTERN "*" DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs
PATTERN html/_sources EXCLUDE) FILES_MATCHING PATTERN "*"
PATTERN html/_sources EXCLUDE)
endif()
install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/text/ install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/text/
DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs) DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs)
install(FILES docs/changelogs/news.rst docs/changelogs/news-dev.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) install(FILES docs/changelogs/news.rst docs/changelogs/news-dev.rst DESTINATION ${DFHACK_USERDOC_DESTINATION})
@ -611,7 +598,7 @@ endif()
set(DFHACK_BUILD_ARCH_PREV "${DFHACK_BUILD_ARCH}" CACHE STRING "Previous build architecture" FORCE) set(DFHACK_BUILD_ARCH_PREV "${DFHACK_BUILD_ARCH}" CACHE STRING "Previous build architecture" FORCE)
option(BUILD_SIZECHECK "Build the sizecheck library, for research" OFF) option(BUILD_SIZECHECK "Build the sizecheck library, for research" OFF)
if(BUILD_SIZECHECK) if(BUILD_LIBRARY AND BUILD_SIZECHECK)
add_subdirectory(depends/sizecheck) add_subdirectory(depends/sizecheck)
add_dependencies(dfhack sizecheck) add_dependencies(dfhack sizecheck)
endif() endif()

@ -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": [ "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", "name": "MSVC 64 Debug",
"generator": "Ninja", "generator": "Ninja",
"configurationType": "RelWithDebInfo", "configurationType": "RelWithDebInfo",
"inheritEnvironments": [ "msvc_x64_x64", "msvc_2015_x64" ], "inheritEnvironments": [ "msvc_x64_x64" ],
"variables": [ "variables": [
{ {
"name": "DFHACK_BUILD_ARCH", "name": "DFHACK_BUILD_ARCH",
@ -94,7 +28,7 @@
"name": "MSVC 64 Release", "name": "MSVC 64 Release",
"generator": "Ninja", "generator": "Ninja",
"configurationType": "Release", "configurationType": "Release",
"inheritEnvironments": [ "msvc_x64_x64", "msvc_2015_x64" ], "inheritEnvironments": [ "msvc_x64_x64" ],
"variables": [ "variables": [
{ {
"name": "DFHACK_BUILD_ARCH", "name": "DFHACK_BUILD_ARCH",

@ -41,9 +41,11 @@ fi
if ! docker run --rm -i -v "$srcdir":/src -v "$srcdir/build/win64-cross/":/src/build \ if ! docker run --rm -i -v "$srcdir":/src -v "$srcdir/build/win64-cross/":/src/build \
-e BUILDER_UID=$builder_uid \ -e BUILDER_UID=$builder_uid \
-e CCACHE_DIR=/src/build/ccache \ -e CCACHE_DIR=/src/build/ccache \
-e steam_username \
-e steam_password \
--name dfhack-win \ --name dfhack-win \
ghcr.io/dfhack/build-env:msvc \ ghcr.io/dfhack/build-env:msvc \
bash -c "cd /src/build && dfhack-configure windows 64 Release -DCMAKE_INSTALL_PREFIX=/src/build/output cmake .. -DBUILD_DOCS=1 $CMAKE_EXTRA_ARGS && dfhack-make -j$jobs install" \ 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" \
; then ; then
echo echo
echo "Build failed" echo "Build failed"

@ -1,4 +0,0 @@
call "%VS140COMNTOOLS%vsvars32.bat"
cd VC2015_32
msbuild /m /p:Platform=Win32 /p:Configuration=RelWithDebInfo ALL_BUILD.vcxproj
cd ..

@ -1,5 +0,0 @@
call "%VS140COMNTOOLS%vsvars32.bat"
cd VC2015_32
msbuild /m /p:Platform=Win32 /p:Configuration=Release ALL_BUILD.vcxproj
cd ..
pause

@ -1,6 +0,0 @@
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015_32
cd VC2015_32
echo generating a build folder
cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_STONESENSE=1

@ -1,7 +0,0 @@
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015_32
cd VC2015_32
echo Pre-generating a build folder
cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%"
cmake-gui .

@ -1,6 +0,0 @@
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015_32
cd VC2015_32
echo generating a build folder
cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_STONESENSE=0

@ -1,6 +0,0 @@
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
mkdir VC2015_32
cd VC2015_32
echo generating a build folder
cmake ..\..\.. -G"Visual Studio 14" -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DOCS=1 -DBUILD_STONESENSE=1

@ -1,4 +0,0 @@
call "%VS140COMNTOOLS%vsvars32.bat"
cd VC2015_32
msbuild /m /p:Platform=Win32 /p:Configuration=RelWithDebInfo INSTALL.vcxproj
cd ..

@ -1,4 +0,0 @@
call "%VS140COMNTOOLS%vsvars32.bat"
cd VC2015_32
msbuild /m /p:Platform=Win32 /p:Configuration=Release INSTALL.vcxproj
cd ..

@ -1,6 +0,0 @@
@echo off
call "%VS140COMNTOOLS%vsvars32.bat"
cd VC2015_32
msbuild /m /p:Platform=Win32 /p:Configuration=RelWithDebInfo PACKAGE.vcxproj
cd ..
exit %ERRORLEVEL%

@ -1,5 +0,0 @@
@echo off
call "%VS140COMNTOOLS%vsvars32.bat"
cd VC2015_32
msbuild /m /p:Platform=Win32 /p:Configuration=Release PACKAGE.vcxproj
cd ..

@ -1,42 +0,0 @@
Option Explicit
Const BIF_returnonlyfsdirs = &H0001
Dim wsh, objDlg, objF, fso, spoFile, args
Set fso = CreateObject("Scripting.FileSystemObject")
set args = Wscript.Arguments
if args.count > 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 InStr(1, TypeName(objF), "Folder") > 0 Then
Set spoFile = fso.CreateTextFile("DF_PATH.txt", True)
spoFile.WriteLine(objF.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

@ -1,4 +1,4 @@
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
echo generating a build folder echo generating a build folder
cmake ..\.. -G"Visual Studio 17 2022" -A x64 -B VC2022 -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=1 -DBUILD_DEV_PLUGINS=1 -DBUILD_STONESENSE=1 cmake ..\.. -G"Visual Studio 17 2022" -A x64 -B VC2022 -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEV_PLUGINS=1 -DBUILD_STONESENSE=1

@ -1,4 +1,4 @@
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
echo generating a build folder echo generating a build folder
cmake ..\.. -G"Visual Studio 17 2022" -A x64 -B VC2022 -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_STONESENSE=0 cmake ..\.. -G"Visual Studio 17 2022" -A x64 -B VC2022 -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEV_PLUGINS=0 -DBUILD_STONESENSE=0

@ -1,4 +1,4 @@
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
echo generating a build folder echo generating a build folder
cmake ..\.. -G"Visual Studio 17 2022" -A x64 -B VC2022 -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_DOCS=1 -DBUILD_STONESENSE=1 cmake ..\.. -G"Visual Studio 17 2022" -A x64 -B VC2022 -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEV_PLUGINS=0 -DBUILD_DOCS=1 -DBUILD_STONESENSE=1

@ -0,0 +1,4 @@
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
echo generating a build folder
cmake ..\.. -G"Visual Studio 17 2022" -A x64 -B VC2022 -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_DEV_PLUGINS=1 -DBUILD_STONESENSE=1 -DBUILD_DFLAUNCH=1

@ -1,4 +1,4 @@
IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt IF EXIST DF_PATH.txt SET /P _DF_PATH=<DF_PATH.txt
IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF IF NOT EXIST DF_PATH.txt SET _DF_PATH=%CD%\DF
echo generating a build folder echo generating a build folder
cmake ..\.. -G"Visual Studio 17 2022" -A x64 -B VC2022 -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_SUPPORTED=0 -DBUILD_DEVEL=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_STONESENSE=0 -DBUILD_SIZECHECK=1 cmake ..\.. -G"Visual Studio 17 2022" -A x64 -B VC2022 -DCMAKE_INSTALL_PREFIX="%_DF_PATH%" -DBUILD_SUPPORTED=0 -DBUILD_DEV_PLUGINS=0 -DBUILD_STONESENSE=0 -DBUILD_SIZECHECK=1

@ -1,71 +0,0 @@
#!/usr/bin/env python3
import argparse
import hashlib
import hmac
import json
import logging
import os
import uuid
import requests
logging.basicConfig(level=logging.DEBUG)
def get_required_env(name):
value = os.environ.get(name)
if not value:
raise ValueError(f'Expected environment variable {name!r} to be non-empty')
return value
def make_sig(body, secret, algorithm):
return hmac.new(secret.encode(), body.encode(), algorithm).hexdigest()
webhook_url = get_required_env('DFHACK_BUILDMASTER_WEBHOOK_URL')
secret = get_required_env('DFHACK_BUILDMASTER_WEBHOOK_SECRET')
api_token = get_required_env('GITHUB_TOKEN')
repo = get_required_env('GITHUB_REPO')
parser = argparse.ArgumentParser()
target_group = parser.add_mutually_exclusive_group(required=True)
target_group.add_argument('--pull-request', type=int, help='Pull request to rebuild')
args = parser.parse_args()
response = requests.get(
f'https://api.github.com/repos/{repo}/pulls/{args.pull_request}',
headers={
'Authorization': f'Bearer {api_token}',
},
)
response.raise_for_status()
pull_request_data = response.json()
body = json.dumps({
'action': 'synchronize',
'number': args.pull_request,
'pull_request': pull_request_data,
})
response = requests.post(
'https://lubar-webhook-proxy.appspot.com/github/buildmaster',
headers={
'Content-Type': 'application/json',
'User-Agent': 'GitHub-Hookshot/' + requests.utils.default_user_agent(),
'X-GitHub-Delivery': 'dfhack-rebuild-' + str(uuid.uuid4()),
'X-GitHub-Event': 'pull_request',
'X-Hub-Signature': 'sha1=' + make_sig(body, secret, hashlib.sha1),
'X-Hub-Signature-256': 'sha256=' + make_sig(body, secret, hashlib.sha256),
},
data=body,
timeout=15,
)
print(response)
print(str(response.text))
response.raise_for_status()

@ -1,8 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import glob import glob
import itertools
import sys import sys
actual = {'': {}} actual = {'': {}}
SEP = ('=' * 80)
with open(sys.argv[1]) as f: with open(sys.argv[1]) as f:
plugin_name = '' plugin_name = ''
@ -26,7 +28,7 @@ for p in glob.iglob('library/proto/*.proto'):
parts = line.split(' ') parts = line.split(' ')
expected[''][parts[2]] = (parts[4], parts[6]) 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')):
plugin_name = '' plugin_name = ''
with open(p) as f: with open(p) as f:
for line in f: for line in f:
@ -53,6 +55,7 @@ for plugin_name in actual:
methods = actual[plugin_name] methods = actual[plugin_name]
if plugin_name not in expected: if plugin_name not in expected:
print(SEP)
print('Missing documentation for plugin proto files: ' + plugin_name) print('Missing documentation for plugin proto files: ' + plugin_name)
print('Add the following lines:') print('Add the following lines:')
print('// Plugin: ' + plugin_name) print('// Plugin: ' + plugin_name)
@ -73,12 +76,14 @@ for plugin_name in actual:
missing.append('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1]) missing.append('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1])
if len(missing) > 0: if len(missing) > 0:
print(SEP)
print('Incomplete documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Add the following lines:') print('Incomplete documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Add the following lines:')
for m in missing: for m in missing:
print(m) print(m)
error_count += 1 error_count += 1
if len(wrong) > 0: if len(wrong) > 0:
print(SEP)
print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Replace the following comments:') print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Replace the following comments:')
for m in wrong: for m in wrong:
print(m) print(m)
@ -88,6 +93,7 @@ for plugin_name in expected:
methods = expected[plugin_name] methods = expected[plugin_name]
if plugin_name not in actual: if plugin_name not in actual:
print(SEP)
print('Incorrect documentation for plugin proto files: ' + plugin_name) print('Incorrect documentation for plugin proto files: ' + plugin_name)
print('The following methods are documented, but the plugin does not provide any RPC methods:') print('The following methods are documented, but the plugin does not provide any RPC methods:')
for m in methods: for m in methods:
@ -102,6 +108,7 @@ for plugin_name in expected:
missing.append('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1]) missing.append('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1])
if len(missing) > 0: if len(missing) > 0:
print(SEP)
print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Remove the following lines:') print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Remove the following lines:')
for m in missing: for m in missing:
print(m) print(m)

@ -1,52 +1,53 @@
#!/bin/sh #!/bin/sh
DF_FOLDER=$1
OS_TARGET=$2
DF_VERSION=$3
set -e set -e
df_tardest="df.tar.bz2" minor=$(echo "$DF_VERSION" | cut -d. -f1)
save_tardest="test_save.tgz" patch=$(echo "$DF_VERSION" | cut -d. -f2)
df_url="https://www.bay12games.com/dwarves/df_${minor}_${patch}"
cd "$(dirname "$0")" if test "$OS_TARGET" = "windows"; then
echo "DF_VERSION: $DF_VERSION" WGET="C:/msys64/usr/bin/wget.exe"
echo "DF_FOLDER: $DF_FOLDER" df_url="${df_url}_win_s.zip"
mkdir -p "$DF_FOLDER" df_archive_name="df.zip"
# back out of df_linux df_extract_cmd="unzip -d ${DF_FOLDER}"
cd "$DF_FOLDER/.." elif test "$OS_TARGET" = "ubuntu"; then
WGET=wget
if ! test -f "$df_tardest"; then df_url="${df_url}_linux.tar.bz2"
minor=$(echo "$DF_VERSION" | cut -d. -f2) df_archive_name="df.tar.bz2"
patch=$(echo "$DF_VERSION" | cut -d. -f3) df_extract_cmd="tar -x -j -C ${DF_FOLDER} -f"
echo "Downloading DF $DF_VERSION" else
while read url; do echo "Unhandled OS target: ${OS_TARGET}"
echo "Attempting download: ${url}" exit 1
if wget -v "$url" -O "$df_tardest"; then fi
break
fi if ! $WGET -v "$df_url" -O "$df_archive_name"; then
done <<URLS echo "Failed to download DF from $df_url"
https://www.bay12games.com/dwarves/df_${minor}_${patch}_linux.tar.bz2 exit 1
https://files.dfhack.org/DF/${minor}.${patch}/df_${minor}_${patch}_linux.tar.bz2 fi
URLS
echo $df_tardest md5sum "$df_archive_name"
if ! test -f "$df_tardest"; then
echo "DF failed to download: $df_tardest not found" save_url="https://dffd.bay12games.com/download.php?id=15434&f=dreamfort.7z"
exit 1 save_archive_name="test_save.7z"
fi save_extract_cmd="7z x -o${DF_FOLDER}/save"
echo "Downloading test save" if ! $WGET -v "$save_url" -O "$save_archive_name"; then
#test_save_url="https://files.dfhack.org/DF/0.${minor}.${patch}/test_save.tgz" echo "Failed to download test save from $save_url"
test_save_url="https://drive.google.com/uc?export=download&id=1XvYngl-DFONiZ9SD9OC4B2Ooecu8rPFz" exit 1
if ! wget -v "$test_save_url" -O "$save_tardest"; then
echo "failed to download test save"
exit 1
fi
echo $save_tardest
fi fi
rm -rf df_linux md5sum "$save_archive_name"
mkdir -p df_linux/save
echo Extracting echo Extracting
tar xf "$df_tardest" --strip-components=1 -C df_linux mkdir -p ${DF_FOLDER}
tar xf "$save_tardest" -C df_linux/save $df_extract_cmd "$df_archive_name"
$save_extract_cmd "$save_archive_name"
mv ${DF_FOLDER}/save/* ${DF_FOLDER}/save/region1
echo Done echo Done
ls -l ls -l

@ -55,33 +55,32 @@ if os.path.exists(test_status_file):
os.remove(test_status_file) os.remove(test_status_file)
print('Backing up init.txt to init.txt.orig') 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') shutil.copyfile(init_txt_path, init_txt_path + '.orig')
with open(init_txt_path) as f: with open(init_txt_path) as f:
init_contents = f.read() 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, 'SOUND', 'NO')
init_contents = change_setting(init_contents, 'WINDOWED', 'YES') init_contents = change_setting(init_contents, 'WINDOWED', 'YES')
init_contents = change_setting(init_contents, 'WINDOWEDX', '80') init_contents = change_setting(init_contents, 'WINDOWEDX', '1200')
init_contents = change_setting(init_contents, 'WINDOWEDY', '25') init_contents = change_setting(init_contents, 'WINDOWEDY', '800')
init_contents = change_setting(init_contents, 'FPS', 'YES') #if args.headless:
if args.headless: # init_contents = change_setting(init_contents, 'PRINT_MODE', 'TEXT')
init_contents = change_setting(init_contents, 'PRINT_MODE', 'TEXT')
init_path = 'dfhack-config/init' init_path = 'dfhack-config/init'
if not os.path.isdir('hack/init'): if not os.path.isdir('hack/init'):
# we're on an old branch that still reads init files from the root dir # we're on an old branch that still reads init files from the root dir
init_path = '.' init_path = '.'
try: os.makedirs(init_path, exist_ok=True)
os.mkdir(init_path)
except OSError as error:
# ignore already exists errors
pass
test_init_file = os.path.join(init_path, 'dfhackzzz_test.init') # Core sorts these alphabetically test_init_file = os.path.join(init_path, 'dfhackzzz_test.init') # Core sorts these alphabetically
with open(test_init_file, 'w') as f: with open(test_init_file, 'w') as f:
f.write(''' f.write('''
devel/dump-rpc dfhack-rpc.txt devel/dump-rpc dfhack-rpc.txt
:lua dfhack.internal.addScriptPath(dfhack.getHackPath())
test --resume -- 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')) ''' % ('NONE' if args.no_quit else 'QUIT'))

@ -1,11 +1,13 @@
-- DFHack developer test harness -- DFHack developer test harness
--@ module = true --@ module = true
local expect = require 'test_util.expect' local expect = require('test_util.expect')
local json = require 'json' local gui = require('gui')
local mock = require 'test_util.mock' local helpdb = require('helpdb')
local script = require 'gui.script' local json = require('json')
local utils = require 'utils' local mock = require('test_util.mock')
local script = require('gui.script')
local utils = require('utils')
local help_text = local help_text =
[====[ [====[
@ -13,49 +15,59 @@ local help_text =
test 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 [<options>] [<done_command>] test [<options>] [<done_command>]
If a done_command is specified, it will be run after the tests complete. If a done_command is specified, it will be run after the tests complete.
Options: Options
-------
-h, --help display this help message and exit.
-d, --test_dir specifies which directory to look in for tests. defaults to -d, --test_dir specifies which directory to look in for tests. defaults to
the "hack/scripts/test" folder in your DF installation. the "hack/scripts/test" folder in your DF installation.
-m, --modes only run tests in the given comma separated list of modes. -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 see the next section for a list of valid modes. if not
specified, the tests are not filtered by modes. specified, the tests are not filtered by modes.
-r, --resume skip tests that have already been run. remove the -r, --resume skip tests that have already been run. remove the
test_status.json file to reset the record. test_status.json file to reset the record.
-s, --save_dir the save folder to load for "fortress" mode tests. this -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 save is only loaded if a fort is not already loaded when
a "fortress" mode test is run. if not specified, defaults to a "fortress" mode test is run. if not specified, defaults to
'region1'. 'region1'.
-t, --tests only run tests that match one of the comma separated list of -t, --tests only run tests that match one of the comma separated list of
patterns. if not specified, no tests are filtered. patterns. if not specified, no tests are filtered and all tessts
are run.
Modes:
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 none the test can be run on any screen
fortress the test must be run while a map is loaded. if the game is title the test must be run on the DF title screen. note that if the game
currently on the title screen, the save specified by the save_dir has a map loaded, "title" mode tests cannot be run
parameter will be loaded. 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
Examples: parameter will be loaded.
test runs all tests Examples
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 runs all tests
test -t quickfort runs quickfort tests test -r runs all tests that haven't been run before
test -d /path/to/dfhack-scripts/repo/test test -m none runs tests that don't need the game to be in a
runs tests in your dev scripts repo 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 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 your DF folder. Options with comma-separated values should be written as json
@ -140,18 +152,37 @@ end
test_envvars.require = clean_require test_envvars.require = clean_require
test_envvars.reqscript = clean_reqscript test_envvars.reqscript = clean_reqscript
local function is_title_screen(scr) local function is_title_screen()
scr = scr or dfhack.gui.getCurViewscreen() return dfhack.gui.matchFocusString('title/Default')
return df.viewscreen_titlest:is_instance(scr) 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 end
-- This only handles pre-fortress-load screens. It will time out if the player -- 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 -- has already loaded a fortress or is in any screen that can't get to the title
-- screen by sending ESC keys. -- screen by sending ESC keys.
local function ensure_title_screen() 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 for i = 1, 100 do
local scr = dfhack.gui.getCurViewscreen() local scr = dfhack.gui.getCurViewscreen()
if is_title_screen(scr) then if is_title_screen() then
print('Found title screen') print('Found title screen')
return return
end end
@ -160,57 +191,94 @@ local function ensure_title_screen()
if i % 10 == 0 then print('Looking for title screen...') end if i % 10 == 0 then print('Looking for title screen...') end
end end
qerror(string.format('Could not find title screen (timed out at %s)', qerror(string.format('Could not find title screen (timed out at %s)',
dfhack.gui.getCurFocus(true))) dfhack.gui.getCurFocus(true)[1]))
end end
local function is_fortress(focus_string) local function is_fortress()
focus_string = focus_string or dfhack.gui.getCurFocus(true) return dfhack.gui.matchFocusString('dwarfmode/Default')
return focus_string == '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 end
-- Requires that a fortress game is already loaded or is ready to be loaded via -- 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. -- will time out and/or exit with error.
local function ensure_fortress(config) local function ensure_fortress(config)
local focus_string = dfhack.gui.getCurFocus(true)
for screen_timeout = 1,10 do for screen_timeout = 1,10 do
if is_fortress(focus_string) then if is_fortress() then
print('Loaded fortress map') print('Fortress map is loaded')
-- pause the game (if it's not already paused) -- pause the game (if it's not already paused)
dfhack.gui.resetDwarfmodeView(true) dfhack.gui.resetDwarfmodeView(true)
return return
end end
local scr = dfhack.gui.getCurViewscreen(true) local scr = dfhack.gui.getCurViewscreen()
if focus_string == 'title' or if dfhack.gui.matchFocusString('title/Default', scr) then
focus_string == 'dfhack/lua/load_screen' 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 -- qerror()'s on falure
dfhack.run_script('load-save', config.save_dir) -- dfhack.run_script('load-save', config.save_dir)
elseif focus_string ~= 'loadgame' then 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 -- if we're not actively loading a game, hope we're in
-- a screen where hitting ESC will get us to the game map -- a screen where hitting ESC will get us to the game map
-- or the title screen -- or the title screen
scr:feed_key(df.interface_key.LEAVESCREEN) scr:feed_key(df.interface_key.LEAVESCREEN)
end end
-- wait for current screen to change -- wait for current screen to change
local prev_focus_string = focus_string local prev_focus_string = dfhack.gui.getCurFocus()[1]
for frame_timeout = 1,100 do wait_for(60000, 'screen change', function()
delay(10) return dfhack.gui.getCurFocus()[1] ~= prev_focus_string
focus_string = dfhack.gui.getCurFocus(true) end)
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::
end end
qerror(string.format('Could not load fortress (timed out at %s)', qerror(string.format('Could not load fortress (timed out at %s)',
focus_string)) table.concat(dfhack.gui.getCurFocus(), ' ')))
end end
local MODES = { local MODES = {
@ -236,6 +304,25 @@ local function load_test_config(config_file)
return config return config
end 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 -- 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 -- output doesn't trigger its own dfhack.printerr usage detection (see
-- detect_printerr below) -- detect_printerr below)
@ -280,7 +367,7 @@ end
local function build_test_env(path) local function build_test_env(path)
local env = { local env = {
test = utils.OrderedTable(), test = TestTable(),
-- config values can be overridden in the test file to define -- config values can be overridden in the test file to define
-- requirements for the tests in that file -- requirements for the tests in that file
config = { config = {
@ -352,33 +439,46 @@ local function load_tests(file, tests)
if not code then if not code then
dfhack.printerr('Failed to load file: ' .. tostring(err)) dfhack.printerr('Failed to load file: ' .. tostring(err))
return false return false
else end
dfhack.internal.IN_TEST = true dfhack.internal.IN_TEST = true
local ok, err = dfhack.pcall(code) local ok, err = dfhack.pcall(code)
dfhack.internal.IN_TEST = false dfhack.internal.IN_TEST = false
if not ok then if not ok then
dfhack.printerr('Error when running file: ' .. tostring(err)) dfhack.printerr('Error when running file: ' .. tostring(err))
return false return false
else end
if not MODES[env.config.mode] then if not MODES[env.config.mode] then
dfhack.printerr('Invalid config.mode: ' .. tostring(env.config.mode)) dfhack.printerr('Invalid config.mode: ' .. tostring(env.config.mode))
return false return false
end end
for name, test_func in pairs(env.test) do if not env.config.target then
if env.config.wrapper then dfhack.printerr('Skipping tests for unspecified target in ' .. file)
local fn = test_func return true -- TODO: change to false once existing tests have targets specified
test_func = function() env.config.wrapper(fn) end end
end local targets = type(env.config.target) == 'table' and env.config.target or {env.config.target}
local test_data = { for _,target in ipairs(targets) do
full_name = short_filename .. ':' .. name, if target == 'core' then goto continue end
func = test_func, if type(target) ~= 'string' or not helpdb.is_entry(target) or
private = env_private, helpdb.get_entry_tags(target).unavailable
config = env.config, then
} dfhack.printerr('Skipping tests for unavailable target: ' .. target)
test_data.name = test_data.full_name:gsub('test/', ''):gsub('.lua', '') return true
table.insert(tests, test_data) end
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 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
return true return true
end end
@ -520,6 +620,10 @@ local function filter_tests(tests, config)
end end
local function run_tests(tests, status, counts, config) 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)) print(('Running %d tests'):format(#tests))
local start_ms = dfhack.getTickCount() local start_ms = dfhack.getTickCount()
local num_skipped = 0 local num_skipped = 0
@ -529,6 +633,7 @@ local function run_tests(tests, status, counts, config)
goto skip goto skip
end end
if not MODES[test.config.mode].detect() then 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) local ok, err = pcall(MODES[test.config.mode].navigate, config)
if not ok then if not ok then
MODES[test.config.mode].failed = true MODES[test.config.mode].failed = true
@ -537,12 +642,13 @@ local function run_tests(tests, status, counts, config)
goto skip goto skip
end end
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 if run_test(test, status, counts) then
status[test.full_name] = TestStatus.PASSED status[test.full_name] = TestStatus.PASSED
else save_test_status(status)
status[test.full_name] = TestStatus.FAILED
end end
save_test_status(status)
::skip:: ::skip::
end end
local elapsed_ms = dfhack.getTickCount() - start_ms local elapsed_ms = dfhack.getTickCount() - start_ms
@ -575,7 +681,7 @@ local function dump_df_state()
enabler = { enabler = {
fps = df.global.enabler.fps, fps = df.global.enabler.fps,
gfps = df.global.enabler.gfps, gfps = df.global.enabler.gfps,
fullscreen = df.global.enabler.fullscreen, fullscreen_state = df.global.enabler.fullscreen_state.whole,
}, },
gps = { gps = {
dimx = df.global.gps.dimx, dimx = df.global.gps.dimx,

@ -2,6 +2,7 @@ library/xml master
scripts master scripts master
plugins/stonesense master plugins/stonesense master
plugins/isoworld dfhack plugins/isoworld dfhack
depends/clsocket master
depends/libzip dfhack depends/libzip dfhack
depends/libexpat dfhack depends/libexpat dfhack
depends/xlsxio dfhack depends/xlsxio dfhack

@ -78,8 +78,7 @@ def write_tool_docs():
os.makedirs(os.path.join('docs/tools', os.path.dirname(k[0])), os.makedirs(os.path.join('docs/tools', os.path.dirname(k[0])),
mode=0o755, exist_ok=True) mode=0o755, exist_ok=True)
with write_file_if_changed('docs/tools/{}.rst'.format(k[0])) as outfile: with write_file_if_changed('docs/tools/{}.rst'.format(k[0])) as outfile:
if k[0] != 'search': outfile.write(label)
outfile.write(label)
outfile.write(include) outfile.write(include)

Before

Width:  |  Height:  |  Size: 997 B

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

@ -3,34 +3,34 @@
"" ""
Here's the procedure: Here's the procedure:
"" ""
1) Dig a tunnel from where you want the water to end up (e.g. your well cistern) off to an unused portion of the map. Be sure to dig a one-tile-wide diagonal segment in this tunnel so water that will eventually flow through the tunnel is depressurized. 1) Dig a tunnel from where you want the water to end up (e.g. your well cistern) off to an unused portion of the map that has an aquifer above it. Be sure to dig a one-tile-wide diagonal segment in this tunnel so water that will eventually flow through the tunnel is depressurized.
"" ""
"2) From the end of that tunnel, dig a staircase straight up to the z-level just below the lowest aquifer level. Also dig the staircase down one z-level below the tunnel level." "2) From the end of that tunnel, dig a staircase straight up to the lowest aquifer level. Erase the top staircase tile (the down-only stairs) so your miners don't dig it yet. We'll be adding it back with the aquifer_tap blueprint. Also dig the staircase column down one z-level below the tunnel level."
"" ""
"3) 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 edge of the map. This is your 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." "3) 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."
"" ""
4) 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. 4) 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.
"" ""
"5) If you care about how nice things look, haul away any boulders in the tunnels and smooth the tiles. You won't be able to access any of this area once it fills up with water!" "5) If you want, haul away any boulders in the tunnels and/or smooth the tiles. You won't be able to access any of this area once it fills up with water!"
"" ""
"6) Apply this blueprint (gui/quickfort library/aquifer_tap.csv -n /dig) to the z-level above the top of the staircase, inside the lowest aquifer level. Do not unpause until after the next step." "6) Apply this blueprint (gui/quickfort aquifer_tap /dig) to the z-level above the top of the staircase, inside the lowest aquifer level. Do not unpause until after the next step."
"" ""
"7) Damp tiles cancel dig designations if the tile is currently hidden, so to avoid having to re-apply this blueprint after every tile your dwarves dig, position the cursor straight up (north) of the left-most tile designated for digging and straight left (west) of the topmost designated tile and run the following commands in the DFHack console:" "7) Damp tiles cancel dig designations if the tile is currently hidden, so to avoid having to re-apply this blueprint after every tile your dwarves dig, position the keyboard cursor straight up (north) of the left-most tile designated for digging and straight left (west) of the topmost designated tile and run the following commands in the DFHack console:"
tiletypes-command f any ; f designated 1 ; p any ; p hidden 0 ; r 23 23 1 tiletypes-command f any ; f designated 1 ; p any ; p hidden 0 ; r 23 23 1
tiletypes-here tiletypes-here
"" ""
"8) Unpause and dig out the tap. If you care about appearances, haul away any boulders and feel free to remove the ramps (d-z). The water will safely flow down the staircase, through the open floodgate, down the drainage tunnel, and off the map until you choose to close the floodgate." "8) Unpause and dig out the tap. You can haul away any boulders and remove the ramps if you like. 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."
"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, the cisterns will stay forever full, but will not flood." "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, 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: A diagram might be useful. Here is a vertical view through the z-levels. This blueprint goes at the top:
"" ""
j <- center of this blueprint "j <- down stairs, center of this blueprint"
i i
... <- make this as tall as you need "... <- up/down stairs, make this as tall as you need"
i i
i <- cistern outlet level i <- cistern outlet level
u <- drainage level "u <- up stairs, drainage level"
"" ""
"Good luck! If done right, this method is the safest way to supply your fort with clean water." "Good luck! If done right, this method is the safest way to supply your fort with clean water."
#dig label(dig) start(13 13 center of tap) light aquifer water collector #dig label(dig) start(13 13 center of tap) light aquifer water collector

Can't render this file because it has a wrong number of fields in line 38.

@ -1,70 +1,74 @@
"#dig start(11; 12) 28 bedrooms, 3 tiles each (efficient layout)" "#dig label(dig) start(12; 12) 28 bedrooms, 3 tiles each"
# 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,d,d,d,d,d,d,d,d,# ,,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d
, , , , ,d,d, , , ,d, ,d, , , ,d, , , , ,# ,,,,,,d,d,,,,d,,d,,,,d
d,d,d,d,d,d,d,d,d,d,d,d,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,i,i,i,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,d,d,,d,,d,d,d,d,d,d,d,d,d,d,d,d,d
, , , ,d, , , ,d, ,d, , , ,d,d, , , , , ,# ,,,,,d,,,,d,,d,,,,d,d
d,d,d,d,d,d,d,d,d, ,d,d,d, ,d, ,d,d,d, , ,# ,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d
, , , ,d, , ,d,d, , , , , ,d, , , , , , ,# ,,,,,d,,,d,d,,,,,,d
, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d,d, , , , ,# ,,,d,d,d,,d,,d,d,d,,d,d,d,d,d
, , , , , ,d, ,d, ,d, ,d, ,d, ,d, , , , ,# ,,,,,,,d,,d,,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" #meta label(rooms)
, , , , , ,f, , , , , ,f, , , , , , , , ,# zone/zone
, , , , , ,h, , , , , ,h, , , , , , , , ,# build/build
, , , ,f, ,b, ,f, ,f, ,b, ,f, , , , , , ,# #zone label(zone) start(12; 12) hidden()
, , , ,h, ,d, ,h, ,h, ,d, ,h, , , , , , ,# ,,,,,,b(3x5),,,,,,b(3x5)
, , , ,b,d,`,d,b, ,b,d,`, ,b, ,b,h,f, , ,# ,,,,,,,`,,,,,,`
, , , , , ,`, , , , , ,`,d, , ,d, , , , ,# ,,,,b(3x5),,,`,b(3x5),,b(3x5),,,`,b(3x5)
, ,f,h,b, ,`, ,f,h,b, ,`,`,`,`,`,d,b,h,f,# ,,,,,`,,`,,`,,`,,`,,`
, , , , ,d,`, , , ,d, ,`, , , ,d, , , , ,# ,,,,,`,,`,,`,,`,,`,,`,b(5x3)
f,h,b,d,`,`,`,`,`,`,`,`,`, ,f, ,b,h,f, , ,# ,,,,,`,`,`,`,`,,`,`,`,,`,,`,`,`
, , , ,d, , , ,`,`,`,`,`, ,h, , , , , , ,# ,,b(5x3),,,,,`,b(5x3),,,,,`,`,,,`,b(5x3)
, ,f,h,b, ,b,d,`,`,`,`,`,d,b, ,b,h,f, , ,# ,,,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,`
, , , , , ,h, ,`,`,`,`,`, , , ,d, , , , ,# b(5x3),,,,,,`,`,,,,`,,`,b(3x5),,b(5x3),`
, ,f,h,b, ,f, ,`,`,`,`,`,`,`,`,`,d,b,h,f,# ,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`
, , , ,d, , , ,`, ,d, , , ,`,d, , , , , ,# ,,b(5x3),,,`,b(3x5),,,`,`,`,`,`,,`,b(5x3)
f,h,b,d,`,`,`,`,`, ,b,h,f, ,`, ,b,h,f, , ,# ,,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`
, , , ,d, , ,d,`, , , , , ,`, , , , , , ,# ,,b(5x3),,,,,`,,`,`,`,`,`,,,,`,b(5x3)
, ,f,h,b, ,b, ,`,d,b, ,b,d,`,d,b, , , , ,# ,,,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`
, , , , , ,h, ,d, ,h, ,h, ,d, ,h, , , , ,# b(5x3),,,,,`,,,,`,b(5x3),`,,,,`,b(5x3)
, , , , , ,f, ,b, ,f, ,f, ,b, ,f, , , , ,# ,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`
, , , , , , , ,h, , , , , ,h, , , , , , ,# ,,b(5x3),,,`,b(3x5),,`,`,b(3x5),,b(3x5),,,`,b(3x5)
, , , , , , , ,f, , , , , ,f, , , , , , ,# ,,,`,`,`,,`,,`,`,`,,`,`,`,`,`
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# ,,,,,,,`,b(3x5),`,,`,,`,b(3x5),`,,`
#query label(rooms) start(11; 11) room designations ,,,,,,,`,,`,,`,,`,,`,,`
, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,`,,,,,,`
, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,`,,,,,,`
, , , , , ,r+,, , , , ,r+,, , , , , , , ,#
, , , , , , , , , , , , , , , , , , , , ,# #build label(build) start(12; 12) hidden()
, , , ,r+,, , ,r+,,r+,, , ,r+,,r+,, , , ,#
, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,f,,,,,,f
, , , ,r+,, , , , ,r+,, , , , , , ,r+,, ,# ,,,,,,,h,,,,,,h
, , , , , , , , , , , , , , , , , , , , ,# ,,,,,f,,b,,f,,f,,b,,f
, ,r+,, , , , , , , , , , , , ,r+,, , , ,# ,,,,,h,,d,,h,,h,,d,,h
, , , , , , , , , , , , , , , , , , , , ,# ,,,,,b,d,`,d,b,,b,d,`,,b,,b,h,f
, , , ,r+,,r+,, , , , , , ,r+,,r+,, , , ,# ,,,,,,,`,,,,,,`,d,,,d
, , , , , , , , , , , , , , , , , , , , ,# ,,,f,h,b,,`,,f,h,b,,`,`,`,`,`,d,b,h,f
, , , ,r+,, , , , , , , , , , , , ,r+,, ,# ,,,,,,d,`,,,,d,,`,,,,d
, , , , , , , , , , , , , , , , , , , , ,# ,f,h,b,d,`,`,`,`,`,`,`,`,`,,f,,b,h,f
, ,r+,, , , , , , ,r+,, , , , ,r+,, , , ,# ,,,,,d,,,,`,`,`,`,`,,h
, , , , , , , , , , , , , , , , , , , , ,# ,,,f,h,b,,b,d,`,`,`,`,`,d,b,,b,h,f
, , , ,r+,,r+,, , ,r+,,r+,, , ,r+,, , , ,# ,,,,,,,h,,`,`,`,`,`,,,,d
, , , , , , , , , , , , , , , , , , , , ,# ,,,f,h,b,,f,,`,`,`,`,`,`,`,`,`,d,b,h,f
, , , , , , , ,r+,, , , , ,r+,, , , , , ,# ,,,,,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

1 #dig start(11; 12) 28 bedrooms, 3 tiles each (efficient layout) #dig label(dig) start(12; 12) 28 bedrooms, 3 tiles each
2 # see an image of this blueprint at https://i.imgur.com/XD7D4ux.png ,,,,,,,d,,,,,,d
3 , , , , , ,d, , , , , ,d, , , , , , , , ,# ,,,,,,,d,,,,,,d
4 , , , , , ,d, , , , , ,d, , , , , , , , ,# ,,,,,d,,d,,d,,d,,d,,d
5 , , , ,d, ,d, ,d, ,d, ,d, ,d, , , , , , ,# ,,,,,d,,d,,d,,d,,d,,d
6 , , , ,d, ,d, ,d, ,d, ,d, ,d, , , , , , ,# ,,,,,d,d,d,d,d,,d,d,d,,d,,d,d,d
7 , , , ,d,d,d,d,d, ,d,d,d, ,d, ,d,d,d, , ,# ,,,,,,,d,,,,,,d,d,,,d
8 , , , , , ,d, , , , , ,d,d, , ,d, , , , ,# ,,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d
9 , ,d,d,d, ,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,# ,,,,,,d,d,,,,d,,d,,,,d
10 , , , , ,d,d, , , ,d, ,d, , , ,d, , , , ,# ,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,,d,d,d
11 d,d,d,d,d,d,d,d,d,d,d,d,d, ,d, ,d,d,d, , ,# ,,,,,d,,,,d,~,~,~,d,,d
12 , , , ,d, , , ,d,i,i,i,d, ,d, , , , , , ,# ,,,d,d,d,,d,d,d,~,~,~,d,d,d,,d,d,d
13 , ,d,d,d, ,d,d,d,i,i,i,d,d,d, ,d,d,d, , ,# ,,,,,,,d,,d,~,~,~,d,,,,d
14 , , , , , ,d, ,d,i,i,i,d, , , ,d, , , , ,# ,,,d,d,d,,d,,d,d,d,d,d,d,d,d,d,d,d,d,d
15 , ,d,d,d, ,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,# ,,,,,d,,,,d,,d,,,,d,d
16 , , , ,d, , , ,d, ,d, , , ,d,d, , , , , ,# ,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d
17 d,d,d,d,d,d,d,d,d, ,d,d,d, ,d, ,d,d,d, , ,# ,,,,,d,,,d,d,,,,,,d
18 , , , ,d, , ,d,d, , , , , ,d, , , , , , ,# ,,,d,d,d,,d,,d,d,d,,d,d,d,d,d
19 , ,d,d,d, ,d, ,d,d,d, ,d,d,d,d,d, , , , ,# ,,,,,,,d,,d,,d,,d,,d,,d
20 , , , , , ,d, ,d, ,d, ,d, ,d, ,d, , , , ,# ,,,,,,,d,,d,,d,,d,,d,,d
21 , , , , , ,d, ,d, ,d, ,d, ,d, ,d, , , , ,# ,,,,,,,,,d,,,,,,d
22 , , , , , , , ,d, , , , , ,d, , , , , , ,# ,,,,,,,,,d,,,,,,d
23 , , , , , , , ,d, , , , , ,d, , , , , , ,# #meta label(rooms)
24 #,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# zone/zone
25 #build label(furniture) start(11; 11) 28x doors, beds, coffers, and cabinets build/build
26 , , , , , ,f, , , , , ,f, , , , , , , , ,# #zone label(zone) start(12; 12) hidden()
27 , , , , , ,h, , , , , ,h, , , , , , , , ,# ,,,,,,b(3x5),,,,,,b(3x5)
28 , , , ,f, ,b, ,f, ,f, ,b, ,f, , , , , , ,# ,,,,,,,`,,,,,,`
29 , , , ,h, ,d, ,h, ,h, ,d, ,h, , , , , , ,# ,,,,b(3x5),,,`,b(3x5),,b(3x5),,,`,b(3x5)
30 , , , ,b,d,`,d,b, ,b,d,`, ,b, ,b,h,f, , ,# ,,,,,`,,`,,`,,`,,`,,`
31 , , , , , ,`, , , , , ,`,d, , ,d, , , , ,# ,,,,,`,,`,,`,,`,,`,,`,b(5x3)
32 , ,f,h,b, ,`, ,f,h,b, ,`,`,`,`,`,d,b,h,f,# ,,,,,`,`,`,`,`,,`,`,`,,`,,`,`,`
33 , , , , ,d,`, , , ,d, ,`, , , ,d, , , , ,# ,,b(5x3),,,,,`,b(5x3),,,,,`,`,,,`,b(5x3)
34 f,h,b,d,`,`,`,`,`,`,`,`,`, ,f, ,b,h,f, , ,# ,,,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,`
35 , , , ,d, , , ,`,`,`,`,`, ,h, , , , , , ,# b(5x3),,,,,,`,`,,,,`,,`,b(3x5),,b(5x3),`
36 , ,f,h,b, ,b,d,`,`,`,`,`,d,b, ,b,h,f, , ,# ,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`
37 , , , , , ,h, ,`,`,`,`,`, , , ,d, , , , ,# ,,b(5x3),,,`,b(3x5),,,`,`,`,`,`,,`,b(5x3)
38 , ,f,h,b, ,f, ,`,`,`,`,`,`,`,`,`,d,b,h,f,# ,,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`
39 , , , ,d, , , ,`, ,d, , , ,`,d, , , , , ,# ,,b(5x3),,,,,`,,`,`,`,`,`,,,,`,b(5x3)
40 f,h,b,d,`,`,`,`,`, ,b,h,f, ,`, ,b,h,f, , ,# ,,,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`
41 , , , ,d, , ,d,`, , , , , ,`, , , , , , ,# b(5x3),,,,,`,,,,`,b(5x3),`,,,,`,b(5x3)
42 , ,f,h,b, ,b, ,`,d,b, ,b,d,`,d,b, , , , ,# ,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`
43 , , , , , ,h, ,d, ,h, ,h, ,d, ,h, , , , ,# ,,b(5x3),,,`,b(3x5),,`,`,b(3x5),,b(3x5),,,`,b(3x5)
44 , , , , , ,f, ,b, ,f, ,f, ,b, ,f, , , , ,# ,,,`,`,`,,`,,`,`,`,,`,`,`,`,`
45 , , , , , , , ,h, , , , , ,h, , , , , , ,# ,,,,,,,`,b(3x5),`,,`,,`,b(3x5),`,,`
46 , , , , , , , ,f, , , , , ,f, , , , , , ,# ,,,,,,,`,,`,,`,,`,,`,,`
47 #,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# ,,,,,,,,,`,,,,,,`
48 #query label(rooms) start(11; 11) room designations ,,,,,,,,,`,,,,,,`
49 , , , , , , , , , , , , , , , , , , , , ,# #build label(build) start(12; 12) hidden()
50 , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,f,,,,,,f
51 , , , , , ,r+,, , , , ,r+,, , , , , , , ,# ,,,,,,,h,,,,,,h
52 , , , , , , , , , , , , , , , , , , , , ,# ,,,,,f,,b,,f,,f,,b,,f
53 , , , ,r+,, , ,r+,,r+,, , ,r+,,r+,, , , ,# ,,,,,h,,d,,h,,h,,d,,h
54 , , , , , , , , , , , , , , , , , , , , ,# ,,,,,b,d,`,d,b,,b,d,`,,b,,b,h,f
55 , , , ,r+,, , , , ,r+,, , , , , , ,r+,, ,# ,,,,,,,`,,,,,,`,d,,,d
56 , , , , , , , , , , , , , , , , , , , , ,# ,,,f,h,b,,`,,f,h,b,,`,`,`,`,`,d,b,h,f
57 , ,r+,, , , , , , , , , , , , ,r+,, , , ,# ,,,,,,d,`,,,,d,,`,,,,d
58 , , , , , , , , , , , , , , , , , , , , ,# ,f,h,b,d,`,`,`,`,`,`,`,`,`,,f,,b,h,f
59 , , , ,r+,,r+,, , , , , , ,r+,,r+,, , , ,# ,,,,,d,,,,`,`,`,`,`,,h
60 , , , , , , , , , , , , , , , , , , , , ,# ,,,f,h,b,,b,d,`,`,`,`,`,d,b,,b,h,f
61 , , , ,r+,, , , , , , , , , , , , ,r+,, ,# ,,,,,,,h,,`,`,`,`,`,,,,d
62 , , , , , , , , , , , , , , , , , , , , ,# ,,,f,h,b,,f,,`,`,`,`,`,`,`,`,`,d,b,h,f
63 , ,r+,, , , , , , ,r+,, , , , ,r+,, , , ,# ,,,,,d,,,,`,,d,,,,`,d
64 , , , , , , , , , , , , , , , , , , , , ,# ,f,h,b,d,`,`,`,`,`,,b,h,f,,`,,b,h,f
65 , , , ,r+,,r+,, , ,r+,,r+,, , ,r+,, , , ,# ,,,,,d,,,d,`,,,,,,`
66 , , , , , , , , , , , , , , , , , , , , ,# ,,,f,h,b,,b,,`,d,b,,b,d,`,d,b
67 , , , , , , , ,r+,, , , , ,r+,, , , , , ,# ,,,,,,,h,,d,,h,,h,,d,,h
68 , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,f,,b,,f,,f,,b,,f
69 , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,h,,,,,,h
70 #,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# ,,,,,,,,,f,,,,,,f
71
72
73
74

@ -1,100 +1,209 @@
"#dig start(16; 17; central 3x3 stairwell) 48 rooms, 4 tiles each (more aesthetic)" "#dig label(dig) start(17; 17) 48 rooms, 4 tiles each"
# 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,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d, , ,d, ,# ,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d
d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d,# ,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d
,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, ,# ,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d
, , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,# ,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d
, , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , , ,# ,,,,,d,,d,,d,,,,d,d,d,d,d,d,d,,,,d,,d,,d
, ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,# ,,,d,,,,d,,,,d,,,d,,d,,d,,,d,,,,d,,,,d
,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, ,# ,,d,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,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,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,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d
,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,# ,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d
,d, , ,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d, , ,d, ,# ,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d
d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d,# ,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d
,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, ,# ,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d
, , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,# ,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d
, , , ,d, , , ,d, , , ,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" #meta label(rooms)
, , , , , , , , , , , , ,f, , , ,f, , , , , , , , , , , , , ,# zone1/zone1
, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# zone2/zone2
, , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# zone3/zone3
,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, ,# zone4/zone4
f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f,# build/build
,d, , , , , , , , , ,d, , , , , , , ,d, , , , , , , , , ,d, ,# #zone label(zone1) start(17; 17) hidden()
, , , , , ,s, , , , , , , , ,s, , , , , , , , ,s, , , , , , ,#
,d, , , , , , , , , ,d, , , , , , , ,d, , , , , , , , , ,d, ,# ,,,,,,,,,,,,,,`,,,,`
f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f,# ,,,,,`,,,,`,,,,`,,`,,`,,`,,,,`,,,,`
,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, ,# ,b,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b
, , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b
, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b
, ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,# b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,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, , ,# ,,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b
, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# ,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b
, , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# ,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b
,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, ,# ,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,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,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b
, , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b
, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b
, , , , , , , , , , , , ,f, , , ,f, , , , , , , , , , , , , ,# b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# ,,,,,,,`,,,,,,,,,`,,,,,,,,,`
#query label(rooms) start(16; 16; central 3x3 stairwell) room designations ,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,`,,`,,,,,,,,`,,`,,,,,,`,,`,,,,,,,,`,,`
, , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# ,,`,,,`,,,,`,,,`,,,,,,,,`,,,`,,,,`,,,`
, , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# ,,,,`,,`,,`,,`,,,,`,,,,`,,,,`,,`,,`,,`
,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# ,,,,,`,,,,`,,,,`,,`,,`,,`,,,,`,,,,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,`,,,,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,#
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# #zone label(zone2) start(17; 17) hidden()
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,b,b,b
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,b,b,b,,,,,,b,b,b,b,,,`,,,,b,b,b
,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# ,,,b,b,b,b,,,`,,,b,b,b,b,,`,,`,,b,b,b,b,,,`
, , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# ,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,~,~
, , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# ~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,~,~
, ,r+,, , , , , , ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, ,# ~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,`,,`,b,b,b,,,,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,`
, ,r+,, , , , , , ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, ,# ,,,b,b,b,b,,`,,`,,b,b,b,b,,,`,,,b,b,b,b,,`,,`
, , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# ,,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,~
, , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# ,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,~,~
,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# ,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,~
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,~,~,~,,,`,,,~,~,~,,,,,,,,~,~,~,,,`,,,~,~,~
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,`,,,,,,,,`,,,,,,,,,,`,,,,,,,,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,`,,,,,,`,,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,`
,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# ,,,b,b,b,b,,,`,,,b,b,b,b,,`,,`,,b,b,b,b,,,`
, , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# ,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,~,~
, , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# ~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,~,~
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# ~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~
,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~
,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,`
,`,,`,b,b,b,,,,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,`
,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,`
,,,b,b,b,b,,`,,`,,b,b,b,b,,,`,,,b,b,b,b,,`,,`
,,,b,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

1 #dig start(16; 17; central 3x3 stairwell) 48 rooms, 4 tiles each (more aesthetic) #dig label(dig) start(17; 17) 48 rooms, 4 tiles each
2 # see an image of this blueprint at: https://i.imgur.com/3pNc0HM.png ,,,,,,,,,,,,,,d,,,,d
3 , , , , , , , , , , , , ,d, , , ,d, , , , , , , , , , , , , ,# ,,,,,d,,,,d,,,,d,d,d,d,d,d,d,,,,d,,,,d
4 , , , ,d, , , ,d, , , ,d,d,d,d,d,d,d, , , ,d, , , ,d, , , , ,# ,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d
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
6 ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, ,# ,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d
7 d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d,# ,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d
8 ,d, , ,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d, , ,d, ,# ,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d
9 ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,# ,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d
10 ,d, , ,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d, , ,d, ,# ,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d
11 d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d,# ,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d
12 ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, ,# ,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d
13 , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,# ,,,,,d,,d,,d,,,,d,d,d,d,d,d,d,,,,d,,d,,d
14 , , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , , ,# ,,,d,,,,d,,,,d,,,d,,d,,d,,,d,,,,d,,,,d
15 , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,# ,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d
16 ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, ,# ,,,d,,,d,d,d,,,d,,,d,~,~,~,d,,,d,,,d,d,d,,,d
17 , ,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
18 , ,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
19 , ,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
20 ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, ,# ,,,d,,,,d,,,,d,,,d,,d,,d,,,d,,,,d,,,,d
21 , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,# ,,,,,d,,d,,d,,,,d,d,d,d,d,d,d,,,,d,,d,,d
22 , , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , , ,# ,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d
23 , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,# ,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d
24 ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, ,# ,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d
25 d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d,# ,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d
26 ,d, , ,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d, , ,d, ,# ,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d
27 ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,# ,,d,,,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,,,d
28 ,d, , ,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d, , ,d, ,# ,d,d,d,,,,d,,,,d,d,d,,d,d,d,,d,d,d,,,,d,,,,d,d,d
29 d,d,d, , , ,d, , , ,d,d,d, ,d,d,d, ,d,d,d, , , ,d, , , ,d,d,d,# ,,d,,,d,,d,,d,,,d,,,,d,,,,d,,,d,,d,,d,,,d
30 ,d, , ,d, ,d, ,d, , ,d, , , ,d, , , ,d, , ,d, ,d, ,d, , ,d, ,# ,,,,d,d,d,d,d,d,d,,,,d,,d,,d,,,,d,d,d,d,d,d,d
31 , , ,d,d,d,d,d,d,d, , , ,d, ,d, ,d, , , ,d,d,d,d,d,d,d, , , ,# ,,,,,d,,,,d,,,,d,d,d,d,d,d,d,,,,d,,,,d
32 , , , ,d, , , ,d, , , ,d,d,d,d,d,d,d, , , ,d, , , ,d, , , , ,# ,,,,,,,,,,,,,,d,,,,d
33 , , , , , , , , , , , , ,d, , , ,d, , , , , , , , , , , , , ,# #meta label(rooms)
34 #,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# zone1/zone1
35 #build label(furniture) start(16; 16; central 3x3 stairwell) 48x doors, beds, cabinets, and coffers; 8x statues zone2/zone2
36 , , , , , , , , , , , , ,f, , , ,f, , , , , , , , , , , , , ,# zone3/zone3
37 , , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# zone4/zone4
38 , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# build/build
39 ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, ,# #zone label(zone1) start(17; 17) hidden()
40 f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f,# ,,,,,,,,,,,,,,`,,,,`
41 ,d, , , , , , , , , ,d, , , , , , , ,d, , , , , , , , , ,d, ,# ,,,,,`,,,,`,,,,`,,`,,`,,`,,,,`,,,,`
42 , , , , , ,s, , , , , , , , ,s, , , , , , , , ,s, , , , , , ,# ,b,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b
43 ,d, , , , , , , , , ,d, , , , , , , ,d, , , , , , , , , ,d, ,# b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b
44 f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f,# b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b
45 ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, ,# b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b
46 , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# ,,,,,,,`,,,,,,,,,`,,,,,,,,,`
47 , , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# ,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,`
48 , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,# ,`,,`,,,,,,,,`,,`,,,,,,`,,`,,,,,,,,`,,`
49 ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, ,# ,,`,,,`,,,,`,,,`,,,,,,,,`,,,`,,,,`,,,`
50 , ,d, , , , , , , ,d, , , , , , , , , ,d, , , , , , , ,d, , ,# ,,,,`,,`,,`,,`,,,,`,,,,`,,,,`,,`,,`,,`
51 , , , , , ,s, , , , , , , , , , , , , , , , , ,s, , , , , , ,# ,,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b
52 , ,d, , , , , , , ,d, , , , , , , , , ,d, , , , , , , ,d, , ,# ,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b
53 ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, ,# ,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b
54 , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,# ,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b
55 , , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# ,,,,,,,`,,,,,,,,,,,,,,,,,,`
56 , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# ,,,`,,,,,,,,`,,,,,,,,,,`,,,,,,,,`
57 ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, ,# ,,`,,`,,,,,,`,,`,,,,,,,,`,,`,,,,,,`,,`
58 f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f,# ,,,`,,,,,,,,`,,,`,,,,`,,,`,,,,,,,,`
59 ,d, , , , , , , , , ,d, , , , , , , ,d, , , , , , , , , ,d, ,# ,,,,,`,,,,`,,,,`,,`,,`,,`,,,,`,,,,`
60 , , , , , ,s, , , , , , , , ,s, , , , , , , , ,s, , , , , , ,# ,b,b,b,`,,`,,`,,`,b,b,b,`,,,,`,b,b,b,`,,`,,`,,`,b,b,b
61 ,d, , , , , , , , , ,d, , , , , , , ,d, , , , , , , , , ,d, ,# b,b,b,b,b,`,,,,`,b,b,b,b,b,,,,b,b,b,b,b,`,,,,`,b,b,b,b,b
62 f, ,h, , , , , , , ,h, ,f, , , , , ,f, ,h, , , , , , , ,h, ,f,# b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b
63 ,b, , ,f, , , ,f, , ,b, , , , , , , ,b, , ,f, , , ,f, , ,b, ,# b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b
64 , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,# ,,,,,,,`,,,,,,,,,`,,,,,,,,,`
65 , , , ,h, , , ,h, , , ,b, ,d, ,d, ,b, , , ,h, , , ,h, , , , ,# ,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,`
66 , , , , , , , , , , , , ,f, , , ,f, , , , , , , , , , , , , ,# ,`,,`,,,,,,,,`,,`,,,,,,`,,`,,,,,,,,`,,`
67 #,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# ,,`,,,`,,,,`,,,`,,,,,,,,`,,,`,,,,`,,,`
68 #query label(rooms) start(16; 16; central 3x3 stairwell) room designations ,,,,`,,`,,`,,`,,,,`,,,,`,,,,`,,`,,`,,`
69 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,`,,,,`,,,,`,,`,,`,,`,,,,`,,,,`
70 , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# ,,,,,,,,,,,,,,`,,,,`
71 , , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# #zone label(zone2) start(17; 17) hidden()
72 ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# ,,,,,,,,,,,,,b,b,b
73 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,b,b,b,,,,,,b,b,b,b,,,`,,,,b,b,b
74 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,b,b,b,b,,,`,,,b,b,b,b,,`,,`,,b,b,b,b,,,`
75 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,~,~
76 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,~,~
77 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~
78 ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# ~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~
79 , , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# ,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~
80 , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# ,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,`
81 , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, ,# ,`,,`,b,b,b,,,,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,`
82 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,`
83 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,b,b,b,b,,`,,`,,b,b,b,b,,,`,,,b,b,b,b,,`,,`
84 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,~
85 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,~,~
86 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,~
87 , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, ,# ,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~
88 , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# ,,~,~,~,,,`,,,~,~,~,,,,,,,,~,~,~,,,`,,,~,~,~
89 , , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# ,,,`,,,,,,,,`,,,,,,,,,,`,,,,,,,,`
90 ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# ,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,`,,,,,,`,,`
91 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,`
92 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,b,b,b,b,,,`,,,b,b,b,b,,`,,`,,b,b,b,b,,,`
93 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,~,~,b,b,b,b,,`,,`,~,b,b,b,b,,,`,~,~,b,b,b,b,,`,,`,~,~,~
94 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ~,~,~,b,b,b,b,,,`,~,~,~,b,b,b,,,~,~,~,b,b,b,b,,,`,~,~,~,~,~
95 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ~,~,~,~,b,b,b,,,,~,~,~,~,~,,,,~,~,~,~,b,b,b,,,,~,~,~,~,~
96 ,r+,, , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , ,r+,,# ~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~
97 , , ,r+,, , , , ,r+,, , , , , , , , , , ,r+,, , , , ,r+,, , ,# ,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~
98 , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , ,# ,,`,,,,,,,,,,`,,,,,,,,`,,,,,,,,,,`
99 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,`,,`,b,b,b,,,,,`,,`,,,,,,`,,`,b,b,b,,,,,`,,`
100 #,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# ,,`,b,b,b,b,,,`,,,`,b,b,b,,,,,`,b,b,b,b,,,`,,,`
101 ,,,b,b,b,b,,`,,`,,b,b,b,b,,,`,,,b,b,b,b,,`,,`
102 ,,,b,b,b,b,,,`,,,b,b,b,b,,`,,`,,b,b,b,b,,,`
103 ,,,,b,b,b,,,,,,b,b,b,b,,,`,,,,b,b,b
104 ,,,,,,,,,,,,,b,b,b
105 #zone label(zone3) start(17; 17) hidden()
106 ,,,,,,,,,,,,,~,~,~
107 ,,,,~,~,~,,,,,,~,~,~,~,~,,`,,,,~,~,~
108 ,,,~,~,~,~,~,,`,,,~,~,~,~,~,`,,`,,~,~,~,~,~,,`
109 ,~,~,~,~,~,~,~,`,,`,~,~,~,~,~,~,,`,~,~,~,~,~,~,~,`,,`,~,~,~
110 ~,~,~,~,~,~,~,~,,`,~,~,~,~,~,~,,,~,~,~,~,~,~,~,~,,`,~,~,~,~,~
111 ~,~,~,~,~,~,~,,,,~,~,~,~,~,,,,~,~,~,~,~,~,~,,,,~,~,~,~,~
112 ~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~
113 ,,,,,,,`,,,,,,,,,`,,,,,,,,,`
114 b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b
115 b,b,b,b,b,~,~,,,,b,b,b,b,b,,,,b,b,b,b,b,~,~,,,,b,b,b,b,b
116 b,b,b,b,b,~,~,~,,`,b,b,b,b,b,~,,,b,b,b,b,b,~,~,~,,`,b,b,b,b,b
117 ,b,b,b,~,~,~,~,`,,`,b,b,b,~,~,~,,`,b,b,b,~,~,~,~,`,,`,b,b,b
118 ,,~,~,~,~,~,~,,`,~,~,~,~,~,~,~,`,,`,~,~,~,~,~,~,,`,~,~,~
119 ,~,~,~,~,~,~,,,~,~,~,~,~,~,~,~,,`,~,~,~,~,~,~,,,~,~,~,~,~
120 ,~,~,~,~,~,,,,~,~,~,~,~,~,~,,,,~,~,~,~,~,,,,~,~,~,~,~
121 ,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~
122 ,,,,,,,`,,,,,,,,,,,,,,,,,,`
123 ,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b
124 ,b,b,b,b,b,,,,b,b,b,b,b,~,~,,,,b,b,b,b,b,,,,b,b,b,b,b
125 ,b,b,b,b,b,~,,,b,b,b,b,b,~,~,~,,`,b,b,b,b,b,~,,,b,b,b,b,b
126 ,,b,b,b,~,~,~,,`,b,b,b,~,~,~,~,`,,`,b,b,b,~,~,~,,`,b,b,b
127 ,~,~,~,~,~,~,~,`,,`,~,~,~,~,~,~,,`,~,~,~,~,~,~,~,`,,`,~,~,~
128 ~,~,~,~,~,~,~,~,,`,~,~,~,~,~,~,,,~,~,~,~,~,~,~,~,,`,~,~,~,~,~
129 ~,~,~,~,~,~,~,,,,~,~,~,~,~,,,,~,~,~,~,~,~,~,,,,~,~,~,~,~
130 ~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~
131 ,,,,,,,`,,,,,,,,,`,,,,,,,,,`
132 b,b,b,b,b,,,,,,b,b,b,b,b,,,,b,b,b,b,b,,,,,,b,b,b,b,b
133 b,b,b,b,b,~,~,,,,b,b,b,b,b,,,,b,b,b,b,b,~,~,,,,b,b,b,b,b
134 b,b,b,b,b,~,~,~,,`,b,b,b,b,b,~,,,b,b,b,b,b,~,~,~,,`,b,b,b,b,b
135 ,b,b,b,~,~,~,~,`,,`,b,b,b,~,~,~,,`,b,b,b,~,~,~,~,`,,`,b,b,b
136 ,,,~,~,~,~,~,,`,,,~,~,~,~,~,`,,`,,~,~,~,~,~,,`
137 ,,,,~,~,~,,,,,,~,~,~,~,~,,`,,,,~,~,~
138 ,,,,,,,,,,,,,~,~,~
139 #zone label(zone4) start(17; 17) hidden()
140 ,,,,,,,,,,,,,~,~,~,,b,b,b
141 ,,,,~,~,~,,b,b,b,,~,~,~,~,,b,b,b,b,,~,~,~,,b,b,b
142 ,,,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b
143 ,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~
144 ~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~
145 ~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~
146 ~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~
147 ,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~
148 ~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~
149 ~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~
150 ~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~
151 ,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~
152 ,,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~
153 ,~,~,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~
154 ,~,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~
155 ,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~
156 ,,~,~,~,,,`,,,~,~,~,,,,,,,,~,~,~,,,`,,,~,~,~
157 ,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~
158 ,~,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~
159 ,~,~,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~
160 ,,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~
161 ,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~
162 ~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~
163 ~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~
164 ~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~
165 ,~,~,~,,,,`,,,,~,~,~,,,`,,,~,~,~,,,,`,,,,~,~,~
166 ~,~,~,~,~,,,,,,~,~,~,~,~,,,,~,~,~,~,~,,,,,,~,~,~,~,~
167 ~,~,~,~,~,~,~,,b,b,b,~,~,~,~,,,,~,~,~,~,~,~,~,,b,b,b,~,~,~,~
168 ~,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,~,~,~,~,~,,b,b,b,b,~,~,~
169 ,~,~,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~
170 ,,,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b,~,~,~,~,,b,b,b,b
171 ,,,,~,~,~,,b,b,b,,~,~,~,~,,b,b,b,b,,~,~,~,,b,b,b
172 ,,,,,,,,,,,,,~,~,~,,b,b,b
173 #build label(build) start(17; 17) hidden()
174 ,,,,,,,,,,,,,,f,,,,f
175 ,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h
176 ,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b
177 ,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b
178 ,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f
179 ,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d
180 ,,,,,,,s,,,,,,,,,s,,,,,,,,,s
181 ,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d
182 ,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f
183 ,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b
184 ,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b
185 ,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h
186 ,,,b,,,,,,,,b,,,f,,,,f,,,b,,,,,,,,b
187 ,,h,,f,,,,,,f,,h,,,,,,,,h,,f,,,,,,f,,h
188 ,,,d,,,,,,,,d,,,,,,,,,,d,,,,,,,,d
189 ,,,,,,,s,,,,,,,,,,,,,,,,,,s
190 ,,,d,,,,,,,,d,,,,,,,,,,d,,,,,,,,d
191 ,,h,,f,,,,,,f,,h,,,,,,,,h,,f,,,,,,f,,h
192 ,,,b,,,,,,,,b,,,f,,,,f,,,b,,,,,,,,b
193 ,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h
194 ,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b
195 ,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b
196 ,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f
197 ,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d
198 ,,,,,,,s,,,,,,,,,s,,,,,,,,,s
199 ,,d,,,,,,,,,,d,,,,,,,,d,,,,,,,,,,d
200 ,f,,h,,,,,,,,h,,f,,,,,,f,,h,,,,,,,,h,,f
201 ,,b,,,f,,,,f,,,b,,,,,,,,b,,,f,,,,f,,,b
202 ,,,,b,,d,,d,,b,,,,h,,,,h,,,,b,,d,,d,,b
203 ,,,,,h,,,,h,,,,b,,d,,d,,b,,,,h,,,,h
204 ,,,,,,,,,,,,,,f,,,,f
205
206
207
208
209

@ -1,232 +1,228 @@
"#dig start(36;74) 97 rooms, 9 tiles each (fractal design)" "#dig label(dig) start(36;73) 95 bedrooms (including 14 suites), 190 tombs"
# 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,d, ,d,d,d, , , , , ,# ,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d
, , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , ,# ,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,,,,,,d,,,d,d,d,,,d,,,,,,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d
, , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d,d,d, ,d, , , , , , ,d, , ,d,d,d, , ,d, , , , , , ,d, ,d,d,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , ,# ,d,d,d,,,d,,,,,,,d,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,d,,,,,,,d,,,d,d,d
,d,d,d, , ,d, , , , , , ,d, , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , ,d, , , , , , ,d, , ,d,d,d, ,# ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d
,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,# ,d,d,d,,,d,,,,,,,d,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,d,,,,,,,d,,,d,d,d
,d,d,d, , ,d, , , , , , ,d, , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , ,d, , , , , , ,d, , ,d,d,d, ,# ,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,,,,,,d,,,d,d,d,,,d,,,,,,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d
, , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d,d,d, ,d, , , , , , ,d, , ,d,d,d, , ,d, , , , , , ,d, ,d,d,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , ,# ,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d
, , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , ,# ,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d
, , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , ,# ,,,,,,,,,,,,,d,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d,,,,,,,d
, , , , , , , , , , , , ,d, , , , , , ,d,d,d, ,d, ,d,d,d, , , , , ,d,d,d, , , , , ,d,d,d, ,d, ,d,d,d, , , , , , ,d, , , , , , , , , , , , , ,# ,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d
, , , , , , , , , , , ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, , , , , , , , , , , , ,# ,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d
, , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , ,# ,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d
, , , , , , , , , , , ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d
, , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , ,d,d,d, , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d
, , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d
, , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,d,d,d,d,d,d,d,d,d,d,d,,,,,,d
, , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d
, , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,d,d,d,d
, , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d
, , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,d,,d,d,d,,d,d,,,,,,,d
, , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,d,d, ,d,d,d, ,d,d, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d
, , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,,d,d,d
, , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d, ,d,d,d, ,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d
, , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d
, , , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,~,~,~,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,~,~,~,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,~,~,~,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, , , , , , , , , , , , , , , , , , , , , , ,# #meta label(rooms)
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# zone/zone
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# build/build
"#build label(furniture) start(36;73) 97 doors; 95 beds, coffers, and cabinets; 190 urns; 14 tables, chairs, weapon racks, armor stands, and statues" #zone label(zone) start(36;73) hidden()
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5)
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1)
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5)
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,f,`,n, ,`, ,n,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`,d,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,n, ,`, ,n,`,h, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5)
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, ,`, ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,`, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5)
, , , , , , , , , , , , , , , , , , , , , , , , , , ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,n, , ,d, , ,`, , ,d, , ,n,`,h, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),b(5x6),,`,,,`,b(5x6),,`,,,T{pets=true}(1x1),`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,`, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5)
, , , , , , , , , , , , , , , , , , , , , , , , , , ,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, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1)
, , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,`, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,b(5x5),,,,b(5x5),,,,,`,b(6x5),,,,,,`,b(6x5),,,,,,`,b(5x5),,,,b(5x5)
, , , , , , , , , , , , , , , , , , , ,h,`,f, ,f,`,n, ,`, ,n,r,a,h, ,`, ,h,a,r,n, ,`, ,n,`,f, ,h,`,f, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`
, , , , , , , , , , , , , , , , , , , ,`,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, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,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)
, , , , , , , , , , , , , , , ,f,`,n, , ,d, , , , , , ,`, , , , , , ,`, , , , , , ,`, , , , , , ,d, , ,n,`,f, , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,,`,,,,,,,`,,,,,,,`,,,,,,,`,,,,,,,`,,,T{pets=true}(1x1),`,`
, , , , , , , , , , , , , , , ,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,`, , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , ,h,`,n, , ,d, , , , , , ,`, , , , , ,`,`,`, , , , , ,`, , , , , , ,d, , ,n,`,h, , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),b(5x5),,`,,b(5x5),,,,,`,b(5x5),,,,,`,`,`,b(5x5),,,,,`,b(5x5),,,,b(5x5),,`,,,T{pets=true}(1x1),`,`
, , , , , , , , , , , , , , , , , , , ,n,`,n, ,f,`,n, ,`, ,n,`,f, ,`,`,`, ,f,`,n, ,`, ,n,`,f, ,n,`,n, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,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,`, ,`,b,`,d,`,d,`,b,`, ,`,`,`, ,`,b,`,d,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`
, , , , , , , , , , , , , , , , , , , ,h,`,f, ,h,`,n, ,`, ,n,`,h, ,`,`,`, ,h,`,n, ,`, ,n,`,h, ,h,`,f, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , ,`,`,`, , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,b(5x5),,`,,b(4x5),,,,`,`,`,b(4x5),,,b(5x5),,`,,b(5x5)
, , , , , , , , , , , , , , , , , , , , , , ,h,`,f, ,n,`,n, ,f,n, ,`,`,`, ,n,f, ,n,`,n, ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,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,`, ,`,b,`, ,b,`,d,`,`,`,d,`,b, ,`,b,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`
, , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,h,`,f, ,h,n, ,`,`,`, ,n,h, ,h,`,f, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1)
, , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,d, , ,`,`,`, , ,d, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,b(5x4),,`,,,`,`,`,b(5x4),,`,,b(5x5),,,,,`,b(5x5)
, , , , , , , , , , , , , , , , , , , ,f,`,n, ,`, ,n,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,f,`,n, ,`, ,n,`,f, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,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,`,d,`,d,`,b,`, ,h,b,f, ,`,`,`, ,h,b,f, ,`,b,`,d,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , ,h,`,n, ,`, ,n,`,h, , ,d, , ,`,`,`, , ,d, , ,h,`,n, ,`, ,n,`,h, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,b(5x5),,`,,,`,`,`,b(5x5),,`,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`
, , , , , , , , , , , , , , , , , , , , , , , ,`, , , , , ,n,`,n, ,`,`,`, ,n,`,n, , , , , ,`, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,,`,b(5x5)
, , , , , , , , , , , , , , , , , , , ,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, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,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)
, , , , , , , , , , , ,h,`,f, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,`,`,`, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,h,`,f, , , , , , , , , , , , ,# ,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,`,`,`
, , , , , , , , , , , ,`,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, , , , , , , , , , , , ,# ,,,,,,,,,,,,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)
, , , , , , , , , , , , ,d, , , , , , ,n,`,n, ,`, ,n,`,n, , , , , ,`,`,`, , , , , ,n,`,n, ,`, ,n,`,n, , , , , , ,d, , , , , , , , , , , , , ,# ,,,,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)
, , , , ,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, , , , , ,# ,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`
, , , , ,`,b,`, ,`,b,`,d,`,d,`,b,`,s, ,a,`,c, ,`, ,h,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,h,`,f, ,`, ,a,`,c, ,s,`,b,`,d,`,d,`,b,`, ,`,b,`, , , , , ,# ,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`
, , , , ,n,`,n, ,h,`,n, ,`, ,n,t,c,f, ,h,s,f, ,`, , , , , , ,d, , ,`,`,`, , ,d, , , , , , ,`, ,h,s,f, ,f,c,t,n, ,`, ,n,`,h, ,n,`,n, , , , , ,# 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)
,f,`,n, , ,d, , , , , , ,`, , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , ,`, , , , , , ,d, , ,n,`,f, ,# ,`,`,T{pets=true}(1x1),,,`,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,`,,,T{pets=true}(1x1),`,`
,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,`, ,# ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`
,h,`,n, , ,d, , , , , , ,`, , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , ,`, , , , , , ,d, , ,n,`,h, ,# ,`,`,T{pets=true}(1x1),b(5x5),,`,,b(5x5),,,,,`,b(6x5),,,,,b(5x6),,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,b(5x6),,,,b(6x5),,,,,,`,b(5x5),,,,b(5x5),,`,,,T{pets=true}(1x1),`,`
, , , , ,n,`,n, ,f,`,n, ,`, ,n,r,a,h, ,h,s,f, ,`, , , , , , ,d, , ,`,`,`, , ,d, , , , , , ,`, ,h,s,f, ,h,a,r,n, ,`, ,n,`,f, ,n,`,n, , , , , ,# ,,,,,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)
, , , , ,`,b,`, ,`,b,`,d,`,d,`,b,`,s, ,a,`,c, ,`, ,h,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,h,`,f, ,`, ,a,`,c, ,s,`,b,`,d,`,d,`,b,`, ,`,b,`, , , , , ,# ,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`
, , , , ,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, , , , , ,# ,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`
, , , , , , , , , , , , ,d, , , , , , ,n,`,n, ,`, ,n,`,n, , , , , ,`,`,`, , , , , ,n,`,n, ,`, ,n,`,n, , , , , , ,d, , , , , , , , , , , , , ,# ,,,,,,,,,,,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),,`
, , , , , , , , , , , ,n,`,n, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,`,`,`, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,n,`,n, , , , , , , , , , , , ,# ,,,,,,,,,,,,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,`, ,`,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, , , , , , , , , , , , ,# ,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),b(5x5),,`,,,`,b(5x5),,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),b(5x5),,`,,,`,b(5x5),,`,,,T{pets=true}(1x1),`,`,,`,`,`
, , , , , , , , , , , , , , , , , , , ,n,`,n, ,`, ,n,`,n, , , , , ,`,`,`, , , , , ,n,`,n, ,`, ,n,`,n, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,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,`, ,`, ,`,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, , , , , ,`, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,,`,`,`,`,`,`,`,`,`,`,`,b(5x5),,,,,`,b(5x5)
, , , , , , , , , , , , , , , , , , , ,f,`,n, ,`, ,n,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,f,`,n, ,`, ,n,`,f, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,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,`,d,`,d,`,b,`, , ,d, , ,`,`,`, , ,d, , ,`,b,`,d,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,,,`,,,`,`,`,,,`,,,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , ,h,`,n, ,`, ,n,`,h, ,`,`,`, ,`,`,`, ,`,`,`, ,h,`,n, ,`, ,n,`,h, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`
, , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,`,`, ,`,`,`, ,`,`, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,b(5x5),,`,,b(5x5),,,,,`,`,,`,`,`,,`,`,b(5x5),,,,b(5x5),,`
, , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,f,`,n, ,`,`, ,`,`,`, ,`,`, ,n,`,f, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,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,`, ,`,b,`,d,`,`, ,`,`,`, ,`,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,,`,`,`
, , , , , , , , , , , , , , , , , , , , , , ,h,`,f, ,h,`,n, ,`,`, ,`,`,`, ,`,`, ,n,`,h, ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,`,,`,`,`,,`,`,,T{pets=true}(1x1),`,`,,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,`,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`
, , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# #build label(build) start(36;73) hidden()
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#
#query label(rooms) start(36;73) message(use burial script to mark urns as usable) room designations ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,f,`,n,,`,,n,`,f
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,d,`,b,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,n,,`,,n,`,h
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,`,,h,`,f
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,`,,`,b,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,f,`,n,,,d,,,`,,,d,,,n,`,f
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,n,,,d,,,`,,,d,,,n,`,h
, , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,r,b,t,,`,,r,b,t,,h,`,f
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,a,`,c,,`,,a,`,c,,`,b,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,h,s,f,,`,,h,s,f,,n,`,n
, , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,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
, , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,f,`,n,,,d,,,,,,,`,,,,,,,`,,,,,,,`,,,,,,,d,,,n,`,f
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,h,`,n,,,d,,,,,,,`,,,,,,`,`,`,,,,,,`,,,,,,,d,,,n,`,h
, , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,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
, , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,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
, , , , , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, ,r+,, , , , , , ,r+,, ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,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
, , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,`,,,,,,n,`,n,,`,`,`,,n,`,n,,,,,,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,h,`,f,,`,,h,`,f,,`,b,`,,`,`,`,,`,b,`,,h,`,f,,`,,h,`,f
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,b,`,,`,,`,b,`,,h,`,f,,`,`,`,,h,`,f,,`,b,`,,`,,`,b,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n
, , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,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
, , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,# ,,,,,,,,,,,,,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,`
, , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,n,`,n,,h,`,n,,`,,n,t,c,f,,h,s,f,,`,,,,,,,d,,,`,`,`,,,d,,,,,,,`,,h,s,f,,f,c,t,n,,`,,n,`,h,,n,`,n
, , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , ,# ,f,`,n,,,d,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,d,,,n,`,f
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,h,`,n,,,d,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,d,,,n,`,h
, ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, ,# ,,,,,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
, , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , ,# ,,,,,,,,,,,,,d,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n,,,,,,,d
, , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,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
, , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,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+,, , , , ,r+,, , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,`,,,,,,r,b,t,d,`,`,`,d,r,b,t,,,,,,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,f,`,n,,`,,n,`,f,,n,`,n,,`,`,`,,n,`,n,,f,`,n,,`,,n,`,f
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,d,`,b,`,,,d,,,`,`,`,,,d,,,`,b,`,d,`,d,`,b,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,h,`,n,,`,,n,`,h,,`,`,`,,`,`,`,,`,`,`,,h,`,n,,`,,n,`,h
, , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,`,`,,`,`,`,,`,`,,,,,,,d
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,f,`,n,,`,`,,`,`,`,,`,`,,n,`,f,,n,`,n
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,d,`,`,,`,`,`,,`,`,d,`,b,`,,`,b,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,h,`,n,,`,`,,`,`,`,,`,`,,n,`,h,,h,`,f
, , , , , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,~,~,~, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,~,~,~, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,#
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,~,~,~, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,#
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,#
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#

1 #dig start(36;74) 97 rooms, 9 tiles each (fractal design) #dig label(dig) start(36;73) 95 bedrooms (including 14 suites), 190 tombs
2 # see an image of this blueprint at: https://i.imgur.com/ENi5QLX.png ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d
3 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d
4 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d
5 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d
6 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d
7 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d
8 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d
9 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d
10 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d
11 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d
12 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d
13 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,,d,,,d,,,d,,,d,d,d
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
15 , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,,d,,,d,,,d,,,d,d,d
16 , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d
17 , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d
18 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d
19 , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d
20 , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,,,,,,,d
21 , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,,d,d,d,d,,d,,d,d,d,,d,d,d
22 , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,d, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d
23 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,,d,d,d,d,,d,,d,d,d,,d,d,d
24 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,d,d,d,,,d,,,,,,,d,,,,,,,d,,,,,,,d,,,,,,,d,,,d,d,d
25 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d
26 , , , , , , , , , , , , , , , ,d,d,d, , ,d, , , , , , ,d, , , , , , ,d, , , , , , ,d, , , , , , ,d, , ,d,d,d, , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,d,d,d,,,d,,,,,,,d,,,,,,d,d,d,,,,,,d,,,,,,,d,,,d,d,d
27 , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d
28 , , , , , , , , , , , , , , , ,d,d,d, , ,d, , , , , , ,d, , , , , ,d,d,d, , , , , ,d, , , , , , ,d, , ,d,d,d, , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d
29 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d
30 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,d,d,d,,,,,,d
31 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d
32 , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , ,d,d,d, , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d
33 , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d
34 , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,,,d,d,d,,,d,,,,,,,d
35 , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d
36 , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,d, , ,d,d,d, , ,d, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d
37 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,,d,,d,d,d
38 , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,d,d,d,,d,d,d,,d,d,d,,,,,,d
39 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d
40 , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , ,d,d,d, ,d,d,d, ,d,d,d, , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d
41 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d
42 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d
43 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , ,d,d,d, , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d
44 , , , , , , , , , , , ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, , , , , , , , , , , , ,# ,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d
45 , , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , ,# ,,,,,,,,,,,,,d,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d,,,,,,,d
46 , , , , , , , , , , , ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, , , , , , , , , , , , ,# ,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d
47 , , , , , , , , , , , , ,d, , , , , , ,d,d,d, ,d, ,d,d,d, , , , , ,d,d,d, , , , , ,d,d,d, ,d, ,d,d,d, , , , , , ,d, , , , , , , , , , , , , ,# ,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d
48 , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , ,# ,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,,,,,,d,,,d,d,d,,,d,,,,,,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d
49 , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , ,# ,d,d,d,,,d,,,,,,,d,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,d,,,,,,,d,,,d,d,d
50 , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d,d,d, ,d, , , , , , ,d, , ,d,d,d, , ,d, , , , , , ,d, ,d,d,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , ,# ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d
51 ,d,d,d, , ,d, , , , , , ,d, , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , ,d, , , , , , ,d, , ,d,d,d, ,# ,d,d,d,,,d,,,,,,,d,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,d,,,,,,,d,,,d,d,d
52 ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,# ,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,,,,,,d,,,d,d,d,,,d,,,,,,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d
53 ,d,d,d, , ,d, , , , , , ,d, , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , ,d, , , , , , ,d, , ,d,d,d, ,# ,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,d,d
54 , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d,d,d, ,d, , , , , , ,d, , ,d,d,d, , ,d, , , , , , ,d, ,d,d,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , ,# ,,,,,d,d,d,,d,d,d,,d,,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,,d,,d,d,d,,d,d,d
55 , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , ,# ,,,,,,,,,,,,,d,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d,,,,,,,d
56 , , , , ,d,d,d, ,d,d,d, ,d, ,d,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, ,d,d,d,d, ,d, ,d,d,d, ,d,d,d, , , , , ,# ,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d
57 , , , , , , , , , , , , ,d, , , , , , ,d,d,d, ,d, ,d,d,d, , , , , ,d,d,d, , , , , ,d,d,d, ,d, ,d,d,d, , , , , , ,d, , , , , , , , , , , , , ,# ,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d
58 , , , , , , , , , , , ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, , , , , , , , , , , , ,# ,,,,,,,,,,,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d,,d,d,d,,,d,,,d,,,d,,,d,d,d,,d,d,d
59 , , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,d,d,d, ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,,,,,d,d,d,,,,,,d,d,d,,d,,d,d,d
60 , , , , , , , , , , , ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, ,d,d,d, , ,d, , ,d, , ,d, , ,d,d,d, ,d,d,d, , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d
61 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, , , , , ,d,d,d, , , , , ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d
62 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,d,d,d,d,d,d,d,d,d,d,d,,,,,,d
63 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d
64 , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , ,d,d,d,d,d,d,d,d,d,d,d, , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,,,d,,,d,d,d,,,d,,,d,d,d,d,d,d,d,d,d
65 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,d,d,d,,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d
66 , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d, , ,d, , ,d,d,d, , ,d, , ,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,d,,d,d,d,,d,d,,,,,,,d
67 , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d,d,d, ,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d
68 , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,d,d, ,d,d,d, ,d,d, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,d,d,d,,d,d,d,,d,d,d,d,d,d,,d,d,d
69 , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,d,d,d,,d,d,d,,d,d,,d,d,d,,d,d,,d,d,d,,d,d,d
70 , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d,d,d,d, ,d,d,d, ,d,d,d,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,d,d
71 , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d, ,d,d,d, ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d
72 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d,d,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,~,~,~,d,d,d,d,d,d,d,d,d,d,d,d
73 , , , , , , , , , , , , , , , , , , , , , ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d, , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,~,~,~,d,d,d,d,d,d,d,d,d,d,d,d
74 , , , , , , , , , , , , , , , , , , , , , ,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
75 , , , , , , , , , , , , , , , , , , , , , ,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, , , , , , , , , , , , , , , , , , , , , , ,# #meta label(rooms)
76 , , , , , , , , , , , , , , , , , , , , , ,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, , , , , , , , , , , , , , , , , , , , , , ,# zone/zone
77 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# build/build
78 #,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# #zone label(zone) start(36;73) hidden()
79 #build label(furniture) start(36;73) 97 doors; 95 beds, coffers, and cabinets; 190 urns; 14 tables, chairs, weapon racks, armor stands, and statues ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5)
80 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`
81 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`
82 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1)
83 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5)
84 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`
85 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,f,`,n, ,`, ,n,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`
86 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`,d,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`
87 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,n, ,`, ,n,`,h, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5)
88 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`
89 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, ,`, ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`
90 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5)
91 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,`, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`
92 , , , , , , , , , , , , , , , , , , , , , , , , , , ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`
93 , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),b(5x6),,`,,,`,b(5x6),,`,,,T{pets=true}(1x1),`,`
94 , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,n, , ,d, , ,`, , ,d, , ,n,`,h, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5)
95 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,`, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`
96 , , , , , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, ,r,b,t, ,`, ,r,b,t, ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`
97 , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, ,a,`,c, ,`, ,a,`,c, ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1)
98 , , , , , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,h,s,f, ,`, ,h,s,f, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,b(5x5),,,,b(5x5),,,,,`,b(6x5),,,,,,`,b(6x5),,,,,,`,b(5x5),,,,b(5x5)
99 , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,`, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`
100 , , , , , , , , , , , , , , , , , , , ,h,`,f, ,f,`,n, ,`, ,n,r,a,h, ,`, ,h,a,r,n, ,`, ,n,`,f, ,h,`,f, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`
101 , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`,b,`,d,`,d,`,b,`,s, ,`, ,s,`,b,`,d,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,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)
102 , , , , , , , , , , , , , , , , , , , ,n,`,n, ,h,`,n, ,`, ,n,t,c,f, ,`, ,f,c,t,n, ,`, ,n,`,h, ,n,`,n, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,,`,,,,,,,`,,,,,,,`,,,,,,,`,,,,,,,`,,,T{pets=true}(1x1),`,`
103 , , , , , , , , , , , , , , , ,f,`,n, , ,d, , , , , , ,`, , , , , , ,`, , , , , , ,`, , , , , , ,d, , ,n,`,f, , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`
104 , , , , , , , , , , , , , , , ,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,`, , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),b(5x5),,`,,b(5x5),,,,,`,b(5x5),,,,,`,`,`,b(5x5),,,,,`,b(5x5),,,,b(5x5),,`,,,T{pets=true}(1x1),`,`
105 , , , , , , , , , , , , , , , ,h,`,n, , ,d, , , , , , ,`, , , , , ,`,`,`, , , , , ,`, , , , , , ,d, , ,n,`,h, , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,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)
106 , , , , , , , , , , , , , , , , , , , ,n,`,n, ,f,`,n, ,`, ,n,`,f, ,`,`,`, ,f,`,n, ,`, ,n,`,f, ,n,`,n, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`
107 , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`,b,`,d,`,d,`,b,`, ,`,`,`, ,`,b,`,d,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`
108 , , , , , , , , , , , , , , , , , , , ,h,`,f, ,h,`,n, ,`, ,n,`,h, ,`,`,`, ,h,`,n, ,`, ,n,`,h, ,h,`,f, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,b(5x5),,,,b(5x5),,`,,b(4x5),,,,`,`,`,b(4x5),,,b(5x5),,`,,b(5x5)
109 , , , , , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , ,`,`,`, , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`
110 , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, ,n,`,n, ,f,n, ,`,`,`, ,n,f, ,n,`,n, ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`
111 , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`,b,`, ,b,`,d,`,`,`,d,`,b, ,`,b,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1)
112 , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,h,`,f, ,h,n, ,`,`,`, ,n,h, ,h,`,f, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,b(5x4),,`,,,`,`,`,b(5x4),,`,,b(5x5),,,,,`,b(5x5)
113 , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,d, , ,`,`,`, , ,d, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,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),`,`
114 , , , , , , , , , , , , , , , , , , , ,f,`,n, ,`, ,n,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,f,`,n, ,`, ,n,`,f, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`
115 , , , , , , , , , , , , , , , , , , , ,`,b,`,d,`,d,`,b,`, ,h,b,f, ,`,`,`, ,h,b,f, ,`,b,`,d,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,b(5x5),,`,,,`,`,`,b(5x5),,`,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`
116 , , , , , , , , , , , , , , , , , , , ,h,`,n, ,`, ,n,`,h, , ,d, , ,`,`,`, , ,d, , ,h,`,n, ,`, ,n,`,h, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),b(5x5),,,,,`,b(5x5)
117 , , , , , , , , , , , , , , , , , , , , , , , ,`, , , , , ,n,`,n, ,`,`,`, ,n,`,n, , , , , ,`, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`
118 , , , , , , , , , , , , , , , , , , , ,h,`,f, ,`, ,h,`,f, ,`,b,`, ,`,`,`, ,`,b,`, ,h,`,f, ,`, ,h,`,f, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`
119 , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`, ,`,b,`, ,h,`,f, ,`,`,`, ,h,`,f, ,`,b,`, ,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,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)
120 , , , , , , , , , , , , , , , , , , , ,n,`,n, ,`, ,n,`,n, , , , , ,`,`,`, , , , , ,n,`,n, ,`, ,n,`,n, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),,,`,,,`,,,`,,,T{pets=true}(1x1),`,`,,`,`,`
121 , , , , , , , , , , , ,h,`,f, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,`,`,`, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,h,`,f, , , , , , , , , , , , ,# ,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`
122 , , , , , , , , , , , ,`,b,`, ,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`, ,`,`,`, ,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , ,# ,,,,,,,,,,,,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)
123 , , , , , , , , , , , ,n,`,n, ,h,`,n, , ,d, , ,`, , ,d, , ,n,`,h, ,`,`,`, ,h,`,n, , ,d, , ,`, , ,d, , ,n,`,h, ,n,`,n, , , , , , , , , , , , ,# ,,,,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)
124 , , , , , , , , , , , , ,d, , , , , , ,n,`,n, ,`, ,n,`,n, , , , , ,`,`,`, , , , , ,n,`,n, ,`, ,n,`,n, , , , , , ,d, , , , , , , , , , , , , ,# ,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`
125 , , , , ,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, , , , , ,# ,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`
126 , , , , ,`,b,`, ,`,b,`,d,`,d,`,b,`,s, ,a,`,c, ,`, ,h,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,h,`,f, ,`, ,a,`,c, ,s,`,b,`,d,`,d,`,b,`, ,`,b,`, , , , , ,# 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)
127 , , , , ,n,`,n, ,h,`,n, ,`, ,n,t,c,f, ,h,s,f, ,`, , , , , , ,d, , ,`,`,`, , ,d, , , , , , ,`, ,h,s,f, ,f,c,t,n, ,`, ,n,`,h, ,n,`,n, , , , , ,# ,`,`,T{pets=true}(1x1),,,`,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,`,,,T{pets=true}(1x1),`,`
128 ,f,`,n, , ,d, , , , , , ,`, , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , ,`, , , , , , ,d, , ,n,`,f, ,# ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`
129 ,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,`, ,# ,`,`,T{pets=true}(1x1),b(5x5),,`,,b(5x5),,,,,`,b(6x5),,,,,b(5x6),,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,b(5x6),,,,b(6x5),,,,,,`,b(5x5),,,,b(5x5),,`,,,T{pets=true}(1x1),`,`
130 ,h,`,n, , ,d, , , , , , ,`, , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , ,`, , , , , , ,d, , ,n,`,h, ,# ,,,,,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)
131 , , , , ,n,`,n, ,f,`,n, ,`, ,n,r,a,h, ,h,s,f, ,`, , , , , , ,d, , ,`,`,`, , ,d, , , , , , ,`, ,h,s,f, ,h,a,r,n, ,`, ,n,`,f, ,n,`,n, , , , , ,# ,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,`,,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,`
132 , , , , ,`,b,`, ,`,b,`,d,`,d,`,b,`,s, ,a,`,c, ,`, ,h,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,h,`,f, ,`, ,a,`,c, ,s,`,b,`,d,`,d,`,b,`, ,`,b,`, , , , , ,# ,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`
133 , , , , ,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, , , , , ,# ,,,,,,,,,,,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),,`
134 , , , , , , , , , , , , ,d, , , , , , ,n,`,n, ,`, ,n,`,n, , , , , ,`,`,`, , , , , ,n,`,n, ,`, ,n,`,n, , , , , , ,d, , , , , , , , , , , , , ,# ,,,,,,,,,,,,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)
135 , , , , , , , , , , , ,n,`,n, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,`,`,`, ,f,`,n, , ,d, , ,`, , ,d, , ,n,`,f, ,n,`,n, , , , , , , , , , , , ,# ,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`
136 , , , , , , , , , , , ,`,b,`, ,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`, ,`,`,`, ,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , ,# ,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),b(5x5),,`,,,`,b(5x5),,`,,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,T{pets=true}(1x1),b(5x5),,`,,,`,b(5x5),,`,,,T{pets=true}(1x1),`,`,,`,`,`
137 , , , , , , , , , , , ,h,`,f, ,h,`,n, , ,d, , ,`, , ,d, , ,n,`,h, ,`,`,`, ,h,`,n, , ,d, , ,`, , ,d, , ,n,`,h, ,h,`,f, , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,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)
138 , , , , , , , , , , , , , , , , , , , ,n,`,n, ,`, ,n,`,n, , , , , ,`,`,`, , , , , ,n,`,n, ,`, ,n,`,n, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`
139 , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`, ,`,b,`, ,h,s,f, ,`,`,`, ,h,s,f, ,`,b,`, ,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,`
140 , , , , , , , , , , , , , , , , , , , ,h,`,f, ,`, ,h,`,f, ,a,`,c, ,`,`,`, ,a,`,c, ,h,`,f, ,`, ,h,`,f, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,b(5x5),,,,,`,b(5x5),,,,,`,`,`,`,`,`,`,`,`,`,`,b(5x5),,,,,`,b(5x5)
141 , , , , , , , , , , , , , , , , , , , , , , , ,`, , , , , ,r,b,t,d,`,`,`,d,r,b,t, , , , , ,`, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,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),`,`
142 , , , , , , , , , , , , , , , , , , , ,f,`,n, ,`, ,n,`,f, ,n,`,n, ,`,`,`, ,n,`,n, ,f,`,n, ,`, ,n,`,f, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,,,`,,,`,`,`,,,`,,,`,`,`,`,`,`,`,`,`
143 , , , , , , , , , , , , , , , , , , , ,`,b,`,d,`,d,`,b,`, , ,d, , ,`,`,`, , ,d, , ,`,b,`,d,`,d,`,b,`, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,T{pets=true}(1x1),,`,,T{pets=true}(1x1),`,`
144 , , , , , , , , , , , , , , , , , , , ,h,`,n, ,`, ,n,`,h, ,`,`,`, ,`,`,`, ,`,`,`, ,h,`,n, ,`, ,n,`,h, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,b(5x5),,`,,b(5x5),,,,,`,`,,`,`,`,,`,`,b(5x5),,,,b(5x5),,`
145 , , , , , , , , , , , , , , , , , , , , , , , ,d, , , , , , ,`,`, ,`,`,`, ,`,`, , , , , , ,d, , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,T{pets=true}(1x1),`,T{pets=true}(1x1),,`,`,T{pets=true}(1x1),,`,`,,`,`,`,,`,`,,T{pets=true}(1x1),`,`,,T{pets=true}(1x1),`,T{pets=true}(1x1)
146 , , , , , , , , , , , , , , , , , , , , , , ,n,`,n, ,f,`,n, ,`,`, ,`,`,`, ,`,`, ,n,`,f, ,n,`,n, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,`,`,`,`,,`,`,`,,`,`,`,`,`,`,,`,`,`
147 , , , , , , , , , , , , , , , , , , , , , , ,`,b,`, ,`,b,`,d,`,`, ,`,`,`, ,`,`,d,`,b,`, ,`,b,`, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,`,`,`,,`,`,T{pets=true}(1x1),,`,`,,`,`,`,,`,`,,T{pets=true}(1x1),`,`,,`,`,`
148 , , , , , , , , , , , , , , , , , , , , , , ,h,`,f, ,h,`,n, ,`,`, ,`,`,`, ,`,`, ,n,`,h, ,h,`,f, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`
149 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,`,`,`, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`
150 , , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
151 , , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
152 , , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
153 , , , , , , , , , , , , , , , , , , , , , ,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`, , , , , , , , , , , , , , , , , , , , , , ,# #build label(build) start(36;73) hidden()
154 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f
155 #,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`
156 #query label(rooms) start(36;73) message(use burial script to mark urns as usable) room designations ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n
157 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,d
158 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,f,`,n,,`,,n,`,f
159 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,d,`,b,`
160 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,n,,`,,n,`,h
161 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`
162 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,`,,h,`,f
163 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,`,,`,b,`
164 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n
165 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,f,`,n,,,d,,,`,,,d,,,n,`,f
166 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`
167 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,n,,,d,,,`,,,d,,,n,`,h
168 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n
169 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,r,b,t,,`,,r,b,t,,h,`,f
170 , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,a,`,c,,`,,a,`,c,,`,b,`
171 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,h,s,f,,`,,h,s,f,,n,`,n
172 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,`,,,,,,,d
173 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,h,`,f,,f,`,n,,`,,n,r,a,h,,`,,h,a,r,n,,`,,n,`,f,,h,`,f
174 , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,s,,`,,s,`,b,`,d,`,d,`,b,`,,`,b,`
175 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,n,`,n,,h,`,n,,`,,n,t,c,f,,`,,f,c,t,n,,`,,n,`,h,,n,`,n
176 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,f,`,n,,,d,,,,,,,`,,,,,,,`,,,,,,,`,,,,,,,d,,,n,`,f
177 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,`
178 , , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,h,`,n,,,d,,,,,,,`,,,,,,`,`,`,,,,,,`,,,,,,,d,,,n,`,h
179 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,n,`,n,,f,`,n,,`,,n,`,f,,`,`,`,,f,`,n,,`,,n,`,f,,n,`,n
180 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,,`,`,`,,`,b,`,d,`,d,`,b,`,,`,b,`
181 , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,h,`,f,,h,`,n,,`,,n,`,h,,`,`,`,,h,`,n,,`,,n,`,h,,h,`,f
182 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,`,`,`,,,,,,d
183 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,n,`,n,,f,n,,`,`,`,,n,f,,n,`,n,,h,`,f
184 , , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,,b,`,d,`,`,`,d,`,b,,`,b,`,,`,b,`
185 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,h,`,f,,h,n,,`,`,`,,n,h,,h,`,f,,n,`,n
186 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,d,,,`,`,`,,,d,,,,,,,d
187 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,f,`,n,,`,,n,`,f,,n,`,n,,`,`,`,,n,`,n,,f,`,n,,`,,n,`,f
188 , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, ,r+,, , , , , , ,r+,, ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,d,`,b,`,,h,b,f,,`,`,`,,h,b,f,,`,b,`,d,`,d,`,b,`
189 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,h,`,n,,`,,n,`,h,,,d,,,`,`,`,,,d,,,h,`,n,,`,,n,`,h
190 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,`,,,,,,n,`,n,,`,`,`,,n,`,n,,,,,,`
191 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,h,`,f,,`,,h,`,f,,`,b,`,,`,`,`,,`,b,`,,h,`,f,,`,,h,`,f
192 , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,b,`,,`,,`,b,`,,h,`,f,,`,`,`,,h,`,f,,`,b,`,,`,,`,b,`
193 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n
194 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,h,`,f,,f,`,n,,,d,,,`,,,d,,,n,`,f,,`,`,`,,f,`,n,,,d,,,`,,,d,,,n,`,f,,h,`,f
195 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,`,b,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,`,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,b,`
196 , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,n,`,n,,h,`,n,,,d,,,`,,,d,,,n,`,h,,`,`,`,,h,`,n,,,d,,,`,,,d,,,n,`,h,,n,`,n
197 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,d,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n,,,,,,,d
198 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,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
199 , , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,# ,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,s,,a,`,c,,`,,h,`,f,,n,`,n,,`,`,`,,n,`,n,,h,`,f,,`,,a,`,c,,s,`,b,`,d,`,d,`,b,`,,`,b,`
200 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,n,`,n,,h,`,n,,`,,n,t,c,f,,h,s,f,,`,,,,,,,d,,,`,`,`,,,d,,,,,,,`,,h,s,f,,f,c,t,n,,`,,n,`,h,,n,`,n
201 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,f,`,n,,,d,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,d,,,n,`,f
202 , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,`,b,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,b,`
203 , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , ,# ,h,`,n,,,d,,,,,,,`,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,`,,,,,,,d,,,n,`,h
204 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,n,`,n,,f,`,n,,`,,n,r,a,h,,h,s,f,,`,,,,,,,d,,,`,`,`,,,d,,,,,,,`,,h,s,f,,h,a,r,n,,`,,n,`,f,,n,`,n
205 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,`,b,`,,`,b,`,d,`,d,`,b,`,s,,a,`,c,,`,,h,`,f,,n,`,n,,`,`,`,,n,`,n,,h,`,f,,`,,a,`,c,,s,`,b,`,d,`,d,`,b,`,,`,b,`
206 , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, ,# ,,,,,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
207 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,d,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n,,,,,,,d
208 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,n,`,n,,f,`,n,,,d,,,`,,,d,,,n,`,f,,`,`,`,,f,`,n,,,d,,,`,,,d,,,n,`,f,,n,`,n
209 , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , ,# ,,,,,,,,,,,,`,b,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,`,`,,`,b,`,d,`,`,`,`,`,`,`,`,`,d,`,b,`,,`,b,`
210 , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , ,r+,, , , , , , ,r+,, , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,h,`,f,,h,`,n,,,d,,,`,,,d,,,n,`,h,,`,`,`,,h,`,n,,,d,,,`,,,d,,,n,`,h,,h,`,f
211 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,n,`,n,,`,,n,`,n,,,,,,`,`,`,,,,,,n,`,n,,`,,n,`,n
212 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,b,`,,`,,`,b,`,,h,s,f,,`,`,`,,h,s,f,,`,b,`,,`,,`,b,`
213 , , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,h,`,f,,`,,h,`,f,,a,`,c,,`,`,`,,a,`,c,,h,`,f,,`,,h,`,f
214 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,`,,,,,,r,b,t,d,`,`,`,d,r,b,t,,,,,,`
215 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,f,`,n,,`,,n,`,f,,n,`,n,,`,`,`,,n,`,n,,f,`,n,,`,,n,`,f
216 , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,`,b,`,d,`,d,`,b,`,,,d,,,`,`,`,,,d,,,`,b,`,d,`,d,`,b,`
217 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,h,`,n,,`,,n,`,h,,`,`,`,,`,`,`,,`,`,`,,h,`,n,,`,,n,`,h
218 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , , , , , ,r+,, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,d,,,,,,,`,`,,`,`,`,,`,`,,,,,,,d
219 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,n,`,n,,f,`,n,,`,`,,`,`,`,,`,`,,n,`,f,,n,`,n
220 , , , , , , , , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , ,r+,, , , , ,r+,, , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,`,b,`,,`,b,`,d,`,`,,`,`,`,,`,`,d,`,b,`,,`,b,`
221 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,h,`,f,,h,`,n,,`,`,,`,`,`,,`,`,,n,`,h,,h,`,f
222 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,`,`,`
223 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`
224 , , , , , , , , , , , , , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , ,r+,, , ,r+,, , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
225 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
226 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,# ,,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`
227 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,#
228 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,~,~,~, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,#
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,~,~,~, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,#
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,~,~,~, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,#
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,#
#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#

File diff suppressed because it is too large Load Diff

@ -1,43 +1,65 @@
#notes label(help) #notes label(help)
A pump stack is useful for moving water or magma up through the z-levels. A pump stack is useful for moving water or magma up through the z-levels.
"" ""
"These blueprints can be used from the quickfort commandline, but are much easier to use with the visual interface. That way you can check the vertical path interactively before you apply. Run gui/quickfort pump_stack" "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."
"" ""
"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."
"" ""
"2) Enable repetitions with the ""R"" hotkey 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."
""
"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 with Ctrl+arrow keys."
"" ""
"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." "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 you do not need to transmit power down below the lowest level, replace the channel designation on the middle tile of the bottom-most pump stack level with a regular dig designation. Likewise, replace the Up/Down staircase designation on the lowest level with an Up staircase designation. Otherwise you might get magma critters climbing up through your access stairway!" "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 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."
"" ""
"6) After the stack is dug out, prepare for building by setting the buildingplan plugin material filters for screw pumps (b-M-s-M). 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." "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."
"" ""
"7) Finally, position the cursor back on the access stairs on the lowest level and run the ""build"" blueprint with the same repetition and transformation settings that you used for the ""dig"" blueprint. As you manufacture the materials you need to construct the screw pumps, your dwarves will build the pump stack from the bottom up." "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."
"" ""
"Sometimes, a screw pump will spontaneously deconstruct while you are building the stack. 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." "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 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 #dig label(digSN) start(2;4;on access stairs) hidden() for a pump from south level
,,,d ,,,d
,,,h ,,,d
,i,d,d ,i,d,d
,,,h ,,,d
#dig label(digNS) start(2;4;on access stairs) hidden() for a pump from north level #dig label(digNS) start(2;4;on access stairs) hidden() for a pump from north level
,,,h ,,,d
,d,d,d ,d,d,d
,i,,h ,i,,d
,,,d ,,,d
#meta label(dig) start(at the bottom level on the access stairs) 2 levels of pump stack - bottom level pumps from the south #meta label(dig) start(at the bottom level on the access stairs) 2 levels of pump stack - bottom level pumps from the south
/digSN /digSN
#< #<
/digNS /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 #build label(buildSN) start(2;4;on access stairs) hidden() for a pump from south level
,,,` ,,,`

Can't render this file because it has a wrong number of fields in line 29.

File diff suppressed because it is too large Load Diff

@ -0,0 +1,5 @@
{
"planner": {
"minimized": true
}
}

@ -2,3 +2,4 @@
# Please use gui/control-panel to edit this file # Please use gui/control-panel to edit this file
enable faststart enable faststart
enable work-now

@ -1,9 +0,0 @@
# Example DFHack init scripts
This folder contains ready-to-use examples of DFHack init scripts.
You can use them by copying them to the dfhack-config/init folder.
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).

@ -1,76 +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! Copy this file to your
# dfhack-config/init directory to use. Feed free to edit or override
# to your liking.
# Uncomment this next line if you want buildingplan (and quickfort) to use only
# blocks (not bars or logs) for constructions and workshops. 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
# Disable cooking of useful item types when you start a new fortress.
on-new-fortress ban-cooking all
# Show a warning dialog when units are starving
repeat -name warn-starving -time 10 -timeUnits days -command [ warn-starving ]
# Force dwarves to drop tattered clothing instead of clinging to the scraps
repeat -name cleanowned -time 1 -timeUnits months -command [ cleanowned X ]
# Automatically enqueue orders to shear and milk animals
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\"}]}" ]
# Fulfill high-volume orders before slower once-daily orders
repeat -name orders-sort -time 1 -timeUnits days -command [ orders sort ]
# 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
# auto-assigns nesting birds to nestbox zones and protects fertile eggs from
# being gathered and eaten
enable autonestbox nestboxes
# manages seed stocks
enable seedwatch
seedwatch all 30
# ensures important tasks get assigned to workers.
# otherwise many job types can get ignored in busy forts.
on-new-fortress prioritize -aq defaults
# 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 enable autobutcher
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
# immediately butcher all unprofitable animals
on-new-fortress autobutcher target 0 0 0 0 HORSE YAK DONKEY WATER_BUFFALO GOAT CAVY BIRD_DUCK BIRD_GUINEAFOWL
# watch for new animals
on-new-fortress autobutcher autowatch

@ -38,17 +38,20 @@ keybinding add Ctrl-V@dwarfmode digv
keybinding add Ctrl-Shift-V@dwarfmode "digv x" keybinding add Ctrl-Shift-V@dwarfmode "digv x"
# clean the selected tile of blood etc # clean the selected tile of blood etc
keybinding add Ctrl-C spotclean keybinding add Ctrl-C@dwarfmode spotclean
# destroy the selected item # destroy the selected item
keybinding add Ctrl-K@dwarfmode autodump-destroy-item keybinding add Ctrl-K@dwarfmode autodump-destroy-item
# destroy items designated for dump in the selected tile # bring up the autodump UI
keybinding add Ctrl-H@dwarfmode autodump-destroy-here keybinding add Ctrl-H@dwarfmode gui/autodump
# apply blueprints to the map # apply blueprints to the map
keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort
# toggle keyboard cursor
keybinding add Alt-K@dwarfmode toggle-kbd-cursor
# show information collected by dwarfmonitor # show information collected by dwarfmonitor
#keybinding add Alt-M@dwarfmode/Default "dwarfmonitor prefs" #keybinding add Alt-M@dwarfmode/Default "dwarfmonitor prefs"
#keybinding add Ctrl-F@dwarfmode/Default "dwarfmonitor stats" #keybinding add Ctrl-F@dwarfmode/Default "dwarfmonitor stats"
@ -154,7 +157,7 @@ keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort
#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" #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 # gui/design
keybinding add Ctrl-D@dwarfmode gui/design keybinding add Ctrl-D@dwarfmode/Default gui/design

@ -78,14 +78,12 @@
# Display DFHack version on title screen # Display DFHack version on title screen
#enable title-version #enable title-version
# Allow DFHack tools to overlay functionality and information on the DF screen # Enable system services
enable overlay
# Allow buildings to be placed now and built later when materials are available
enable buildingplan enable buildingplan
enable burrow
#Allow designated stockpiles to automatically mark items for melting enable confirm
enable automelt enable logistics
enable overlay
# Dwarf Manipulator (simple in-game Dwarf Therapist replacement) # Dwarf Manipulator (simple in-game Dwarf Therapist replacement)
#enable manipulator #enable manipulator
@ -97,28 +95,17 @@ enable automelt
#enable automaterial #enable automaterial
# Other interface improvement tools # Other interface improvement tools
enable \
confirm
# dwarfmonitor \ # dwarfmonitor \
# mousequery \ # mousequery \
# autogems \ # autogems \
# autodump \
# automelt \
# autotrade \
# buildingplan \
# trackstop \
# zone \ # zone \
# stocks \ # stocks \
# autochop \ #
# stockpiles
#end a line with a backslash to make it continue to the next line. The \ is deleted for the final command. #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. # 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 cannot extend a commented line.
# You can comment out the extension of a 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 option to enter embark assistant
#enable embark-assistant #enable embark-assistant
@ -144,3 +131,4 @@ enable \
alias add autounsuspend suspendmanager alias add autounsuspend suspendmanager
alias add gui/dig gui/design alias add gui/dig gui/design
alias add version help

@ -1,31 +1,9 @@
[ [
{
"amount_left" : 150,
"amount_total" : 150,
"frequency" : "Monthly",
"id" : 0,
"is_active" : false,
"is_validated" : false,
"item_conditions" :
[
{
"condition" : "LessThan",
"flags" :
[
"unrotten"
],
"item_type" : "FOOD",
"value" : 400
}
],
"job" : "PrepareMeal",
"meal_ingredients" : 2
},
{ {
"amount_left" : 10, "amount_left" : 10,
"amount_total" : 10, "amount_total" : 10,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 1, "id" : 0,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -47,7 +25,7 @@
"unrotten", "unrotten",
"cookable" "cookable"
], ],
"value" : 500 "value" : 80
}, },
{ {
"condition" : "AtMost", "condition" : "AtMost",
@ -57,15 +35,6 @@
], ],
"item_type" : "FOOD", "item_type" : "FOOD",
"value" : 3500 "value" : 3500
},
{
"condition" : "AtLeast",
"flags" :
[
"unrotten"
],
"item_type" : "FOOD",
"value" : 400
} }
], ],
"job" : "PrepareMeal", "job" : "PrepareMeal",
@ -75,7 +44,7 @@
"amount_left" : 2, "amount_left" : 2,
"amount_total" : 2, "amount_total" : 2,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 2, "id" : 1,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -112,7 +81,7 @@
"amount_left" : 2, "amount_left" : 2,
"amount_total" : 2, "amount_total" : 2,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 3, "id" : 2,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -149,7 +118,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 4, "id" : 3,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -170,7 +139,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 5, "id" : 4,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -205,7 +174,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 6, "id" : 5,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -237,7 +206,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 7, "id" : 6,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -268,7 +237,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 8, "id" : 7,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -290,7 +259,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 9, "id" : 8,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -322,7 +291,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 10, "id" : 9,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -353,7 +322,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 11, "id" : 10,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -386,7 +355,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 12, "id" : 11,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -426,7 +395,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 13, "id" : 12,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -452,7 +421,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 14, "id" : 13,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -487,7 +456,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 15, "id" : 14,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -522,7 +491,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 16, "id" : 15,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -557,7 +526,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 17, "id" : 16,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -587,7 +556,7 @@
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,
"frequency" : "Daily", "frequency" : "Daily",
"id" : 18, "id" : 17,
"is_active" : false, "is_active" : false,
"is_validated" : false, "is_validated" : false,
"item_conditions" : "item_conditions" :
@ -618,6 +587,36 @@
"job" : "MakeTool", "job" : "MakeTool",
"material" : "INORGANIC" "material" : "INORGANIC"
}, },
{
"amount_left" : 1,
"amount_total" : 1,
"frequency" : "Daily",
"id" : 18,
"is_active" : false,
"is_validated" : false,
"item_conditions" :
[
{
"condition" : "AtLeast",
"item_type" : "WOOD",
"value" : 50
},
{
"condition" : "AtMost",
"flags" :
[
"empty"
],
"item_type" : "BIN",
"value" : 5
}
],
"job" : "ConstructBin",
"material_category" :
[
"wood"
]
},
{ {
"amount_left" : 1, "amount_left" : 1,
"amount_total" : 1, "amount_total" : 1,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -43,7 +43,7 @@
"condition" : "AtLeast", "condition" : "AtLeast",
"item_type" : "BOULDER", "item_type" : "BOULDER",
"material" : "INORGANIC:CASSITERITE", "material" : "INORGANIC:CASSITERITE",
"value" : 5 "value" : 25
}, },
{ {
"condition" : "AtLeast", "condition" : "AtLeast",
@ -668,7 +668,7 @@
"bearing" : "TIN", "bearing" : "TIN",
"condition" : "AtLeast", "condition" : "AtLeast",
"item_type" : "BOULDER", "item_type" : "BOULDER",
"value" : 5 "value" : 25
}, },
{ {
"bearing" : "COPPER", "bearing" : "COPPER",
@ -729,7 +729,7 @@
"bearing" : "TIN", "bearing" : "TIN",
"condition" : "AtMost", "condition" : "AtMost",
"item_type" : "BOULDER", "item_type" : "BOULDER",
"value" : 5 "value" : 25
}, },
{ {
"bearing" : "COPPER", "bearing" : "COPPER",
@ -791,13 +791,13 @@
"bearing" : "TIN", "bearing" : "TIN",
"condition" : "AtLeast", "condition" : "AtLeast",
"item_type" : "BOULDER", "item_type" : "BOULDER",
"value" : 5 "value" : 25
}, },
{ {
"bearing" : "COPPER", "bearing" : "COPPER",
"condition" : "AtLeast", "condition" : "AtLeast",
"item_type" : "BOULDER", "item_type" : "BOULDER",
"value" : 5 "value" : 25
}, },
{ {
"condition" : "AtLeast", "condition" : "AtLeast",
@ -828,13 +828,13 @@
"condition" : "AtLeast", "condition" : "AtLeast",
"item_type" : "BAR", "item_type" : "BAR",
"material" : "INORGANIC:TIN", "material" : "INORGANIC:TIN",
"value" : 5 "value" : 25
}, },
{ {
"condition" : "AtLeast", "condition" : "AtLeast",
"item_type" : "BAR", "item_type" : "BAR",
"material" : "INORGANIC:COPPER", "material" : "INORGANIC:COPPER",
"value" : 5 "value" : 25
}, },
{ {
"condition" : "AtLeast", "condition" : "AtLeast",
@ -1068,13 +1068,13 @@
"bearing" : "TIN", "bearing" : "TIN",
"condition" : "AtLeast", "condition" : "AtLeast",
"item_type" : "BOULDER", "item_type" : "BOULDER",
"value" : 5 "value" : 25
}, },
{ {
"bearing" : "COPPER", "bearing" : "COPPER",
"condition" : "AtLeast", "condition" : "AtLeast",
"item_type" : "BOULDER", "item_type" : "BOULDER",
"value" : 5 "value" : 25
}, },
{ {
"condition" : "AtLeast", "condition" : "AtLeast",

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -4,11 +4,19 @@ add_subdirectory(lua)
add_subdirectory(md5) add_subdirectory(md5)
add_subdirectory(protobuf) add_subdirectory(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()
if(UNIX AND NOT APPLE) # remove this once our MSVC build env has been updated if(UNIX AND NOT APPLE) # remove this once our MSVC build env has been updated
option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" OFF) option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" OFF)
add_subdirectory(googletest) add_subdirectory(googletest)
if(UNIX) if(UNIX)
set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-Wno-maybe-uninitialized -Wno-sign-compare") set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-Wno-maybe-uninitialized -Wno-sign-compare -Wno-restrict")
endif() endif()
endif() endif()
@ -31,8 +39,6 @@ option(CLSOCKET_DEP_ONLY "Build for use inside other CMake projects as dependenc
add_subdirectory(clsocket) add_subdirectory(clsocket)
ide_folder(clsocket "Depends") 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 # set the default values of libexpat options - the descriptions are left empty
# because later option() calls *do* override those # because later option() calls *do* override those
set(EXPAT_BUILD_EXAMPLES OFF CACHE BOOL "") set(EXPAT_BUILD_EXAMPLES OFF CACHE BOOL "")

@ -1 +1 @@
Subproject commit 6ed8aa46462ea01a1122fc49422840a2facc9757 Subproject commit 8cf949340e22001bee1ca25c9d6c1d6a89e8faf2

@ -1 +1 @@
Subproject commit 081249cceb59adc857a72d67e60c32047680f787 Subproject commit fc4a77ea28eb5eba0ecd11443f291335ec3d2aa0

@ -1,5 +1,5 @@
project(lua CXX) 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") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLUA_USE_APICHECK")

@ -46,6 +46,10 @@
#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__ #ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__
#define GOOGLE_PROTOBUF_REPEATED_FIELD_H__ #define GOOGLE_PROTOBUF_REPEATED_FIELD_H__
#ifdef __GNUC__
#pragma GCC system_header
#endif
#include <string> #include <string>
#include <iterator> #include <iterator>
#include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/common.h>

@ -1 +1 @@
Subproject commit 439fdbc259c13f23a3122e68ba35ad5a13bcd97c Subproject commit 0a994526622c2201756e386ef98b44b193e25f06

@ -53,7 +53,7 @@ double quotes. To include a double quote character, use ``\"``.
If the first non-whitespace character is ``:``, the command is parsed in If the first non-whitespace character is ``:``, the command is parsed in
an alternative mode. The non-whitespace characters following the ``:`` are 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 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:: As an example, the following two command lines are exactly equivalent::
:foo a b "c d" e f :foo a b "c d" e f
@ -306,6 +306,23 @@ the root DF folder.
Note that ``script-paths.txt`` is only read at startup, but the paths can also be 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 <lua-api-internal>`. modified programmatically at any time through the `Lua API <lua-api-internal>`.
Commandline options
===================
In addition to `Using an OS terminal`_ to execute commands on startup, DFHack
also recognizes a single commandline option that can be specified on the
commandline:
- ``--disable-dfhack``: If this option is passed on the Dwarf Fortress
commandline, then DFHack will be disabled for the session. You will have to
restart Dwarf Fortress without specifying this option in order to use DFHack.
If you are launching Dwarf Fortress from Steam, you can enter the option in
the "Launch Options" text box in the properties for the Dwarf Fortress app.
Note that if you do this, DFHack will be disabled regardless of whether you
run Dwarf Fortress from its own app or DFHack's. You will have to clear the
DF Launch Options in order to use DFHack again. 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.
.. _env-vars: .. _env-vars:
@ -319,6 +336,11 @@ on UNIX-like systems:
DFHACK_SOME_VAR=1 ./dfhack 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`` - ``DFHACK_PORT``: the port to use for the RPC server (used by ``dfhack-run``
and `remotefortressreader` among others) instead of the default ``5000``. As and `remotefortressreader` among others) instead of the default ``5000``. As
with the default, if this port cannot be used, the server is not started. with the default, if this port cannot be used, the server is not started.
@ -355,6 +377,23 @@ Other (non-DFHack-specific) variables that affect DFHack:
sensitive), ``DF2CONSOLE()`` will produce UTF-8-encoded text. Note that this sensitive), ``DF2CONSOLE()`` will produce UTF-8-encoded text. Note that this
should be the case in most UTF-8-capable \*nix terminal emulators already. should be the case in most UTF-8-capable \*nix terminal emulators already.
Core preferences
================
There are a few settings that can be changed dynamically via
`gui/control-panel` to affect runtime behavior. You can also toggle these from
the commandline using the `lua` command, e.g.
``lua dfhack.HIDE_ARMOK_TOOLS=true`` or by editing the generated
``dfhack-config/init/dfhack.control-panel-preferences.init`` file and
restarting DF.
- ``dfhack.HIDE_CONSOLE_ON_STARTUP``: Whether to hide the external DFHack
terminal window on startup. This, of course, is not useful to change
dynamically. You'll have to use `gui/control-panel` or edit the init file
directly and restart DF for it to have an effect.
- ``dfhack.HIDE_ARMOK_TOOLS``: Whether to hide "armok" tools in command lists.
Miscellaneous notes Miscellaneous notes
=================== ===================
This section is for odd but important notes that don't fit anywhere else. This section is for odd but important notes that don't fit anywhere else.

@ -7,163 +7,127 @@ Installing DFHack
.. contents:: .. contents::
:local: :local:
Requirements Requirements
============ ============
DFHack supports Windows, Linux, and macOS, and both 64-bit and 32-bit builds DFHack supports all operating systems and platforms that Dwarf Fortress itself
of Dwarf Fortress. supports, which at the moment is just 64-bit Windows. However, the Windows
build of DFHack works well under ``wine`` (or ``Proton``, Steam's fork of
``wine``) on other operating systems.
.. _installing-df-version: .. _installing-df-version:
DFHack releases generally only support the version of Dwarf Fortress that they 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. are named after. For example, DFHack 50.05 only supported DF 50.05. DFHack
DFHack releases *never* support newer versions of DF, because DFHack requires releases *never* support newer versions of DF -- DFHack requires data about DF
data about DF that is only possible to obtain after DF has been released. that is only possible to obtain after DF has been released. Occasionally,
Occasionally, DFHack releases will be able to maintain support for older DFHack releases will be able to maintain support for older versions of DF - for
versions of DF - for example, DFHack 0.34.11-r5 supported both DF 0.34.11 and example, DFHack 0.34.11-r5 supported both DF 0.34.11 and 0.34.10. For maximum
0.34.10. For maximum stability, you should usually use the latest versions of stability, you should usually use the latest versions of both DF and DFHack.
both DF and DFHack.
Windows
-------
* 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 <https://stackoverflow.com/questions/32452777/visual-c-2015-express-stat-not-working-on-windows-xp>`_
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.
.. _installing-reqs-linux:
Linux
-----
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.
In the event that none of the provided binaries work on your distribution,
you may need to `compile DFHack from source <building-dfhack-index>`.
macOS
-----
OS X 10.6.8 or later is required.
.. _downloading: .. _downloading:
Downloading DFHack Downloading DFHack
================== ==================
Stable builds of DFHack are available on `GitHub <https://github.com/dfhack/dfhack/releases>`_. Stable builds of DFHack are available on
GitHub has been known to change their layout periodically, but as of July 2020, `Steam <https://store.steampowered.com/app/2346660/DFHack>`__
downloads are available at the bottom of the release notes for each release, under a section or from our `GitHub <https://github.com/dfhack/dfhack/releases>`__. Either
named "Assets" (which you may have to expand). The name of the file indicates location will give you exactly the same package.
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 On Steam, note that DFHack is a separate app, not a DF Steam Workshop mod. You
version should also match your DF version - see `above <installing-df-version>` can run DF with DFHack by launching either the DFHack app or the original Dwarf
for details. For example: Fortress app.
* ``dfhack-0.47.04-r1-Windows-64bit.zip`` supports 64-bit DF on Windows If you download from GitHub, downloads are available at the bottom of the
* ``dfhack-0.47.04-r1-Linux-32bit-gcc-7.tar.bz2`` supports 32-bit DF on Linux release notes for each release, under a section named "Assets" (which you may
(see `installing-reqs-linux` for details on the GCC version indicator) 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 <installing-df-version>` for details. For example:
The `DFHack website <https://dfhack.org/builds>`_ also provides links to * ``dfhack-50.07-r1-Windows-64bit.zip`` supports 64-bit DF on Windows
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).
.. warning:: .. warning::
Do *not* download the source code from GitHub, either from the releases page 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 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 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 you want to compile DFHack instead of using a pre-built release, please see
`building-dfhack-index` for instructions.) `building-dfhack-index` for instructions.)
Beta releases
-------------
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" suffix.
Development builds
------------------
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.
To download a development build from GitHub:
- Ensure you are logged into your GitHub account
- Go to https://github.com/DFHack/dfhack/actions/workflows/build.yml?query=branch%3Adevelop+event%3Apush
- Click on the first entry that has a green checkmark
- Click the number under "Artifacts" (or scroll down)
- Click on the "dfhack-*-build-*" artifact for your platform to download
You can extract this package the same as if you are doing a manual install (see the next section).
Installing DFHack 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 <downloading>`, you will end up with a release archive When you `download DFHack <downloading>`, you will end up with a release archive
(a ``.zip`` file on Windows, or a ``.tar.bz2`` file on other platforms). Your (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 operating system should have built-in utilities capable of extracting files from
these archives. these archives.
The release archives contain several folders, including a ``hack`` folder where If you are on Windows, please remember to right click on the file after
DFHack binary and system data is stored, a ``dfhack-config`` folder where user downloading, open the file properties, and select the "Unblock" checkbox. This
data and configuration is stored, and a ``blueprints`` folder where `quickfort` will prevent issues with Windows antivirus programs.
blueprints are stored. 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.)
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.
Uninstalling DFHack Uninstalling DFHack
=================== ===================
Uninstalling DFHack essentially involves reversing what you did to install Just renaming or removing the ``dfhooks`` library file is enough to disable
DFHack. On Windows, replace ``SDL.dll`` with ``SDLreal.dll`` first. Then, you DFHack. If you would like to remove all DFHack files, consult the DFHack install
can remove any files that were part of the DFHack archive. DFHack does not archive to see the list of files and remove the corresponding files in the Dwarf
currently maintain a list of these files, so if you want to completely remove Fortress folder. Any DFHack files left behind will not negatively affect DF.
them, you should consult the DFHack archive that you installed for a full list.
Generally, any files left behind should not negatively affect DF.
On Steam, uninstalling DFHack will cleanly remove everything that was installed
with DFHack, so there is nothing else for you to do.
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.
Upgrading DFHack Upgrading DFHack
================ ================
The recommended approach to upgrade DFHack is to uninstall DFHack first, then Again, if you have installed from Steam, your copy of DFHack will automatically be kept up to date. This section is for manual installers.
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).
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).
.. note::
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.
Pre-packaged DFHack installations
=================================
There are :wiki:`several packs available <Utility:Lazy_Newb_Pack>` 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.
Linux packages
==============
Third-party DFHack packages are available for some Linux distributions,
including in:
* `AUR <https://aur.archlinux.org/packages/dfhack/>`__, for Arch and related First, remove the ``hack`` and ``stonesense`` folders in their entirety. This
distributions ensures that files that don't exist in the latest version are properly removed
* `RPM Fusion <https://admin.rpmfusion.org/pkgdb/package/nonfree/dfhack/>`__, and don't affect your new installation.
for Fedora and related distributions
Note that these may lag behind DFHack releases. If you want to use a newer Then, extract the DFHack release archive into your Dwarf Fortress folder,
version of DFHack, we generally recommended installing it in a clean copy of DF overwriting any remaining top-level files.
in your home folder. Attempting to upgrade an installation of DFHack from a
package manager may break it.

@ -45,67 +45,75 @@ Here are some common tasks people use DFHack tools to accomplish:
- Quickly scan the map for visible ores of specific types so you can focus - Quickly scan the map for visible ores of specific types so you can focus
your mining efforts your mining efforts
Some tools are one-shot commands. For example, you can run `unforbid all <unforbid>` Some tools are one-shot commands. For example, you can run
to claim all (reachable) items on the map after a messy siege. `unforbid all <unforbid>` to claim all (reachable) items on the map after a
messy siege.
Other tools must be `enabled <enable>` and then they will run in the background.
For example, `enable seedwatch <seedwatch>` will start monitoring your stocks of Other tools must be `enabled <enable>` once and then they will run in the
seeds and prevent your chefs from cooking seeds that you need for planting. background. For example, once enabled, `seedwatch` will start monitoring your
Tools that are enabled in the context of a fort will save their state with that stocks of seeds and prevent your chefs from cooking seeds that you need for
fort, and they will remember that they are enabled the next time you load your save. 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
A third class of tools add information to the screen or provide new integrated load your save.
functionality via the DFHack `overlay` framework. For example, the `unsuspend`
tool, in addition to its basic function of unsuspending all building construction A third class of tools adds information to the screen or provides new integrated
jobs, can also overlay a marker on suspended buildings to indicate that they are functionality via the DFHack `overlay` framework. For example, the `sort` tool
suspended (and will use different markers to tell you whether this is a problem). adds widgets to the squad member selection screen that allow you to search,
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? 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. 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 hover hotspot. It's in the upper The first place to check is the DFHack logo menu. It's in the upper left corner
left corner of the screen by default, though you can move it anywhere you want of the screen by default, though you can move it anywhere you want with the
with the `gui/overlay` configuration UI. `gui/overlay` configuration UI.
When you hover the mouse over the logo (or hit the Ctrl-Shift-C keyboard shortcut) When you click on the logo (or hit the Ctrl-Shift-C keyboard shortcut), a short
a list of DFHack tools relevant to the current context comes up. For example, when list of popular, relevant DFHack tools comes up. These are the tools that have
you have a unit selected, the hotspot will show a list of tools that inspect been assigned hotkeys that are active in the current context. For example, when
units, allow you to edit them, or maybe even teleport them. Next to each tool, you're looking at a fort map, the list will contain fortress design tools like
you'll see the hotkey you can hit to invoke the command without even opening the `gui/quickfort` and `gui/design`. You can click on the tools in the list, or
hover list. 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 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 will give you an overview of which tools are currently enabled, and will allow
you to toggle them on or off, see help text for them, or launch their dedicated you to toggle them on or off, see help text for them, or launch their dedicated
configuration UIs. You can open the control panel from anywhere with the configuration UIs. You can open the control panel from anywhere with the
Ctrl-Shift-E hotkey or by selecting it from the logo hover list. 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 In the control panel, you can also select which tools you'd like to be
automatically enabled when you start a new fort. There are also system settings automatically enabled and popular commands you'd like to run when you start a
you can change, like whether DFHack windows will pause the game when they come new fort. On the "Preferences" tab, there are settings you can change, like
up. whether you want to limit DFHack functionality to interface improvements,
bugfixes, and productivity tools, hiding the god-mode tools ("mortal mode") or
Finally, you can explore the full extent of the DFHack catalog in `gui/launcher`, whether you want DFHack windows to pause the game when they come up.
which is always listed first in the DFHack logo hover list. You can also bring up
the launcher by tapping the backtick key (\`) or hitting Ctrl-Shift-D. In the Finally, you can explore the full extent of the DFHack catalog in
launcher, you can quickly autocomplete any command name by selecting it in the `gui/launcher`, which is always listed first in the DFHack logo menu list. You
list on the right side of the window. Commands are ordered by how often you run can also bring up the launcher by tapping the backtick key (\`) or hitting
them, so your favorite commands will always be on top. You can also pull full Ctrl-Shift-D. In the launcher, you can quickly autocomplete any command name by
commandlines out of your history with Alt-S or by clicking on the "history search" selecting it in the list on the right side of the window. Commands are ordered
hotkey hint. 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
Once you have typed (or autocompleted, or searched for) a command, other commands on the "history search" hotkey hint.
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 Once you have typed (or autocompleted, or searched for) a command, other
useful. You can also see how commands are grouped by running the `tags` command. 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. You can also see how commands are grouped by running the
`tags` command.
The bottom panel will show the full help text for the command you are running, 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 allowing you to refer to the usage documentation and examples when you are
your command. After you run a command, the bottom panel switches to command output typing your command. After you run a command, the bottom panel switches to
mode, but you can get back to the help text by hitting Ctrl-T or clicking on the command output mode, but you can get back to the help text by hitting Ctrl-T or
``Help`` tab. clicking on the ``Help`` tab.
How do DFHack in-game windows work? How do DFHack in-game windows work?
----------------------------------- -----------------------------------
@ -122,84 +130,88 @@ 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 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 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 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 focus. If no DFHack windows are focused, you can right click directly on a
to close it without left clicking to focus it first. 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 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 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). (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 You can generally use DFHack tools without interrupting the game. That is, if
game is unpaused, it can continue to run while a DFHack window is open. If configured the game is unpaused, it can continue to run while a DFHack window is open. If
to do so in `gui/control-panel`, tools will initially pause the game to let you configured to do so in `gui/control-panel`, tools will initially pause the game
focus on the task at hand, but you can unpause like normal if you want. You can to let you focus on the task at hand, but you can unpause like normal if you
also interact with the map, scrolling it with the keyboard or mouse and selecting want. You can also interact with the map, scrolling it with the keyboard or
units, buildings, and items. Some tools will intercept all mouse clicks to allow mouse and selecting units, buildings, and items. Some tools will intercept all
you to select regions on the map. When these tools have focus, you will not be able mouse clicks to allow you to select regions of the map. When these tools have
to use the mouse to interact with map elements or pause/unpause the game. Therefore, focus, you will not be able to use the mouse to interact with map elements or
these tools will pause the game when they open, regardless of your settings in pause/unpause the game. Therefore, these tools will pause the game when they
`gui/control-panel`. You can still unpause with the keyboard (spacebar by default), open, regardless of your settings in `gui/control-panel`. You can still unpause
though. with the keyboard (spacebar by default), though.
Where do I go next? Where do I go next?
------------------- -------------------
To recap: To recap:
You can get to popular, relevant tools for the current context by hovering You can get to popular, relevant tools for the current context by clicking on
the mouse over the DFHack logo or by hitting Ctrl-Shift-C. the DFHack logo or by hitting Ctrl-Shift-C.
You can enable DFHack tools and configure settings with `gui/control-panel`, You can enable DFHack tools and configure settings with `gui/control-panel`,
which you can access directly with the Ctrl-Shift-E hotkey. 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, 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 and help text by hitting backtick (\`) or Ctrl-Shift-D, or, of course, by
running it from the logo hover list. running it from the logo menu list.
With those three interfaces, you have the complete DFHack tool suite at your With those three interfaces, you have the complete DFHack tool suite at your
fingertips. So what to run first? Here are a few commands to get you started. fingertips. So what to run first? Here are a few examples to get you started.
You can run them all from the launcher.
First, let's import some useful manager orders to keep your fort stocked with 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 basic necessities. Run ``orders import library/basic``. If you go to your
mangager orders screen, you can see all the orders that have been created for you. manager orders screen, you can see all the orders that have been created for
Note that you could have imported the orders directly from this screen as well, you. Note that you could have imported the orders directly from this screen as
using the DFHack `overlay` widget at the bottom of the manager orders panel. 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 select ``autochop`` in the Next, try setting up `autochop` to automatically designate trees for chopping
``Fort`` list. Click on the button to the left of the name or hit Enter to enable when you get low on usable logs. Run `gui/control-panel` and select
it. You can then click on the configure button (the gear icon) to launch ``autochop`` in the ``Fort`` list. Click on the button to the left of the name
`gui/autochop` if you'd like to customize its settings. If you have the extra or hit Enter to enable it. You can then click on the configure button (the gear
screen space, you can go ahead and set the `gui/autochop` window to minimal mode icon) to launch `gui/autochop` if you'd like to customize its settings. If you
(click on the hint near the upper right corner of the window or hit Alt-M) and have the extra screen space, you can go ahead and set the `gui/autochop` window
click on the map so the window loses keyboard focus. As you play the game, you can to minimal mode (click on the hint near the upper right corner of the window or
glance at the live status panel to check on your stocks of wood. 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
Finally, let's do some fort design copy-pasting. Go to some bedrooms that you have wood.
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), typing "rooms" (or whatever) Finally, let's do some fort design copy-pasting. Go to some bedrooms that you
and hitting Enter to set. Then draw a box around the target area by clicking with have set up in your fort. Run `gui/blueprint`, set a name for your blueprint by
the mouse. When you select the second corner, the blueprint will be saved to your clicking on the name field (or hitting the 'n' hotkey), typing "rooms" (or
``blueprints`` subfolder. whatever) and hitting 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
Now open up `gui/quickfort`. You can search for the blueprint you just created by be saved to your ``dfhack-config/blueprints`` subfolder.
typing its name, but it should be up near the top already. If you copied a dug-out
area with furniture in it, your blueprint will have two labels: "/dig" and "/build". Now open up `gui/quickfort`. You can search for the blueprint you just created
Click on the "/dig" blueprint or select it with the keyboard arrow keys and hit Enter. by typing its name, but it should be up near the top already. If you copied a
You can rotate or flip the blueprint around if you need to with the transform hotkeys. dug-out area with furniture in it, your blueprint will have two labels: "/dig"
You'll see a preview of where the blueprint will be applied as you move the mouse and "/build". Click on the "/dig" blueprint or select it with the keyboard
cursor around the map. Red outlines mean that the blueprint may fail to fully apply arrow keys and hit Enter. You can rotate or flip the blueprint around if you
at that location, so be sure to choose a spot where all the preview tiles are shown need to with the transform hotkeys. You'll see a preview of where the blueprint
with green diamonds. Click the mouse or hit Enter to apply the blueprint and will be applied as you move the mouse cursor around the map. Red outlines mean
designate the tiles for digging. Your dwarves will come and dig it out as if you that the blueprint may fail to fully apply at that location, so be sure to
had designated the tiles yourself. 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
Once the area is dug out, run `gui/quickfort` again and select the "/build" blueprint digging. Your dwarves will come and dig it out as if you had designated the
this time. Apply the blueprint in the dug-out area, and your furniture will be tiles yourself.
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 Once the area is dug out, run `gui/quickfort` again and select your "/build"
materials in stock. The planned furniture/buildings will get built whenever you are blueprint this time. Hit ``o`` to generate manager orders for the required
able to produce the building materials. furniture. 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. Have fun! There are many, many more tools to explore. Have fun!

@ -21,7 +21,9 @@ for the tag assignment spreadsheet.
"why" tags "why" tags
---------- ----------
- `armok <armok-tag-index>`: Tools that give you complete control over an aspect of the game or provide access to information that the game intentionally keeps hidden. - `armok <armok-tag-index>`: Tools which give the player god-like powers of any variety, such as control over game events, creating items from thin air, or viewing information the game intentionally keeps hidden. Players that do not wish to see these tools listed in DFHack command lists can hide them in the ``Preferences`` tab of `gui/control-panel`.
- `auto <auto-tag-index>`: Tools that run in the background and automatically manage routine, toilsome aspects of your fortress. - `auto <auto-tag-index>`: Tools that run in the background and automatically manage routine, toilsome aspects of your fortress.
- `bugfix <bugfix-tag-index>`: Tools that fix specific bugs, either permanently or on-demand. - `bugfix <bugfix-tag-index>`: Tools that fix specific bugs, either permanently or on-demand.
- `design <design-tag-index>`: Tools that help you design your fort. - `design <design-tag-index>`: Tools that help you design your fort.

@ -3,8 +3,8 @@
DFHack tools DFHack tools
============ ============
DFHack has **a lot** of tools. This page attempts to make it clearer what they DFHack comes with **a lot** of tools. This page attempts to make it clearer
are, how they work, and how to find the ones you want. what they are, how they work, and how to find the ones you want.
.. contents:: Contents .. contents:: Contents
:local: :local:
@ -36,6 +36,12 @@ 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 `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 <all-tag-index>`. one flat list, please refer to the `annotated index <all-tag-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 <unavailable-tag-index>`. 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 DFHack tools by game mode
------------------------- -------------------------

@ -3,7 +3,7 @@ List of authors
The following is a list of people who have contributed to DFHack, in The following is a list of people who have contributed to DFHack, in
alphabetical order. 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! or make a pull request!
======================= ======================= =========================== ======================= ======================= ===========================
@ -12,6 +12,7 @@ Name Github Other
8Z 8Z 8Z 8Z
Abel abstern Abel abstern
acwatkins acwatkins acwatkins acwatkins
Alex Blamey Cubittus
Alexander Collins gearsix Alexander Collins gearsix
Alexander Gavrilov angavrilov ag Alexander Gavrilov angavrilov ag
Amber Brown hawkowl Amber Brown hawkowl
@ -82,6 +83,7 @@ Herwig Hochleitner bendlas
Hevlikn Hevlikn Hevlikn Hevlikn
Ian S kremlin- Ian S kremlin-
IndigoFenix IndigoFenix
Jacek Konieczny Jajcus
James 20k James 20k
James Gilles kazimuth James Gilles kazimuth
James Logsdon jlogsdon James Logsdon jlogsdon
@ -128,13 +130,16 @@ Michael Crouch creidieki
Michon van Dooren MaienM Michon van Dooren MaienM
miffedmap miffedmap miffedmap miffedmap
Mike Stewart thewonderidiot Mike Stewart thewonderidiot
Mikhail Panov Halifay
Mikko Juola Noeda Adeon Mikko Juola Noeda Adeon
Milo Christiansen milochristiansen Milo Christiansen milochristiansen
MithrilTuxedo MithrilTuxedo MithrilTuxedo MithrilTuxedo
mizipzor mizipzor mizipzor mizipzor
moversti moversti moversti moversti
mrrho mrrho
Murad Beybalaev Erquint Murad Beybalaev Erquint
Myk Taylor myk002 Myk Taylor myk002
Najeeb Al-Shabibi master-spike
napagokc napagokc napagokc napagokc
Neil Little nmlittle Neil Little nmlittle
Nick Rart nickrart comestible Nick Rart nickrart comestible
@ -158,6 +163,7 @@ Petr Mrázek peterix
Pfhreak Pfhreak Pfhreak Pfhreak
Pierre Lulé plule Pierre Lulé plule
Pierre-David Bélanger pierredavidbelanger Pierre-David Bélanger pierredavidbelanger
PopnROFL PopnROFL
potato potato
ppaawwll ppaawwll 🐇🐇🐇🐇 ppaawwll ppaawwll 🐇🐇🐇🐇
Priit Laes plaes Priit Laes plaes
@ -192,6 +198,7 @@ rubybrowncoat rubybrowncoat
Rumrusher rumrusher Rumrusher rumrusher
RusAnon RusAnon RusAnon RusAnon
Ryan Bennitt ryanbennitt Ryan Bennitt ryanbennitt
Ryan Dwyer ToxicBananaParty Jimdude2435
Ryan Williams Bumber64 Bumber Ryan Williams Bumber64 Bumber
sami sami
scamtank scamtank scamtank scamtank
@ -200,7 +207,9 @@ Sebastian Wolfertz Enkrod
SeerSkye SeerSkye SeerSkye SeerSkye
seishuuu seishuuu seishuuu seishuuu
Seth Woodworth sethwoodworth Seth Woodworth sethwoodworth
shevernitskiy shevernitskiy
Shim Panze Shim-Panze Shim Panze Shim-Panze
Silver silverflyone
simon simon
Simon Jackson sizeak Simon Jackson sizeak
Simon Lees simotek Simon Lees simotek
@ -235,6 +244,7 @@ ViTuRaS ViTuRaS
Vjek vjek Vjek vjek
Warmist warmist Warmist warmist
Wes Malone wesQ3 Wes Malone wesQ3
Will H TSM-EVO
Will Rogers wjrogers Will Rogers wjrogers
WoosterUK WoosterUK WoosterUK WoosterUK
XianMaeve XianMaeve XianMaeve XianMaeve

@ -10,6 +10,13 @@ work (e.g. links from the `changelog`).
:local: :local:
:depth: 1 :depth: 1
.. _workorder-recheck:
workorder-recheck
=================
Tool to set 'Checking' status of the selected work order, allowing conditions to be
reevaluated. Merged into `orders`.
.. _autohauler: .. _autohauler:
autohauler autohauler
@ -26,6 +33,20 @@ Moved frequently used materials to the top of the materials list when building
buildings. Also offered extended options when building constructions. All buildings. Also offered extended options when building constructions. All
functionality has been merged into `buildingplan`. 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:
autounsuspend autounsuspend
@ -56,7 +77,7 @@ Replaced by `gui/launcher --minimal <gui/launcher>`.
create-items create-items
============ ============
Replaced by `gui/create-item --multi <gui/create-item>`. Replaced by `gui/create-item`.
.. _deteriorateclothes: .. _deteriorateclothes:
@ -152,6 +173,12 @@ This script is no longer useful in current DF versions. The script required a
binpatch <binpatches/needs-patch>`, which has not been available since DF binpatch <binpatches/needs-patch>`, which has not been available since DF
0.34.11. 0.34.11.
.. _gui/automelt:
gui/automelt
============
Replaced by the `stockpiles` overlay and the gui for `logistics`.
.. _gui/dig: .. _gui/dig:
gui/dig gui/dig
@ -164,6 +191,12 @@ gui/hack-wish
============= =============
Replaced by `gui/create-item`. Replaced by `gui/create-item`.
.. _gui/mechanisms:
gui/mechanisms
==============
Linked building interface has been added to the vanilla UI.
.. _gui/no-dfhack-init: .. _gui/no-dfhack-init:
gui/no-dfhack-init gui/no-dfhack-init
@ -193,6 +226,12 @@ ruby
Support for the Ruby language in DFHack scripts was removed due to the issues Support for the Ruby language in DFHack scripts was removed due to the issues
the Ruby library causes when used as an embedded language. the Ruby library causes when used as an embedded language.
.. _search-plugin:
search
======
Functionality was merged into `sort`.
.. _show-unit-syndromes: .. _show-unit-syndromes:
show-unit-syndromes show-unit-syndromes
@ -206,6 +245,12 @@ stocksettings
Along with ``copystock``, ``loadstock`` and ``savestock``, replaced with the new Along with ``copystock``, ``loadstock`` and ``savestock``, replaced with the new
`stockpiles` API. `stockpiles` API.
.. _title-version:
title-version
=============
Replaced with an `overlay`.
.. _warn-stuck-trees: .. _warn-stuck-trees:
warn-stuck-trees warn-stuck-trees

@ -33,6 +33,11 @@ The ``<key>`` parameter above has the following **case-sensitive** syntax::
where the ``KEY`` part can be any recognized key and :kbd:`[`:kbd:`]` denote where the ``KEY`` part can be any recognized key and :kbd:`[`:kbd:`]` denote
optional parts. optional parts.
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 When multiple commands are bound to the same key combination, DFHack selects
the first applicable one. Later ``add`` commands, and earlier entries within one the first applicable one. Later ``add`` commands, and earlier entries within one
``add`` command have priority. Commands that are not specifically intended for ``add`` command have priority. Commands that are not specifically intended for

@ -22,61 +22,411 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
spans multiple lines. Three ``]`` characters indicate the end of such a block. 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 phrase set up to be replaced (see gen_changelog.py) stops that occurrence from being replaced.
Template for new versions:
## New Tools
## New Features
## Fixes
## Misc Improvements
## Documentation
## API
## Lua
## Removed
===end ===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 ======== ======== making a new DFHack release, even if the only changes made ========
======== were in submodules with their own changelogs! ======== ======== were in submodules with their own changelogs! ========
================================================================================ ================================================================================
# Future # Future
## 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
## 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 work animal assignment screen; allow filtering by miltary/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
## 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
## Removed
# 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 possilbe 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 propery 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 foereground.
## 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 propery 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 ## New Plugins
- `faststart`: speeds up the "Loading..." screen so the Main Menu appears sooner - `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 ## Fixes
- `hotkeys`: hotkey hints on menu popup will no longer get their last character cut off by the scrollbar - `buildingplan`: don't include artifacts when max quality is masterful
- ``launchdf``: launch Dwarf Fortress via the Steam client so Steam Workshop is functional - `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 - `blueprint`: interpret saplings, shrubs, and twigs as floors instead of walls
- `combine`: fix error processing stockpiles with boundaries that extend outside of the map - `combine`: fix error processing stockpiles with boundaries that extend outside of the map
- `prospector`: display both "raw" Z levels and "cooked" elevations -@ `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 ## Misc Improvements
- `buildingplan`: items in the item selection dialog should now use the same item quality symbols as the base game -@ `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`: 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 ``planneroverlay`` interface
-@ `buildingplan`: rearranged elements of ``itemselection`` 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 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: 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 -@ 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 - `gui/control-panel`: bugfix services are now enabled by default
- Core: hide DFHack terminal console by default when running on Steam Deck
## Documentation ## Documentation
- `installing`: updated to include Steam installation instructions
## API
## Lua ## 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`` - 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``
## Removed
# 50.07-beta2 # 50.07-beta2
## New Plugins ## New Plugins
- `getplants`: designate trees for chopping and shrubs for gathering according to type - `getplants`: reinstated: designate trees for chopping and shrubs for gathering according to type
- `prospector`: get stone, ore, gem, and other tile property counts in fort mode. embark site estimates are not yet available. - `prospector`: reinstated: get stone, ore, gem, and other tile property counts in fort mode.
## Fixes ## Fixes
- `buildingplan`: filters are now properly applied to planned stairs -@ `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`: 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`: 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`: 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`: 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) -@ `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`: properly discriminate between dyed and undyed cloth
- `tailor`: no longer default to using adamantine cloth for producing clothes -@ `tailor`: no longer default to using adamantine cloth for producing clothes
- `tailor`: take queued orders into account when calculating available materials - `tailor`: take queued orders into account when calculating available materials
- `tailor`: skip units who can't wear clothes - `tailor`: skip units who can't wear clothes
- `tailor`: identify more available items as available, solving issues with over-production - `tailor`: identify more available items as available, solving issues with over-production
@ -95,17 +445,17 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
- `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 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 - `orders`: add option to delete exported files from the import dialog
- `enable`: can now interpret aliases defined with the `alias` command - `enable`: can now interpret aliases defined with the `alias` command
- scripts in ``data/installed mods/`` subfolders 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. - 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 ## Documentation
- `modding-guide`: guide updated to include information for 3rd party script developers - `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 unavaialable 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. - the ``untested`` tag has been renamed to ``unavailable`` to better reflect the status of the remaining unavaialable 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 ## Lua
- ``widget.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``: tokens can now specify a ``htile`` property to indicate the tile that should be shown when the Label is hovered over with the mouse
- ``widget.Label``: click handlers no longer get the label itself as the first param to the click handler - ``widgets.Label``: click handlers no longer get the label itself as the first param to the click handler
- ``widget.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``: options that are bare integers will no longer be interpreted as the pen color in addition to being the label and value
- ``widget.CycleHotkeyLabel``: option labels and pens can now be functions that return a label or pen - ``widgets.CycleHotkeyLabel``: option labels and pens can now be functions that return a label or pen
# 50.07-beta1 # 50.07-beta1
@ -167,14 +517,14 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
## Fixes ## Fixes
-@ `nestboxes`: fixed bug causing nestboxes themselves to be forbidden, which prevented citizens from using them to lay eggs. Now only eggs are forbidden. -@ `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. -@ `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 -@ `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. - `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 -@ `autochop`: generate default names for burrows with no assigned names
- ``Buildings::StockpileIterator``: fix check for stockpile items on block boundary. - ``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 - `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 -@ `confirm`: fix fps drop when enabled
- `channel-safely`: fix an out of bounds error regarding the REPORT event listener receiving (presumably) stale id's -@ `channel-safely`: fix an out of bounds error regarding the REPORT event listener receiving (presumably) stale id's
## Misc Improvements ## Misc Improvements
- `autobutcher`: logs activity to the console terminal instead of making disruptive in-game announcements - `autobutcher`: logs activity to the console terminal instead of making disruptive in-game announcements
@ -198,13 +548,13 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
## Fixes ## Fixes
- ``Units::isFortControlled``: Account for agitated wildlife - ``Units::isFortControlled``: Account for agitated wildlife
-@ Fix right click sometimes closing both a DFHack window and a vanilla panel -@ 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 -@ 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 -@ `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 -@ `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 -@ `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 -@ `nestboxes`: now cancels any in-progress hauling jobs when it protects a fertile egg
-@ Fix persisted data not being written on manual save -@ 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 -@ `nestboxes`: now scans for eggs more frequently and cancels any in-progress hauling jobs when it protects a fertile egg
## Misc Improvements ## Misc Improvements
-@ `automelt`: is now more resistent to vanilla savegame corruption -@ `automelt`: is now more resistent to vanilla savegame corruption
@ -296,7 +646,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
# 50.05-alpha2 # 50.05-alpha2
## Fixes ## Fixes
- `autofarm`: don't duplicate status line entries for crops with no current supply -@ `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) -@ `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 - `tailor`: now respects the setting of the "used dyed clothing" standing order toggle

@ -306,7 +306,32 @@ All types and the global object have the following features:
* ``type._identity`` * ``type._identity``
Contains a lightuserdata pointing to the underlying Contains a lightuserdata pointing to the underlying
``DFHack::type_instance`` object. ``DFHack::type_identity`` object.
All compound types (structs, classes, unions, and the global object) support:
* ``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: Types excluding the global object also support:
@ -659,7 +684,7 @@ Persistent configuration storage
-------------------------------- --------------------------------
This api is intended for storing configuration options in the world itself. This api is intended for storing configuration options in the world itself.
It probably should be restricted to data that is world-dependent. It is intended for data that is world-dependent.
Entries are identified by a string ``key``, but it is also possible to manage 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``. multiple entries with the same key; their identity is determined by ``entry_id``.
@ -692,10 +717,8 @@ Every entry has a mutable string ``value``, and an array of 7 mutable ``ints``.
otherwise the existing one is simply updated. otherwise the existing one is simply updated.
Returns *entry, did_create_new* Returns *entry, did_create_new*
Since the data is hidden in data structures owned by the DF world, The data is kept in memory, so no I/O occurs when getting or saving keys. It is
and automatically stored in the save game, these save and retrieval all written to a json file in the game save directory when the game is saved.
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, It is also possible to associate one bit per map tile with an entry,
using these two methods: using these two methods:
@ -985,41 +1008,26 @@ General-purpose selections
~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~
* ``dfhack.gui.getSelectedWorkshopJob([silent])`` * ``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])`` * ``dfhack.gui.getSelectedJob([silent])``
Returns the job selected in a workshop or unit/jobs screen.
* ``dfhack.gui.getSelectedUnit([silent])`` * ``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])`` * ``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])`` * ``dfhack.gui.getSelectedBuilding([silent])``
Returns the building selected via :kbd:`q`, :kbd:`t`, :kbd:`k` or :kbd:`i`.
* ``dfhack.gui.getSelectedCivZone([silent])`` * ``dfhack.gui.getSelectedCivZone([silent])``
* ``dfhack.gui.getSelectedStockpile([silent])``
Returns the zone currently selected via :kbd:`z`
* ``dfhack.gui.getSelectedPlant([silent])`` * ``dfhack.gui.getSelectedPlant([silent])``
Returns the plant selected via :kbd:`k`. 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
ommitted or set to ``false`` and a selected object cannot be found, then an
error is printed to the console.
* ``dfhack.gui.getAnyUnit(screen)`` * ``dfhack.gui.getAnyUnit(screen)``
* ``dfhack.gui.getAnyItem(screen)`` * ``dfhack.gui.getAnyItem(screen)``
* ``dfhack.gui.getAnyBuilding(screen)`` * ``dfhack.gui.getAnyBuilding(screen)``
* ``dfhack.gui.getAnyCivZone(screen)``
* ``dfhack.gui.getAnyStockpile(screen)``
* ``dfhack.gui.getAnyPlant(screen)`` * ``dfhack.gui.getAnyPlant(screen)``
Similar to the corresponding ``getSelected`` functions, but operate on the Similar to the corresponding ``getSelected`` functions, but operate on the
@ -1045,11 +1053,13 @@ Fortress mode
Same as ``resetDwarfmodeView``, but also recenter if position is valid. If ``pause`` is false, skip pausing. Respects 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.) ``RECENTER_INTERFACE_SHUTDOWN_MS`` in DF's ``init.txt`` (the delay before input is recognized when a recenter occurs.)
* ``dfhack.gui.revealInDwarfmodeMap(pos[,center])`` * ``dfhack.gui.revealInDwarfmodeMap(pos[,center[,highlight]])``
``dfhack.gui.revealInDwarfmodeMap(x,y,z[,center])`` ``dfhack.gui.revealInDwarfmodeMap(x,y,z[,center[,highlight]])``
Centers the view on the given coordinates. If ``center`` is true, make sure the Centers the view on the given coordinates. If ``center`` is true, make sure
position is in the exact center of the view, else just bring it on screen. 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`), ``pos`` can be a ``df.coord`` instance or a table assignable to a ``df.coord`` (see `lua-api-table-assignment`),
e.g.:: e.g.::
@ -1130,10 +1140,12 @@ Announcements
If you want a guaranteed announcement without parsing, use ``dfhack.gui.showAutoAnnouncement`` instead. If you want a guaranteed announcement without parsing, use ``dfhack.gui.showAutoAnnouncement`` instead.
* ``dfhack.gui.getMousePos()`` * ``dfhack.gui.getMousePos([allow_out_of_bounds])``
Returns the map coordinates of the map tile the mouse is over as a table of 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 the map, returns ``nil``. ``{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 Other
~~~~~ ~~~~~
@ -1355,11 +1367,16 @@ Units module
* ``dfhack.units.isTame(unit)`` * ``dfhack.units.isTame(unit)``
* ``dfhack.units.isTamable(unit)`` * ``dfhack.units.isTamable(unit)``
* ``dfhack.units.isDomesticated(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.isMarkedForSlaughter(unit)``
* ``dfhack.units.isMarkedForGelding(unit)`` * ``dfhack.units.isMarkedForGelding(unit)``
* ``dfhack.units.isGeldable(unit)`` * ``dfhack.units.isGeldable(unit)``
* ``dfhack.units.isGelded(unit)`` * ``dfhack.units.isGelded(unit)``
* ``dfhack.units.isEggLayer(unit)`` * ``dfhack.units.isEggLayer(unit)``
* ``dfhack.units.isEggLayerRace(unit)``
* ``dfhack.units.isGrazer(unit)`` * ``dfhack.units.isGrazer(unit)``
* ``dfhack.units.isMilkable(unit)`` * ``dfhack.units.isMilkable(unit)``
@ -1438,10 +1455,22 @@ Units module
Note that ``pos2xyz()`` cannot currently be used to convert coordinate objects to Note that ``pos2xyz()`` cannot currently be used to convert coordinate objects to
the arguments required by this function. the arguments required by this function.
* ``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([ignore_sanity])`` * ``dfhack.units.getCitizens([ignore_sanity])``
Returns a table (list) of all citizens, which you would otherwise have to loop over all Returns a list of all living citizens.
units in world and test against ``isCitizen()`` to discover.
* ``dfhack.units.teleport(unit, pos)`` * ``dfhack.units.teleport(unit, pos)``
@ -1487,6 +1516,11 @@ Units module
Computes the effective attribute value, including curse effect. 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])`` * ``dfhack.units.getMiscTrait(unit, type[, create])``
Finds (or creates if requested) a misc trait object with the given id. Finds (or creates if requested) a misc trait object with the given id.
@ -1576,6 +1610,12 @@ Units module
Currently only one dream per unit is supported by Dwarf Fortress. Currently only one dream per unit is supported by Dwarf Fortress.
Support for multiple dreams may be added in future versions of Dwarf Fortress. Support for multiple dreams may be added in future versions of Dwarf Fortress.
* ``dfhack.units.getReadableName(unit)``
Returns a string that includes the language name of the unit (if any), the
race of the unit, whether it is trained for war or hunting, and any
syndrome-given descriptions (such as "necromancer").
* ``dfhack.units.getStressCategory(unit)`` * ``dfhack.units.getStressCategory(unit)``
Returns a number from 0-6 indicating stress. 0 is most stressed; 6 is least. Returns a number from 0-6 indicating stress. 0 is most stressed; 6 is least.
@ -1755,9 +1795,17 @@ Items module
Calculates the base value for an item of the specified type and material. Calculates the base value for an item of the specified type and material.
* ``dfhack.items.getValue(item)`` * ``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.main_interface.trade.mer``), then the value is modified by civ
properties and any trade agreements that might be in effect.
Calculates the Basic Value of an item, as seen in the View Item screen. * ``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.createItem(item_type, item_subtype, mat_type, mat_index, unit)`` * ``dfhack.items.createItem(item_type, item_subtype, mat_type, mat_index, unit)``
@ -1773,7 +1821,16 @@ Items module
* ``dfhack.items.canTradeWithContents(item)`` * ``dfhack.items.canTradeWithContents(item)``
Checks whether the item and all items it contains, if any, can be traded. 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.isRouteVehicle(item)`` * ``dfhack.items.isRouteVehicle(item)``
@ -1905,10 +1962,11 @@ Maps module
Returns the plant struct that owns the tile at the specified position. Returns the plant struct that owns the tile at the specified position.
* ``dfhack.maps.canWalkBetween(pos1, pos2)`` * ``dfhack.maps.getWalkableGroup(pos)``
Checks if a dwarf may be able to walk between the two tiles, Returns the walkability group for the given tile position. A return value of
using a pathfinding cache maintained by the game. ``0`` indicates that the tile is not walkable. The data comes from a
pathfinding cache maintained by DF.
.. note:: .. note::
This cache is only updated when the game is unpaused, and thus This cache is only updated when the game is unpaused, and thus
@ -1917,6 +1975,10 @@ Maps module
take into account anything that depends on the actual units, like take into account anything that depends on the actual units, like
burrows, or the presence of invaders. 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)`` * ``dfhack.maps.hasTileAssignment(tilemask)``
Checks if the tile_bitmask object is not *nil* and contains any set bits; returns *true* or *false*. Checks if the tile_bitmask object is not *nil* and contains any set bits; returns *true* or *false*.
@ -1937,9 +1999,11 @@ Maps module
Burrows module Burrows module
-------------- --------------
* ``dfhack.burrows.findByName(name)`` * ``dfhack.burrows.findByName(name[, ignore_final_plus])``
Returns the burrow pointer or *nil*. 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)`` * ``dfhack.burrows.clearUnits(burrow)``
@ -1992,9 +2056,9 @@ General
Searches for a specific_ref with the given type. Searches for a specific_ref with the given type.
* ``dfhack.buildings.setOwner(item,unit)`` * ``dfhack.buildings.setOwner(civzone,unit)``
Replaces the owner of the building. If unit is *nil*, removes ownership. Replaces the owner of the civzone. If unit is *nil*, removes ownership.
Returns *false* in case of error. Returns *false* in case of error.
* ``dfhack.buildings.getSize(building)`` * ``dfhack.buildings.getSize(building)``
@ -2522,10 +2586,10 @@ Supported callbacks and fields are:
Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code for convenience. Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code for convenience.
``_MOUSE_L, _MOUSE_R, _MOUSE_M`` ``_MOUSE_L, _MOUSE_R, _MOUSE_M``
If the left, right, and/or middle mouse button is being pressed. If the left, right, and/or middle mouse button was just pressed.
``_MOUSE_L_DOWN, _MOUSE_R_DOWN, _MOUSE_M_DOWN`` ``_MOUSE_L_DOWN, _MOUSE_R_DOWN, _MOUSE_M_DOWN``
If the left, right, and/or middle mouse button was just pressed. 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. If this method is omitted, the screen is dismissed on reception of the ``LEAVESCREEN`` key.
@ -2575,6 +2639,67 @@ a ``dfhack.penarray`` instance to cache their output.
``bufferx`` and ``buffery`` default to 0. ``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 <lua-screen-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 Filesystem module
----------------- -----------------
@ -2745,6 +2870,11 @@ and are only documented here for completeness:
The oldval, newval or delta arguments may be used to specify additional constraints. The oldval, newval or delta arguments may be used to specify additional constraints.
Returns: *found_index*, or *nil* if end reached. 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)`` * ``dfhack.internal.getDir(path)``
Lists files/directories in a directory. Lists files/directories in a directory.
@ -2816,6 +2946,67 @@ and are only documented here for completeness:
Returns a numeric identifier of the current thread. 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 (ie valid).
Requires a heap snapshot.
* ``dfhack.internal.isAddressUsedAfterFreeInHeap(address)``
Checks if an address is a member of the heap, but is not currently allocated (ie 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.
Eg, 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.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.
.. _lua-core-context: .. _lua-core-context:
Core interpreter context Core interpreter context
@ -2950,6 +3141,9 @@ environment by the mandatory init file dfhack.lua:
COLOR_LIGHTBLUE, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN, COLOR_LIGHTRED, COLOR_LIGHTBLUE, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN, COLOR_LIGHTRED,
COLOR_LIGHTMAGENTA, COLOR_YELLOW, COLOR_WHITE COLOR_LIGHTMAGENTA, COLOR_YELLOW, COLOR_WHITE
``COLOR_GREY`` and ``COLOR_DARKGREY`` can also be spelled ``COLOR_GRAY`` and
``COLOR_DARKGRAY``.
* State change event codes, used by ``dfhack.onStateChange`` * State change event codes, used by ``dfhack.onStateChange``
Available only in the `core context <lua-core-context>`, as is the event itself: Available only in the `core context <lua-core-context>`, as is the event itself:
@ -3019,6 +3213,11 @@ environment by the mandatory init file dfhack.lua:
set to the value of ``default_value``, which defaults to ``{}`` if not set. set to the value of ``default_value``, which defaults to ``{}`` if not set.
The new or existing value of ``t[key]`` is then returned. 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: .. _lua-string:
String class extensions String class extensions
@ -3201,6 +3400,20 @@ utils
Exactly like ``erase_sorted_key``, but if field is specified, takes the key from ``item[field]``. 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,...)`` * ``utils.call_with_string(obj,methodname,...)``
Allocates a temporary string object, calls ``obj:method(tmp,...)``, and Allocates a temporary string object, calls ``obj:method(tmp,...)``, and
@ -3411,6 +3624,13 @@ parameters.
``tonumber(arg)``. If ``arg_name`` is specified, it is used to make error ``tonumber(arg)``. If ``arg_name`` is specified, it is used to make error
messages more useful. 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 dumper
====== ======
@ -3807,6 +4027,14 @@ Misc
of keycodes to *true* or *false*. For instance, it is possible to use the of keycodes to *true* or *false*. For instance, it is possible to use the
table passed as argument to ``onInput``. table passed as argument to ``onInput``.
You can send mouse clicks as will 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)`` * ``mkdims_xy(x1,y1,x2,y2)``
Returns a table containing the arguments as fields, and also ``width`` and Returns a table containing the arguments as fields, and also ``width`` and
@ -4240,11 +4468,11 @@ 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 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. control what kind of unhandled input is passed to the lower layers.
If multiple ZScreens are visible and the player left or right clicks on a If multiple ZScreens are visible and the player scrolls or left/right clicks on
visible element of a non-focused ZScreen, that ZScreen will be given focus. This a visible element of a non-focused ZScreen, that ZScreen will be given focus.
allows multiple DFHack GUI tools to be usable at the same time. If the mouse is This allows multiple DFHack GUI tools to be usable at the same time. If the
clicked away from the ZScreen widgets, that ZScreen loses focus. If no ZScreen mouse is clicked away from the ZScreen widgets, that ZScreen loses focus. If no
has focus, all input is passed directly through to the first underlying ZScreen has focus, all input is passed directly through to the first underlying
non-ZScreen viewscreen. non-ZScreen viewscreen.
For a ZScreen with keyboard focus, if :kbd:`Esc` or the right mouse button is For a ZScreen with keyboard focus, if :kbd:`Esc` or the right mouse button is
@ -4371,6 +4599,13 @@ Here is an example skeleton for a ZScreen tool window::
view = view and view:raise() or MyScreen{}:show() 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.
FramedScreen class FramedScreen class
------------------ ------------------
@ -4388,32 +4623,36 @@ A framed screen has the following attributes:
There are the following predefined frame style tables: There are the following predefined frame style tables:
* ``WINDOW_FRAME`` * ``FRAME_WINDOW``
A frame suitable for a draggable, optionally resizable window. A frame suitable for a draggable, optionally resizable window.
* ``PANEL_FRAME`` * ``FRAME_PANEL``
A frame suitable for a static (non-draggable, non-resizable) panel. A frame suitable for a static (non-draggable, non-resizable) panel.
* ``MEDIUM_FRAME`` * ``FRAME_MEDIUM``
A frame suitable for overlay widget panels. A frame suitable for overlay widget panels.
* ``BOLD_FRAME`` * ``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, A frame suitable for a non-draggable panel meant to capture the user's focus,
like an important notification, confirmation dialog or error message. like an important notification, confirmation dialog or error message.
* ``INTERIOR_FRAME`` * ``FRAME_INTERIOR``
A frame suitable for light interior accent elements. This frame does *not* 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 most have a visible ``DFHack`` signature on it, so it must not be used as the most
external frame for a DFHack-owned UI. external frame for a DFHack-owned UI.
* ``INTERIOR_MEDIUM_FRAME`` * ``FRAME_INTERIOR_MEDIUM``
A copy of ``MEDIUM_FRAME`` that lacks the ``DFHack`` signature. Suitable for 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 panels that are part of a larger widget cluster. Must *not* be used as the
most external frame for a DFHack-owned UI. most external frame for a DFHack-owned UI.
@ -4496,15 +4735,15 @@ Has attributes:
Called from ``postComputeFrame``. Called from ``postComputeFrame``.
* ``draggable = bool`` (default: ``false``) * ``draggable = bool`` (default: ``false``)
* ``drag_anchors = {}`` (default: ``{title=true, frame=false, body=false}``) * ``drag_anchors = {}`` (default: ``{title=true, frame=false/true, body=true}``)
* ``drag_bound = 'frame' or 'body'`` (default: ``'frame'``) * ``drag_bound = 'frame' or 'body'`` (default: ``'frame'``)
* ``on_drag_begin = function()`` (default: ``nil``) * ``on_drag_begin = function()`` (default: ``nil``)
* ``on_drag_end = function(bool)`` (default: ``nil``) * ``on_drag_end = function(success, new_frame)`` (default: ``nil``)
If ``draggable`` is set to ``true``, then the above attributes come into play 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 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 keyboard. ``drag_anchors`` sets which parts of the panel can be clicked on
with the left mouse button to start dragging. ``drag_bound`` configures 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 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, 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 but you can allow the frame to cross the boundary by setting ``drag_bound`` to
@ -4513,13 +4752,15 @@ Has attributes:
otherwise. Dragging can be canceled by right clicking while dragging with the 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 mouse, hitting :kbd:`Esc` (while dragging with the mouse or keyboard), or by
calling ``Panel:setKeyboaredDragEnabled(false)`` (while dragging with the calling ``Panel:setKeyboaredDragEnabled(false)`` (while dragging with the
keyboard). 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``) * ``resizable = bool`` (default: ``false``)
* ``resize_anchors = {}`` (default: ``{t=false, l=true, r=true, b=true}`` * ``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}``) * ``resize_min = {}`` (default: w and h from the ``frame``, or ``{w=5, h=5}``)
* ``on_resize_begin = function()`` (default: ``nil``) * ``on_resize_begin = function()`` (default: ``nil``)
* ``on_resize_end = function(bool)`` (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 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 any edge specified in ``resize_anchors`` and drag the border to resize the
@ -4533,6 +4774,9 @@ Has attributes:
Dragging can be canceled by right clicking while resizing with the mouse, 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 hitting :kbd:`Esc` (while resizing with the mouse or keyboard), or by calling
``Panel:setKeyboardResizeEnabled(false)`` (while resizing with the keyboard). ``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_subviews = bool`` (default: ``false``)
* ``autoarrange_gap = int`` (default: ``0``) * ``autoarrange_gap = int`` (default: ``0``)
@ -4577,6 +4821,15 @@ Has functions:
commit the new window size or :kbd:`Esc` to cancel. If resizing is canceled, 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. 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: Double clicking:
If the panel is resizable and the user double-clicks on the top edge (the frame If the panel is resizable and the user double-clicks on the top edge (the frame
@ -4676,6 +4929,12 @@ following keyboard hotkeys:
- Ctrl-B/Ctrl-F: move the cursor one word back or forward. - Ctrl-B/Ctrl-F: move the cursor one word back or forward.
- Ctrl-A/Ctrl-E: move the cursor to the beginning/end of the text. - Ctrl-A/Ctrl-E: 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: The ``EditField`` class also provides the following functions:
* ``editfield:setCursor([cursor_pos])`` * ``editfield:setCursor([cursor_pos])``
@ -4953,12 +5212,17 @@ It has the following attributes:
:key: The hotkey keycode to display, e.g. ``'CUSTOM_A'``. :key: The hotkey keycode to display, e.g. ``'CUSTOM_A'``.
:key_back: Similar to ``key``, but will cycle backwards (optional) :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 :label: The string (or a function that returns a string) to display after the
hotkey. hotkey.
:label_width: The number of spaces to allocate to the ``label`` (for use in :label_width: The number of spaces to allocate to the ``label`` (for use in
aligning a column of ``CycleHotkeyLabel`` labels). aligning a column of ``CycleHotkeyLabel`` labels).
:label_below: If ``true``, then the option value will apear below the label :label_below: If ``true``, then the option value will appear below the label
instead of to the right of it. Defaults to ``false``. 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 :options: A list of strings or tables of
``{label=string or fn, value=val[, pen=pen]}``. String options use the same ``{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`` string for the label and value and use the default pen. The optional ``pen``
@ -4999,13 +5263,50 @@ The CycleHotkeyLabel widget implements the following methods:
selected option if no index is given. If an option was defined as just a 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. string, then this function will return ``nil`` for that option.
ToggleHotkeyLabel ToggleHotkeyLabel class
----------------- -----------------------
This is a specialized subclass of CycleHotkeyLabel that has two options: 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`` (with a value of ``true``) and ``Off`` (with a value of ``false``). The
``On`` option is rendered in green. ``On`` option is rendered in green.
HelpButton class
----------------
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`.
ConfigureButton class
---------------------
A 3x1 tile button with a gear mark on it, intended to represent a configure
icon. Clicking on the icon will run the given callback.
It has the following attributes:
:on_click: The function on run when the icon is clicked.
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 List class
---------- ----------
@ -5092,12 +5393,11 @@ FilteredList class
------------------ ------------------
This widget combines List, EditField and Label into a combo-box like This widget combines List, EditField and Label into a combo-box like
construction that allows filtering the list by subwords of its items. construction that allows filtering the list.
In addition to passing through all attributes supported by List, it In addition to passing through all attributes supported by List, it
supports: supports:
:case_sensitive: If ``true``, matching is case sensitive. Defaults to ``false``.
:edit_pen: If specified, used instead of ``cursor_pen`` for the edit field. :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_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_key: If specified, the edit field is disabled until this key is pressed.
@ -5142,6 +5442,14 @@ The widget implements:
Same as with an ordinary list. 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 with a command like::
:lua require('utils').FILTER_FULL_TEXT=true
TabBar class TabBar class
------------ ------------
@ -5149,7 +5457,9 @@ This widget implements a set of one or more tabs to allow navigation between gro
the width of the window and will continue rendering on the next line(s) if all tabs cannot fit on a single line. the width of the window and will continue rendering on the next line(s) if all tabs cannot fit on a single line.
:key: Specifies a keybinding that can be used to switch to the next tab. :key: Specifies a keybinding that can be used to switch to the next tab.
:key_back: Specifies a keybinding that can be used to switch to the previous 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 :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. 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 :on_select: Callback executed when a tab is selected. It receives the selected tab index as an argument. The provided function
@ -5178,6 +5488,45 @@ widget does not require direct usage of ``Tab``.
usage of ``Tab`` in ``TabBar:init()`` for an example. See the default value of ``active_tab_pens`` or ``inactive_tab_pens`` 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. 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.
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: .. _lua-plugins:
======= =======
@ -5315,51 +5664,6 @@ Native functions provided by the `buildingplan` plugin:
* ``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 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. * ``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-api: .. _cxxrandom-api:
cxxrandom cxxrandom

@ -88,9 +88,9 @@ assistance.
All Platforms All Platforms
============= =============
Before you can compile the code you'll need to configure your build with cmake. Some IDEs can do this, Before you can compile the code you'll need to configure your build with cmake. Some IDEs can do this
but from command line is the usual way to do this; thought the Windows section below points out some for you, but it's more common to do it from the command line. Windows developers can refer to the
Windows batch files that can be used to avoid opening a terminal/command-prompt. 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 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. the `build-options` page for help finding the DFHack build options relevant to you.

@ -90,6 +90,10 @@ The ``overlay.OverlayWidget`` superclass defines the following class attributes:
This will be filled in with the display name of your widget, in case you This will be filled in with the display name of your widget, in case you
have multiple widgets with the same implementation but different have multiple widgets with the same implementation but different
configurations. configurations.
- ``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.
- ``default_pos`` (default: ``{x=-2, y=-2}``) - ``default_pos`` (default: ``{x=-2, y=-2}``)
Override this attribute with your desired default widget position. See Override this attribute with your desired default widget position. See
the `overlay` docs for information on what positive and negative numbers the `overlay` docs for information on what positive and negative numbers
@ -131,7 +135,10 @@ The ``overlay.OverlayWidget`` superclass defines the following class attributes:
seconds) that your widget can take to react to changes in information and 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 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, that running more often than you really need to will impact game FPS,
especially if your widget can run while the game is unpaused. 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.
Registering a widget with the overlay framework Registering a widget with the overlay framework
*********************************************** ***********************************************
@ -183,7 +190,7 @@ Scripts
#. If the script is not in your `script-paths`, install your script (see the #. 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 `modding-guide` for help setting up a dev environment so that you don't need
to reinstall your scripts after every edit). to reinstall your scripts after every edit).
#. Call ``:lua require('plugins.overlay').reload()`` to reload your overlay #. Call ``:lua require('plugins.overlay').rescan()`` to reload your overlay
widget widget
Plugins Plugins
@ -194,7 +201,7 @@ Plugins
:file:`hack/lua/plugins/` :file:`hack/lua/plugins/`
#. If you have changed the compiled plugin, `reload` it #. If you have changed the compiled plugin, `reload` it
#. If you have changed the lua code, run ``:lua reload('plugins.mypluginname')`` #. If you have changed the lua code, run ``:lua reload('plugins.mypluginname')``
#. Call ``:lua require('plugins.overlay').reload()`` to reload your overlay #. Call ``:lua require('plugins.overlay').rescan()`` to reload your overlay
widget widget
Troubleshooting Troubleshooting

@ -1,49 +0,0 @@
.. _config-examples-guide:
.. _dfhack-examples-guide:
DFHack config file examples
===========================
The :source:`hack/examples <data/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/ <data/dfhack-config/init/examples>` subfolder contains useful
DFHack `init-files` that you can copy into your :file:`dfhack-config/init`
folder -- the same directory as ``dfhack.init``.
.. _onMapLoad-dreamfort-init:
:source:`onMapLoad_dreamfort.init <data/dfhack-config/init/examples/onMapLoad_dreamfort.init>`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is the config file that designed for 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 scripts, 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 protect 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`.

@ -8,7 +8,5 @@ These pages are detailed guides covering DFHack tools.
:maxdepth: 1 :maxdepth: 1
/docs/guides/modding-guide /docs/guides/modding-guide
/docs/guides/examples-guide
/docs/guides/quickfort-library-guide /docs/guides/quickfort-library-guide
/docs/guides/quickfort-user-guide /docs/guides/quickfort-user-guide
/docs/guides/quickfort-alias-guide

@ -45,6 +45,7 @@ this::
info.txt info.txt
graphics/... graphics/...
objects/... objects/...
blueprints/...
scripts_modactive/example-mod.lua scripts_modactive/example-mod.lua
scripts_modactive/internal/example-mod/... scripts_modactive/internal/example-mod/...
scripts_modinstalled/... scripts_modinstalled/...
@ -58,6 +59,9 @@ Let's go through that line by line.
- Modifications to the game raws (potentially with custom raw tokens) go in - 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 :file:`graphics/` and :file:`objects/` folders. You can read more about
the files that go in these directories on the :wiki:`Modding` wiki page. 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
nothing else if you like.
- A control script in :file:`scripts_modactive/` directory that handles - A control script in :file:`scripts_modactive/` directory that handles
system-level event hooks (e.g. reloading state when a world is loaded), system-level event hooks (e.g. reloading state when a world is loaded),
registering `overlays <overlay-dev-guide>`, and registering `overlays <overlay-dev-guide>`, and

@ -1,875 +0,0 @@
.. _quickfort-alias-guide:
Quickfort keystroke alias reference
===================================
Aliases allow you to use simple words to represent complicated key sequences
when configuring buildings and stockpiles in quickfort ``#query`` and
``#config`` 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 <quickfort-alias-library>`.
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 <quickfort-aliases-blueprints>`
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 necessary. 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 <Quantum_stockpile#The_Minecart_Stop>`.
+----------------------+------------------+
| 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 <quickfort-stockpile-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 <quickfort-stockpile-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 configuration 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
forbidsearch search
permitsearch search
togglesearch search
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}^
``forbidsearch``, ``permitsearch``, and ``togglesearch`` use the DFHack
`search-plugin` plugin to forbid or permit a filtered list, or toggle the first
(or only) item in the list. Specify the search string in the ``search``
sub-alias. Be sure to move the cursor over to the right column before invoking
these aliases. The search filter will be cleared before this alias completes.
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 everything 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
usablehair forbidusablehair permitusablehair
craftrefuse forbidcraftrefuse permitcraftrefuse
=========== ================== ==================
Notes:
* ``usablehair`` Only hair and wool that can make usable clothing is included,
i.e. from sheep, llamas, alpacas, and trolls.
* ``craftrefuse`` includes everything a craftsdwarf or tailor can use: skulls,
bones, shells, teeth, horns, and "usable" hair/wool (defined above).
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
======================= ============================= =============================
stonetools
woodentools
crafts forbidcrafts permitcrafts
goblets forbidgoblets permitgoblets
masterworkfinishedgoods forbidmasterworkfinishedgoods permitmasterworkfinishedgoods
artifactfinishedgoods forbidartifactfinishedgoods permitartifactfinishedgoods
======================= ============================= =============================
Cloth stockpile adjustments
```````````````````````````
================ ====================== ======================
Exclusive Forbid Permit
================ ====================== ======================
thread forbidthread permitthread
adamantinethread forbidadamantinethread permitadamantinethread
cloth forbidcloth permitcloth
adamantinecloth forbidadamantinecloth permitadamantinecloth
================ ====================== ======================
Notes:
* ``thread`` and ``cloth`` refers to all materials that are not adamantine.
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
=============== ====================== =====================

@ -28,103 +28,117 @@ Dreamfort
Dreamfort is a fully functional, self-sustaining fortress with defenses, Dreamfort is a fully functional, self-sustaining fortress with defenses,
farming, a complete set of workshops, self-managing quantum stockpiles, a grand farming, a complete set of workshops, self-managing quantum stockpiles, a grand
dining hall, hospital, jail, fresh water well system, guildhalls, noble suites, dining hall, hospital (werecreature-ready), library, temple, jail, fresh water
and bedrooms for hundreds of dwarves. It also comes with manager work orders to well system, guildhalls, noble suites, and bedrooms for hundreds of dwarves. It
automate basic fort needs, such as food, booze, and item production. It can also comes with manager work orders to automate basic fort needs, such as food,
function by itself or as the core of a larger, more ambitious fortress. Read the booze, and item production. It can function by itself or as the core of a
high-level walkthrough by running ``quickfort run library/dreamfort.csv`` and larger, more ambitious fortress. Read the walkthrough by running
list the walkthroughs for the individual levels by running ``quickfort list `gui/quickfort`, searching for ``dreamfort help``, and selecting the blueprints.
dreamfort notes`` or ``gui/quickfort dreamfort notes``.
Dreamfort blueprints are available for easy viewing and copying `online Dreamfort blueprints are available for easy viewing and copying `online
<https://drive.google.com/drive/folders/1iS90EEVqUkxTeZiiukVj1pLloZqabKuP>`__. <https://drive.google.com/drive/folders/1dsmvnzbOKsyFS3DCj0F8ibSnMhVHEjdV>`__.
The online spreadsheets also include `embark profile suggestions The online spreadsheets also include `embark profile suggestions
<https://docs.google.com/spreadsheets/d/13PVZ2h3Mm3x_G1OXQvwKd7oIR2lK4A1Ahf6Om1kFigw/edit#gid=149144025>`__, <https://docs.google.com/spreadsheets/d/15TDBebP8rBNvsFbezb9xuKPmGWNzv7j4XZWq1AsfCio/edit#gid=149144025>`__,
a complete `example embark profile a complete `example embark profile
<https://docs.google.com/spreadsheets/d/13PVZ2h3Mm3x_G1OXQvwKd7oIR2lK4A1Ahf6Om1kFigw/edit#gid=1727884387>`__, <https://docs.google.com/spreadsheets/d/15TDBebP8rBNvsFbezb9xuKPmGWNzv7j4XZWq1AsfCio/edit#gid=1727884387>`__,
and a convenient `checklist and a convenient `checklist
<https://docs.google.com/spreadsheets/d/13PVZ2h3Mm3x_G1OXQvwKd7oIR2lK4A1Ahf6Om1kFigw/edit#gid=1459509569>`__ <https://docs.google.com/spreadsheets/d/15TDBebP8rBNvsFbezb9xuKPmGWNzv7j4XZWq1AsfCio/edit#gid=1459509569>`__
from which you can copy the ``quickfort`` commands. that you can use to track your progress.
If you like, you can download a fully built Dreamfort-based fort from If you like, you can download a fully built Dreamfort-based fort from
:dffd:`dffd <15434>`, load it, and explore it interactively. :dffd:`dffd <15434>`, load it, and explore it interactively.
Visual overview
```````````````
Here are annotated screenshots of the major Dreamfort levels (or click `here Here are annotated screenshots of the major Dreamfort levels (or click `here
<https://drive.google.com/drive/folders/14KdE2E2wQKj4F_E-NAe3G3E4x1wiWtrc>`__ <https://drive.google.com/drive/folders/1_gtMQAqa13zZjGkf3fiY3CNEuRpt_WF2>`__
for a slideshow). for a slideshow).
Surface level Surface level
\\\\\\\\\\\\\ `````````````
.. image:: https://drive.google.com/uc?export=download&id=1YL_vQJLB2YnUEFrAg9y3HEdFq3Wpw9WP .. image:: https://drive.google.com/uc?export=download&id=1dlu3nmwQszav-ZaTx-ac28wrcaYBQc_t
:alt: Annotated screenshot of the dreamfort surface level :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 :align: center
Farming level Farming level
\\\\\\\\\\\\\ `````````````
.. image:: https://drive.google.com/uc?export=download&id=1fBC3G5Y888l4tVe5REAyAd_zeojADVme .. image:: https://drive.google.com/uc?export=download&id=1vDaedLcgoexUdKREUz75ZXQi0ZSdwWwj
:alt: Annotated screenshot of the dreamfort farming level :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 :align: center
Industry level Industry level
\\\\\\\\\\\\\\ ``````````````
.. image:: https://drive.google.com/uc?export=download&id=1emMaHHCaUPcdRbkLQqvr-0ZCs2tdM5X7 .. image:: https://drive.google.com/uc?export=download&id=1c8YTHxTgJY5tUII-BOWdLhmDFAHwIOEs
:alt: Annotated screenshot of the dreamfort industry level :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 :align: center
Services level Services levels (4 deep)
\\\\\\\\\\\\\\ ````````````````````````
.. image:: https://drive.google.com/uc?export=download&id=13vDIkTVOZGkM84tYf4O5nmRs4VZdE1gh .. image:: https://drive.google.com/uc?export=download&id=1RQMy_zYQWM5GN7-zjn6LoLWmnrJjkxPM
:alt: Annotated screenshot of the dreamfort services level :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 :align: center
.. image:: https://drive.google.com/uc?export=download&id=1jlGr6tAhS8i-XFTz8gowTZBhXcfjfL_L
:alt: Annotated screenshot of the dreamfort cistern Services waterway:
:target: https://drive.google.com/file/d/1jlGr6tAhS8i-XFTz8gowTZBhXcfjfL_L
.. image:: https://drive.google.com/uc?export=download&id=1SXknicNS13Dkq1A_8QLoK8OMxdolw-BY
:alt: Annotated screenshot of the dreamfort waterway
:target: https://drive.google.com/file/d/1SXknicNS13Dkq1A_8QLoK8OMxdolw-BY
:align: center :align: center
.. _example-plumbing-to-fill-cisterns: **Example plumbing to fill cisterns**
If you are routing water to fill the cisterns, you can do it like this (1
z-level below the preceding screenshot)
.. image:: https://drive.google.com/uc?export=download&id=1paXqPJ-7h9_jG_eNXU1z5GGvR0J8C0uJ
:alt: Annotated screenshot of an example aqueduct addition to 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 .. image:: https://drive.google.com/uc?export=download&id=1SwSluJcN_kOrCYPdcFOfJ13wEDvZGcJe
:alt: Annotated screenshot of an example aqueduct addition to the dreamfort cistern :alt: Annotated screenshot of an example drainage addition to the dreamfort cisterns
:target: https://drive.google.com/file/d/1GvhX_pVDOlmqTi2OujoBqCG_qX36ExAv :target: https://drive.google.com/file/d/1SwSluJcN_kOrCYPdcFOfJ13wEDvZGcJe
:align: center :align: center
Guildhall level Guildhall level
\\\\\\\\\\\\\\\ ```````````````
.. image:: https://drive.google.com/uc?export=download&id=17jHiCKeZm6FSS-CI4V0r0GJZh09nzcO_ .. image:: https://drive.google.com/uc?export=download&id=1mt66QOkfBqFLtw6AJKU6GNYmhB72XSJG
:alt: Annotated screenshot of the dreamfort guildhall level :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 :align: center
Noble suites Noble suites
\\\\\\\\\\\\ ````````````
.. image:: https://drive.google.com/uc?export=download&id=1IBqCf6fF3lw7sHiBE_15Euubysl5AAiS .. image:: https://drive.google.com/uc?export=download&id=16XRb1w5zFoyVq2LBMx_aCwOyjFq7GULc
:alt: Annotated screenshot of the dreamfort noble suites :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 :align: center
Apartments Apartments
\\\\\\\\\\ ``````````
.. image:: https://drive.google.com/uc?export=download&id=1mDQQXG8BnXqasRGFC9R5N6xNALiswEyr .. image:: https://drive.google.com/uc?export=download&id=16-NXlodLIQjeZUMSmsWRafeytwU2dXQo
:alt: Annotated screenshot of the dreamfort apartments :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
Crypt
`````
.. image:: https://drive.google.com/uc?export=download&id=16iT_ho7BIRPD_eofuxdlVQ4FunR1Li23
:alt: Annotated screenshot of the dreamfort crypt
:target: https://drive.google.com/file/d/16iT_ho7BIRPD_eofuxdlVQ4FunR1Li23
:align: center :align: center
The Quick Fortress The Quick Fortress
@ -158,8 +172,8 @@ Bedrooms
-------- --------
These are popular bedroom layouts from the :wiki:`Bedroom design` page on the 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 wiki. Each file has blueprints to dig the rooms, zone them as bedrooms, and
rooms, build the furniture, and configure the beds as bedrooms, respectively. build the furniture.
- :source:`library/bedrooms/48-4-Raynard_Whirlpool_Housing.csv <data/blueprints/bedrooms/48-4-Raynard_Whirlpool_Housing.csv>` - :source:`library/bedrooms/48-4-Raynard_Whirlpool_Housing.csv <data/blueprints/bedrooms/48-4-Raynard_Whirlpool_Housing.csv>`
- :source:`library/bedrooms/95-9-Hactar1_3_Branch_Tree.csv <data/blueprints/bedrooms/95-9-Hactar1_3_Branch_Tree.csv>` - :source:`library/bedrooms/95-9-Hactar1_3_Branch_Tree.csv <data/blueprints/bedrooms/95-9-Hactar1_3_Branch_Tree.csv>`
@ -178,8 +192,8 @@ Exploratory mining
------------------ ------------------
Several mining patterns to choose from when searching for gems or ores. The Several mining patterns to choose from when searching for gems or ores. The
patterns can be repeated up or down z-levels (via quickfort's ``--repeat`` patterns can be repeated up or down z-levels (via `gui/quickfort`\'s
commandline option) for exploring through the depths. :kbd:`r`\epeat functionality) for exploring through the depths.
- :source:`library/exploratory-mining/tunnels.csv <data/blueprints/exploratory-mining/tunnels.csv>` - :source:`library/exploratory-mining/tunnels.csv <data/blueprints/exploratory-mining/tunnels.csv>`
- :source:`library/exploratory-mining/vertical-mineshafts.csv <data/blueprints/exploratory-mining/vertical-mineshafts.csv>` - :source:`library/exploratory-mining/vertical-mineshafts.csv <data/blueprints/exploratory-mining/vertical-mineshafts.csv>`
@ -200,14 +214,19 @@ Light aquifer tap
The aquifer tap helps you create a safe, everlasting source of fresh water from 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 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 create a drainage system so your dwarves don't drown when digging the tap, by
running ``quickfort run library/aquifer_tap.csv -n /help``. running the ``library/aquifer_tap.csv`` ``/help`` blueprint.
You can see how to nullify the water pressure (so you don't flood your fort) in You can see how to nullify the water pressure (so you don't flood your fort) in
the `Dreamfort screenshot above <example-plumbing-to-fill-cisterns>`. the Dreamfort cistern screenshot above: `Services levels (4 deep)`_.
The blueprint spreadsheet is also available The blueprint spreadsheet is also available
`online <https://docs.google.com/spreadsheets/d/1kwuCipF9FYAHNP9C_XlMpqVseaPu4SmL9YLUSQkbW4s/edit#gid=611877584>`__. `online <https://docs.google.com/spreadsheets/d/1kwuCipF9FYAHNP9C_XlMpqVseaPu4SmL9YLUSQkbW4s/edit#gid=611877584>`__.
.. image:: https://drive.google.com/uc?export=download&id=11bzEF615QTyTNbN8A8M4UYi1YWtqPuCf
:alt: Annotated screenshot of the aquifer tap
:target: https://drive.google.com/file/d/11bzEF615QTyTNbN8A8M4UYi1YWtqPuCf
:align: center
Post-embark Post-embark
~~~~~~~~~~~ ~~~~~~~~~~~
@ -220,8 +239,8 @@ Pump stack
~~~~~~~~~~ ~~~~~~~~~~
The pump stack blueprints help you move water and magma up to more convenient 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 locations in your fort. See the step-by-step guide for using it by running the
``quickfort run library/pump_stack.csv -n /help``. ``library/pump_stack.csv`` ``/help`` blueprint.
The blueprint spreadsheet is also available The blueprint spreadsheet is also available
`online <https://docs.google.com/spreadsheets/d/1TP2n-W-O9f30Dtl6yoTcn6yczWQRu11iM7U6TEE9634/edit#gid=0>`__. `online <https://docs.google.com/spreadsheets/d/1TP2n-W-O9f30Dtl6yoTcn6yczWQRu11iM7U6TEE9634/edit#gid=0>`__.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

@ -3,7 +3,7 @@
.. dfhack-tool:: .. dfhack-tool::
:summary: Rewrite layer veins to expand in 3D space. :summary: Rewrite layer veins to expand in 3D space.
:tags: unavailable fort gameplay map :tags: fort gameplay map
Existing, flat veins are removed and new 3D veins that naturally span z-levels Existing, flat veins are removed and new 3D veins that naturally span z-levels
are generated in their place. The transformation preserves the mineral counts are generated in their place. The transformation preserves the mineral counts

@ -2,8 +2,8 @@ add-spatter
=========== ===========
.. dfhack-tool:: .. dfhack-tool::
:summary: Make tagged reactions produce contaminants. :summary: Add poisons and magical effects to weapons.
:tags: unavailable adventure fort gameplay items :tags: adventure fort gameplay items
:no-command: :no-command:
Give some use to all those poisons that can be bought from caravans! The plugin Give some use to all those poisons that can be bought from caravans! The plugin

@ -70,7 +70,7 @@ Usage
``autobutcher list_export`` ``autobutcher list_export``
Print commands required to set the current settings in another fort. Print commands required to set the current settings in another fort.
To see a list of all races, run this command: To see a list of all races, run this command::
devel/query --table df.global.world.raws.creatures.all --search ^creature_id --maxdepth 1 devel/query --table df.global.world.raws.creatures.all --search ^creature_id --maxdepth 1

@ -3,7 +3,7 @@ autogems
.. dfhack-tool:: .. dfhack-tool::
:summary: Automatically cut rough gems. :summary: Automatically cut rough gems.
:tags: unavailable fort auto workorders :tags: unavailable
:no-command: :no-command:
.. dfhack-command:: autogems-reload .. dfhack-command:: autogems-reload

Some files were not shown because too many files have changed in this diff Show More