From 42117bb16506b3d4dbe4a995028f9e072e140af8 Mon Sep 17 00:00:00 2001 From: Amber Brown Date: Thu, 5 Jan 2023 13:00:04 +1100 Subject: [PATCH 0001/1234] nix the downloaded win32-i386 libs --- CMakeLists.txt | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5877f69c6..f8a99bb2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,15 +287,9 @@ include(CMake/DownloadFile.cmake) if(WIN32) # Download zlib on Windows set(ZLIB_DOWNLOAD_DIR ${dfhack_SOURCE_DIR}/depends/zlib/lib/win${DFHACK_BUILD_ARCH}) - if(${DFHACK_BUILD_ARCH} STREQUAL "64") - download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-zlib.lib" - ${ZLIB_DOWNLOAD_DIR}/zlib.lib - "a3b2fc6b68efafa89b0882e354fc8418") - else() - download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win32-zlib.lib" - ${ZLIB_DOWNLOAD_DIR}/zlib.lib - "f4ebaa21d9de28566e88b1edfcdff901") - endif() + download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-zlib.lib" + ${ZLIB_DOWNLOAD_DIR}/zlib.lib + "a3b2fc6b68efafa89b0882e354fc8418") # Move zlib to the build folder so possible 32 and 64-bit builds # in the same source tree don't conflict @@ -307,15 +301,9 @@ if(WIN32) # 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() + download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-SDL.dll" + ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll + "1ae242c4b94cb03756a1288122a66faf") endif() if(APPLE) From 7a6946654e47c47083a273602e3594f715af9708 Mon Sep 17 00:00:00 2001 From: Amber Brown Date: Thu, 5 Jan 2023 13:00:36 +1100 Subject: [PATCH 0002/1234] remove the currently non-functional win32 build dir --- build/win32/build-debug.bat | 4 ---- build/win32/build-release.bat | 5 ----- build/win32/generate-MSVC-all.bat | 6 ----- build/win32/generate-MSVC-gui.bat | 7 ------ build/win32/generate-MSVC-minimal.bat | 6 ----- build/win32/generate-MSVC-release.bat | 6 ----- build/win32/install-debug.bat | 4 ---- build/win32/install-release.bat | 4 ---- build/win32/package-debug.bat | 6 ----- build/win32/package-release.bat | 5 ----- build/win32/set_df_path.vbs | 32 --------------------------- 11 files changed, 85 deletions(-) delete mode 100644 build/win32/build-debug.bat delete mode 100644 build/win32/build-release.bat delete mode 100644 build/win32/generate-MSVC-all.bat delete mode 100644 build/win32/generate-MSVC-gui.bat delete mode 100644 build/win32/generate-MSVC-minimal.bat delete mode 100644 build/win32/generate-MSVC-release.bat delete mode 100644 build/win32/install-debug.bat delete mode 100644 build/win32/install-release.bat delete mode 100644 build/win32/package-debug.bat delete mode 100644 build/win32/package-release.bat delete mode 100644 build/win32/set_df_path.vbs diff --git a/build/win32/build-debug.bat b/build/win32/build-debug.bat deleted file mode 100644 index dd972093d..000000000 --- a/build/win32/build-debug.bat +++ /dev/null @@ -1,4 +0,0 @@ -call "%VS140COMNTOOLS%vsvars32.bat" -cd VC2015_32 -msbuild /m /p:Platform=Win32 /p:Configuration=RelWithDebInfo ALL_BUILD.vcxproj -cd .. diff --git a/build/win32/build-release.bat b/build/win32/build-release.bat deleted file mode 100644 index 71f14eaf0..000000000 --- a/build/win32/build-release.bat +++ /dev/null @@ -1,5 +0,0 @@ -call "%VS140COMNTOOLS%vsvars32.bat" -cd VC2015_32 -msbuild /m /p:Platform=Win32 /p:Configuration=Release ALL_BUILD.vcxproj -cd .. -pause diff --git a/build/win32/generate-MSVC-all.bat b/build/win32/generate-MSVC-all.bat deleted file mode 100644 index 5c113c7b6..000000000 --- a/build/win32/generate-MSVC-all.bat +++ /dev/null @@ -1,6 +0,0 @@ -IF EXIST DF_PATH.txt SET /P _DF_PATH= 0 Then - Set spoFile = fso.CreateTextFile("DF_PATH.txt", True) - spoFile.WriteLine(objF.Self.Path) - End If -End If - -Function IsValue(obj) - ' Check whether the value has been returned. - Dim tmp - On Error Resume Next - tmp = " " & obj - If Err <> 0 Then - IsValue = False - Else - IsValue = True - End If - On Error GoTo 0 -End Function From 16309bd4670944adcab34a2df3cb7fa4cfb36113 Mon Sep 17 00:00:00 2001 From: Amber Brown Date: Thu, 5 Jan 2023 13:01:28 +1100 Subject: [PATCH 0003/1234] remove MSVC 32-bit build configurations --- CMakeSettings.json | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/CMakeSettings.json b/CMakeSettings.json index fda8ecfd3..266626804 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -26,46 +26,6 @@ } ], "configurations": [ - { - "name": "MSVC 32 Debug", - "generator": "Ninja", - "configurationType": "RelWithDebInfo", - "inheritEnvironments": [ "msvc_x86_x64", "msvc_2015_x86" ], - "variables": [ - { - "name": "DFHACK_BUILD_ARCH", - "value": "32" - }, - { - "name": "BUILD_STONESENSE", - "value": "1" - }, - { - "name": "REMOVE_SYMBOLS_FROM_DF_STUBS", - "value": "0" - }, - { - "name": "DFHACK_INCLUDE_CORE", - "value": "1" - } - ] - }, - { - "name": "MSVC 32 Release", - "generator": "Ninja", - "configurationType": "Release", - "inheritEnvironments": [ "msvc_x86_x64", "msvc_2015_x86" ], - "variables": [ - { - "name": "DFHACK_BUILD_ARCH", - "value": "32" - }, - { - "name": "BUILD_STONESENSE", - "value": "1" - } - ] - }, { "name": "MSVC 64 Debug", "generator": "Ninja", From ba32440e4022d5b63cb0cc0c37fd41257a1cd5ae Mon Sep 17 00:00:00 2001 From: Amber Brown Date: Thu, 5 Jan 2023 13:02:25 +1100 Subject: [PATCH 0004/1234] MSVC environments 2015 are not required and cmake should raise the alarm if it's not VS2022 --- CMakeSettings.json | 30 ++---------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/CMakeSettings.json b/CMakeSettings.json index 266626804..d1511716f 100644 --- a/CMakeSettings.json +++ b/CMakeSettings.json @@ -1,36 +1,10 @@ { - "environments": [ - { - "environment": "msvc_2015_x86", - "PATH": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\BIN\\amd64_x86;${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\BIN\\amd64;${env.ProgramFiles(x86)}\\Windows Kits\\10\\bin\\x86;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\bin\\x86;${env.PATH}", - "VS140COMNTOOLS": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", - "VCINSTALLDIR": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\", - "WindowsSdkDir": "${env.ProgramFiles(x86)}\\Windows Kits\\10\\", - "UCRTVersion": "10.0.10240.0", - "UniversalCRTSdkDir": "${env.ProgramFiles(x86)}\\Windows Kits\\10\\", - "LIB": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\LIB;${env.ProgramFiles(x86)}\\Windows Kits\\10\\lib\\10.0.10240.0\\ucrt\\x86;${env.ProgramFiles(x86)}\\Windows Kits\\10\\lib\\um\\x86;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Lib\\winv6.3\\um\\x86", - "INCLUDE": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\INCLUDE;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\shared;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\um;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\winrt;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Include\\um;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Include\\shared", - "LIBPATH": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\LIB" - }, - { - "environment": "msvc_2015_x64", - "PATH": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\BIN\\amd64;${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\BIN;${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\BIN\\1033;${env.ProgramFiles(x86)}\\Windows Kits\\bin\\x64;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\bin\\x64;${env.PATH}", - "VS140COMNTOOLS": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\Common7\\Tools\\", - "VCINSTALLDIR": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\", - "WindowsSdkDir": "${env.ProgramFiles(x86)}\\Windows Kits\\10\\", - "UCRTVersion": "10.0.10240.0", - "UniversalCRTSdkDir": "${env.ProgramFiles(x86)}\\Windows Kits\\10\\", - "LIB": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64;${env.ProgramFiles(x86)}\\Windows Kits\\10\\lib\\10.0.10240.0\\ucrt\\x64;${env.ProgramFiles(x86)}\\Windows Kits\\10\\lib\\um\\x64;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Lib\\winv6.3\\um\\x64", - "INCLUDE": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\INCLUDE;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\10.0.10240.0\\ucrt;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\shared;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\um;${env.ProgramFiles(x86)}\\Windows Kits\\10\\include\\winrt;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Include\\um;${env.ProgramFiles(x86)}\\Windows Kits\\8.1\\Include\\shared", - "LIBPATH": "${env.ProgramFiles(x86)}\\Microsoft Visual Studio 14.0\\VC\\LIB\\amd64" - } - ], "configurations": [ { "name": "MSVC 64 Debug", "generator": "Ninja", "configurationType": "RelWithDebInfo", - "inheritEnvironments": [ "msvc_x64_x64", "msvc_2015_x64" ], + "inheritEnvironments": [ "msvc_x64_x64" ], "variables": [ { "name": "DFHACK_BUILD_ARCH", @@ -54,7 +28,7 @@ "name": "MSVC 64 Release", "generator": "Ninja", "configurationType": "Release", - "inheritEnvironments": [ "msvc_x64_x64", "msvc_2015_x64" ], + "inheritEnvironments": [ "msvc_x64_x64" ], "variables": [ { "name": "DFHACK_BUILD_ARCH", From fe0b1fcefc6a65f904fb3f4aa81eecc0c020c159 Mon Sep 17 00:00:00 2001 From: Amber Brown Date: Thu, 5 Jan 2023 13:03:15 +1100 Subject: [PATCH 0005/1234] support VS2022 Community + build tools --- build/win64/build-debug.bat | 6 +++++- build/win64/build-release.bat | 6 +++++- build/win64/install-debug.bat | 6 +++++- build/win64/install-release.bat | 6 +++++- build/win64/package-debug.bat | 6 +++++- build/win64/package-release.bat | 6 +++++- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/build/win64/build-debug.bat b/build/win64/build-debug.bat index a04cb9984..be62460d0 100644 --- a/build/win64/build-debug.bat +++ b/build/win64/build-debug.bat @@ -1,4 +1,8 @@ -call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" ( + call "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) else ( + call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) cd VC2022 msbuild /m /p:Platform=x64 /p:Configuration=RelWithDebInfo ALL_BUILD.vcxproj cd .. diff --git a/build/win64/build-release.bat b/build/win64/build-release.bat index 8068e5074..695c35a90 100644 --- a/build/win64/build-release.bat +++ b/build/win64/build-release.bat @@ -1,4 +1,8 @@ -call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" ( + call "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) else ( + call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) cd VC2022 msbuild /m /p:Platform=x64 /p:Configuration=Release ALL_BUILD.vcxproj cd .. diff --git a/build/win64/install-debug.bat b/build/win64/install-debug.bat index 2724990fc..7d94fef80 100644 --- a/build/win64/install-debug.bat +++ b/build/win64/install-debug.bat @@ -1,4 +1,8 @@ -call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" ( + call "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) else ( + call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) cd VC2022 msbuild /m /p:Platform=x64 /p:Configuration=RelWithDebInfo INSTALL.vcxproj cd .. diff --git a/build/win64/install-release.bat b/build/win64/install-release.bat index 30dc1f6ff..0162a8827 100644 --- a/build/win64/install-release.bat +++ b/build/win64/install-release.bat @@ -1,4 +1,8 @@ -call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" ( + call "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) else ( + call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) cd VC2022 msbuild /m /p:Platform=x64 /p:Configuration=Release INSTALL.vcxproj cd .. diff --git a/build/win64/package-debug.bat b/build/win64/package-debug.bat index 450db0dfd..d029f9bc3 100644 --- a/build/win64/package-debug.bat +++ b/build/win64/package-debug.bat @@ -1,5 +1,9 @@ @echo off -call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" ( + call "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) else ( + call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) cd VC2022 msbuild /m /p:Platform=x64 /p:Configuration=RelWithDebInfo PACKAGE.vcxproj cd .. diff --git a/build/win64/package-release.bat b/build/win64/package-release.bat index 1c81ccf92..5c347c3b4 100644 --- a/build/win64/package-release.bat +++ b/build/win64/package-release.bat @@ -1,5 +1,9 @@ @echo off -call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +if exist "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" ( + call "%ProgramFiles(x86)%\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) else ( + call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 +) cd VC2022 msbuild /m /p:Platform=x64 /p:Configuration=Release PACKAGE.vcxproj cd .. From 3327ba174b378e43421f970722b0fcf7e563b536 Mon Sep 17 00:00:00 2001 From: Amber Brown Date: Thu, 5 Jan 2023 13:42:45 +1100 Subject: [PATCH 0006/1234] don't build on 32-bit windows --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f8a99bb2a..4fae14970 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,7 +103,7 @@ endif() # Automatically detect architecture based on Visual Studio generator if(MSVC AND NOT DEFINED DFHACK_BUILD_ARCH) 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() set(DFHACK_BUILD_ARCH "64") endif() From 212026861fc9fb80455df21f14ed5a641465bd50 Mon Sep 17 00:00:00 2001 From: Robob27 Date: Tue, 14 Feb 2023 20:33:33 -0500 Subject: [PATCH 0007/1234] WIP list fix --- library/lua/gui/widgets.lua | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index ffe26936d..9343be548 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1611,6 +1611,15 @@ function List:setChoices(choices, selected) end self:setSelected(selected) + + -- Check if page_top needs to be adjusted + if #self.choices - self.page_size < 0 then + self.page_top = 1 + elseif self.selected <= math.floor(self.page_size / 2) then + self.page_top = 1 + elseif self.selected >= #self.choices - math.floor(self.page_size / 2) then + self.page_top = #self.choices - self.page_size + 1 + end end function List:setSelected(selected) @@ -1651,10 +1660,26 @@ local function update_list_scrollbar(list) end function List:postComputeFrame(body) - self.page_size = math.max(1, math.floor(body.height / self.row_height)) - if #self.choices - self.page_size < 0 then + local row_count = math.floor(body.height / self.row_height) + self.page_size = math.max(1, row_count) + + local num_choices = #self.choices + if num_choices == 0 then self.page_top = 1 + update_list_scrollbar(self) + return end + + local max_page_top = math.max(1, num_choices - row_count + 1) + + if self.selected > num_choices - row_count then + self.page_top = max_page_top + elseif self.selected < self.page_top then + self.page_top = self.selected + else + self.page_top = math.max(1, self.selected - row_count + 1) + end + update_list_scrollbar(self) end From 084d28b0aedc93b2b4d7880a9f3bfbd0236102c9 Mon Sep 17 00:00:00 2001 From: 20k Date: Wed, 25 Jan 2023 18:40:27 +0000 Subject: [PATCH 0008/1234] Reworked heap debugging + tools implementation --- docs/dev/Lua API.rst | 48 +++++++++++++ library/LuaApi.cpp | 165 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 9f2386660..b5e66ef8b 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2768,6 +2768,54 @@ and are only documented here for completeness: 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. + + .. _lua-core-context: Core interpreter context diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index c9bdc3021..babf2f7c0 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2833,12 +2833,177 @@ static int8_t getModstate() { return Core::getInstance().getModstate(); } static std::string internal_strerror(int n) { return strerror(n); } static std::string internal_md5(std::string s) { return md5_wrap.getHashFromString(s); } +struct heap_pointer_info +{ + size_t size = 0; + int status = 0; +}; + +static std::map snapshot; + +static int heap_take_snapshot() +{ + #ifdef _WIN32 + snapshot.clear(); + + std::vector> entries; + //heap allocating while iterating the heap is suboptimal + entries.reserve(256*1024*1024); + + _HEAPINFO hinfo; + int heapstatus; + int numLoops; + hinfo._pentry = NULL; + numLoops = 0; + while((heapstatus = _heapwalk(&hinfo)) == _HEAPOK && + numLoops < 1024*1024*1024) + { + heap_pointer_info inf; + inf.size = hinfo._size; + inf.status = hinfo._useflag; //0 == _FREEENTRY, 1 == _USEDENTRY + + entries.push_back({hinfo._pentry, inf}); + + numLoops++; + } + + for (auto i : entries) + { + uintptr_t val = 0; + memcpy(&val, &i.first, sizeof(void*)); + snapshot[val] = i.second; + } + + if (heapstatus == _HEAPEMPTY || heapstatus == _HEAPEND) + return 0; + + if (heapstatus == _HEAPBADPTR) + return 1; + + if (heapstatus == _HEAPBADBEGIN) + return 2; + + if (heapstatus == _HEAPBADNODE) + return 3; + #endif + + return 0; +} + +static void* address_to_pointer(uintptr_t ptr) +{ + void* as_ptr = nullptr; + memcpy((void*)&as_ptr, &ptr, sizeof(uintptr_t)); + + return as_ptr; +} + +//this function probably should not allocate. Then again we're shimming through lua which.... probably does +static int get_heap_state() +{ + #ifdef _WIN32 + int heapstatus = _heapchk(); + + if (heapstatus == _HEAPEMPTY || heapstatus == _HEAPOK) + return 0; + + if (heapstatus == _HEAPBADPTR) + return 1; + + if (heapstatus == _HEAPBADBEGIN) + return 2; + + if (heapstatus == _HEAPBADNODE) + return 3; + #endif + + return 0; +} + +static bool is_address_in_heap(uintptr_t ptr) +{ + return snapshot.find(ptr) != snapshot.end(); +} + +static bool is_address_active_in_heap(uintptr_t ptr) +{ + auto it = snapshot.find(ptr); + + if (it == snapshot.end()) + return false; + + return it->second.status == 1; +} + +static bool is_address_used_after_free_in_heap(uintptr_t ptr) +{ + auto it = snapshot.find(ptr); + + if (it == snapshot.end()) + return false; + + return it->second.status != 1; +} + +static int get_address_size_in_heap(uintptr_t ptr) +{ + auto it = snapshot.find(ptr); + + if (it == snapshot.end()) + return -1; + + return it->second.size; +} + +//eg if I have a struct, does any address lie within the struct? +static uintptr_t get_root_address_of_heap_object(uintptr_t ptr) +{ + //find the first element strictly greater than our pointer + auto it = snapshot.upper_bound(ptr); + + //if we're at the start of the snapshot, no elements are less than our pointer + //therefore it is invalid + if (it == snapshot.begin()) + return 0; + + //get the first element less than or equal to ours + it--; + + //our pointer is only valid if we lie in the first pointer lower in memory than it + if (ptr >= it->first && ptr < it->first + it->second.size) + return it->first; + + return 0; +} + +//msize crashes if you pass an invalid pointer to it, only use it if you *know* the thing you're looking at +//is in the heap/valid +static int msize_address(uintptr_t ptr) +{ + void* vptr = address_to_pointer(ptr); + + #ifdef _WIN32 + if (vptr) + return _msize(vptr); + #endif + + return -1; +} + static const LuaWrapper::FunctionReg dfhack_internal_module[] = { WRAP(getImageBase), WRAP(getRebaseDelta), WRAP(getModstate), WRAPN(strerror, internal_strerror), WRAPN(md5, internal_md5), + WRAPN(heapTakeSnapshot, heap_take_snapshot), + WRAPN(getHeapState, get_heap_state), + WRAPN(isAddressInHeap, is_address_in_heap), + WRAPN(isAddressActiveInHeap, is_address_active_in_heap), + WRAPN(isAddressUsedAfterFreeInHeap, is_address_used_after_free_in_heap), + WRAPN(getAddressSizeInHeap, get_address_size_in_heap), + WRAPN(getRootAddressOfHeapObject, get_root_address_of_heap_object), + WRAPN(msizeAddress, msize_address), { NULL, NULL } }; From 5cc6293407f68302113c1737ef8bc07074135e2c Mon Sep 17 00:00:00 2001 From: 20k Date: Fri, 27 Jan 2023 06:04:55 +0000 Subject: [PATCH 0009/1234] fix unused variable on linux --- library/LuaApi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index babf2f7c0..04f771928 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2980,9 +2980,9 @@ static uintptr_t get_root_address_of_heap_object(uintptr_t ptr) //is in the heap/valid static int msize_address(uintptr_t ptr) { + #ifdef _WIN32 void* vptr = address_to_pointer(ptr); - #ifdef _WIN32 if (vptr) return _msize(vptr); #endif From 5a7debfc777fb8c3bfe2b5fc11dfdec92fd551f3 Mon Sep 17 00:00:00 2001 From: 20k Date: Fri, 27 Jan 2023 06:12:24 +0000 Subject: [PATCH 0010/1234] cleanup, linux fix --- library/LuaApi.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 04f771928..873b0bcd2 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2869,8 +2869,7 @@ static int heap_take_snapshot() for (auto i : entries) { - uintptr_t val = 0; - memcpy(&val, &i.first, sizeof(void*)); + uintptr_t val = reinterpret_cast(i.first); snapshot[val] = i.second; } @@ -2890,14 +2889,6 @@ static int heap_take_snapshot() return 0; } -static void* address_to_pointer(uintptr_t ptr) -{ - void* as_ptr = nullptr; - memcpy((void*)&as_ptr, &ptr, sizeof(uintptr_t)); - - return as_ptr; -} - //this function probably should not allocate. Then again we're shimming through lua which.... probably does static int get_heap_state() { @@ -2981,7 +2972,7 @@ static uintptr_t get_root_address_of_heap_object(uintptr_t ptr) static int msize_address(uintptr_t ptr) { #ifdef _WIN32 - void* vptr = address_to_pointer(ptr); + void* vptr = reinterpret_cast(ptr); if (vptr) return _msize(vptr); From 18160da82e7c7e723affef6b949e0da0c97bcd81 Mon Sep 17 00:00:00 2001 From: 20k Date: Mon, 6 Mar 2023 18:10:43 +0000 Subject: [PATCH 0011/1234] rework to be allocation free, cleanup --- library/LuaApi.cpp | 102 ++++++++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 42 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 873b0bcd2..5e5fa7ff3 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2835,76 +2835,91 @@ static std::string internal_md5(std::string s) { return md5_wrap.getHashFromStri struct heap_pointer_info { + size_t address = 0; size_t size = 0; int status = 0; }; -static std::map snapshot; +//fixed sized, sorted +static std::vector heap_data; +//when dfhack upgrades to c++17, this would do well as a std::optional +static std::pair heap_find(uintptr_t address) +{ + auto it = std::lower_bound(heap_data.begin(), heap_data.end(), address, + [](heap_pointer_info t, uintptr_t address) + { + return t.address < address; + }); + + if (it == heap_data.end() || it->address != address) + return {false, heap_pointer_info()}; + + return {true, *it}; +} + +//this function only allocates the first time it is called static int heap_take_snapshot() { #ifdef _WIN32 - snapshot.clear(); + size_t max_entries = 256 * 1024 * 1024 / sizeof(heap_pointer_info); - std::vector> entries; - //heap allocating while iterating the heap is suboptimal - entries.reserve(256*1024*1024); + //clearing the vector is guaranteed not to deallocate the memory + heap_data.clear(); + heap_data.reserve(max_entries); _HEAPINFO hinfo; - int heapstatus; - int numLoops; - hinfo._pentry = NULL; - numLoops = 0; - while((heapstatus = _heapwalk(&hinfo)) == _HEAPOK && - numLoops < 1024*1024*1024) + hinfo._pentry = nullptr; + int heap_status = 0; + + while ((heap_status = _heapwalk(&hinfo)) == _HEAPOK && heap_data.size() < max_entries) { heap_pointer_info inf; + inf.address = reinterpret_cast(hinfo._pentry); inf.size = hinfo._size; inf.status = hinfo._useflag; //0 == _FREEENTRY, 1 == _USEDENTRY - entries.push_back({hinfo._pentry, inf}); - - numLoops++; + heap_data.push_back(inf); } - for (auto i : entries) + //sort by address + std::sort(heap_data.begin(), heap_data.end(), + [](heap_pointer_info t1, heap_pointer_info t2) { - uintptr_t val = reinterpret_cast(i.first); - snapshot[val] = i.second; - } + return t1.address < t2.address; + }); - if (heapstatus == _HEAPEMPTY || heapstatus == _HEAPEND) + if (heap_status == _HEAPEMPTY || heap_status == _HEAPEND) return 0; - if (heapstatus == _HEAPBADPTR) + if (heap_status == _HEAPBADPTR) return 1; - if (heapstatus == _HEAPBADBEGIN) + if (heap_status == _HEAPBADBEGIN) return 2; - if (heapstatus == _HEAPBADNODE) + if (heap_status == _HEAPBADNODE) return 3; #endif return 0; } -//this function probably should not allocate. Then again we're shimming through lua which.... probably does static int get_heap_state() { #ifdef _WIN32 - int heapstatus = _heapchk(); + int heap_status = _heapchk(); - if (heapstatus == _HEAPEMPTY || heapstatus == _HEAPOK) + if (heap_status == _HEAPEMPTY || heap_status == _HEAPOK) return 0; - if (heapstatus == _HEAPBADPTR) + if (heap_status == _HEAPBADPTR) return 1; - if (heapstatus == _HEAPBADBEGIN) + if (heap_status == _HEAPBADBEGIN) return 2; - if (heapstatus == _HEAPBADNODE) + if (heap_status == _HEAPBADNODE) return 3; #endif @@ -2913,56 +2928,59 @@ static int get_heap_state() static bool is_address_in_heap(uintptr_t ptr) { - return snapshot.find(ptr) != snapshot.end(); + return heap_find(ptr).first; } static bool is_address_active_in_heap(uintptr_t ptr) { - auto it = snapshot.find(ptr); + std::pair inf = heap_find(ptr); - if (it == snapshot.end()) + if (!inf.first) return false; - return it->second.status == 1; + return inf.second.status == 1; } static bool is_address_used_after_free_in_heap(uintptr_t ptr) { - auto it = snapshot.find(ptr); + std::pair inf = heap_find(ptr); - if (it == snapshot.end()) + if (!inf.first) return false; - return it->second.status != 1; + return inf.second.status != 1; } static int get_address_size_in_heap(uintptr_t ptr) { - auto it = snapshot.find(ptr); + std::pair inf = heap_find(ptr); - if (it == snapshot.end()) + if (!inf.first) return -1; - return it->second.size; + return inf.second.size; } //eg if I have a struct, does any address lie within the struct? static uintptr_t get_root_address_of_heap_object(uintptr_t ptr) { //find the first element strictly greater than our pointer - auto it = snapshot.upper_bound(ptr); + auto it = std::upper_bound(heap_data.begin(), heap_data.end(), ptr, [](uintptr_t ptr, heap_pointer_info t1) + { + return ptr < t1.address; + }); //if we're at the start of the snapshot, no elements are less than our pointer //therefore it is invalid - if (it == snapshot.begin()) + if (it == heap_data.begin()) return 0; //get the first element less than or equal to ours it--; //our pointer is only valid if we lie in the first pointer lower in memory than it - if (ptr >= it->first && ptr < it->first + it->second.size) - return it->first; + if (ptr >= it->address && ptr < it->address + it->size) + return it->address; return 0; } From 7ff9d73a4cafa6fdd63dc208cbd988240fafa04a Mon Sep 17 00:00:00 2001 From: John Cosker Date: Thu, 30 Mar 2023 15:17:08 -0400 Subject: [PATCH 0012/1234] Technically drawing works --- plugins/CMakeLists.txt | 1 + plugins/design.cpp | 452 +++++++++++++++++++++++++++++++++++++++++ plugins/lua/design.lua | 9 + 3 files changed, 462 insertions(+) create mode 100644 plugins/design.cpp create mode 100644 plugins/lua/design.lua diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 477e83436..c880a89ff 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -77,6 +77,7 @@ set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) #dfhack_plugin(add-spatter add-spatter.cpp) dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua) dfhack_plugin(autochop autochop.cpp LINK_LIBRARIES lua) +dfhack_plugin(design design.cpp LINK_LIBRARIES lua) dfhack_plugin(autoclothing autoclothing.cpp) dfhack_plugin(autodump autodump.cpp) dfhack_plugin(autofarm autofarm.cpp) diff --git a/plugins/design.cpp b/plugins/design.cpp new file mode 100644 index 000000000..25f876d3e --- /dev/null +++ b/plugins/design.cpp @@ -0,0 +1,452 @@ +#include +#include +#include +#include +#include +#include + +#include "ColorText.h" +#include "Debug.h" +#include "LuaTools.h" +#include "PluginManager.h" +#include "df/graphic_viewportst.h" +#include "df/world.h" +#include "modules/Persistence.h" +#include "modules/Screen.h" +#include "modules/World.h" + +DFHACK_PLUGIN("design"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); +using DFHack::color_value; + +REQUIRE_GLOBAL(window_x); +REQUIRE_GLOBAL(window_y); +REQUIRE_GLOBAL(world); +REQUIRE_GLOBAL(plotinfo); +using namespace DFHack; +using namespace df::enums; + +enum ConfigValues { + CONFIG_IS_ENABLED = 0, +}; +namespace DFHack { +// // for configuration-related logging +DBG_DECLARE(design, status, DebugCategory::LDEBUG); +// for logging during the periodic scan +DBG_DECLARE(design, cycle, DebugCategory::LDEBUG); +} // namespace DFHack +static const std::string CONFIG_KEY = std::string(plugin_name) + "/config"; +static PersistentDataItem config; +static const int32_t CYCLE_TICKS = 1200; +static int32_t cycle_timestamp = 0; // world->frame_counter at last cycle + +static command_result do_command(color_ostream &out, + std::vector ¶meters); +static int32_t do_cycle(color_ostream &out, bool force_designate = false); + +DFhackCExport command_result plugin_init(color_ostream &out, + std::vector &commands) { + DEBUG(status, out).print("initializing %s\n", plugin_name); + + // provide a configuration interface for the plugin + commands.push_back( + PluginCommand(plugin_name, "Designs stuff TBD", do_command)); + + return CR_OK; +} + +static int get_config_val(PersistentDataItem &c, int index) { + if (!c.isValid()) return -1; + return c.ival(index); +} + +static bool get_config_bool(PersistentDataItem &c, int index) { + return get_config_val(c, index) == 1; +} + +static void set_config_val(PersistentDataItem &c, int index, int value) { + if (c.isValid()) c.ival(index) = value; +} + +static void set_config_bool(PersistentDataItem &c, int index, bool value) { + set_config_val(c, index, value ? 1 : 0); +} + +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { + if (!Core::getInstance().isWorldLoaded()) { + out.printerr("Cannot enable %s without a loaded world.\n", plugin_name); + + return CR_FAILURE; + } + + if (enable != is_enabled) { + is_enabled = enable; + DEBUG(status, out) + .print("%s from the API; persisting\n", + is_enabled ? "enabled" : "disabled"); + set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); + if (enable) do_cycle(out, true); + } else { + DEBUG(status, out) + .print("%s from the API, but already %s; no action\n", + is_enabled ? "enabled" : "disabled", + is_enabled ? "enabled" : "disabled"); + } + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown(color_ostream &out) { + DEBUG(status, out).print("shutting down %s\n", plugin_name); + + return CR_OK; +} + +DFhackCExport command_result plugin_load_data(color_ostream &out) { + cycle_timestamp = 0; + config = World::GetPersistentData(CONFIG_KEY); + + if (!config.isValid()) { + DEBUG(status, out).print("no config found in this save; initializing\n"); + config = World::AddPersistentData(CONFIG_KEY); + set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); + } + + // we have to copy our enabled flag into the global plugin variable, but + // all the other state we can directly read/modify from the persistent + // data structure. + is_enabled = get_config_bool(config, CONFIG_IS_ENABLED); + DEBUG(status, out) + .print("loading persisted enabled state: %s\n", + is_enabled ? "true" : "false"); + + return CR_OK; +} + +DFhackCExport command_result plugin_onstatechange(color_ostream &out, + state_change_event event) { + if (event == DFHack::SC_WORLD_UNLOADED) { + if (is_enabled) { + DEBUG(status, out).print("world unloaded; disabling %s\n", plugin_name); + is_enabled = false; + } + } + + return CR_OK; +} + +DFhackCExport command_result plugin_onupdate(color_ostream &out) { + if (is_enabled && world->frame_counter - cycle_timestamp >= CYCLE_TICKS) { + int32_t ret = do_cycle(out); + } + + return CR_OK; +} +int selected_tile_texpos = 0; +const static bool hi = + Screen::findGraphicsTile("CURSORS", 4, 3, &selected_tile_texpos); + +static command_result do_command(color_ostream &out, + std::vector ¶meters) { + return CR_OK; +} + +static int32_t do_cycle(color_ostream &out, bool force_designate) { return 0; } + +// Assuming the existence of a class named Point, similar to the one in Lua +class Point { + public: + int x; + int y; + + Point(int x, int y) : x(x), y(y) {} + + bool operator==(const Point &other) const { + return x == other.x && y == other.y; + } +}; + +// Assuming the existence of a class named Color, similar to the one in Lua +class Color { + public: + // Define your color values here +}; + +// Assuming the existence of a class named Pen, similar to the one in Lua +class Pen { + public: + std::string ch; + int tile; + color_value fg; + // Define your pen properties and methods here +}; + +class Design { + public: + std::map PENS; + + enum PEN_MASK { + NORTH = 0, + SOUTH, + EAST, + WEST, + DRAG_POINT, + MOUSEOVER, + INSHAPE, + EXTRA_POINT, + NUM_FLAGS + }; + + // Define the function similar to the Lua version + + uint32_t gen_pen_key(bool n, bool s, bool e, bool w, bool is_corner, + bool is_mouse_over, bool inshape, bool extra_point) { + std::bitset ret; + ret[NORTH] = n; + ret[SOUTH] = s; + ret[EAST] = e; + ret[WEST] = w; + ret[DRAG_POINT] = is_corner; + ret[MOUSEOVER] = is_mouse_over; + ret[INSHAPE] = inshape; + ret[EXTRA_POINT] = extra_point; + + return static_cast(ret.to_ulong()); + } + + Pen Design::get_pen(int x, int y, + const std::map> &arr); + // Define the function similar to the Lua version +}; + +Design design; + +// Add other methods and member variables needed for the class + +static int design_getPen(lua_State *L) { + std::map> arr; + if (lua_istable(L, -1)) { + // Iterate over the outer table + lua_pushnil(L); // First key + while (lua_next(L, -2) != 0) { + int x = lua_tointeger(L, -2); // Convert key to an integer + + if (lua_istable(L, -1)) { + // Iterate over the inner table + lua_pushnil(L); // First key + while (lua_next(L, -2) != 0) { + int y = lua_tointeger(L, -2); // Convert key to an integer + bool value = lua_toboolean(L, -1); + + if (value) { + if (arr.count(x) == 0) arr[x] = {}; + arr[x][y] = value; + } + lua_pop(L, 1); // Remove value, keep the key for the next iteration + } + } + lua_pop(L, 1); // Remove inner table, keep the key for the next iteration + } + } + + for (auto x : arr) { + for (auto y : x.second) { + Screen::Pen cur_tile = Screen::readTile(x.first, y.first, true); + // cur_tile.tile = selected_tile_texpos; + Pen pen = design.get_pen(x.first, y.first, arr); + cur_tile.tile = pen.tile; + Screen::paintTile(cur_tile, x.first - *window_x, y.first - *window_y, + true); + } + } + return 0; +} +enum class CURSORS { + INSIDE, + NORTH, + N_NUB, + S_NUB, + W_NUB, + E_NUB, + NE, + NW, + WEST, + EAST, + SW, + SOUTH, + SE, + VERT_NS, + VERT_EW, + POINT +}; + +std::map> CURSORS_MAP = { + {CURSORS::INSIDE, {1, 2}}, {CURSORS::NORTH, {1, 1}}, + {CURSORS::N_NUB, {3, 2}}, {CURSORS::S_NUB, {4, 2}}, + {CURSORS::W_NUB, {3, 1}}, {CURSORS::E_NUB, {5, 1}}, + {CURSORS::NE, {2, 1}}, {CURSORS::NW, {0, 1}}, + {CURSORS::WEST, {0, 2}}, {CURSORS::EAST, {2, 2}}, + {CURSORS::SW, {0, 3}}, {CURSORS::SOUTH, {1, 3}}, + {CURSORS::SE, {2, 3}}, {CURSORS::VERT_NS, {3, 3}}, + {CURSORS::VERT_EW, {4, 1}}, {CURSORS::POINT, {4, 3}}, +}; +Pen make_pen(const std::pair &direction, bool is_corner, + bool is_mouse_over, bool inshape, bool extra_point) { + color_value color = COLOR_GREEN; + int ycursor_mod = 0; + + if (!extra_point) { + if (is_corner) { + color = COLOR_CYAN; + ycursor_mod += 6; + if (is_mouse_over) { + color = COLOR_MAGENTA; + ycursor_mod += 3; + } + } + } else { + ycursor_mod += 15; + color = COLOR_LIGHTRED; + + if (is_mouse_over) { + color = COLOR_RED; + ycursor_mod += 3; + } + } + + Pen pen; + pen.ch = inshape ? "X" : "o"; + pen.fg = color; + int selected_tile_texpos = 0; + Screen::findGraphicsTile("CURSORS", direction.first, direction.second, &selected_tile_texpos); + pen.tile = selected_tile_texpos; + + // Assuming dfhack.screen.findGraphicsTile is replaced with a custom function + // findGraphicsTile pen.tile = findGraphicsTile("CURSORS", direction.first, + // direction.second + ycursor_mod); + + return pen; +} +Pen Design::get_pen(int x, int y, + const std::map> &arr) { + auto has_point = [&arr](int _x, int _y) { + return arr.count(_x) != 0 && arr.at(_x).count(_y) != 0 && arr.at(_x).at(_y); + }; + bool get_point = has_point(x, y); + + // Basic shapes are bounded by rectangles and therefore can have corner drag + // points even if they're not real points in the shape if (marks.size() >= + // shape.min_points && shape.basic_shape) { + // Point shape_top_left, shape_bot_right; + // shape.get_point_dims(shape_top_left, shape_bot_right); + + // if (x == shape_top_left.x && y == shape_top_left.y && + // shape.drag_corners.nw) { + // drag_point = true; + // } else if (x == shape_bot_right.x && y == shape_top_left.y && + // shape.drag_corners.ne) { + // drag_point = true; + // } else if (x == shape_top_left.x && y == shape_bot_right.y && + // shape.drag_corners.sw) { + // drag_point = true; + // } else if (x == shape_bot_right.x && y == shape_bot_right.y && + // shape.drag_corners.se) { + // drag_point = true; + // } + // } + + // for (const auto& mark : marks) { + // if (mark == Point(x, y)) { + // drag_point = true; + // } + // } + + // if (mirror_point && *mirror_point == Point(x, y)) { + // drag_point = true; + // } + + // // Check for an extra point + // bool extra_point = false; + // for (const auto& point : extra_points) { + // if (x == point.x && y == point.y) { + // extra_point = true; + // break; + // } + // } + + // // Show center point if both marks are set + // if ((shape.basic_shape && marks.size() == shape.max_points) || + // (!shape.basic_shape && !placing_mark.active && !marks.empty())) { + // int center_x, center_y; + // shape.get_center(center_x, center_y); + + // if (x == center_x && y == center_y) { + // extra_point = true; + // } + // } + + bool n = false, w = false, e = false, s = false; + if (get_point) { + if (y == 0 || !has_point(x, y - 1)) n = true; + if (x == 0 || !has_point(x - 1, y)) w = true; + if (!has_point(x + 1, y)) e = true; + if (!has_point(x, y + 1)) s = true; + } + // DEBUG(status).print("jcosker %d %d %d %d\n", n, s, e, w); + + // Get the bit field to use as a key for the PENS map + uint32_t pen_key = gen_pen_key(n, s, e, w, false, false, get_point, false); + // DEBUG(status).print("jcosker %zu\n", pen_key); + + if (PENS.find(pen_key) == PENS.end()) { + std::pair cursor{-1, -1}; + // int cursor = -1; // Assuming -1 is an invalid cursor value + + // Determine the cursor to use based on the input parameters + // The CURSORS enum or equivalent should be defined in your code + if (get_point && !n && !w && !e && !s) + cursor = CURSORS_MAP.at(CURSORS::INSIDE); + else if (get_point && n && w && !e && !s) + cursor = CURSORS_MAP.at(CURSORS::NW); + else if (get_point && n && !w && !e && !s) + cursor = CURSORS_MAP.at(CURSORS::NORTH); + else if (get_point && n && e && !w && !s) + cursor = CURSORS_MAP.at(CURSORS::NE); + else if (get_point && !n && w && !e && !s) + cursor = CURSORS_MAP.at(CURSORS::WEST); + else if (get_point && !n && !w && e && !s) + cursor = CURSORS_MAP.at(CURSORS::EAST); + else if (get_point && !n && w && !e && s) + cursor = CURSORS_MAP.at(CURSORS::SW); + else if (get_point && !n && !w && !e && s) + cursor = CURSORS_MAP.at(CURSORS::SOUTH); + else if (get_point && !n && !w && e && s) + cursor = CURSORS_MAP.at(CURSORS::SE); + else if (get_point && n && w && e && !s) + cursor = CURSORS_MAP.at(CURSORS::N_NUB); + else if (get_point && n && !w && e && s) + cursor = CURSORS_MAP.at(CURSORS::E_NUB); + else if (get_point && n && w && !e && s) + cursor = CURSORS_MAP.at(CURSORS::W_NUB); + else if (get_point && !n && w && e && s) + cursor = CURSORS_MAP.at(CURSORS::S_NUB); + else if (get_point && !n && w && e && !s) + cursor = CURSORS_MAP.at(CURSORS::VERT_NS); + else if (get_point && n && !w && !e && s) + cursor = CURSORS_MAP.at(CURSORS::VERT_EW); + else if (get_point && n && w && e && s) + cursor = CURSORS_MAP.at(CURSORS::POINT); + // else if (drag_point && !get_point) cursor = CURSORS::INSIDE; + // else if (extra_point) cursor = CURSORS::INSIDE; + // Create the pen if the cursor is set + + DEBUG(status).print("jcosker %d, %d\n", cursor.first, cursor.second); + if (cursor.first != -1) { + PENS[pen_key] = make_pen(cursor, false, false, get_point, false); + } + } + + // Return the pen for the caller + return PENS.at(pen_key); +} + +DFHACK_PLUGIN_LUA_COMMANDS{DFHACK_LUA_COMMAND(design_getPen), DFHACK_LUA_END}; diff --git a/plugins/lua/design.lua b/plugins/lua/design.lua new file mode 100644 index 000000000..fe916aa41 --- /dev/null +++ b/plugins/lua/design.lua @@ -0,0 +1,9 @@ +local _ENV = mkmodule('plugins.design') + +view2 = {design_window = { name = "hello"}} + +function getPen(hi) + design_getPen(hi) +end + +return _ENV From 5aa246f6b0fb62b472386b9830c3734c6f27c9e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Vuchener?= Date: Sat, 8 Apr 2023 12:33:24 +0200 Subject: [PATCH 0013/1234] plugins: include proto directory from current source directory Updated remotefortressreader for the new behavior. --- plugins/Plugins.cmake | 10 +++++----- plugins/remotefortressreader/CMakeLists.txt | 16 +--------------- plugins/remotefortressreader/proto/.gitignore | 3 +++ .../proto/AdventureControl.proto | 0 .../proto/DwarfControl.proto | 0 .../proto/ItemdefInstrument.proto | 0 .../proto/RemoteFortressReader.proto | 0 .../proto/ui_sidebar_mode.proto | 0 8 files changed, 9 insertions(+), 20 deletions(-) create mode 100644 plugins/remotefortressreader/proto/.gitignore rename plugins/{ => remotefortressreader}/proto/AdventureControl.proto (100%) rename plugins/{ => remotefortressreader}/proto/DwarfControl.proto (100%) rename plugins/{ => remotefortressreader}/proto/ItemdefInstrument.proto (100%) rename plugins/{ => remotefortressreader}/proto/RemoteFortressReader.proto (100%) rename plugins/{ => remotefortressreader}/proto/ui_sidebar_mode.proto (100%) diff --git a/plugins/Plugins.cmake b/plugins/Plugins.cmake index db7582c09..a0cea765f 100644 --- a/plugins/Plugins.cmake +++ b/plugins/Plugins.cmake @@ -6,11 +6,6 @@ if(UNIX) endif() endif() -include_directories("${dfhack_SOURCE_DIR}/library/include") -include_directories("${dfhack_SOURCE_DIR}/library/proto") -include_directories("${CMAKE_CURRENT_SOURCE_DIR}/proto") -include_directories("${dfhack_SOURCE_DIR}/library/depends/xgetopt") - macro(car var) set(${var} ${ARGV1}) endmacro() @@ -123,6 +118,11 @@ macro(dfhack_plugin) add_library(${PLUGIN_NAME} MODULE ${PLUGIN_SOURCES}) ide_folder(${PLUGIN_NAME} "Plugins") + target_include_directories(${PLUGIN_NAME} PRIVATE "${dfhack_SOURCE_DIR}/library/include") + target_include_directories(${PLUGIN_NAME} PRIVATE "${dfhack_SOURCE_DIR}/library/proto") + target_include_directories(${PLUGIN_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/proto") + target_include_directories(${PLUGIN_NAME} PRIVATE "${dfhack_SOURCE_DIR}/library/depends/xgetopt") + if(NUM_PROTO) add_dependencies(${PLUGIN_NAME} generate_proto_${PLUGIN_NAME}) target_link_libraries(${PLUGIN_NAME} dfhack protobuf-lite dfhack-version ${PLUGIN_LINK_LIBRARIES}) diff --git a/plugins/remotefortressreader/CMakeLists.txt b/plugins/remotefortressreader/CMakeLists.txt index 55525bc21..262d163f1 100644 --- a/plugins/remotefortressreader/CMakeLists.txt +++ b/plugins/remotefortressreader/CMakeLists.txt @@ -24,23 +24,9 @@ set(PROJECT_PROTO ui_sidebar_mode ) -set(PLUGIN_PROTOS) -foreach(pbuf ${PROJECT_PROTO}) - list(APPEND PLUGIN_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/../proto/${pbuf}.proto) -endforeach() - -string(REPLACE ".proto" ".pb.cc" PLUGIN_PROTO_SRCS "${PLUGIN_PROTOS}") -string(REPLACE ".proto" ".pb.h" PLUGIN_PROTO_HDRS "${PLUGIN_PROTOS}") -set_source_files_properties(${PLUGIN_PROTO_SRCS} ${PLUGIN_PROTO_HDRS} PROPERTIES GENERATED TRUE) - -set_source_files_properties( ${PROJECT_HDRS} ${PLUGIN_PROTO_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE) - -# mash them together (headers are marked as headers and nothing will try to compile them) -list(APPEND PROJECT_SRCS ${PROJECT_HDRS} ${PLUGIN_PROTOS} ${PLUGIN_PROTO_SRCS} ${PLUGIN_PROTO_HDRS}) - if(UNIX AND NOT APPLE) set(PROJECT_LIBS ${PROJECT_LIBS} SDL) endif() # this makes sure all the stuff is put in proper places and linked to dfhack -dfhack_plugin(RemoteFortressReader ${PROJECT_SRCS} LINK_LIBRARIES protobuf-lite ${PROJECT_LIBS} COMPILE_FLAGS_MSVC "/FI\"Export.h\"" COMPILE_FLAGS_GCC "-include Export.h -Wno-misleading-indentation" ) +dfhack_plugin(RemoteFortressReader ${PROJECT_SRCS} LINK_LIBRARIES ${PROJECT_LIBS} PROTOBUFS ${PROJECT_PROTO}) diff --git a/plugins/remotefortressreader/proto/.gitignore b/plugins/remotefortressreader/proto/.gitignore new file mode 100644 index 000000000..befabf79d --- /dev/null +++ b/plugins/remotefortressreader/proto/.gitignore @@ -0,0 +1,3 @@ +*.pb.cc +*.pb.cc.rule +*.pb.h diff --git a/plugins/proto/AdventureControl.proto b/plugins/remotefortressreader/proto/AdventureControl.proto similarity index 100% rename from plugins/proto/AdventureControl.proto rename to plugins/remotefortressreader/proto/AdventureControl.proto diff --git a/plugins/proto/DwarfControl.proto b/plugins/remotefortressreader/proto/DwarfControl.proto similarity index 100% rename from plugins/proto/DwarfControl.proto rename to plugins/remotefortressreader/proto/DwarfControl.proto diff --git a/plugins/proto/ItemdefInstrument.proto b/plugins/remotefortressreader/proto/ItemdefInstrument.proto similarity index 100% rename from plugins/proto/ItemdefInstrument.proto rename to plugins/remotefortressreader/proto/ItemdefInstrument.proto diff --git a/plugins/proto/RemoteFortressReader.proto b/plugins/remotefortressreader/proto/RemoteFortressReader.proto similarity index 100% rename from plugins/proto/RemoteFortressReader.proto rename to plugins/remotefortressreader/proto/RemoteFortressReader.proto diff --git a/plugins/proto/ui_sidebar_mode.proto b/plugins/remotefortressreader/proto/ui_sidebar_mode.proto similarity index 100% rename from plugins/proto/ui_sidebar_mode.proto rename to plugins/remotefortressreader/proto/ui_sidebar_mode.proto From 6a7446780b401c721a64fb28ce42094243448ff4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 9 Apr 2023 22:59:55 -0700 Subject: [PATCH 0014/1234] hide terminal console when running on steam deck --- docs/changelog.txt | 1 + library/CMakeLists.txt | 2 + library/Core.cpp | 7 ++++ library/include/modules/DFSteam.h | 32 ++++++++++++++++ library/modules/DFSteam.cpp | 64 +++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+) create mode 100644 library/include/modules/DFSteam.h create mode 100644 library/modules/DFSteam.cpp diff --git a/docs/changelog.txt b/docs/changelog.txt index adc4ca786..e63b80bd7 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -52,6 +52,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Mods: scripts from only the most recent version of an installed mod are added to the script path - Mods: give active mods a chance to reattach their load hooks when a world is reloaded - `gui/control-panel`: bugfix services are now enabled by default +- Core: hide DFHack terminal console by default when running on Steam Deck ## Documentation diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 92db43563..a3fcb8b6f 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -125,6 +125,7 @@ set(MODULE_HEADERS include/modules/Burrows.h include/modules/Constructions.h include/modules/DFSDL.h + include/modules/DFSteam.h include/modules/Designations.h include/modules/EventManager.h include/modules/Filesystem.h @@ -154,6 +155,7 @@ set(MODULE_SOURCES modules/Burrows.cpp modules/Constructions.cpp modules/DFSDL.cpp + modules/DFSteam.cpp modules/Designations.cpp modules/EventManager.cpp modules/Filesystem.cpp diff --git a/library/Core.cpp b/library/Core.cpp index 97c69946e..d03e8c632 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -49,6 +49,7 @@ distribution. #include "PluginManager.h" #include "ModuleFactory.h" #include "modules/DFSDL.h" +#include "modules/DFSteam.h" #include "modules/EventManager.h" #include "modules/Filesystem.h" #include "modules/Gui.h" @@ -1303,6 +1304,10 @@ static void run_dfhack_init(color_ostream &out, Core *core) return; } + // if we're running on Steam Deck, hide the terminal by default + if (DFSteam::DFIsSteamRunningOnSteamDeck()) + core->getConsole().hide(); + // load baseline defaults core->loadScriptFile(out, CONFIG_PATH + "init/default.dfhack.init", false); @@ -1668,6 +1673,8 @@ bool Core::Init() fatal("cannot bind SDL libraries"); return false; } + if (DFSteam::init(con)) + std::cerr << "Found Steam.\n"; std::cerr << "Initializing textures.\n"; Textures::init(con); // create mutex for syncing with interactive tasks diff --git a/library/include/modules/DFSteam.h b/library/include/modules/DFSteam.h new file mode 100644 index 000000000..3144830da --- /dev/null +++ b/library/include/modules/DFSteam.h @@ -0,0 +1,32 @@ +#pragma once + +#include "ColorText.h" +#include "Export.h" + +namespace DFHack +{ + +/** + * The DFSteam module - provides access to Steam functions without actually + * requiring build-time linkage to Steam + * \ingroup grp_modules + * \ingroup grp_dfsdl + */ +namespace DFSteam +{ + +/** + * Call this on DFHack init so we can load the function pointers. Returns false on + * failure. + */ +bool init(DFHack::color_ostream& out); + +/** + * Call this when DFHack is being unloaded. + */ +void cleanup(); + +DFHACK_EXPORT bool DFIsSteamRunningOnSteamDeck(); + +} +} diff --git a/library/modules/DFSteam.cpp b/library/modules/DFSteam.cpp new file mode 100644 index 000000000..d32eec961 --- /dev/null +++ b/library/modules/DFSteam.cpp @@ -0,0 +1,64 @@ +#include "Internal.h" + +#include "modules/DFSteam.h" + +#include "Debug.h" +#include "PluginManager.h" + +namespace DFHack +{ +DBG_DECLARE(core, dfsteam, DebugCategory::LINFO); +} + +using namespace DFHack; + +static DFLibrary* g_steam_handle = nullptr; +static const std::vector STEAM_LIBS { + "steam_api64.dll", + "steam_api", // TODO: validate this on OSX + "libsteam_api.so" // TODO: validate this on Linux +}; + +bool (*g_SteamAPI_Init)() = nullptr; +bool (*g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck)() = nullptr; + +bool DFSteam::init(color_ostream& out) { + for (auto& lib_str : STEAM_LIBS) { + if ((g_steam_handle = OpenPlugin(lib_str.c_str()))) + break; + } + if (!g_steam_handle) { + DEBUG(dfsteam, out).print("steam library not found; stubbing calls\n"); + return false; + } + +#define bind(handle, name) \ + g_##name = (decltype(g_##name))LookupPlugin(handle, #name); \ + if (!g_##name) { \ + WARN(dfsteam, out).print("steam library function not found: " #name "\n"); \ + } + + bind(g_steam_handle, SteamAPI_Init); + if (!g_SteamAPI_Init || !g_SteamAPI_Init()) + return false; + + bind(g_steam_handle, SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck); +#undef bind + + DEBUG(dfsteam, out).print("steam library linked\n"); + return true; +} + +void DFSteam::cleanup() { + if (!g_steam_handle) + return; + + ClosePlugin(g_steam_handle); + g_steam_handle = nullptr; +} + +bool DFSteam::DFIsSteamRunningOnSteamDeck() { + if (!g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck) + return false; + return g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck(); +} From f0d19c93631b32ea96d078985502a3244897b104 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 9 Apr 2023 23:30:23 -0700 Subject: [PATCH 0015/1234] add note about dfhooks --- library/modules/DFSteam.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/modules/DFSteam.cpp b/library/modules/DFSteam.cpp index d32eec961..8cc921608 100644 --- a/library/modules/DFSteam.cpp +++ b/library/modules/DFSteam.cpp @@ -39,6 +39,8 @@ bool DFSteam::init(color_ostream& out) { } bind(g_steam_handle, SteamAPI_Init); + + // TODO: can we remove this initialization of the Steam API once we move to dfhooks? if (!g_SteamAPI_Init || !g_SteamAPI_Init()) return false; From e4777d268836d34f1a11ff376dd26cb4a9130c0a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 10 Apr 2023 00:00:47 -0700 Subject: [PATCH 0016/1234] add shutdown and cleanup logic --- library/Core.cpp | 1 + library/modules/DFSteam.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/library/Core.cpp b/library/Core.cpp index d03e8c632..b1fe2d389 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2281,6 +2281,7 @@ int Core::Shutdown ( void ) allModules.clear(); Textures::cleanup(); DFSDL::cleanup(); + DFSteam::cleanup(); memset(&(s_mods), 0, sizeof(s_mods)); d.reset(); return -1; diff --git a/library/modules/DFSteam.cpp b/library/modules/DFSteam.cpp index 8cc921608..f58bc7cb4 100644 --- a/library/modules/DFSteam.cpp +++ b/library/modules/DFSteam.cpp @@ -20,6 +20,7 @@ static const std::vector STEAM_LIBS { }; bool (*g_SteamAPI_Init)() = nullptr; +void (*g_SteamAPI_Shutdown)() = nullptr; bool (*g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck)() = nullptr; bool DFSteam::init(color_ostream& out) { @@ -39,9 +40,10 @@ bool DFSteam::init(color_ostream& out) { } bind(g_steam_handle, SteamAPI_Init); + bind(g_steam_handle, SteamAPI_Shutdown); // TODO: can we remove this initialization of the Steam API once we move to dfhooks? - if (!g_SteamAPI_Init || !g_SteamAPI_Init()) + if (!g_SteamAPI_Init || !g_SteamAPI_Shutdown || !g_SteamAPI_Init()) return false; bind(g_steam_handle, SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck); @@ -55,6 +57,9 @@ void DFSteam::cleanup() { if (!g_steam_handle) return; + if (g_SteamAPI_Shutdown) + g_SteamAPI_Shutdown(); + ClosePlugin(g_steam_handle); g_steam_handle = nullptr; } From ce017ee4a88648809d789c57ff3504f00e91870e Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 10 Apr 2023 03:01:36 -0500 Subject: [PATCH 0017/1234] properly callIs SteamRunningOnSteamDeck --- library/modules/DFSteam.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/modules/DFSteam.cpp b/library/modules/DFSteam.cpp index f58bc7cb4..1226f2a27 100644 --- a/library/modules/DFSteam.cpp +++ b/library/modules/DFSteam.cpp @@ -21,7 +21,8 @@ static const std::vector STEAM_LIBS { bool (*g_SteamAPI_Init)() = nullptr; void (*g_SteamAPI_Shutdown)() = nullptr; -bool (*g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck)() = nullptr; +void* (*g_SteamInternal_FindOrCreateUserInterface)(int, char *) = nullptr; +bool (*g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck)(void*) = nullptr; bool DFSteam::init(color_ostream& out) { for (auto& lib_str : STEAM_LIBS) { @@ -46,6 +47,7 @@ bool DFSteam::init(color_ostream& out) { if (!g_SteamAPI_Init || !g_SteamAPI_Shutdown || !g_SteamAPI_Init()) return false; + bind(g_steam_handle, SteamInternal_FindOrCreateUserInterface); bind(g_steam_handle, SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck); #undef bind @@ -67,5 +69,11 @@ void DFSteam::cleanup() { bool DFSteam::DFIsSteamRunningOnSteamDeck() { if (!g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck) return false; - return g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck(); + + if (!g_SteamInternal_FindOrCreateUserInterface) + return false; + + void* SteamUtils = g_SteamInternal_FindOrCreateUserInterface(0, "SteamUtils010"); + + return g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck(SteamUtils); } From 836a3edcb958959ba9a4157b7419dacfb431e617 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 10 Apr 2023 01:12:43 -0700 Subject: [PATCH 0018/1234] add some more logging --- library/modules/DFSteam.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/modules/DFSteam.cpp b/library/modules/DFSteam.cpp index 1226f2a27..4c45f1114 100644 --- a/library/modules/DFSteam.cpp +++ b/library/modules/DFSteam.cpp @@ -21,7 +21,7 @@ static const std::vector STEAM_LIBS { bool (*g_SteamAPI_Init)() = nullptr; void (*g_SteamAPI_Shutdown)() = nullptr; -void* (*g_SteamInternal_FindOrCreateUserInterface)(int, char *) = nullptr; +void* (*g_SteamInternal_FindOrCreateUserInterface)(int, char*) = nullptr; bool (*g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck)(void*) = nullptr; bool DFSteam::init(color_ostream& out) { @@ -44,8 +44,10 @@ bool DFSteam::init(color_ostream& out) { bind(g_steam_handle, SteamAPI_Shutdown); // TODO: can we remove this initialization of the Steam API once we move to dfhooks? - if (!g_SteamAPI_Init || !g_SteamAPI_Shutdown || !g_SteamAPI_Init()) + if (!g_SteamAPI_Init || !g_SteamAPI_Shutdown || !g_SteamAPI_Init()) { + DEBUG(dfsteam, out).print("steam detected but cannot be initialized\n"); return false; + } bind(g_steam_handle, SteamInternal_FindOrCreateUserInterface); bind(g_steam_handle, SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck); From 17373dcffd6ec40cc1c8bdb105e1e92adff7f1ec Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 10 Apr 2023 01:16:22 -0700 Subject: [PATCH 0019/1234] constify! --- library/modules/DFSteam.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/DFSteam.cpp b/library/modules/DFSteam.cpp index 4c45f1114..b27cc1744 100644 --- a/library/modules/DFSteam.cpp +++ b/library/modules/DFSteam.cpp @@ -21,7 +21,7 @@ static const std::vector STEAM_LIBS { bool (*g_SteamAPI_Init)() = nullptr; void (*g_SteamAPI_Shutdown)() = nullptr; -void* (*g_SteamInternal_FindOrCreateUserInterface)(int, char*) = nullptr; +void* (*g_SteamInternal_FindOrCreateUserInterface)(int, const char*) = nullptr; bool (*g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck)(void*) = nullptr; bool DFSteam::init(color_ostream& out) { From c0fe5776fb760d3cdfc3b8966ffde2e5416455dd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 10 Apr 2023 18:29:41 -0700 Subject: [PATCH 0020/1234] update Installing docs for Steam --- docs/Installing.rst | 163 ++++++++++++++++---------------------------- docs/changelog.txt | 1 + 2 files changed, 58 insertions(+), 106 deletions(-) diff --git a/docs/Installing.rst b/docs/Installing.rst index bc58a39b7..a80133e88 100644 --- a/docs/Installing.rst +++ b/docs/Installing.rst @@ -7,78 +7,50 @@ Installing DFHack .. contents:: :local: - Requirements ============ -DFHack supports Windows, Linux, and macOS, and both 64-bit and 32-bit builds -of Dwarf Fortress. +DFHack supports all operating systems and platforms that Dwarf Fortress itself +supports, which at the moment is 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: DFHack releases generally only support the version of Dwarf Fortress that they -are named after. For example, DFHack 0.40.24-r5 only supported DF 0.40.24. -DFHack releases *never* support newer versions of DF, because DFHack requires -data about DF that is only possible to obtain after DF has been released. -Occasionally, DFHack releases will be able to maintain support for older -versions of DF - for example, DFHack 0.34.11-r5 supported both DF 0.34.11 and -0.34.10. For maximum stability, you should usually use the latest versions of -both DF and DFHack. - -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 `_ - -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 `. - -macOS ------ - -OS X 10.6.8 or later is required. - +are named after. For example, DFHack 50.05 only supported DF 50.05. DFHack +releases *never* support newer versions of DF -- DFHack requires data about DF +that is only possible to obtain after DF has been released. Occasionally, +DFHack releases will be able to maintain support for older versions of DF - for +example, DFHack 0.34.11-r5 supported both DF 0.34.11 and 0.34.10. For maximum +stability, you should usually use the latest versions of both DF and DFHack. .. _downloading: Downloading DFHack ================== -Stable builds of DFHack are available on `GitHub `_. -GitHub has been known to change their layout periodically, but as of July 2020, -downloads are available at the bottom of the release notes for each release, under a section -named "Assets" (which you may have to expand). The name of the file indicates -which DF version, platform, and architecture the build supports - the platform -and architecture (64-bit or 32-bit) **must** match your build of DF. The DF -version should also match your DF version - see `above ` -for details. For example: +Stable builds of DFHack are available on +`Steam `__ +or from our `GitHub `__. Either +location will give you exactly the same package. + +On Steam, note that DFHack is a separate app, not a DF Steam Workshop mod. You +can run DF with DFHack by launching either the DFHack app or the original Dwarf +Fortress app. + +If you download from GitHub, downloads are available at the bottom of the +release notes for each release, under a section named "Assets" (which you may +have to expand). The name of the file indicates which DF version, platform, and +architecture the build supports - the platform and architecture (64-bit or +32-bit) **must** match your build of DF. The DF version should also match your +DF version - see `above ` for details. For example: -* ``dfhack-0.47.04-r1-Windows-64bit.zip`` supports 64-bit DF on Windows -* ``dfhack-0.47.04-r1-Linux-32bit-gcc-7.tar.bz2`` supports 32-bit DF on Linux - (see `installing-reqs-linux` for details on the GCC version indicator) +* ``dfhack-50.07-r1-Windows-64bit.zip`` supports 64-bit DF on Windows -The `DFHack website `_ also provides links to -unstable builds. These files have a different naming scheme, but the same -restrictions apply (e.g. a file named ``Windows64`` is for 64-bit Windows DF). +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" suffix. .. warning:: @@ -91,19 +63,22 @@ restrictions apply (e.g. a file named ``Windows64`` is for 64-bit Windows DF). Installing DFHack ================= +If you are installing from Steam, this is handled for you automatically. The +instructions here are for manual installs. + When you `download DFHack `, you will end up with a release archive (a ``.zip`` file on Windows, or a ``.tar.bz2`` file on other platforms). Your operating system should have built-in utilities capable of extracting files from these archives. -The release archives contain several folders, including a ``hack`` folder where -DFHack binary and system data is stored, a ``dfhack-config`` folder where user -data and configuration is stored, and a ``blueprints`` folder where `quickfort` -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. +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 ``mods`` 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. .. note:: @@ -112,58 +87,34 @@ folder ends up next to the ``data`` folder. overwrite ``SDL.dll`` if prompted. (If you are not prompted, you may be installing DFHack in the wrong place.) - Uninstalling DFHack =================== -Uninstalling DFHack essentially involves reversing what you did to install -DFHack. On Windows, replace ``SDL.dll`` with ``SDLreal.dll`` first. Then, you +Manually uninstalling DFHack essentially involves reversing what you did to +install. On Windows, replace ``SDL.dll`` with ``SDLreal.dll`` first. Then, you can remove any files that were part of the DFHack archive. DFHack does not currently maintain a list of these files, so if you want to completely remove them, you should consult the DFHack archive that you installed for a full list. Generally, any files left behind should not negatively affect DF. +On Steam, uninstalling DFHack will cleanly remove everything that was installed +with DFHack, **including** the ``SDL.dll`` file, which will render Dwarf +Fortress inoperative. In your Steam client, open the properties window for +Dwarf Fortress, select "Local Files", and click on "Verify integrity of game +files...". This will get Dwarf Fortress working properly again. + +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 ================ -The recommended approach to upgrade DFHack is to uninstall DFHack first, then -install the new version. This will ensure that any files that are only part -of the older DFHack installation do not affect the new DFHack installation -(although this is unlikely to occur). - -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 ` 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: +Again, if you have installed from Steam, your copy of DFHack will automatically be kept up to date. This section is for manual installers. -* `AUR `__, for Arch and related - distributions -* `RPM Fusion `__, - for Fedora and related distributions +First, remove the ``hack`` and ``stonesense`` folders in their entirety. This +ensures that files that don't exist in the latest version are properly removed +and don't affect your new installation. -Note that these may lag behind DFHack releases. If you want to use a newer -version of DFHack, we generally recommended installing it in a clean copy of DF -in your home folder. Attempting to upgrade an installation of DFHack from a -package manager may break it. +Then, extract the DFHack release archive into your Dwarf Fortress folder, +overwriting any remaining top-level files (including SDL.dll). diff --git a/docs/changelog.txt b/docs/changelog.txt index e63b80bd7..8beb3dc6e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -55,6 +55,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Core: hide DFHack terminal console by default when running on Steam Deck ## Documentation +- `installing`: updated to include Steam installation instructions ## API From e16b01898b7f8788dcaf7ec97caef36f86847e7d Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 10 Apr 2023 20:35:05 -0700 Subject: [PATCH 0021/1234] Mention save instead of mods --- docs/Installing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Installing.rst b/docs/Installing.rst index a80133e88..15a6276bf 100644 --- a/docs/Installing.rst +++ b/docs/Installing.rst @@ -75,7 +75,7 @@ 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 ``mods`` folder, +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. From 51047367f4e29694f0a5b78f5c418826d6b5a09e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 10 Apr 2023 23:07:18 -0700 Subject: [PATCH 0022/1234] fix index out of bounds error when reading gems --- docs/changelog.txt | 2 ++ plugins/lua/stockpiles.lua | 2 +- plugins/stockpiles/StockpileSerializer.cpp | 20 ++++++++++++-------- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 8beb3dc6e..7c52315ea 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -42,6 +42,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `blueprint`: interpret saplings, shrubs, and twigs as floors instead of walls - `combine`: fix error processing stockpiles with boundaries that extend outside of the map - `prospector`: display both "raw" Z levels and "cooked" elevations +- `stockpiles`: fix crash when importing settings for gems from other worlds +- `stockpiles`: allow numbers in saved stockpile filenames ## Misc Improvements - `buildingplan`: items in the item selection dialog should now use the same item quality symbols as the base game diff --git a/plugins/lua/stockpiles.lua b/plugins/lua/stockpiles.lua index 6134f0a1b..9e17cbe2b 100644 --- a/plugins/lua/stockpiles.lua +++ b/plugins/lua/stockpiles.lua @@ -62,7 +62,7 @@ local function assert_safe_name(name) if not name or #name == 0 then qerror('name missing or empty') end - if name:find('[^%a._]') then + if name:find('[^%w._]') then qerror('name can only contain numbers, letters, periods, and underscores') end end diff --git a/plugins/stockpiles/StockpileSerializer.cpp b/plugins/stockpiles/StockpileSerializer.cpp index f6a63ff4f..529e402bd 100644 --- a/plugins/stockpiles/StockpileSerializer.cpp +++ b/plugins/stockpiles/StockpileSerializer.cpp @@ -1848,7 +1848,7 @@ void StockpileSerializer::read_gems(DeserializeMode mode, const vector& unserialize_list_material("mats/rough", all, val, filters, gem_mat_is_allowed, [&](const size_t& idx) -> const string& { return bgems.rough_mats(idx); }, - bgems.rough_mats_size(),pgems.rough_mats); + bgems.rough_mats_size(), pgems.rough_mats); unserialize_list_material("mats/cut", all, val, filters, gem_cut_mat_is_allowed, [&](const size_t& idx) -> const string& { return bgems.cut_mats(idx); }, @@ -1871,13 +1871,17 @@ void StockpileSerializer::read_gems(DeserializeMode mode, const vector& return; } else { MaterialInfo mi; - for (size_t i = 0; i < builtin_size; ++i) { - string id = bgems.rough_other_mats(i); - if (mi.find(id) && mi.isValid() && size_t(mi.type) < builtin_size) - set_filter_elem("other/rough", filters, val, id, mi.type, pgems.rough_other_mats.at(mi.type)); - id = bgems.cut_other_mats(i); - if (mi.find(id) && mi.isValid() && size_t(mi.type) < builtin_size) - set_filter_elem("other/cut", filters, val, id, mi.type, pgems.cut_other_mats.at(mi.type)); + for (int i = 0; i < (int)builtin_size; ++i) { + if (i < bgems.rough_other_mats_size()) { + string id = bgems.rough_other_mats(i); + if (mi.find(id) && mi.isValid() && size_t(mi.type) < builtin_size) + set_filter_elem("other/rough", filters, val, id, mi.type, pgems.rough_other_mats.at(mi.type)); + } + if (i < bgems.cut_other_mats_size()) { + string id = bgems.cut_other_mats(i); + if (mi.find(id) && mi.isValid() && size_t(mi.type) < builtin_size) + set_filter_elem("other/cut", filters, val, id, mi.type, pgems.cut_other_mats.at(mi.type)); + } } } }); From c5ff1622cd82113aabee9c2d55184c67ed95dca9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 11 Apr 2023 00:39:22 -0700 Subject: [PATCH 0023/1234] reformat code and clean up headers --- plugins/getplants.cpp | 319 ++++++++++++++++-------------------------- 1 file changed, 119 insertions(+), 200 deletions(-) diff --git a/plugins/getplants.cpp b/plugins/getplants.cpp index 565316fa6..c9db92f5a 100644 --- a/plugins/getplants.cpp +++ b/plugins/getplants.cpp @@ -1,13 +1,5 @@ -// (un)designate matching plants for gathering/cutting -#include - -#include "Core.h" -#include "Console.h" -#include "Export.h" #include "PluginManager.h" -#include "DataDefs.h" #include "TileTypes.h" -#include "MiscUtils.h" #include "df/map_block.h" #include "df/map_block_column.h" @@ -76,48 +68,38 @@ enum class selectability { // result in the plants not being usable for farming or even collectable at all). //selectability selectablePlant(color_ostream &out, const df::plant_raw *plant, bool farming) -selectability selectablePlant(const df::plant_raw *plant, bool farming) -{ +selectability selectablePlant(const df::plant_raw* plant, bool farming) { const DFHack::MaterialInfo basic_mat = DFHack::MaterialInfo(plant->material_defs.type[plant_material_def::basic_mat], plant->material_defs.idx[plant_material_def::basic_mat]); bool outOfSeason = false; selectability result = selectability::Nonselectable; - if (plant->flags.is_set(plant_raw_flags::TREE)) - { -// out.print("%s is a selectable tree\n", plant->id.c_str()); - if (farming) - { + if (plant->flags.is_set(plant_raw_flags::TREE)) { + // out.print("%s is a selectable tree\n", plant->id.c_str()); + if (farming) { return selectability::Nonselectable; } - else - { + else { return selectability::Selectable; } } - else if (plant->flags.is_set(plant_raw_flags::GRASS)) - { -// out.print("%s is a non selectable Grass\n", plant->id.c_str()); + else if (plant->flags.is_set(plant_raw_flags::GRASS)) { + // out.print("%s is a non selectable Grass\n", plant->id.c_str()); return selectability::Grass; } - if (farming && plant->material_defs.type[plant_material_def::seed] == -1) - { + if (farming && plant->material_defs.type[plant_material_def::seed] == -1) { return selectability::Nonselectable; } if (basic_mat.material->flags.is_set(material_flags::EDIBLE_RAW) || - basic_mat.material->flags.is_set(material_flags::EDIBLE_COOKED)) - { -// out.print("%s is edible\n", plant->id.c_str()); - if (farming) - { - if (basic_mat.material->flags.is_set(material_flags::EDIBLE_RAW)) - { + basic_mat.material->flags.is_set(material_flags::EDIBLE_COOKED)) { + // out.print("%s is edible\n", plant->id.c_str()); + if (farming) { + if (basic_mat.material->flags.is_set(material_flags::EDIBLE_RAW)) { result = selectability::Selectable; } } - else - { + else { return selectability::Selectable; } } @@ -126,54 +108,43 @@ selectability selectablePlant(const df::plant_raw *plant, bool farming) plant->flags.is_set(plant_raw_flags::MILL) || plant->flags.is_set(plant_raw_flags::EXTRACT_VIAL) || plant->flags.is_set(plant_raw_flags::EXTRACT_BARREL) || - plant->flags.is_set(plant_raw_flags::EXTRACT_STILL_VIAL)) - { -// out.print("%s is thread/mill/extract\n", plant->id.c_str()); - if (farming) - { + plant->flags.is_set(plant_raw_flags::EXTRACT_STILL_VIAL)) { + // out.print("%s is thread/mill/extract\n", plant->id.c_str()); + if (farming) { result = selectability::Selectable; } - else - { + else { return selectability::Selectable; } } if (basic_mat.material->reaction_product.id.size() > 0 || - basic_mat.material->reaction_class.size() > 0) - { -// out.print("%s has a reaction\n", plant->id.c_str()); - if (farming) - { + basic_mat.material->reaction_class.size() > 0) { + // out.print("%s has a reaction\n", plant->id.c_str()); + if (farming) { result = selectability::Selectable; } - else - { + else { return selectability::Selectable; } } - for (size_t i = 0; i < plant->growths.size(); i++) - { + for (size_t i = 0; i < plant->growths.size(); i++) { if (plant->growths[i]->item_type == df::item_type::SEEDS || // Only trees have seed growths in vanilla, but raws can be modded... - plant->growths[i]->item_type == df::item_type::PLANT_GROWTH) - { + plant->growths[i]->item_type == df::item_type::PLANT_GROWTH) { const DFHack::MaterialInfo growth_mat = DFHack::MaterialInfo(plant->growths[i]->mat_type, plant->growths[i]->mat_index); if ((plant->growths[i]->item_type == df::item_type::SEEDS && - (growth_mat.material->flags.is_set(material_flags::EDIBLE_COOKED) || - growth_mat.material->flags.is_set(material_flags::EDIBLE_RAW))) || + (growth_mat.material->flags.is_set(material_flags::EDIBLE_COOKED) || + growth_mat.material->flags.is_set(material_flags::EDIBLE_RAW))) || (plant->growths[i]->item_type == df::item_type::PLANT_GROWTH && - growth_mat.material->flags.is_set(material_flags::LEAF_MAT))) // Will change name to STOCKPILE_PLANT_GROWTH any day now... + growth_mat.material->flags.is_set(material_flags::LEAF_MAT))) // Will change name to STOCKPILE_PLANT_GROWTH any day now... { bool seedSource = plant->growths[i]->item_type == df::item_type::SEEDS; - if (plant->growths[i]->item_type == df::item_type::PLANT_GROWTH) - { - for (size_t k = 0; growth_mat.material->reaction_product.material.mat_type.size(); k++) - { + if (plant->growths[i]->item_type == df::item_type::PLANT_GROWTH) { + for (size_t k = 0; growth_mat.material->reaction_product.material.mat_type.size(); k++) { if (growth_mat.material->reaction_product.material.mat_type[k] == plant->material_defs.type[plant_material_def::seed] && - growth_mat.material->reaction_product.material.mat_index[k] == plant->material_defs.idx[plant_material_def::seed]) - { + growth_mat.material->reaction_product.material.mat_index[k] == plant->material_defs.idx[plant_material_def::seed]) { seedSource = true; break; } @@ -182,52 +153,46 @@ selectability selectablePlant(const df::plant_raw *plant, bool farming) if (*cur_year_tick >= plant->growths[i]->timing_1 && (plant->growths[i]->timing_2 == -1 || - *cur_year_tick <= plant->growths[i]->timing_2)) - { -// out.print("%s has an edible seed or a stockpile growth\n", plant->id.c_str()); - if (!farming || seedSource) - { + *cur_year_tick <= plant->growths[i]->timing_2)) { + // out.print("%s has an edible seed or a stockpile growth\n", plant->id.c_str()); + if (!farming || seedSource) { return selectability::Selectable; } } - else - { - if (!farming || seedSource) - { + else { + if (!farming || seedSource) { outOfSeason = true; } } } } -/* else if (plant->growths[i]->behavior.bits.has_seed) // This code designates beans, etc. when DF doesn't, but plant gatherers still fail to collect anything, so it's useless: bug #0006940. - { - const DFHack::MaterialInfo seed_mat = DFHack::MaterialInfo(plant->material_defs.type[plant_material_def::seed], plant->material_defs.idx[plant_material_def::seed]); - - if (seed_mat.material->flags.is_set(material_flags::EDIBLE_RAW) || - seed_mat.material->flags.is_set(material_flags::EDIBLE_COOKED)) - { - if (*cur_year_tick >= plant->growths[i]->timing_1 && - (plant->growths[i]->timing_2 == -1 || - *cur_year_tick <= plant->growths[i]->timing_2)) + /* else if (plant->growths[i]->behavior.bits.has_seed) // This code designates beans, etc. when DF doesn't, but plant gatherers still fail to collect anything, so it's useless: bug #0006940. { - return selectability::Selectable; - } - else - { - outOfSeason = true; - } - } - } */ + const DFHack::MaterialInfo seed_mat = DFHack::MaterialInfo(plant->material_defs.type[plant_material_def::seed], plant->material_defs.idx[plant_material_def::seed]); + + if (seed_mat.material->flags.is_set(material_flags::EDIBLE_RAW) || + seed_mat.material->flags.is_set(material_flags::EDIBLE_COOKED)) + { + if (*cur_year_tick >= plant->growths[i]->timing_1 && + (plant->growths[i]->timing_2 == -1 || + *cur_year_tick <= plant->growths[i]->timing_2)) + { + return selectability::Selectable; + } + else + { + outOfSeason = true; + } + } + } */ } - if (outOfSeason) - { -// out.print("%s has an out of season growth\n", plant->id.c_str()); + if (outOfSeason) { + // out.print("%s has an out of season growth\n", plant->id.c_str()); return selectability::OutOfSeason; } - else - { -// out.printerr("%s cannot be gathered\n", plant->id.c_str()); + else { + // out.printerr("%s cannot be gathered\n", plant->id.c_str()); return result; } } @@ -241,17 +206,17 @@ bool ripe(int32_t x, int32_t y, int32_t start, int32_t end) { } // Looks in the picked growths vector to see if a matching growth has been marked as picked. -bool picked(const df::plant *plant, int32_t growth_subtype) { - df::world_data *world_data = world->world_data; - df::world_site *site = df::world_site::find(plotinfo->site_id); +bool picked(const df::plant* plant, int32_t growth_subtype) { + df::world_data* world_data = world->world_data; + df::world_site* site = df::world_site::find(plotinfo->site_id); int32_t pos_x = site->global_min_x + plant->pos.x / 48; int32_t pos_y = site->global_min_y + plant->pos.y / 48; size_t id = pos_x + pos_y * 16 * world_data->world_width; - df::world_object_data *object_data = df::world_object_data::find(id); + df::world_object_data* object_data = df::world_object_data::find(id); if (!object_data) { return false; } - df::map_block_column *column = world->map.map_block_columns[(plant->pos.x / 16) * world->map.x_count_block + (plant->pos.y / 16)]; + df::map_block_column* column = world->map.map_block_columns[(plant->pos.x / 16) * world->map.x_count_block + (plant->pos.y / 16)]; for (size_t i = 0; i < object_data->picked_growths.x.size(); i++) { if (object_data->picked_growths.x[i] == plant->pos.x && @@ -266,13 +231,12 @@ bool picked(const df::plant *plant, int32_t growth_subtype) { return false; } -bool designate(const df::plant *plant, bool farming) { - df::plant_raw *plant_raw = world->raws.plants.all[plant->material]; +bool designate(const df::plant* plant, bool farming) { + df::plant_raw* plant_raw = world->raws.plants.all[plant->material]; const DFHack::MaterialInfo basic_mat = DFHack::MaterialInfo(plant_raw->material_defs.type[plant_material_def::basic_mat], plant_raw->material_defs.idx[plant_material_def::basic_mat]); if (basic_mat.material->flags.is_set(material_flags::EDIBLE_RAW) || - basic_mat.material->flags.is_set(material_flags::EDIBLE_COOKED)) - { + basic_mat.material->flags.is_set(material_flags::EDIBLE_COOKED)) { return Designations::markPlant(plant); } @@ -280,42 +244,35 @@ bool designate(const df::plant *plant, bool farming) { plant_raw->flags.is_set(plant_raw_flags::MILL) || plant_raw->flags.is_set(plant_raw_flags::EXTRACT_VIAL) || plant_raw->flags.is_set(plant_raw_flags::EXTRACT_BARREL) || - plant_raw->flags.is_set(plant_raw_flags::EXTRACT_STILL_VIAL)) - { + plant_raw->flags.is_set(plant_raw_flags::EXTRACT_STILL_VIAL)) { if (!farming) { return Designations::markPlant(plant); } } if (basic_mat.material->reaction_product.id.size() > 0 || - basic_mat.material->reaction_class.size() > 0) - { + basic_mat.material->reaction_class.size() > 0) { if (!farming) { return Designations::markPlant(plant); } } - for (size_t i = 0; i < plant_raw->growths.size(); i++) - { + for (size_t i = 0; i < plant_raw->growths.size(); i++) { if (plant_raw->growths[i]->item_type == df::item_type::SEEDS || // Only trees have seed growths in vanilla, but raws can be modded... - plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH) - { + plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH) { const DFHack::MaterialInfo growth_mat = DFHack::MaterialInfo(plant_raw->growths[i]->mat_type, plant_raw->growths[i]->mat_index); if ((plant_raw->growths[i]->item_type == df::item_type::SEEDS && (growth_mat.material->flags.is_set(material_flags::EDIBLE_COOKED) || growth_mat.material->flags.is_set(material_flags::EDIBLE_RAW))) || - (plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH && - growth_mat.material->flags.is_set(material_flags::LEAF_MAT))) // Will change name to STOCKPILE_PLANT_GROWTH any day now... + (plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH && + growth_mat.material->flags.is_set(material_flags::LEAF_MAT))) // Will change name to STOCKPILE_PLANT_GROWTH any day now... { bool seedSource = plant_raw->growths[i]->item_type == df::item_type::SEEDS; - if (plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH) - { - for (size_t k = 0; growth_mat.material->reaction_product.material.mat_type.size(); k++) - { + if (plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH) { + for (size_t k = 0; growth_mat.material->reaction_product.material.mat_type.size(); k++) { if (growth_mat.material->reaction_product.material.mat_type[k] == plant_raw->material_defs.type[plant_material_def::seed] && - growth_mat.material->reaction_product.material.mat_index[k] == plant_raw->material_defs.idx[plant_material_def::seed]) - { + growth_mat.material->reaction_product.material.mat_index[k] == plant_raw->material_defs.idx[plant_material_def::seed]) { seedSource = true; break; } @@ -324,8 +281,7 @@ bool designate(const df::plant *plant, bool farming) { bool istree = (tileMaterial(Maps::getTileBlock(plant->pos)->tiletype[plant->pos.x % 16][plant->pos.y % 16]) == tiletype_material::TREE); bool isripe = ripe(plant->pos.x, plant->pos.y, plant_raw->growths[i]->timing_1, plant_raw->growths[i]->timing_2); - if ((!farming || seedSource) && (istree || isripe) && !picked(plant, i)) - { + if ((!farming || seedSource) && (istree || isripe) && !picked(plant, i)) { return Designations::markPlant(plant); } } @@ -335,8 +291,7 @@ bool designate(const df::plant *plant, bool farming) { return false; } -command_result df_getplants (color_ostream &out, vector & parameters) -{ +command_result df_getplants(color_ostream& out, vector & parameters) { string plantMatStr = ""; std::vector plantSelections; std::vector collectionCount; @@ -348,16 +303,14 @@ command_result df_getplants (color_ostream &out, vector & parameters) plantSelections.resize(world->raws.plants.all.size()); collectionCount.resize(world->raws.plants.all.size()); - for (size_t i = 0; i < plantSelections.size(); i++) - { + for (size_t i = 0; i < plantSelections.size(); i++) { plantSelections[i] = selectability::Unselected; collectionCount[i] = 0; } bool anyPlantsSelected = false; - for (size_t i = 0; i < parameters.size(); i++) - { + for (size_t i = 0; i < parameters.size(); i++) { if (parameters[i] == "help" || parameters[i] == "?") return CR_WRONG_USAGE; else if (parameters[i] == "-t") @@ -374,23 +327,18 @@ command_result df_getplants (color_ostream &out, vector & parameters) verbose = true; else if (parameters[i] == "-f") farming = true; - else if (parameters[i] == "-n") - { - if (parameters.size() > i + 1) - { + else if (parameters[i] == "-n") { + if (parameters.size() > i + 1) { maxCount = atoi(parameters[i + 1].c_str()); - if (maxCount >= 1) - { + if (maxCount >= 1) { i++; // We've consumed the next parameter, so we need to progress the iterator. } - else - { + else { out.printerr("-n requires a positive integer parameter!\n"); return CR_WRONG_USAGE; } } - else - { + else { out.printerr("-n requires a positive integer parameter!\n"); return CR_WRONG_USAGE; } @@ -398,55 +346,45 @@ command_result df_getplants (color_ostream &out, vector & parameters) else plantNames.insert(toUpper(parameters[i])); } - if (treesonly && shrubsonly) - { + if (treesonly && shrubsonly) { out.printerr("Cannot specify both -t and -s at the same time!\n"); return CR_WRONG_USAGE; } - if (treesonly && farming) - { + if (treesonly && farming) { out.printerr("Cannot specify both -t and -f at the same time!\n"); return CR_WRONG_USAGE; } - if (all && exclude) - { + if (all && exclude) { out.printerr("Cannot specify both -a and -x at the same time!\n"); return CR_WRONG_USAGE; } - if (all && plantNames.size()) - { + if (all && plantNames.size()) { out.printerr("Cannot specify -a along with plant IDs!\n"); return CR_WRONG_USAGE; } CoreSuspender suspend; - for (size_t i = 0; i < world->raws.plants.all.size(); i++) - { - df::plant_raw *plant = world->raws.plants.all[i]; - if (all) - { -// plantSelections[i] = selectablePlant(out, plant, farming); + for (size_t i = 0; i < world->raws.plants.all.size(); i++) { + df::plant_raw* plant = world->raws.plants.all[i]; + if (all) { + // plantSelections[i] = selectablePlant(out, plant, farming); plantSelections[i] = selectablePlant(plant, farming); } - else if (plantNames.find(plant->id) != plantNames.end()) - { + else if (plantNames.find(plant->id) != plantNames.end()) { plantNames.erase(plant->id); -// plantSelections[i] = selectablePlant(out, plant, farming); + // plantSelections[i] = selectablePlant(out, plant, farming); plantSelections[i] = selectablePlant(plant, farming); - switch (plantSelections[i]) - { + switch (plantSelections[i]) { case selectability::Grass: out.printerr("%s is a grass and cannot be gathered\n", plant->id.c_str()); break; case selectability::Nonselectable: - if (farming) - { + if (farming) { out.printerr("%s does not have any parts that can be gathered for seeds for farming\n", plant->id.c_str()); } - else - { + else { out.printerr("%s does not have any parts that can be gathered\n", plant->id.c_str()); } break; @@ -463,8 +401,7 @@ command_result df_getplants (color_ostream &out, vector & parameters) } } } - if (plantNames.size() > 0) - { + if (plantNames.size() > 0) { out.printerr("Invalid plant ID(s):"); for (set::const_iterator it = plantNames.begin(); it != plantNames.end(); it++) out.printerr(" %s", it->c_str()); @@ -472,33 +409,27 @@ command_result df_getplants (color_ostream &out, vector & parameters) return CR_FAILURE; } - for (size_t i = 0; i < plantSelections.size(); i++) - { + for (size_t i = 0; i < plantSelections.size(); i++) { if (plantSelections[i] == selectability::OutOfSeason || - plantSelections[i] == selectability::Selectable) - { + plantSelections[i] == selectability::Selectable) { anyPlantsSelected = true; break; } } - if (!anyPlantsSelected) - { + if (!anyPlantsSelected) { out.print("Valid plant IDs:\n"); - for (size_t i = 0; i < world->raws.plants.all.size(); i++) - { - df::plant_raw *plant = world->raws.plants.all[i]; -// switch (selectablePlant(out, plant, farming)) - switch (selectablePlant(plant, farming)) - { + for (size_t i = 0; i < world->raws.plants.all.size(); i++) { + df::plant_raw* plant = world->raws.plants.all[i]; + // switch (selectablePlant(out, plant, farming)) + switch (selectablePlant(plant, farming)) { case selectability::Grass: case selectability::Nonselectable: continue; case selectability::OutOfSeason: { - if (!treesonly) - { + if (!treesonly) { out.print("* (shrub) %s - %s is out of season\n", plant->id.c_str(), plant->name.c_str()); } break; @@ -523,22 +454,19 @@ command_result df_getplants (color_ostream &out, vector & parameters) } count = 0; - for (size_t i = 0; i < world->plants.all.size(); i++) - { - const df::plant *plant = world->plants.all[i]; - df::map_block *cur = Maps::getTileBlock(plant->pos); + for (size_t i = 0; i < world->plants.all.size(); i++) { + const df::plant* plant = world->plants.all[i]; + df::map_block* cur = Maps::getTileBlock(plant->pos); int x = plant->pos.x % 16; int y = plant->pos.y % 16; if (plantSelections[plant->material] == selectability::OutOfSeason || - plantSelections[plant->material] == selectability::Selectable) - { + plantSelections[plant->material] == selectability::Selectable) { if (exclude || plantSelections[plant->material] == selectability::OutOfSeason) continue; } - else - { + else { if (!exclude) continue; } @@ -553,37 +481,29 @@ command_result df_getplants (color_ostream &out, vector & parameters) continue; if (collectionCount[plant->material] >= maxCount) continue; - if (deselect && Designations::unmarkPlant(plant)) - { + if (deselect && Designations::unmarkPlant(plant)) { collectionCount[plant->material]++; ++count; } - if (!deselect && designate(plant, farming)) - { -// out.print("Designated %s at (%i, %i, %i), %d\n", world->raws.plants.all[plant->material]->id.c_str(), plant->pos.x, plant->pos.y, plant->pos.z, (int)i); + if (!deselect && designate(plant, farming)) { + // out.print("Designated %s at (%i, %i, %i), %d\n", world->raws.plants.all[plant->material]->id.c_str(), plant->pos.x, plant->pos.y, plant->pos.z, (int)i); collectionCount[plant->material]++; ++count; } } - if (count) - { - if (verbose) - { - for (size_t i = 0; i < plantSelections.size(); i++) - { - if (collectionCount[i] > 0) - out.print("Updated %d %s designations.\n", (int)collectionCount[i], world->raws.plants.all[i]->id.c_str()); - } - out.print("\n"); + if (count && verbose) { + for (size_t i = 0; i < plantSelections.size(); i++) { + if (collectionCount[i] > 0) + out.print("Updated %d %s designations.\n", (int)collectionCount[i], world->raws.plants.all[i]->id.c_str()); } + out.print("\n"); } out.print("Updated %d plant designations.\n", (int)count); return CR_OK; } -DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) -{ +DFhackCExport command_result plugin_init(color_ostream& out, vector & commands) { commands.push_back(PluginCommand( "getplants", "Designate trees for chopping and shrubs for gathering.", @@ -591,7 +511,6 @@ DFhackCExport command_result plugin_init ( color_ostream &out, vector Date: Tue, 11 Apr 2023 00:58:40 -0700 Subject: [PATCH 0024/1234] add debug logging --- plugins/getplants.cpp | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/plugins/getplants.cpp b/plugins/getplants.cpp index c9db92f5a..821dfa0b7 100644 --- a/plugins/getplants.cpp +++ b/plugins/getplants.cpp @@ -1,3 +1,4 @@ +#include "Debug.h" #include "PluginManager.h" #include "TileTypes.h" @@ -24,6 +25,11 @@ using std::set; using namespace DFHack; using namespace df::enums; +namespace DFHack +{ +DBG_DECLARE(getplants, log, DebugCategory::LINFO); +} + DFHACK_PLUGIN("getplants"); REQUIRE_GLOBAL(plotinfo); REQUIRE_GLOBAL(world); @@ -67,14 +73,13 @@ enum class selectability { // is one of the issues in bug 6940 on the bug tracker (the others cases are detected and // result in the plants not being usable for farming or even collectable at all). -//selectability selectablePlant(color_ostream &out, const df::plant_raw *plant, bool farming) -selectability selectablePlant(const df::plant_raw* plant, bool farming) { +selectability selectablePlant(color_ostream& out, const df::plant_raw* plant, bool farming) { const DFHack::MaterialInfo basic_mat = DFHack::MaterialInfo(plant->material_defs.type[plant_material_def::basic_mat], plant->material_defs.idx[plant_material_def::basic_mat]); bool outOfSeason = false; selectability result = selectability::Nonselectable; if (plant->flags.is_set(plant_raw_flags::TREE)) { - // out.print("%s is a selectable tree\n", plant->id.c_str()); + DEBUG(log, out).print("%s is a selectable tree\n", plant->id.c_str()); if (farming) { return selectability::Nonselectable; } @@ -83,7 +88,7 @@ selectability selectablePlant(const df::plant_raw* plant, bool farming) { } } else if (plant->flags.is_set(plant_raw_flags::GRASS)) { - // out.print("%s is a non selectable Grass\n", plant->id.c_str()); + DEBUG(log, out).print("%s is a non selectable Grass\n", plant->id.c_str()); return selectability::Grass; } @@ -93,7 +98,7 @@ selectability selectablePlant(const df::plant_raw* plant, bool farming) { if (basic_mat.material->flags.is_set(material_flags::EDIBLE_RAW) || basic_mat.material->flags.is_set(material_flags::EDIBLE_COOKED)) { - // out.print("%s is edible\n", plant->id.c_str()); + DEBUG(log, out).print("%s is edible\n", plant->id.c_str()); if (farming) { if (basic_mat.material->flags.is_set(material_flags::EDIBLE_RAW)) { result = selectability::Selectable; @@ -109,7 +114,7 @@ selectability selectablePlant(const df::plant_raw* plant, bool farming) { plant->flags.is_set(plant_raw_flags::EXTRACT_VIAL) || plant->flags.is_set(plant_raw_flags::EXTRACT_BARREL) || plant->flags.is_set(plant_raw_flags::EXTRACT_STILL_VIAL)) { - // out.print("%s is thread/mill/extract\n", plant->id.c_str()); + DEBUG(log, out).print("%s is thread/mill/extract\n", plant->id.c_str()); if (farming) { result = selectability::Selectable; } @@ -120,7 +125,7 @@ selectability selectablePlant(const df::plant_raw* plant, bool farming) { if (basic_mat.material->reaction_product.id.size() > 0 || basic_mat.material->reaction_class.size() > 0) { - // out.print("%s has a reaction\n", plant->id.c_str()); + DEBUG(log, out).print("%s has a reaction\n", plant->id.c_str()); if (farming) { result = selectability::Selectable; } @@ -154,7 +159,7 @@ selectability selectablePlant(const df::plant_raw* plant, bool farming) { if (*cur_year_tick >= plant->growths[i]->timing_1 && (plant->growths[i]->timing_2 == -1 || *cur_year_tick <= plant->growths[i]->timing_2)) { - // out.print("%s has an edible seed or a stockpile growth\n", plant->id.c_str()); + DEBUG(log, out).print("%s has an edible seed or a stockpile growth\n", plant->id.c_str()); if (!farming || seedSource) { return selectability::Selectable; } @@ -188,11 +193,11 @@ selectability selectablePlant(const df::plant_raw* plant, bool farming) { } if (outOfSeason) { - // out.print("%s has an out of season growth\n", plant->id.c_str()); + DEBUG(log, out).print("%s has an out of season growth\n", plant->id.c_str()); return selectability::OutOfSeason; } else { - // out.printerr("%s cannot be gathered\n", plant->id.c_str()); + DEBUG(log, out).print("%s cannot be gathered\n", plant->id.c_str()); return result; } } @@ -368,13 +373,11 @@ command_result df_getplants(color_ostream& out, vector & parameters) { for (size_t i = 0; i < world->raws.plants.all.size(); i++) { df::plant_raw* plant = world->raws.plants.all[i]; if (all) { - // plantSelections[i] = selectablePlant(out, plant, farming); - plantSelections[i] = selectablePlant(plant, farming); + plantSelections[i] = selectablePlant(out, plant, farming); } else if (plantNames.find(plant->id) != plantNames.end()) { plantNames.erase(plant->id); - // plantSelections[i] = selectablePlant(out, plant, farming); - plantSelections[i] = selectablePlant(plant, farming); + plantSelections[i] = selectablePlant(out, plant, farming); switch (plantSelections[i]) { case selectability::Grass: out.printerr("%s is a grass and cannot be gathered\n", plant->id.c_str()); @@ -421,8 +424,7 @@ command_result df_getplants(color_ostream& out, vector & parameters) { out.print("Valid plant IDs:\n"); for (size_t i = 0; i < world->raws.plants.all.size(); i++) { df::plant_raw* plant = world->raws.plants.all[i]; - // switch (selectablePlant(out, plant, farming)) - switch (selectablePlant(plant, farming)) { + switch (selectablePlant(out, plant, farming)) { case selectability::Grass: case selectability::Nonselectable: continue; @@ -486,7 +488,7 @@ command_result df_getplants(color_ostream& out, vector & parameters) { ++count; } if (!deselect && designate(plant, farming)) { - // out.print("Designated %s at (%i, %i, %i), %d\n", world->raws.plants.all[plant->material]->id.c_str(), plant->pos.x, plant->pos.y, plant->pos.z, (int)i); + DEBUG(log, out).print("Designated %s at (%i, %i, %i), %d\n", world->raws.plants.all[plant->material]->id.c_str(), plant->pos.x, plant->pos.y, plant->pos.z, (int)i); collectionCount[plant->material]++; ++count; } From cbf1e236721ee79f212d504ccfb6428d5c763208 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 11 Apr 2023 02:34:45 -0700 Subject: [PATCH 0025/1234] fix designation of non-fruit trees --- plugins/getplants.cpp | 66 +++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/plugins/getplants.cpp b/plugins/getplants.cpp index 821dfa0b7..87f1c0e76 100644 --- a/plugins/getplants.cpp +++ b/plugins/getplants.cpp @@ -236,7 +236,15 @@ bool picked(const df::plant* plant, int32_t growth_subtype) { return false; } -bool designate(const df::plant* plant, bool farming) { +bool designate(color_ostream& out, const df::plant* plant, bool farming) { + TRACE(log, out).print("Attempting to designate %s at (%i, %i, %i)\n", world->raws.plants.all[plant->material]->id.c_str(), plant->pos.x, plant->pos.y, plant->pos.z); + + if (!farming) { + bool istree = (tileMaterial(Maps::getTileBlock(plant->pos)->tiletype[plant->pos.x % 16][plant->pos.y % 16]) == tiletype_material::TREE); + if (istree) + return Designations::markPlant(plant); + } + df::plant_raw* plant_raw = world->raws.plants.all[plant->material]; const DFHack::MaterialInfo basic_mat = DFHack::MaterialInfo(plant_raw->material_defs.type[plant_material_def::basic_mat], plant_raw->material_defs.idx[plant_material_def::basic_mat]); @@ -263,34 +271,40 @@ bool designate(const df::plant* plant, bool farming) { } for (size_t i = 0; i < plant_raw->growths.size(); i++) { - if (plant_raw->growths[i]->item_type == df::item_type::SEEDS || // Only trees have seed growths in vanilla, but raws can be modded... - plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH) { - const DFHack::MaterialInfo growth_mat = DFHack::MaterialInfo(plant_raw->growths[i]->mat_type, plant_raw->growths[i]->mat_index); - if ((plant_raw->growths[i]->item_type == df::item_type::SEEDS && - (growth_mat.material->flags.is_set(material_flags::EDIBLE_COOKED) || - growth_mat.material->flags.is_set(material_flags::EDIBLE_RAW))) || - (plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH && - growth_mat.material->flags.is_set(material_flags::LEAF_MAT))) // Will change name to STOCKPILE_PLANT_GROWTH any day now... - { - bool seedSource = plant_raw->growths[i]->item_type == df::item_type::SEEDS; + TRACE(log, out).print("growth item type=%d\n", plant_raw->growths[i]->item_type); + // Only trees have seed growths in vanilla, but raws can be modded... + if (plant_raw->growths[i]->item_type != df::item_type::SEEDS && + plant_raw->growths[i]->item_type != df::item_type::PLANT_GROWTH) + continue; - if (plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH) { - for (size_t k = 0; growth_mat.material->reaction_product.material.mat_type.size(); k++) { - if (growth_mat.material->reaction_product.material.mat_type[k] == plant_raw->material_defs.type[plant_material_def::seed] && - growth_mat.material->reaction_product.material.mat_index[k] == plant_raw->material_defs.idx[plant_material_def::seed]) { - seedSource = true; - break; - } - } - } + const DFHack::MaterialInfo growth_mat = DFHack::MaterialInfo(plant_raw->growths[i]->mat_type, plant_raw->growths[i]->mat_index); + TRACE(log, out).print("edible_cooked=%d edible_raw=%d leaf_mat=%d\n", + growth_mat.material->flags.is_set(material_flags::EDIBLE_COOKED), + growth_mat.material->flags.is_set(material_flags::EDIBLE_RAW), + growth_mat.material->flags.is_set(material_flags::LEAF_MAT)); + if (!(plant_raw->growths[i]->item_type == df::item_type::SEEDS && + (growth_mat.material->flags.is_set(material_flags::EDIBLE_COOKED) || + growth_mat.material->flags.is_set(material_flags::EDIBLE_RAW))) && + !(plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH && + growth_mat.material->flags.is_set(material_flags::LEAF_MAT))) // Will change name to STOCKPILE_PLANT_GROWTH any day now... + continue; + + bool seedSource = plant_raw->growths[i]->item_type == df::item_type::SEEDS; - bool istree = (tileMaterial(Maps::getTileBlock(plant->pos)->tiletype[plant->pos.x % 16][plant->pos.y % 16]) == tiletype_material::TREE); - bool isripe = ripe(plant->pos.x, plant->pos.y, plant_raw->growths[i]->timing_1, plant_raw->growths[i]->timing_2); - if ((!farming || seedSource) && (istree || isripe) && !picked(plant, i)) { - return Designations::markPlant(plant); + if (plant_raw->growths[i]->item_type == df::item_type::PLANT_GROWTH) { + for (size_t k = 0; growth_mat.material->reaction_product.material.mat_type.size(); k++) { + if (growth_mat.material->reaction_product.material.mat_type[k] == plant_raw->material_defs.type[plant_material_def::seed] && + growth_mat.material->reaction_product.material.mat_index[k] == plant_raw->material_defs.idx[plant_material_def::seed]) { + seedSource = true; + break; } } } + + if ((!farming || seedSource) && + ripe(plant->pos.x, plant->pos.y, plant_raw->growths[i]->timing_1, plant_raw->growths[i]->timing_2) && + !picked(plant, i)) + return Designations::markPlant(plant); } return false; @@ -460,6 +474,8 @@ command_result df_getplants(color_ostream& out, vector & parameters) { const df::plant* plant = world->plants.all[i]; df::map_block* cur = Maps::getTileBlock(plant->pos); + TRACE(log, out).print("Examining %s at (%i, %i, %i) [index=%d]\n", world->raws.plants.all[plant->material]->id.c_str(), plant->pos.x, plant->pos.y, plant->pos.z, (int)i); + int x = plant->pos.x % 16; int y = plant->pos.y % 16; if (plantSelections[plant->material] == selectability::OutOfSeason || @@ -487,7 +503,7 @@ command_result df_getplants(color_ostream& out, vector & parameters) { collectionCount[plant->material]++; ++count; } - if (!deselect && designate(plant, farming)) { + if (!deselect && designate(out, plant, farming)) { DEBUG(log, out).print("Designated %s at (%i, %i, %i), %d\n", world->raws.plants.all[plant->material]->id.c_str(), plant->pos.x, plant->pos.y, plant->pos.z, (int)i); collectionCount[plant->material]++; ++count; From 20bea5fa217353fb73235cc2d58b2a55bde597e6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 11 Apr 2023 03:49:28 -0700 Subject: [PATCH 0026/1234] add ability to filter by cloth and silk --- docs/changelog.txt | 1 + plugins/buildingplan/buildingplan.cpp | 42 +++++++++++++++----- plugins/lua/buildingplan/filterselection.lua | 2 + 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 7c52315ea..2104158f5 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -48,6 +48,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - `buildingplan`: items in the item selection dialog should now use the same item quality symbols as the base game - `buildingplan`: hide planner overlay while the DF tutorial is active so that it can detect when you have placed the carpenter's workshop and bed and allow you to finish the tutorial +- `buildingplan`: can now filter by cloth and silk materials (for ropes) -@ `buildingplan`: rearranged elements of ``planneroverlay`` interface -@ `buildingplan`: rearranged elements of ``itemselection`` interface - Mods: scripts in mods that are only in the steam workshop directory are now accessible. this means that a script-only mod that you never mark as "active" when generating a world will still receive automatic updates and be usable from in-game diff --git a/plugins/buildingplan/buildingplan.cpp b/plugins/buildingplan/buildingplan.cpp index 2193b380b..1d9f58416 100644 --- a/plugins/buildingplan/buildingplan.cpp +++ b/plugins/buildingplan/buildingplan.cpp @@ -12,6 +12,7 @@ #include "df/construction_type.h" #include "df/item.h" #include "df/job_item.h" +#include "df/organic_mat_category.h" #include "df/world.h" using std::map; @@ -150,6 +151,8 @@ static const df::dfhack_material_category wood_cat(df::dfhack_material_category: static const df::dfhack_material_category metal_cat(df::dfhack_material_category::mask_metal); static const df::dfhack_material_category glass_cat(df::dfhack_material_category::mask_glass); static const df::dfhack_material_category clay_cat(df::dfhack_material_category::mask_clay); +static const df::dfhack_material_category cloth_cat(df::dfhack_material_category::mask_cloth); +static const df::dfhack_material_category silk_cat(df::dfhack_material_category::mask_silk); static void cache_matched(int16_t type, int32_t index) { MaterialInfo mi; @@ -169,11 +172,26 @@ static void cache_matched(int16_t type, int32_t index) { } else if (mi.matches(clay_cat)) { DEBUG(status).print("cached clay material: %s (%d, %d)\n", mi.toString().c_str(), type, index); mat_cache.emplace(mi.toString(), std::make_pair(mi, "clay")); + } else if (mi.matches(cloth_cat)) { + DEBUG(status).print("cached cloth material: %s (%d, %d)\n", mi.toString().c_str(), type, index); + mat_cache.emplace(mi.toString(), std::make_pair(mi, "cloth")); + } else if (mi.matches(silk_cat)) { + DEBUG(status).print("cached silk material: %s (%d, %d)\n", mi.toString().c_str(), type, index); + mat_cache.emplace(mi.toString(), std::make_pair(mi, "silk")); } else TRACE(status).print("not matched: %s\n", mi.toString().c_str()); } +static void load_organic_material_cache(df::organic_mat_category cat) { + auto& mat_tab = world->raws.mat_table; + auto& cat_vec = mat_tab.organic_types[cat]; + auto& cat_indices = mat_tab.organic_indexes[cat]; + for (size_t i = 0; i < cat_vec.size(); i++) { + cache_matched(cat_vec[i], cat_indices[i]); + } +} + static void load_material_cache() { df::world_raws &raws = world->raws; for (int i = 1; i < DFHack::MaterialInfo::NUM_BUILTIN; ++i) @@ -183,17 +201,9 @@ static void load_material_cache() { for (size_t i = 0; i < raws.inorganics.size(); i++) cache_matched(0, i); - for (size_t i = 0; i < raws.plants.all.size(); i++) { - df::plant_raw *p = raws.plants.all[i]; - if (p->material.size() <= 1) - continue; - for (size_t j = 0; j < p->material.size(); j++) { - if (p->material[j]->id == "WOOD") { - cache_matched(DFHack::MaterialInfo::PLANT_BASE+j, i); - break; - } - } - } + load_organic_material_cache(df::organic_mat_category::Wood); + load_organic_material_cache(df::organic_mat_category::PlantFiber); + load_organic_material_cache(df::organic_mat_category::Silk); } static HeatSafety get_heat_safety_filter(const BuildingTypeKey &key) { @@ -792,6 +802,10 @@ static int setMaterialMaskFilter(lua_State *L) { mask |= glass_cat.whole; else if (cat == "clay") mask |= clay_cat.whole; + else if (cat == "cloth") + mask |= cloth_cat.whole; + else if (cat == "silk") + mask |= silk_cat.whole; } DEBUG(status,*out).print( "setting material mask filter for building_type=%d subtype=%d custom=%d index=%d to %x\n", @@ -837,6 +851,8 @@ static int getMaterialMaskFilter(lua_State *L) { ret.emplace("metal", !bits || bits & metal_cat.whole); ret.emplace("glass", !bits || bits & glass_cat.whole); ret.emplace("clay", !bits || bits & clay_cat.whole); + ret.emplace("cloth", !bits || bits & cloth_cat.whole); + ret.emplace("silk", !bits || bits & silk_cat.whole); Lua::Push(L, ret); return 1; } @@ -883,6 +899,10 @@ static int setMaterialFilter(lua_State *L) { mask.whole |= glass_cat.whole; else if (mat.matches(clay_cat)) mask.whole |= clay_cat.whole; + else if (mat.matches(cloth_cat)) + mask.whole |= cloth_cat.whole; + else if (mat.matches(silk_cat)) + mask.whole |= silk_cat.whole; } filter.setMaterialMask(mask.whole); get_item_filters(*out, key).setItemFilter(*out, filter, index); diff --git a/plugins/lua/buildingplan/filterselection.lua b/plugins/lua/buildingplan/filterselection.lua index 84b5c46ea..498c89c1e 100644 --- a/plugins/lua/buildingplan/filterselection.lua +++ b/plugins/lua/buildingplan/filterselection.lua @@ -453,6 +453,8 @@ function QualityAndMaterialsPage:refresh() make_cat_choice('Metal', 'metal', 'CUSTOM_SHIFT_M', cats), make_cat_choice('Glass', 'glass', 'CUSTOM_SHIFT_G', cats), make_cat_choice('Clay', 'clay', 'CUSTOM_SHIFT_C', cats), + make_cat_choice('Cloth', 'cloth', 'CUSTOM_SHIFT_L', cats), + make_cat_choice('Silk', 'silk', 'CUSTOM_SHIFT_K', cats), } self.subviews.materials_categories:setChoices(category_choices) From 460b1e8eaf05f5dafad745ccc5776a66f47de431 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 11 Apr 2023 10:14:28 -0700 Subject: [PATCH 0027/1234] adjust code to new tree root type --- library/modules/MapCache.cpp | 17 ++++++++++------- library/modules/Maps.cpp | 1 + .../remotefortressreader.cpp | 13 ++++++++----- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/library/modules/MapCache.cpp b/library/modules/MapCache.cpp index b88a078b1..c329220c9 100644 --- a/library/modules/MapCache.cpp +++ b/library/modules/MapCache.cpp @@ -60,6 +60,7 @@ using namespace std; #include "df/flow_info.h" #include "df/job.h" #include "df/plant.h" +#include "df/plant_root_tile.h" #include "df/plant_tree_info.h" #include "df/plant_tree_tile.h" #include "df/region_map_entry.h" @@ -805,14 +806,16 @@ void MapExtras::BlockInfo::prepare(Block *mblock) // If the block is at or above the plant's base level, we use the body array // otherwise we use the roots. // TODO: verify that the tree bounds intersect the block. - df::plant_tree_tile tile; + bool has_tree_tile = false; int z_diff = block->map_pos.z - pp->pos.z; - if (z_diff >= 0) - tile = info->body[z_diff][xx + (yy*info->dim_x)]; - else - tile = info->roots[-1 - z_diff][xx + (yy*info->dim_x)]; - if (tile.whole && !(tile.bits.blocked)) - { + if (z_diff >= 0) { + df::plant_tree_tile tile = info->body[z_diff][xx + (yy * info->dim_x)]; + has_tree_tile = tile.whole && !(tile.bits.blocked); + } else { + df::plant_root_tile tile = info->roots[-1 - z_diff][xx + (yy * info->dim_x)]; + has_tree_tile = tile.whole && !(tile.bits.blocked); + } + if (has_tree_tile) { df::coord pos = pp->pos; pos.x = pos.x - (info->dim_x / 2) + xx; pos.y = pos.y - (info->dim_y / 2) + yy; diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index ddcd6078f..2e831075d 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -57,6 +57,7 @@ using namespace std; #include "df/flow_info.h" #include "df/map_block_column.h" #include "df/plant.h" +#include "df/plant_root_tile.h" #include "df/plant_tree_info.h" #include "df/plant_tree_tile.h" #include "df/region_map_entry.h" diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index f33044877..061cf2698 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -76,7 +76,9 @@ #include "df/ocean_wave.h" #include "df/physical_attribute_type.h" #include "df/plant.h" +#include "df/plant_tree_tile.h" #include "df/plant_raw_flags.h" +#include "df/plant_root_tile.h" #include "df/projectile.h" #include "df/proj_itemst.h" #include "df/proj_unitst.h" @@ -971,17 +973,18 @@ void CopyBlock(df::map_block * DfBlock, RemoteFortressReader::MapBlock * NetBloc || yyy >= 16 ) continue; - df::plant_tree_tile tile; if (-localPos.z < 0) { - tile = tree_info->roots[-1 + localPos.z][xx + (yy*tree_info->dim_x)]; + df::plant_root_tile tile = tree_info->roots[-1 + localPos.z][xx + (yy * tree_info->dim_x)]; + if (!tile.whole || tile.bits.blocked) + continue; } else { - tile = tree_info->body[-localPos.z][xx + (yy*tree_info->dim_x)]; + df::plant_tree_tile tile = tree_info->body[-localPos.z][xx + (yy * tree_info->dim_x)]; + if (!tile.whole || tile.bits.blocked) + continue; } - if (!tile.whole || tile.bits.blocked) - continue; if (tree_info->body_height <= 1) trunk_percent[xxx][yyy] = 0; else From 63b95994051615261ebfab22460a212697d6cd9e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 11 Apr 2023 10:15:24 -0700 Subject: [PATCH 0028/1234] update xml head --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 78a2008e4..eea005e8c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 78a2008e4d20a47f0533f285c3457a278dba5556 +Subproject commit eea005e8cec4448ab865862c744d6da16106f641 From f813e6fa939306b48af66e926724074630d2cffd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 11 Apr 2023 10:23:29 -0700 Subject: [PATCH 0029/1234] update stonesense head --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index 3e494d9d9..9046525c9 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 3e494d9d968add443ebd63cc167933cc813f0eee +Subproject commit 9046525c91fd91e90685dfc071aa952bfe906155 From 766ec620b5cfff4a9c2a2bbd3b494fd81c722f93 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 11 Apr 2023 19:06:51 +0000 Subject: [PATCH 0030/1234] Auto-update submodules library/xml: master plugins/stonesense: master --- library/xml | 2 +- plugins/stonesense | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index eea005e8c..4453c0dcd 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit eea005e8cec4448ab865862c744d6da16106f641 +Subproject commit 4453c0dcda1255845c358f34f57c0471cf85ab2c diff --git a/plugins/stonesense b/plugins/stonesense index 9046525c9..b7073b664 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 9046525c91fd91e90685dfc071aa952bfe906155 +Subproject commit b7073b664310b909989ebe68de36a164e452825a From 49d55b2f07263fbb1179f6f8ec16a9f8f72026dd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 11 Apr 2023 12:31:27 -0700 Subject: [PATCH 0031/1234] bump version for beta --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dfb6dfb21..9168ebd85 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,7 +192,7 @@ endif() # set up versioning. set(DF_VERSION "50.07") -set(DFHACK_RELEASE "beta2") +set(DFHACK_RELEASE "r1b4") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 6c1740e2ca2556dd1deca0e2d6115b0368adcaef Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 11 Apr 2023 17:13:56 -0700 Subject: [PATCH 0032/1234] re-version to rc1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9168ebd85..3077bf139 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,7 +192,7 @@ endif() # set up versioning. set(DF_VERSION "50.07") -set(DFHACK_RELEASE "r1b4") +set(DFHACK_RELEASE "rc1") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From f7e3973da8e6fc07574412c98de6f146f030ff6a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 12 Apr 2023 01:45:42 -0700 Subject: [PATCH 0033/1234] bump to 50.07-r1, scrub changelog --- CMakeLists.txt | 4 +-- docs/changelog.txt | 78 ++++++++++++++++++++++++++-------------------- library/xml | 2 +- scripts | 2 +- 4 files changed, 49 insertions(+), 37 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3077bf139..b9f323640 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,8 +192,8 @@ endif() # set up versioning. set(DF_VERSION "50.07") -set(DFHACK_RELEASE "rc1") -set(DFHACK_PRERELEASE TRUE) +set(DFHACK_RELEASE "r1") +set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/docs/changelog.txt b/docs/changelog.txt index 2104158f5..351e13d76 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -26,7 +26,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ]]] ================================================================================ -======== IMPORTANT: rename this, and add a new "future" section, BEFORE ======== +======== IMPORTANT: rename this, and add a new "Future" section, BEFORE ======== ======== making a new DFHack release, even if the only changes made ======== ======== were in submodules with their own changelogs! ======== ================================================================================ @@ -34,54 +34,66 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # Future ## New Plugins -- `faststart`: speeds up the "Loading..." screen so the Main Menu appears sooner ## 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 + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 50.07-r1 + +## New Plugins +- `faststart`: speeds up the "Loading..." screen so the Main Menu appears faster + +## Fixes +-@ `hotkeys`: hotkey hints on menu popup will no longer get their last character cut off by the scrollbar +-@ ``launchdf``: launch Dwarf Fortress via the Steam client so Steam Workshop is functional - `blueprint`: interpret saplings, shrubs, and twigs as floors instead of walls - `combine`: fix error processing stockpiles with boundaries that extend outside of the map -- `prospector`: display both "raw" Z levels and "cooked" elevations +-@ `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 +-@ `stockpiles`: allow numbers in saved stockpile filenames ## Misc Improvements -- `buildingplan`: items in the item selection dialog should now use the same item quality symbols as the base game -- `buildingplan`: hide planner overlay while the DF tutorial is active so that it can detect when you have placed the carpenter's workshop and bed and allow you to finish the tutorial +-@ `buildingplan`: items in the item selection dialog should now use the same item quality symbols as the base game +-@ `buildingplan`: hide planner overlay while the DF tutorial is active so that it can detect when you have placed the carpenter's workshop and bed and allow you to finish the tutorial - `buildingplan`: can now filter by cloth and silk materials (for ropes) -@ `buildingplan`: rearranged elements of ``planneroverlay`` interface -@ `buildingplan`: rearranged elements of ``itemselection`` interface -- Mods: scripts in mods that are only in the steam workshop directory are now accessible. this means that a script-only mod that you never mark as "active" when generating a world will still receive automatic updates and be usable from in-game -- Mods: scripts from only the most recent version of an installed mod are added to the script path -- Mods: give active mods a chance to reattach their load hooks when a world is reloaded +-@ Mods: scripts in mods that are only in the steam workshop directory are now accessible. this means that a script-only mod that you never mark as "active" when generating a world will still receive automatic updates and be usable from in-game +-@ Mods: scripts from only the most recent version of an installed mod are added to the script path +-@ Mods: give active mods a chance to reattach their load hooks when a world is reloaded - `gui/control-panel`: bugfix services are now enabled by default - Core: hide DFHack terminal console by default when running on Steam Deck ## Documentation - `installing`: updated to include Steam installation instructions -## API - ## 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`` -## Removed - # 50.07-beta2 ## New Plugins - `getplants`: 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`: get stone, ore, gem, and other tile property counts in fort mode. ## Fixes -- `buildingplan`: filters are now properly applied to planned stairs -- `buildingplan`: existing carved up/down stairs are now taken into account when determining which stair shape to construct +-@ `buildingplan`: filters are now properly applied to planned stairs +-@ `buildingplan`: existing carved up/down stairs are now taken into account when determining which stair shape to construct - `buildingplan`: upright spike traps are now placed extended rather than retracted - `buildingplan`: you can no longer designate constructions on tiles with magma or deep water, mirroring the vanilla restrictions -- `buildingplan`: fixed material filters getting lost for planning buildings on save/reload -- `buildingplan`: respect building size limits (e.g. roads and bridges cannot be more than 31 tiles in any dimension) +-@ `buildingplan`: fixed material filters getting lost for planning buildings on save/reload +-@ `buildingplan`: respect building size limits (e.g. roads and bridges cannot be more than 31 tiles in any dimension) - `tailor`: properly discriminate between dyed and undyed cloth -- `tailor`: no longer default to using adamantine cloth for producing clothes +-@ `tailor`: no longer default to using adamantine cloth for producing clothes - `tailor`: take queued orders into account when calculating available materials - `tailor`: skip units who can't wear clothes - `tailor`: identify more available items as available, solving issues with over-production @@ -100,17 +112,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 option to delete exported files from the import dialog - `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 - `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. ## 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 -- ``widget.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 -- ``widget.CycleHotkeyLabel``: option labels and pens can now be functions that return a label or pen +- ``widgets.Label``: tokens can now specify a ``htile`` property to indicate the tile that should be shown when the Label is hovered over with the mouse +- ``widgets.Label``: click handlers no longer get the label itself as the first param to the click handler +- ``widgets.CycleHotkeyLabel``: options that are bare integers will no longer be interpreted as the pen color in addition to being the label and value +- ``widgets.CycleHotkeyLabel``: option labels and pens can now be functions that return a label or pen # 50.07-beta1 @@ -172,14 +184,14 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes -@ `nestboxes`: fixed bug causing nestboxes themselves to be forbidden, which prevented citizens from using them to lay eggs. Now only eggs are forbidden. -- `autobutcher`: implemented work-around for Dwarf Fortress not setting nicknames properly, so that nicknames created in the in-game interface are detected & protect animals from being butchered properly. Note that nicknames for unnamed units are not currently saved by dwarf fortress - use ``enable fix/protect-nicks`` to fix any nicknames created/removed within dwarf fortress so they can be saved/reloaded when you reload the game. +-@ `autobutcher`: implemented work-around for Dwarf Fortress not setting nicknames properly, so that nicknames created in the in-game interface are detected & protect animals from being butchered properly. Note that nicknames for unnamed units are not currently saved by dwarf fortress - use ``enable fix/protect-nicks`` to fix any nicknames created/removed within dwarf fortress so they can be saved/reloaded when you reload the game. -@ `seedwatch`: fix saving and loading of seed stock targets - `autodump`: changed behaviour to only change ``dump`` and ``forbid`` flags if an item is successfully dumped. -@ `autochop`: generate default names for burrows with no assigned names - ``Buildings::StockpileIterator``: fix check for stockpile items on block boundary. - `tailor`: block making clothing sized for toads; make replacement clothing orders use the size of the wearer, not the size of the garment -@ `confirm`: fix fps drop when enabled -- `channel-safely`: fix an out of bounds error regarding the REPORT event listener receiving (presumably) stale id's +-@ `channel-safely`: fix an out of bounds error regarding the REPORT event listener receiving (presumably) stale id's ## Misc Improvements - `autobutcher`: logs activity to the console terminal instead of making disruptive in-game announcements @@ -203,13 +215,13 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes - ``Units::isFortControlled``: Account for agitated wildlife -@ Fix right click sometimes closing both a DFHack window and a vanilla panel -- Fixed issue with scrollable lists having some data off-screen if they were scrolled before being made visible -- `channel-safely`: fixed bug resulting in marker mode never being set for any designation +-@ Fixed issue with scrollable lists having some data off-screen if they were scrolled before being made visible +-@ `channel-safely`: fixed bug resulting in marker mode never being set for any designation -@ `automelt`: fixed bug related to lua stack smashing behavior in returned stockpile configs -@ `autochop`: fixed bug related to lua stack smashing behavior in returned stockpile configs -- `nestboxes`: now cancels any in-progress hauling jobs when it protects a fertile egg +-@ `nestboxes`: now cancels any in-progress hauling jobs when it protects a fertile egg -@ Fix persisted data not being written on manual save -- `nestboxes`: now scans for eggs more frequently and cancels any in-progress hauling jobs when it protects a fertile egg +-@ `nestboxes`: now scans for eggs more frequently and cancels any in-progress hauling jobs when it protects a fertile egg ## Misc Improvements -@ `automelt`: is now more resistent to vanilla savegame corruption @@ -301,7 +313,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # 50.05-alpha2 ## 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) - `tailor`: now respects the setting of the "used dyed clothing" standing order toggle diff --git a/library/xml b/library/xml index 4453c0dcd..43a89a268 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 4453c0dcda1255845c358f34f57c0471cf85ab2c +Subproject commit 43a89a268b825fc05457678b19e551bf632dcd19 diff --git a/scripts b/scripts index 973b8ef19..ec1a69788 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 973b8ef191cc92cff62d96aa591c7631818d19b6 +Subproject commit ec1a69788fd6329008672523b622fd8b390fea73 From 21784568bd144d3a70444f9cbc35705619297a1c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 4 Jan 2023 09:57:06 -0800 Subject: [PATCH 0034/1234] migrate from SDL interposing to the hooks API --- CMakeLists.txt | 13 - library/CMakeLists.txt | 10 +- library/Core.cpp | 26 +- library/Hooks-darwin.cpp | 318 --------------- library/Hooks-linux.cpp | 139 ------- library/Hooks-windows.cpp | 838 -------------------------------------- library/Hooks.cpp | 3 + library/include/Core.h | 15 +- plugins/title-folder.cpp | 2 +- 9 files changed, 18 insertions(+), 1346 deletions(-) delete mode 100644 library/Hooks-darwin.cpp delete mode 100644 library/Hooks-linux.cpp delete mode 100644 library/Hooks-windows.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b9f323640..02857f91d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -299,19 +299,6 @@ if(WIN32) 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() if(APPLE) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index a3fcb8b6f..418c9b371 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -95,7 +95,6 @@ endif() set(MAIN_SOURCES_WINDOWS ${CONSOLE_SOURCES} - Hooks-windows.cpp Hooks.cpp PlugLoad-windows.cpp Process-windows.cpp @@ -108,14 +107,12 @@ endif() set(MAIN_SOURCES_LINUX ${CONSOLE_SOURCES} - Hooks-linux.cpp PlugLoad-posix.cpp Process-linux.cpp ) set(MAIN_SOURCES_DARWIN ${CONSOLE_SOURCES} - Hooks-darwin.cpp PlugLoad-posix.cpp Process-darwin.cpp ) @@ -376,8 +373,7 @@ add_executable(binpatch binpatch.cpp) target_link_libraries(binpatch dfhack-md5) if(WIN32) - # name the resulting library SDL.dll on Windows - set_target_properties(dfhack PROPERTIES OUTPUT_NAME "SDL" ) + set_target_properties(dfhack PROPERTIES OUTPUT_NAME "dfhooks" ) set_target_properties(dfhack PROPERTIES COMPILE_FLAGS "/FI\"Export.h\"" ) set_target_properties(dfhack-client PROPERTIES COMPILE_FLAGS "/FI\"Export.h\"" ) else() @@ -436,10 +432,6 @@ if(UNIX) install(TARGETS dfhooks LIBRARY DESTINATION . RUNTIME DESTINATION .) -else() - # On windows, copy the renamed SDL so DF can still run. - install(PROGRAMS ${dfhack_SOURCE_DIR}/package/windows/win${DFHACK_BUILD_ARCH}/SDLreal.dll - DESTINATION ${DFHACK_LIBRARY_DESTINATION}) endif() # install the main lib diff --git a/library/Core.cpp b/library/Core.cpp index b1fe2d389..7bdaed80c 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2292,12 +2292,13 @@ int Core::Shutdown ( void ) #define KEY_F0 0410 /* Function keys. Space for 64 */ #define KEY_F(n) (KEY_F0+(n)) /* Value of function key n */ +// returns true if the event has been handled bool Core::ncurses_wgetch(int in, int & out) { if(!started) { out = in; - return true; + return false; } if(in >= KEY_F(1) && in <= KEY_F(8)) { @@ -2312,18 +2313,18 @@ bool Core::ncurses_wgetch(int in, int & out) df::global::plotinfo->main.hotkeys[idx].cmd == df::ui_hotkey::T_cmd::None) { setHotkeyCmd(df::global::plotinfo->main.hotkeys[idx].name); - return false; + return true; } else { out = in; - return true; + return false; } } */ } out = in; - return true; + return false; } bool Core::DFH_ncurses_key(int key) @@ -2331,7 +2332,7 @@ bool Core::DFH_ncurses_key(int key) if (getenv("DFHACK_HEADLESS")) return true; int dummy; - return !ncurses_wgetch(key, dummy); + return ncurses_wgetch(key, dummy); } int UnicodeAwareSym(const SDL::KeyboardEvent& ke) @@ -2382,21 +2383,19 @@ int UnicodeAwareSym(const SDL::KeyboardEvent& ke) return unicode; } - -//MEMO: return false if event is consumed -int Core::DFH_SDL_Event(SDL::Event* ev) +// returns true if the event is handled +bool Core::DFH_SDL_Event(SDL::Event* ev) { // do NOT process events before we are ready. - if(!started) return true; - if(!ev) - return true; + if(!started || !ev) + return false; if(ev->type == SDL::ET_ACTIVEEVENT && ev->active.gain) { // clear modstate when gaining focus in case alt-tab was used when // losing focus and modstate is now incorrectly set modstate = 0; - return true; + return false; } if(ev->type == SDL::ET_KEYDOWN || ev->type == SDL::ET_KEYUP) @@ -2431,8 +2430,7 @@ int Core::DFH_SDL_Event(SDL::Event* ev) hotkey_states[ke->ksym.sym] = false; } } - return true; - // do stuff with the events... + return false; } bool Core::SelectHotkey(int sym, int modifiers) diff --git a/library/Hooks-darwin.cpp b/library/Hooks-darwin.cpp deleted file mode 100644 index 418cf5472..000000000 --- a/library/Hooks-darwin.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/* -https://github.com/peterix/dfhack -Copyright (c) 2009-2012 Petr Mrázek (peterix@gmail.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef struct interpose_s -{ - void *new_func; - void *orig_func; -} interpose_t; - -#include "DFHack.h" -#include "Core.h" -#include "Hooks.h" -#include "SDL_events.h" -#include - -/*static const interpose_t interposers[] __attribute__ ((section("__DATA, __interpose"))) = -{ - { (void *)DFH_SDL_Init, (void *)SDL_Init }, - { (void *)DFH_SDL_PollEvent, (void *)SDL_PollEvent }, - { (void *)DFH_SDL_Quit, (void *)SDL_Quit }, - { (void *)DFH_SDL_NumJoysticks, (void *)SDL_NumJoysticks }, - -};*/ - -#define DYLD_INTERPOSE(_replacement,_replacee) \ - __attribute__((used)) static struct{ const void* replacment; const void* replacee; } \ - _interpose_##_replacee __attribute__ ((section ("__DATA,__interpose"))) = \ - { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee }; - -DYLD_INTERPOSE(DFH_SDL_Init,SDL_Init); -DYLD_INTERPOSE(DFH_SDL_PollEvent,SDL_PollEvent); -DYLD_INTERPOSE(DFH_SDL_Quit,SDL_Quit); -DYLD_INTERPOSE(DFH_SDL_NumJoysticks,SDL_NumJoysticks); -DYLD_INTERPOSE(DFH_wgetch,wgetch); - -/******************************************************************************* -* SDL part starts here * -*******************************************************************************/ - -#define SDL_APPMOUSEFOCUS 0x01 /**< The app has mouse coverage */ -#define SDL_APPINPUTFOCUS 0x02 /**< The app has input focus */ -#define SDL_APPACTIVE 0x04 /**< The application is active */ -static uint8_t (*_SDL_GetAppState)(void) = 0; -DFhackCExport uint8_t SDL_GetAppState(void) -{ - return _SDL_GetAppState(); -} - -// hook - called for each game tick (or more often) -DFhackCExport int DFH_SDL_NumJoysticks(void) -{ - DFHack::Core & c = DFHack::Core::getInstance(); - return c.Update(); -} - -// hook - called at program exit -static void (*_SDL_Quit)(void) = 0; -DFhackCExport void DFH_SDL_Quit(void) -{ - DFHack::Core & c = DFHack::Core::getInstance(); - c.Shutdown(); - - SDL_Quit(); -} - -// called by DF to check input events -static int (*_SDL_PollEvent)(SDL::Event* event) = 0; -DFhackCExport int DFH_SDL_PollEvent(SDL::Event* event) -{ - pollevent_again: - // if SDL returns 0 here, it means there are no more events. return 0 - int orig_return = SDL_PollEvent(event); - if(!orig_return || (!(SDL_GetAppState() & SDL_APPINPUTFOCUS) && - (event->type == SDL::ET_KEYDOWN || event->type == SDL::ET_KEYUP))) - return 0; - // otherwise we have an event to filter - else if( event != 0 ) - { - DFHack::Core & c = DFHack::Core::getInstance(); - // if we consume the event, ask SDL for more. - if(!c.DFH_SDL_Event(event)) - goto pollevent_again; - } - return orig_return; -} - -static int (*_SDL_PushEvent)(SDL::Event* event) = 0; -DFhackCExport int SDL_PushEvent(SDL::Event* event) -{ - return _SDL_PushEvent(event); -} - -struct WINDOW; -DFhackCExport int DFH_wgetch(WINDOW *win) -{ - DFHack::Core & c = DFHack::Core::getInstance(); - wgetch_again: - int in = wgetch(win); - int out; - if(c.ncurses_wgetch(in, out)) - { - // not consumed, give to DF - return out; - } - else - { - // consumed, repeat - goto wgetch_again; - } -} - -void dlsym_bind_or_exit(void **target, const char *name) -{ - void *sym = dlsym(RTLD_NEXT, name); - if (sym) - { - if (*target && *target != sym) - { - fprintf(stderr, "warning: rebinding symbol %s from %p to %p\n", - name, *target, sym); - } - *target = sym; - } - else - { - fprintf(stderr, "Fatal: Could not find symbol: %s\n", name); - fprintf(stdout, "dfhack: something went horribly wrong\n" - "Check stderr.log for details\n"); - exit(1); - } -} - - -// New SDL functions starting in r5 -static vPtr (*_SDL_CreateRGBSurface)(uint32_t flags, int width, int height, int depth, - uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) = 0; -DFhackCExport vPtr SDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, - uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) -{ - return _SDL_CreateRGBSurface(flags, width, height, depth, Rmask, Gmask, Bmask, Amask); -} - -static vPtr (*_SDL_CreateRGBSurfaceFrom)(vPtr pixels, int width, int height, int depth, int pitch, - uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) = 0; -DFhackCExport vPtr SDL_CreateRGBSurfaceFrom(vPtr pixels, int width, int height, int depth, int pitch, - uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) -{ - return _SDL_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask); -} - -static void (*_SDL_FreeSurface)(vPtr surface) = 0; -DFhackCExport void SDL_FreeSurface(vPtr surface) -{ - _SDL_FreeSurface(surface); -} - -static vPtr (*_SDL_ConvertSurface)(vPtr surface, vPtr format, uint32_t flags) = 0; -DFhackCExport vPtr SDL_ConvertSurface(vPtr surface, vPtr format, uint32_t flags) -{ - return _SDL_ConvertSurface(surface, format, flags); -} - -static int (*_SDL_LockSurface)(vPtr surface) = 0; -DFhackCExport int SDL_LockSurface(vPtr surface) -{ - return _SDL_LockSurface(surface); -} - -static void (*_SDL_UnlockSurface)(vPtr surface) = 0; -DFhackCExport void SDL_UnlockSurface(vPtr surface) -{ - _SDL_UnlockSurface(surface); -} - -static uint8_t (*_SDL_GetMouseState)(int *, int *) = 0; -DFhackCExport uint8_t SDL_GetMouseState(int *x, int *y) -{ - return _SDL_GetMouseState(x,y); -} - -static void * (*_SDL_GetVideoSurface)( void ) = 0; -DFhackCExport void * SDL_GetVideoSurface(void) -{ - return _SDL_GetVideoSurface(); -} - -static int (*_SDL_UpperBlit)(DFHack::DFSDL_Surface* src, DFHack::DFSDL_Rect* srcrect, DFHack::DFSDL_Surface* dst, DFHack::DFSDL_Rect* dstrect) = 0; -DFhackCExport int SDL_UpperBlit(DFHack::DFSDL_Surface* src, DFHack::DFSDL_Rect* srcrect, DFHack::DFSDL_Surface* dst, DFHack::DFSDL_Rect* dstrect) -{ - DFHack::Core & c = DFHack::Core::getInstance(); - if ( c.isValid() && dstrect != NULL && dstrect->h != 0 && dstrect->w != 0 ) - { - DFHack::Graphic* g = c.getGraphic(); - DFHack::DFTileSurface* ov = g->Call(dstrect->x/dstrect->w, dstrect->y/dstrect->h); - - if ( ov != NULL ) - { - if ( ov->paintOver ) - { - _SDL_UpperBlit(src, srcrect, dst, dstrect); - } - - DFHack::DFSDL_Rect* dstrect2 = new DFHack::DFSDL_Rect; - dstrect2->x = dstrect->x; - dstrect2->y = dstrect->y; - dstrect2->w = dstrect->w; - dstrect2->h = dstrect->h; - - if ( ov->dstResize != NULL ) - { - DFHack::DFSDL_Rect* r = (DFHack::DFSDL_Rect*)ov->dstResize; - dstrect2->x += r->x; - dstrect2->y += r->y; - dstrect2->w += r->w; - dstrect2->h += r->h; - } - - int result = _SDL_UpperBlit(ov->surface, ov->rect, dst, dstrect2); - delete dstrect2; - return result; - } - } - - return _SDL_UpperBlit(src, srcrect, dst, dstrect); -} - -static int (*_SDL_SemWait)(vPtr) = 0; -DFhackCExport int SDL_SemWait(vPtr sem) -{ - return _SDL_SemWait(sem); -} - -static int (*_SDL_SemPost)(vPtr) = 0; -DFhackCExport int SDL_SemPost(vPtr sem) -{ - return _SDL_SemPost(sem); -} - -// hook - called at program start, initialize some stuffs we'll use later -static int (*_SDL_Init)(uint32_t flags) = 0; -DFhackCExport int DFH_SDL_Init(uint32_t flags) -{ - // reroute stderr - fprintf(stderr,"dfhack: attempting to hook in\n"); - // we don't reroute stdout until we figure out if this should be done at all - // See: Console-posix.cpp - - // find real functions - fprintf(stderr,"dfhack: saving real SDL functions\n"); - - #define bind(sym) dlsym_bind_or_exit((void**)&_##sym, #sym) - bind(SDL_Init); - bind(SDL_Quit); - bind(SDL_PollEvent); - bind(SDL_PushEvent); - - bind(SDL_UpperBlit); - bind(SDL_CreateRGBSurface); - bind(SDL_CreateRGBSurfaceFrom); - bind(SDL_FreeSurface); - bind(SDL_ConvertSurface); - bind(SDL_LockSurface); - bind(SDL_UnlockSurface); - bind(SDL_GetMouseState); - bind(SDL_GetVideoSurface); - - bind(SDL_SemWait); - bind(SDL_SemPost); - bind(SDL_GetAppState); - #undef bind - - fprintf(stderr, "dfhack: saved real SDL functions\n"); - assert(_SDL_Init && _SDL_Quit && _SDL_PollEvent); - fprintf(stderr, "dfhack: hooking successful\n"); - - // prevent any subprocesses from trying to load libdfhack.dylib - setenv("DYLD_INSERT_LIBRARIES", "", 1); - - int ret = SDL_Init(flags); - return ret; -} diff --git a/library/Hooks-linux.cpp b/library/Hooks-linux.cpp deleted file mode 100644 index 7a0cdf947..000000000 --- a/library/Hooks-linux.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* -https://github.com/peterix/dfhack -Copyright (c) 2009-2012 Petr Mrázek (peterix@gmail.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "DFHack.h" -#include "Core.h" -#include "Hooks.h" -#include - -/******************************************************************************* -* SDL part starts here * -*******************************************************************************/ -// hook - called for each game tick (or more often) -DFhackCExport int SDL_NumJoysticks(void) -{ - DFHack::Core & c = DFHack::Core::getInstance(); - return c.Update(); -} - -// hook - called at program exit -static void (*_SDL_Quit)(void) = 0; -DFhackCExport void SDL_Quit(void) -{ - DFHack::Core & c = DFHack::Core::getInstance(); - c.Shutdown(); - if(_SDL_Quit) - { - _SDL_Quit(); - } -} - -// called by DF to check input events -static int (*_SDL_PollEvent)(SDL::Event* event) = 0; -DFhackCExport int SDL_PollEvent(SDL::Event* event) -{ - pollevent_again: - // if SDL returns 0 here, it means there are no more events. return 0 - int orig_return = _SDL_PollEvent(event); - if(!orig_return) - return 0; - // otherwise we have an event to filter - else if( event != 0 ) - { - DFHack::Core & c = DFHack::Core::getInstance(); - // if we consume the event, ask SDL for more. - if(!c.DFH_SDL_Event(event)) - goto pollevent_again; - } - return orig_return; -} - -struct WINDOW; -DFhackCExport int wgetch(WINDOW *win) -{ - if (getenv("DFHACK_HEADLESS")) - { - return 0; - } - static int (*_wgetch)(WINDOW * win) = (int (*)( WINDOW * )) dlsym(RTLD_NEXT, "wgetch"); - if(!_wgetch) - { - exit(EXIT_FAILURE); - } - DFHack::Core & c = DFHack::Core::getInstance(); - wgetch_again: - int in = _wgetch(win); - int out; - if(c.ncurses_wgetch(in, out)) - { - // not consumed, give to DF - return out; - } - else - { - // consumed, repeat - goto wgetch_again; - } -} - -// hook - called at program start, initialize some stuffs we'll use later -static int (*_SDL_Init)(uint32_t flags) = 0; -DFhackCExport int SDL_Init(uint32_t flags) -{ - // find real functions - _SDL_Init = (int (*)( uint32_t )) dlsym(RTLD_NEXT, "SDL_Init"); - _SDL_Quit = (void (*)( void )) dlsym(RTLD_NEXT, "SDL_Quit"); - _SDL_PollEvent = (int (*)(SDL::Event*))dlsym(RTLD_NEXT,"SDL_PollEvent"); - - // check if we got them - if(_SDL_Init && _SDL_Quit && _SDL_PollEvent) - { - fprintf(stderr,"dfhack: hooking successful\n"); - } - else - { - // bail, this would be a disaster otherwise - fprintf(stderr,"dfhack: something went horribly wrong\n"); - exit(1); - } - - int ret = _SDL_Init(flags); - return ret; -} diff --git a/library/Hooks-windows.cpp b/library/Hooks-windows.cpp deleted file mode 100644 index d3f39b969..000000000 --- a/library/Hooks-windows.cpp +++ /dev/null @@ -1,838 +0,0 @@ -/* -https://github.com/peterix/dfhack -Copyright (c) 2009-2012 Petr Mrázek (peterix@gmail.com) - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any -damages arising from the use of this software. - -Permission is granted to anyone to use this software for any -purpose, including commercial applications, and to alter it and -redistribute it freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must -not claim that you wrote the original software. If you use this -software in a product, an acknowledgment in the product documentation -would be appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and -must not be misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*/ - -#define DFhackCExport extern "C" __declspec(dllexport) - -#include -#include -#include -#include -#include -#include "Core.h" -#include "Hooks.h" -#include - -#include "tinythread.h" -#include "modules/Graphic.h" - -/*************************************************************************/ -// extremely boring wrappers beyond this point. Only fix when broken - -// we don't know which of the SDL functions will be called first... so we -// just catch the first one and init all our function pointers at that time -static void InitSDLPointers(void); -static std::once_flag inited; - -/// wrappers for SDL 1.2 functions used in 40d16 -/***** Condition variables - -SDL_CreateCond - SDL_cond * SDLCALL SDL_CreateCond(void); -SDL_CondSignal - int SDLCALL SDL_CondSignal(SDL_cond *cond); -SDL_CondWait - int SDLCALL SDL_CondWait(SDL_cond *cond, SDL_mutex *mut); -SDL_DestroyCond - void SDLCALL SDL_DestroyCond(SDL_cond *cond); -*/ -static vPtr (*_SDL_CreateCond)() = 0; -DFhackCExport vPtr SDL_CreateCond() -{ - return _SDL_CreateCond(); -} - -static int (*_SDL_CondSignal)( vPtr ) = 0; -DFhackCExport int SDL_CondSignal( vPtr cond ) -{ - return _SDL_CondSignal(cond); -} - -static int (*_SDL_CondWait)( vPtr,vPtr ) = 0; -DFhackCExport int SDL_CondWait( vPtr cond, vPtr mutex ) -{ - return _SDL_CondWait(cond, mutex); -} - -static void (*_SDL_DestroyCond)( vPtr ) = 0; -DFhackCExport void SDL_DestroyCond( vPtr cond ) -{ - _SDL_DestroyCond(cond); -} - -/***** mutexes - -SDL_CreateMutex - SDL_mutex * SDLCALL SDL_CreateMutex(void); -SDL_mutexP - int SDLCALL SDL_mutexP(SDL_mutex *mutex); -SDL_DestroyMutex - void SDLCALL SDL_DestroyMutex(SDL_mutex *mutex); -*/ -static vPtr (*_SDL_CreateMutex)(void) = 0; -DFhackCExport vPtr SDL_CreateMutex(void) -{ - return _SDL_CreateMutex(); -} - -static int (*_SDL_mutexP)(vPtr mutex) = 0; -DFhackCExport int SDL_mutexP(vPtr mutex) -{ - return _SDL_mutexP(mutex); -} - -static int (*_SDL_mutexV)(vPtr mutex) = 0; -DFhackCExport int SDL_mutexV(vPtr mutex) -{ - return _SDL_mutexV(mutex); -} - -static void (*_SDL_DestroyMutex)(vPtr mutex) = 0; -DFhackCExport void SDL_DestroyMutex(vPtr mutex) -{ - _SDL_DestroyMutex(mutex); -} - - -/***** timers - -SDL_AddTimer - SDL_TimerID SDLCALL SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param); -SDL_RemoveTimer - SDL_bool SDLCALL SDL_RemoveTimer(SDL_TimerID t); -SDL_GetTicks - Uint32 SDLCALL SDL_GetTicks(void); -*/ -static vPtr (*_SDL_AddTimer)(uint32_t interval, fPtr callback, vPtr param) = 0; -DFhackCExport vPtr SDL_AddTimer(uint32_t interval, fPtr callback, vPtr param) -{ - return _SDL_AddTimer(interval, callback, param); -} - -static bool (*_SDL_RemoveTimer)(vPtr timer) = 0; -DFhackCExport bool SDL_RemoveTimer(vPtr timer) -{ - return _SDL_RemoveTimer(timer); -} - -static uint32_t (*_SDL_GetTicks)(void) = 0; -DFhackCExport uint32_t SDL_GetTicks(void) -{ - return _SDL_GetTicks(); -} - -/***** Surfaces -SDL_CreateRGBSurface - SDL_Surface * SDLCALL SDL_CreateRGBSurface - (Uint32 flags, int width, int height, int depth, - Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask); - -SDL_CreateRGBSurfaceFrom - SDL_Surface * SDLCALL SDL_CreateRGBSurfaceFrom - (void *pixels, int width, int height, int depth, int pitch, - Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask); - -SDL_FreeSurface - void SDLCALL SDL_FreeSurface(SDL_Surface *surface); - -SDL_ConvertSurface - SDL_Surface * SDLCALL SDL_ConvertSurface - (SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags); - -SDL_LockSurface - int SDLCALL SDL_LockSurface(SDL_Surface *surface); - -SDL_UnlockSurface - void SDLCALL SDL_UnlockSurface(SDL_Surface *surface); -*/ - -static vPtr (*_SDL_CreateRGBSurface)(uint32_t flags, int width, int height, int depth, - uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) = 0; -DFhackCExport vPtr SDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, - uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) -{ - return _SDL_CreateRGBSurface(flags, width, height, depth, Rmask, Gmask, Bmask, Amask); -} - -static vPtr (*_SDL_CreateRGBSurfaceFrom)(vPtr pixels, int width, int height, int depth, int pitch, - uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) = 0; -DFhackCExport vPtr SDL_CreateRGBSurfaceFrom(vPtr pixels, int width, int height, int depth, int pitch, - uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) -{ - return _SDL_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask); -} - -static void (*_SDL_FreeSurface)(vPtr surface) = 0; -DFhackCExport void SDL_FreeSurface(vPtr surface) -{ - _SDL_FreeSurface(surface); -} - -static vPtr (*_SDL_ConvertSurface)(vPtr surface, vPtr format, uint32_t flags) = 0; -DFhackCExport vPtr SDL_ConvertSurface(vPtr surface, vPtr format, uint32_t flags) -{ - return _SDL_ConvertSurface(surface, format, flags); -} - -static int (*_SDL_LockSurface)(vPtr surface) = 0; -DFhackCExport int SDL_LockSurface(vPtr surface) -{ - return _SDL_LockSurface(surface); -} - -static void (*_SDL_UnlockSurface)(vPtr surface) = 0; -DFhackCExport void SDL_UnlockSurface(vPtr surface) -{ - _SDL_UnlockSurface(surface); -} - -/***** More surface stuff -SDL_MapRGB - Uint32 SDLCALL SDL_MapRGB - (const SDL_PixelFormat * const format, const Uint8 r, const Uint8 g, const Uint8 b); - -SDL_SaveBMP_RW - int SDLCALL SDL_SaveBMP_RW - (SDL_Surface *surface, SDL_RWops *dst, int freedst); - -SDL_SetAlpha - int SDLCALL SDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha); - -SDL_SetColorKey - int SDLCALL SDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key); - -SDL_GetVideoInfo - const SDL_VideoInfo * SDLCALL SDL_GetVideoInfo(void); - -SDL_SetVideoMode - SDL_Surface * SDLCALL SDL_SetVideoMode - (int width, int height, int bpp, Uint32 flags); - -SDL_UpperBlit - int SDLCALL SDL_UpperBlit - (SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect); -*/ - -static uint32_t (*_SDL_MapRGB)(vPtr pixelformat, uint8_t r, uint8_t g, uint8_t b) = 0; -DFhackCExport uint32_t SDL_MapRGB(vPtr pixelformat, uint8_t r, uint8_t g, uint8_t b) -{ - return _SDL_MapRGB(pixelformat,r,g,b); -} - -static int (*_SDL_SaveBMP_RW)(vPtr surface, vPtr dst, int freedst) = 0; -DFhackCExport int SDL_SaveBMP_RW(vPtr surface, vPtr dst, int freedst) -{ - return _SDL_SaveBMP_RW(surface,dst,freedst); -} - -static int (*_SDL_SetAlpha)(vPtr surface, uint32_t flag, uint8_t alpha) = 0; -DFhackCExport int SDL_SetAlpha(vPtr surface, uint32_t flag, uint8_t alpha) -{ - return _SDL_SetAlpha(surface,flag,alpha); -} - -static int (*_SDL_SetColorKey)(vPtr surface, uint32_t flag, uint32_t key) = 0; -DFhackCExport int SDL_SetColorKey(vPtr surface, uint32_t flag, uint32_t key) -{ - return _SDL_SetColorKey(surface,flag,key); -} - -static vPtr (*_SDL_GetVideoInfo)(void) = 0; -DFhackCExport vPtr SDL_GetVideoInfo(void) -{ - return _SDL_GetVideoInfo(); -} - -static vPtr (*_SDL_SetVideoMode)(int width, int height, int bpp, uint32_t flags) = 0; -DFhackCExport vPtr SDL_SetVideoMode(int width, int height, int bpp, uint32_t flags) -{ - return _SDL_SetVideoMode(width, height, bpp, flags); -} - -static int (*_SDL_UpperBlit)(DFHack::DFSDL_Surface* src, DFHack::DFSDL_Rect* srcrect, DFHack::DFSDL_Surface* dst, DFHack::DFSDL_Rect* dstrect) = 0; -DFhackCExport int SDL_UpperBlit(DFHack::DFSDL_Surface* src, DFHack::DFSDL_Rect* srcrect, DFHack::DFSDL_Surface* dst, DFHack::DFSDL_Rect* dstrect) -{ - DFHack::Core & c = DFHack::Core::getInstance(); - if ( c.isValid() && dstrect != NULL && dstrect->h != 0 && dstrect->w != 0 ) - { - DFHack::Graphic* g = c.getGraphic(); - DFHack::DFTileSurface* ov = g->Call(dstrect->x/dstrect->w, dstrect->y/dstrect->h); - - if ( ov != NULL ) - { - if ( ov->paintOver ) - { - _SDL_UpperBlit(src, srcrect, dst, dstrect); - } - - DFHack::DFSDL_Rect* dstrect2 = new DFHack::DFSDL_Rect; - dstrect2->x = dstrect->x; - dstrect2->y = dstrect->y; - dstrect2->w = dstrect->w; - dstrect2->h = dstrect->h; - - if ( ov->dstResize != NULL ) - { - DFHack::DFSDL_Rect* r = (DFHack::DFSDL_Rect*)ov->dstResize; - dstrect2->x += r->x; - dstrect2->y += r->y; - dstrect2->w += r->w; - dstrect2->h += r->h; - } - - int result = _SDL_UpperBlit(ov->surface, ov->rect, dst, dstrect2); - delete dstrect2; - return result; - } - } - - return _SDL_UpperBlit(src, srcrect, dst, dstrect); -} - -/***** Even more surface -SDL_GL_GetAttribute - int SDLCALL SDL_GL_GetAttribute(SDL_GLattr attr, int* value); - -SDL_GL_SetAttribute - int SDLCALL SDL_GL_SetAttribute(SDL_GLattr attr, int value); - -SDL_WM_SetCaption - void SDLCALL SDL_WM_SetCaption(const char *title, const char *icon); - -SDL_WM_SetIcon - void SDLCALL SDL_WM_SetIcon(SDL_Surface *icon, Uint8 *mask); - -SDL_FillRect - int SDLCALL SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color); -*/ - - -static void * (*_SDL_GetVideoSurface)( void ) = 0; -DFhackCExport void * SDL_GetVideoSurface(void) -{ - return _SDL_GetVideoSurface(); -} - -static void * (*_SDL_DisplayFormat)( void * surface ) = 0; -DFhackCExport void * SDL_DisplayFormat(void *surface) -{ - return _SDL_DisplayFormat(surface); -} - -// SDL_Surface *SDL_DisplayFormatAlpha(SDL_Surface *surface); -static void * (*_SDL_DisplayFormatAlpha)( void * surface ) = 0; -DFhackCExport void * SDL_DisplayFormatAlpha(void *surface) -{ - return _SDL_DisplayFormatAlpha(surface); -} - -//void SDL_GetRGBA(Uint32 pixel, SDL_PixelFormat *fmt, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a); - -static void (*_SDL_GetRGBA)(uint32_t pixel, void * fmt, uint8_t * r, uint8_t * g, uint8_t * b, uint8_t *a) = 0; -DFhackCExport void SDL_GetRGBA(uint32_t pixel, void * fmt, uint8_t * r, uint8_t * g, uint8_t * b, uint8_t *a) -{ - return _SDL_GetRGBA(pixel, fmt, r, g, b, a); -} - -static int (*_SDL_GL_GetAttribute)(int attr, int * value) = 0; -DFhackCExport int SDL_GL_GetAttribute(int attr, int * value) -{ - return _SDL_GL_GetAttribute(attr,value); -} - -static int (*_SDL_GL_SetAttribute)(int attr, int value) = 0; -DFhackCExport int SDL_GL_SetAttribute(int attr, int value) -{ - return _SDL_GL_SetAttribute(attr,value); -} - -static void (*_SDL_WM_SetCaption)(const char *title, const char *icon) = 0; -DFhackCExport void SDL_WM_SetCaption(const char *title, const char *icon) -{ - //_SDL_WM_SetCaption("DwarfHacked the Fortress of Hacks",icon); - _SDL_WM_SetCaption(title,icon); -} - -static void (*_SDL_WM_SetIcon)(vPtr icon, uint8_t *mask) = 0; -DFhackCExport void SDL_WM_SetIcon(vPtr icon, uint8_t *mask) -{ - _SDL_WM_SetIcon(icon, mask); -} - -static int (*_SDL_FillRect)(vPtr dst, vPtr dstrect, uint32_t color) = 0; -DFhackCExport int SDL_FillRect(vPtr dst, vPtr dstrect, uint32_t color) -{ - return _SDL_FillRect(dst,dstrect,color); -} - -/***** Events and input -SDL_EnableKeyRepeat - int SDLCALL SDL_EnableKeyRepeat(int delay, int interval); -SDL_EnableUNICODE - int SDLCALL SDL_EnableUNICODE(int enable); -SDL_GetKeyState - Uint8 * SDLCALL SDL_GetKeyState(int *numkeys); -SDL_PollEvent - int SDLCALL SDL_PollEvent(SDL_Event *event); -SDL_PushEvent - int SDLCALL SDL_PushEvent(SDL_Event *event); -*/ - -static int (*_SDL_EnableKeyRepeat)(int delay, int interval) = 0; -DFhackCExport int SDL_EnableKeyRepeat(int delay, int interval) -{ - return _SDL_EnableKeyRepeat(delay, interval); -} - -static int (*_SDL_EnableUNICODE)(int enable) = 0; -DFhackCExport int SDL_EnableUNICODE(int enable) -{ - if(!enable) - { - fprintf(stderr, "SDL_EnableUNICODE turned off. Keybindings may break.\n"); - } - return _SDL_EnableUNICODE(enable); -} - -static uint8_t * (*_SDL_GetKeyState)(int* numkeys) = 0; -DFhackCExport uint8_t * SDL_GetKeyState(int* numkeys) -{ - return _SDL_GetKeyState(numkeys); -} - -// called by DF to check input events -static int (*_SDL_PollEvent)(SDL::Event* event) = 0; -DFhackCExport int SDL_PollEvent(SDL::Event* event) -{ - pollevent_again: - // if SDL returns 0 here, it means there are no more events. return 0 - int orig_return = _SDL_PollEvent(event); - if(!orig_return) - return 0; - // otherwise we have an event to filter - else if( event != 0 ) - { - DFHack::Core & c = DFHack::Core::getInstance(); - // if we consume the event, ask SDL for more. - if(!c.DFH_SDL_Event(event)) - goto pollevent_again; - } - return orig_return; -} - -static int (*_SDL_PushEvent)(SDL::Event* event) = 0; -DFhackCExport int SDL_PushEvent(SDL::Event* event) -{ - return _SDL_PushEvent(event); -} - -/***** error handling -SDL_GetError - char * SDLCALL SDL_GetError(void); -SDL_SetError - extern DECLSPEC void SDLCALL SDL_SetError(const char *fmt, ...); -SDL_ClearError - extern DECLSPEC void SDLCALL SDL_ClearError(void); -SDL_Error - extern DECLSPEC void SDLCALL SDL_Error(SDL_errorcode code); -*/ - -static char * (*_SDL_GetError)(void) = 0; -DFhackCExport char * SDL_GetError(void) -{ - return _SDL_GetError(); -} - -static void (*_SDL_SetError)(const char *fmt, ...) = 0; -DFhackCExport void SDL_SetError(const char *fmt, ...) Wformat(printf,1,2) -{ - char buf[1024]; - va_list args; - va_start(args,fmt); - vsnprintf(buf, sizeof(buf) - 1 ,fmt,args); - va_end(args); - _SDL_SetError(buf); -} - -static void (*_SDL_ClearError)(void) = 0; -DFhackCExport void SDL_ClearError(void) -{ - _SDL_ClearError(); -} - -static void (*_SDL_Error)(int code) = 0; -DFhackCExport void SDL_Error(int code) -{ - _SDL_Error(code); -} - -/***** symbol resolution -SDL_LoadFunction - extern DECLSPEC void * SDLCALL SDL_LoadFunction(void *handle, const char *name); -SDL_LoadObject - extern DECLSPEC void * SDLCALL SDL_LoadObject(const char *sofile); -SDL_UnloadObject - extern DECLSPEC void SDLCALL SDL_UnloadObject(void *handle); -*/ - -static void * (*_SDL_LoadFunction)(vPtr handle, const char *name) = 0; -DFhackCExport void * SDL_LoadFunction(vPtr handle, const char *name) -{ - return _SDL_LoadFunction(handle, name); -} - -extern "C" static vPtr (*_SDL_LoadObject)(const char *sofile) = 0; -DFhackCExport vPtr SDL_LoadObject(const char *sofile) -{ - return _SDL_LoadObject(sofile); -} - -static void (*_SDL_UnloadObject)(vPtr handle) = 0; -DFhackCExport void SDL_UnloadObject(vPtr handle) -{ - _SDL_UnloadObject(handle); -} - -/***** r/w -SDL_ReadBE32 - extern DECLSPEC Uint32 SDLCALL SDL_ReadBE32(SDL_RWops *src); -SDL_ReadLE16 - extern DECLSPEC Uint16 SDLCALL SDL_ReadLE16(SDL_RWops *src); -SDL_ReadLE32 - extern DECLSPEC Uint32 SDLCALL SDL_ReadLE32(SDL_RWops *src); -*/ - -static uint32_t (*_SDL_ReadBE32)(vPtr src) = 0; -DFhackCExport uint32_t SDL_ReadBE32(vPtr src) -{ - return _SDL_ReadBE32(src); -} - -static uint16_t (*_SDL_ReadLE16)(vPtr src) = 0; -DFhackCExport uint16_t SDL_ReadLE16(vPtr src) -{ - return _SDL_ReadLE16(src); -} - -static uint32_t (*_SDL_ReadLE32)(vPtr src) = 0; -DFhackCExport uint32_t SDL_ReadLE32(vPtr src) -{ - return _SDL_ReadLE32(src); -} - -/***** Misc -SDL_RWFromFile - SDL_RWops * SDLCALL SDL_RWFromFile(const char *file, const char *mode); -SDL_SetModuleHandle - void SDLCALL SDL_SetModuleHandle(void *hInst); -SDL_ShowCursor - int SDLCALL SDL_ShowCursor(int toggle); -SDL_strlcpy - size_t SDLCALL SDL_strlcpy(char *dst, const char *src, size_t maxlen); -*/ - -static vPtr (*_SDL_RWFromFile)(const char* file, const char *mode) = 0; -DFhackCExport vPtr SDL_RWFromFile(const char* file, const char *mode) -{ - return _SDL_RWFromFile(file, mode); -} - -static void (*_SDL_SetModuleHandle)(vPtr hInst) = 0; -DFhackCExport void SDL_SetModuleHandle(vPtr hInst) -{ - _SDL_SetModuleHandle(hInst); -} - -static int (*_SDL_ShowCursor)(int toggle) = 0; -DFhackCExport int SDL_ShowCursor(int toggle) -{ - return _SDL_ShowCursor(toggle); -} - -static size_t (*_SDL_strlcpy)(char *dst, const char *src, size_t maxlen) = 0; -DFhackCExport size_t SDL_strlcpy(char *dst, const char *src, size_t maxlen) -{ - if(!_SDL_strlcpy) - { - HMODULE realSDLlib = LoadLibrary("SDLreal.dll"); - if(!realSDLlib) - { - exit(-111); - } - _SDL_strlcpy = (size_t (*)(char*, const char*, size_t))GetProcAddress(realSDLlib,"SDL_strlcpy"); - } - return _SDL_strlcpy(dst,src,maxlen); -} - -/***** The real meat of this -SDL_Init -SDL_Quit -SDL_GL_SwapBuffers - void SDLCALL SDL_GL_SwapBuffers(void); -*/ - - -// hook - called at program exit -static void (*_SDL_Quit)(void) = 0; -DFhackCExport void SDL_Quit(void) -{ - DFHack::Core & c = DFHack::Core::getInstance(); - c.Shutdown(); - if(_SDL_Quit) - { - _SDL_Quit(); - } -} -// this is supported from 0.31.04 forward -DFhackCExport int SDL_NumJoysticks(void) -{ - DFHack::Core & c = DFHack::Core::getInstance(); - return c.Update(); -} - -static void (*_SDL_GL_SwapBuffers)(void) = 0; -DFhackCExport void SDL_GL_SwapBuffers(void) -{ - InitSDLPointers(); - _SDL_GL_SwapBuffers(); -} - -// hook - called every tick in the 2D mode of DF -static int (*_SDL_Flip)(void * some_ptr) = 0; -DFhackCExport int SDL_Flip(void * some_ptr) -{ - InitSDLPointers(); - return _SDL_Flip(some_ptr); -} - -static int (*_SDL_Init)(uint32_t flags) = 0; -DFhackCExport int SDL_Init(uint32_t flags) -{ - InitSDLPointers(); - return _SDL_Init(flags); -} - -/* -MORE CRAP -*/ -static void * (*_SDL_CreateSemaphore)(uint32_t initial_value) = 0; -DFhackCExport void *SDL_CreateSemaphore(uint32_t initial_value) -{ - InitSDLPointers(); - return _SDL_CreateSemaphore(initial_value); -} - -static vPtr (*_SDL_CreateThread)(int (*fn)(void *), void *data) = 0; -DFhackCExport vPtr SDL_CreateThread(int (*fn)(void *), void *data) -{ - InitSDLPointers(); - return _SDL_CreateThread(fn,data); -} - - -static void (*_SDL_Delay)(uint32_t ms) = 0; -DFhackCExport void SDL_Delay(uint32_t ms) -{ - InitSDLPointers(); - _SDL_Delay(ms); -} - -static void (*_SDL_DestroySemaphore)(void *sem) = 0; -DFhackCExport void SDL_DestroySemaphore(void *sem) -{ - InitSDLPointers(); - _SDL_DestroySemaphore(sem); -} - -static vPtr (*_SDL_ListModes)(vPtr format, uint32_t flags) = 0; -DFhackCExport vPtr SDL_ListModes(vPtr format, uint32_t flags) -{ - InitSDLPointers(); - return _SDL_ListModes(format, flags); -} - -static uint8_t (*_SDL_GetAppState)(void) = 0; -DFhackCExport uint8_t SDL_GetAppState(void) -{ - InitSDLPointers(); - return _SDL_GetAppState(); -} - -static uint8_t (*_SDL_GetMouseState)(int *, int *) = 0; -DFhackCExport uint8_t SDL_GetMouseState(int *x, int *y) -{ - InitSDLPointers(); - return _SDL_GetMouseState(x,y); -} - -static int (*_SDL_InitSubSystem)(uint32_t flags) = 0; -DFhackCExport int SDL_InitSubSystem(uint32_t flags) -{ - InitSDLPointers(); - return _SDL_InitSubSystem(flags); -} - -static int (*_SDL_SemPost)(void *sem) = 0; -DFhackCExport int SDL_SemPost(void *sem) -{ - InitSDLPointers(); - return _SDL_SemPost(sem); -} - -static int (*_SDL_SemTryWait)(void *sem) = 0; -DFhackCExport int SDL_SemTryWait(void *sem) -{ - InitSDLPointers(); - return _SDL_SemTryWait(sem); -} - -static int (*_SDL_SemWait)(void *sem) = 0; -DFhackCExport int SDL_SemWait(void *sem) -{ - InitSDLPointers(); - return _SDL_SemWait(sem); -} - -static uint32_t (*_SDL_ThreadID)(void) = 0; -DFhackCExport uint32_t SDL_ThreadID(void) -{ - InitSDLPointers(); - return _SDL_ThreadID(); -} - -static char* (*_SDL_getenv)(const char *name) = 0; -DFhackCExport char* SDL_getenv(const char *name) -{ - InitSDLPointers(); - return _SDL_getenv(name); -} - -static size_t (*_SDL_strlcat)(char *dst, const char *src, size_t maxlen) = 0; -DFhackCExport size_t SDL_strlcat(char *dst, const char *src, size_t maxlen) -{ - InitSDLPointers(); - return _SDL_strlcat(dst, src, maxlen); -} - -void FirstCall() -{ - // reroute stdout and stderr - freopen("stdout.log", "w", stdout); - freopen("stderr.log", "w", stderr); - HMODULE realSDLlib = LoadLibrary("SDLreal.dll"); - if(!realSDLlib) - { - MessageBox(0,"Can't load SDLreal.dll\n","Error", MB_OK); - fprintf(stderr, "Can't load SDLreal.dll\n"); - return; - } - fprintf(stderr, "FirstCall()\n"); - // stuff for DF - _SDL_AddTimer = (void*(*)(uint32_t, void*, void*)) GetProcAddress(realSDLlib,"SDL_AddTimer"); - _SDL_CondSignal = (int (*)(vPtr))GetProcAddress(realSDLlib,"SDL_CondSignal"); - _SDL_CondWait = (int (*)(vPtr, vPtr))GetProcAddress(realSDLlib,"SDL_CondWait"); - _SDL_ConvertSurface = (void*(*)(void*, void*, uint32_t))GetProcAddress(realSDLlib,"SDL_ConvertSurface"); - _SDL_CreateCond = (vPtr(*)())GetProcAddress(realSDLlib,"SDL_CreateCond"); - _SDL_CreateMutex = (vPtr(*)())GetProcAddress(realSDLlib,"SDL_CreateMutex"); - _SDL_CreateRGBSurface = (void*(*)(uint32_t, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t))GetProcAddress(realSDLlib,"SDL_CreateRGBSurface"); - _SDL_CreateRGBSurfaceFrom = (void*(*)(void*, int, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t))GetProcAddress(realSDLlib,"SDL_CreateRGBSurfaceFrom"); - _SDL_DestroyCond = (void (*)(vPtr))GetProcAddress(realSDLlib,"SDL_DestroyCond"); - _SDL_DestroyMutex = (void (*)(vPtr))GetProcAddress(realSDLlib,"SDL_DestroyMutex"); - _SDL_EnableKeyRepeat = (int (*)(int, int))GetProcAddress(realSDLlib,"SDL_EnableKeyRepeat"); - _SDL_EnableUNICODE = (int (*)(int))GetProcAddress(realSDLlib,"SDL_EnableUNICODE"); - _SDL_GetVideoSurface = (void*(*)())GetProcAddress(realSDLlib,"SDL_GetVideoSurface"); - _SDL_DisplayFormat = (void * (*) (void *))GetProcAddress(realSDLlib,"SDL_DisplayFormat"); - _SDL_DisplayFormatAlpha = (void * (*) (void *))GetProcAddress(realSDLlib,"SDL_DisplayFormatAlpha"); - _SDL_GetRGBA = (void (*) (uint32_t, void *, uint8_t *, uint8_t *, uint8_t *, uint8_t *))GetProcAddress(realSDLlib,"SDL_GetRGBA"); - _SDL_FreeSurface = (void (*)(void*))GetProcAddress(realSDLlib,"SDL_FreeSurface"); - _SDL_GL_GetAttribute = (int (*)(int, int*))GetProcAddress(realSDLlib,"SDL_GL_GetAttribute"); - _SDL_GL_SetAttribute = (int (*)(int, int))GetProcAddress(realSDLlib,"SDL_GL_SetAttribute"); - _SDL_GL_SwapBuffers = (void (*)())GetProcAddress(realSDLlib,"SDL_GL_SwapBuffers"); - _SDL_GetError = (char*(*)())GetProcAddress(realSDLlib,"SDL_GetError"); - _SDL_GetKeyState = (uint8_t*(*)(int*))GetProcAddress(realSDLlib,"SDL_GetKeyState"); - _SDL_GetTicks = (uint32_t (*)())GetProcAddress(realSDLlib,"SDL_GetTicks"); - _SDL_GetVideoInfo = (void*(*)())GetProcAddress(realSDLlib,"SDL_GetVideoInfo"); - _SDL_Init = (int (*)(uint32_t))GetProcAddress(realSDLlib,"SDL_Init"); - _SDL_Flip = (int (*)( void * )) GetProcAddress(realSDLlib, "SDL_Flip"); - _SDL_LockSurface = (int (*)(void*))GetProcAddress(realSDLlib,"SDL_LockSurface"); - _SDL_MapRGB = (uint32_t (*)(void*, uint8_t, uint8_t, uint8_t))GetProcAddress(realSDLlib,"SDL_MapRGB"); - _SDL_PollEvent = (int (*)(SDL::Event*))GetProcAddress(realSDLlib,"SDL_PollEvent"); - _SDL_PushEvent = (int (*)(SDL::Event*))GetProcAddress(realSDLlib,"SDL_PushEvent"); - _SDL_Quit = (void (*)())GetProcAddress(realSDLlib,"SDL_Quit"); - _SDL_RWFromFile = (void*(*)(const char*, const char*))GetProcAddress(realSDLlib,"SDL_RWFromFile"); - _SDL_RemoveTimer = (bool (*)(void*))GetProcAddress(realSDLlib,"SDL_RemoveTimer"); - _SDL_SaveBMP_RW = (int (*)(void*, void*, int))GetProcAddress(realSDLlib,"SDL_SaveBMP_RW"); - _SDL_SetAlpha = (int (*)(void*, uint32_t, uint8_t))GetProcAddress(realSDLlib,"SDL_SetAlpha"); - _SDL_SetColorKey = (int (*)(void*, uint32_t, uint32_t))GetProcAddress(realSDLlib,"SDL_SetColorKey"); - _SDL_SetModuleHandle = (void (*)(void*))GetProcAddress(realSDLlib,"SDL_SetModuleHandle"); - _SDL_SetVideoMode = (void*(*)(int, int, int, uint32_t))GetProcAddress(realSDLlib,"SDL_SetVideoMode"); - _SDL_ShowCursor = (int (*)(int))GetProcAddress(realSDLlib,"SDL_ShowCursor"); - _SDL_UnlockSurface = (void (*)(void*))GetProcAddress(realSDLlib,"SDL_UnlockSurface"); - _SDL_UpperBlit = (int (*)(DFHack::DFSDL_Surface*, DFHack::DFSDL_Rect*, DFHack::DFSDL_Surface*, DFHack::DFSDL_Rect*))GetProcAddress(realSDLlib,"SDL_UpperBlit"); - _SDL_WM_SetCaption = (void (*)(const char*, const char*))GetProcAddress(realSDLlib,"SDL_WM_SetCaption"); - _SDL_WM_SetIcon = (void (*)(void*, uint8_t*))GetProcAddress(realSDLlib,"SDL_WM_SetIcon"); - _SDL_mutexP = (int (*)(vPtr))GetProcAddress(realSDLlib,"SDL_mutexP"); - _SDL_mutexV = (int (*)(vPtr))GetProcAddress(realSDLlib,"SDL_mutexV"); - _SDL_strlcpy = (size_t (*)(char*, const char*, size_t))GetProcAddress(realSDLlib,"SDL_strlcpy"); - - // stuff for SDL_Image - _SDL_ClearError = (void (*)())GetProcAddress(realSDLlib,"SDL_ClearError"); - _SDL_Error = (void (*)(int))GetProcAddress(realSDLlib,"SDL_Error"); - _SDL_LoadFunction = (void*(*)(vPtr, const char*))GetProcAddress(realSDLlib,"SDL_LoadFunction"); - _SDL_LoadObject = (vPtr(*)(const char*))GetProcAddress(realSDLlib,"SDL_LoadObject"); - _SDL_ReadBE32 = (uint32_t (*)(void*))GetProcAddress(realSDLlib,"SDL_ReadBE32"); - _SDL_ReadLE16 = (uint16_t (*)(void*))GetProcAddress(realSDLlib,"SDL_ReadLE16"); - _SDL_ReadLE32 = (uint32_t (*)(void*))GetProcAddress(realSDLlib,"SDL_ReadLE32"); - _SDL_SetError = (void (*)(const char*, ...))GetProcAddress(realSDLlib,"SDL_SetError"); - _SDL_UnloadObject = (void (*)(vPtr))GetProcAddress(realSDLlib,"SDL_UnloadObject"); - _SDL_FillRect = (int (*)(void*,void*,uint32_t))GetProcAddress(realSDLlib,"SDL_FillRect"); - - // new in DF 0.31.04 - _SDL_CreateSemaphore = (void* (*)(uint32_t))GetProcAddress(realSDLlib,"SDL_CreateSemaphore"); - _SDL_CreateThread = (vPtr (*)(int (*fn)(void *), void *data))GetProcAddress(realSDLlib,"SDL_CreateThread"); - _SDL_Delay = (void (*)(uint32_t))GetProcAddress(realSDLlib,"SDL_Delay"); - _SDL_DestroySemaphore = (void (*)(void *))GetProcAddress(realSDLlib,"SDL_DestroySemaphore"); - _SDL_GetAppState = (uint8_t (*)(void))GetProcAddress(realSDLlib,"SDL_GetAppState"); - _SDL_GetMouseState = (uint8_t (*)(int *, int *))GetProcAddress(realSDLlib,"SDL_GetMouseState"); - _SDL_InitSubSystem = (int (*)(uint32_t))GetProcAddress(realSDLlib,"SDL_InitSubSystem"); - _SDL_SemPost = (int (*)(void *))GetProcAddress(realSDLlib,"SDL_SemPost"); - _SDL_SemTryWait = (int (*)(void *))GetProcAddress(realSDLlib,"SDL_SemTryWait"); - _SDL_SemWait = (int (*)(void *))GetProcAddress(realSDLlib,"SDL_SemWait"); - _SDL_ThreadID = (uint32_t (*)(void))GetProcAddress(realSDLlib,"SDL_ThreadID"); - - // new in DF 0.43.05 - _SDL_getenv = (char* (*)(const char*))GetProcAddress(realSDLlib,"SDL_getenv"); - _SDL_strlcat = (size_t (*)(char*, const char*, size_t))GetProcAddress(realSDLlib,"SDL_strlcat"); - - // new in DF v50.01 - _SDL_ListModes = (void *(*)(void*, uint32_t))GetProcAddress(realSDLlib,"SDL_ListModes"); - - _SDL_EnableUNICODE(1); - - fprintf(stderr,"Initized HOOKS!\n"); -} - -void InitSDLPointers() -{ - std::call_once(inited, [](){ FirstCall(); }); -} diff --git a/library/Hooks.cpp b/library/Hooks.cpp index 36af2617c..b4a865c18 100644 --- a/library/Hooks.cpp +++ b/library/Hooks.cpp @@ -26,8 +26,11 @@ DFhackCExport void dfhooks_prerender() { DFhackCExport bool dfhooks_sdl_event(SDL::Event* event) { return DFHack::Core::getInstance().DFH_SDL_Event(event); } + // called for each utf-8 char read from the ncurses input // key is positive for ncurses keys and negative for everything else +// if true is returned, then the event has been consumed and further processing +// shouldn't happen DFhackCExport bool dfhooks_ncurses_key(int key) { return DFHack::Core::getInstance().DFH_ncurses_key(key); } diff --git a/library/include/Core.h b/library/include/Core.h index 2e022d6ca..386769fcb 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -108,19 +108,6 @@ namespace DFHack // Better than tracking some weird variables all over the place. class DFHACK_EXPORT Core { -#ifdef _DARWIN - friend int ::DFH_SDL_NumJoysticks(void); - friend void ::DFH_SDL_Quit(void); - friend int ::DFH_SDL_PollEvent(SDL::Event *); - friend int ::DFH_SDL_Init(uint32_t flags); - friend int ::DFH_wgetch(WINDOW * w); -#else - friend int ::SDL_NumJoysticks(void); - friend void ::SDL_Quit(void); - friend int ::SDL_PollEvent(SDL::Event *); - friend int ::SDL_Init(uint32_t flags); - friend int ::wgetch(WINDOW * w); -#endif friend void ::dfhooks_init(); friend void ::dfhooks_shutdown(); friend void ::dfhooks_update(); @@ -207,7 +194,7 @@ namespace DFHack bool Init(); int Update (void); int Shutdown (void); - int DFH_SDL_Event(SDL::Event* event); + bool DFH_SDL_Event(SDL::Event* event); bool ncurses_wgetch(int in, int & out); bool DFH_ncurses_key(int key); diff --git a/plugins/title-folder.cpp b/plugins/title-folder.cpp index 4f93a6c7f..2659a094f 100644 --- a/plugins/title-folder.cpp +++ b/plugins/title-folder.cpp @@ -20,7 +20,7 @@ static std::string original_title; static DFLibrary *sdl_handle = NULL; static const std::vector sdl_libs { - "SDLreal.dll", + "SDL.dll", "SDL.framework/Versions/A/SDL", "SDL.framework/SDL", "libSDL-1.2.so.0" From 03d42634f9621c96a8a3dbc03d9af0d170f89caf Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 4 Jan 2023 10:11:40 -0800 Subject: [PATCH 0035/1234] remove unused windows package dir --- package/windows/sdl license.txt | 502 ------------------------------- package/windows/win32/.gitignore | 1 - package/windows/win64/.gitignore | 1 - 3 files changed, 504 deletions(-) delete mode 100644 package/windows/sdl license.txt delete mode 100644 package/windows/win32/.gitignore delete mode 100644 package/windows/win64/.gitignore diff --git a/package/windows/sdl license.txt b/package/windows/sdl license.txt deleted file mode 100644 index e5ab03e12..000000000 --- a/package/windows/sdl license.txt +++ /dev/null @@ -1,502 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/package/windows/win32/.gitignore b/package/windows/win32/.gitignore deleted file mode 100644 index 6a7461313..000000000 --- a/package/windows/win32/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dll diff --git a/package/windows/win64/.gitignore b/package/windows/win64/.gitignore deleted file mode 100644 index 6a7461313..000000000 --- a/package/windows/win64/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dll From b2f32be117aa09672447c9983134c43227081333 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 4 Jan 2023 10:30:10 -0800 Subject: [PATCH 0036/1234] simplify installation instructions now that we don't overwrite SDL.dll on Windows --- docs/Installing.rst | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/docs/Installing.rst b/docs/Installing.rst index 15a6276bf..8a04b7cb9 100644 --- a/docs/Installing.rst +++ b/docs/Installing.rst @@ -80,28 +80,16 @@ 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. -.. note:: - - On Windows, installing DFHack will overwrite ``SDL.dll``. This is - intentional and necessary for DFHack to work, so be sure to choose to - overwrite ``SDL.dll`` if prompted. (If you are not prompted, you may be - installing DFHack in the wrong place.) - Uninstalling DFHack =================== -Manually uninstalling DFHack essentially involves reversing what you did to -install. On Windows, replace ``SDL.dll`` with ``SDLreal.dll`` first. Then, you -can remove any files that were part of the DFHack archive. DFHack does not -currently maintain a list of these files, so if you want to completely remove -them, you should consult the DFHack archive that you installed for a full list. -Generally, any files left behind should not negatively affect DF. +Just renaming or removing the ``dfhooks`` library file is enough to disable +DFHack. If you would like to remove all DFHack files, consult the DFHack install +archive to see the list of files and remove the corresponding files in the Dwarf +Fortress folder. Any DFHack files left behind will not negatively affect DF. On Steam, uninstalling DFHack will cleanly remove everything that was installed -with DFHack, **including** the ``SDL.dll`` file, which will render Dwarf -Fortress inoperative. In your Steam client, open the properties window for -Dwarf Fortress, select "Local Files", and click on "Verify integrity of game -files...". This will get Dwarf Fortress working properly again. +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, @@ -117,4 +105,4 @@ ensures that files that don't exist in the latest version are properly removed and don't affect your new installation. Then, extract the DFHack release archive into your Dwarf Fortress folder, -overwriting any remaining top-level files (including SDL.dll). +overwriting any remaining top-level files. From 9f605d639696fc94f8ce939b3cff4d51f2c6c9c5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 4 Jan 2023 19:55:46 -0800 Subject: [PATCH 0037/1234] call DF's stubs for SDL semaphore functions --- library/include/df/custom/enabler.methods.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/include/df/custom/enabler.methods.inc b/library/include/df/custom/enabler.methods.inc index 26a23a4dd..b06af2345 100644 --- a/library/include/df/custom/enabler.methods.inc +++ b/library/include/df/custom/enabler.methods.inc @@ -1,6 +1,6 @@ void zoom_display(df::zoom_commands command) { - SDL_SemWait(async_zoom.sem); + DFHack::DFSDL::DFSDL_SemWait(async_zoom.sem); async_zoom.queue.push_back(command); - SDL_SemPost(async_zoom.sem); - SDL_SemPost(async_zoom.sem_fill); + DFHack::DFSDL::DFSDL_SemPost(async_zoom.sem); + DFHack::DFSDL::DFSDL_SemPost(async_zoom.sem_fill); } From 275513319cd5b80a99c5ea63a9d4e7bfa5bcd8d1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 12 Apr 2023 23:14:03 -0700 Subject: [PATCH 0038/1234] remove last reference to SDLReal --- library/modules/DFSDL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp index 6a3e6af2f..b95b6302a 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -14,7 +14,7 @@ using namespace DFHack; static DFLibrary *g_sdl_handle = nullptr; static DFLibrary *g_sdl_image_handle = nullptr; static const std::vector SDL_LIBS { - "SDLreal.dll", // TODO: change to SDL.dll once we move to dfhooks + "SDL.dll", "SDL.framework/Versions/A/SDL", "SDL.framework/SDL", "libSDL-1.2.so.0" From 6c577fbe26cdbe0fdc2136eb66472359f5812271 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 13 Apr 2023 00:27:20 -0700 Subject: [PATCH 0039/1234] don't initialize Core from the main thread that's too early --- library/Hooks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Hooks.cpp b/library/Hooks.cpp index b4a865c18..13f8bd908 100644 --- a/library/Hooks.cpp +++ b/library/Hooks.cpp @@ -3,7 +3,7 @@ // called before main event loop starts DFhackCExport void dfhooks_init() { - DFHack::Core::getInstance().Init(); + // TODO: initialize things we need to do while still in the main thread } // called after main event loops exits From 48c3a2c98738dcf3f8b16c8d50de6904db96d970 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 13 Apr 2023 00:40:10 -0700 Subject: [PATCH 0040/1234] document which thread each call is coming from --- library/Hooks.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/library/Hooks.cpp b/library/Hooks.cpp index 13f8bd908..c241e4875 100644 --- a/library/Hooks.cpp +++ b/library/Hooks.cpp @@ -1,33 +1,35 @@ #include "Core.h" #include "Export.h" -// called before main event loop starts +// called from the main thread before the simulation thread is started +// and the main event loop is initiated DFhackCExport void dfhooks_init() { // TODO: initialize things we need to do while still in the main thread } -// called after main event loops exits +// called from the main thread after the main event loops exits DFhackCExport void dfhooks_shutdown() { DFHack::Core::getInstance().Shutdown(); } -// called in the main event loop +// called from the simulation thread in the main event loop DFhackCExport void dfhooks_update() { DFHack::Core::getInstance().Update(); } -// called just before adding the macro recording/playback overlay +// called from the simulation thread just before adding the macro +// recording/playback overlay DFhackCExport void dfhooks_prerender() { // TODO: render overlay widgets that are not attached to a viewscreen } -// called for each SDL event, if true is returned, then the event has been -// consumed and further processing shouldn't happen +// called from the main thread for each SDL event. if true is returned, then +// the event has been consumed and further processing shouldn't happen DFhackCExport bool dfhooks_sdl_event(SDL::Event* event) { return DFHack::Core::getInstance().DFH_SDL_Event(event); } -// called for each utf-8 char read from the ncurses input +// called from the main thread for each utf-8 char read from the ncurses input // key is positive for ncurses keys and negative for everything else // if true is returned, then the event has been consumed and further processing // shouldn't happen From f13548a47d53eaa45e66da5a932be5c945815784 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 13 Apr 2023 01:16:22 -0700 Subject: [PATCH 0041/1234] continue to ship SDL.dll until DF moves to SDL2 --- CMakeLists.txt | 16 + library/CMakeLists.txt | 4 + package/windows/sdl license.txt | 502 +++++++++++++++++++++++++++++++ package/windows/win32/.gitignore | 1 + package/windows/win64/.gitignore | 1 + 5 files changed, 524 insertions(+) create mode 100644 package/windows/sdl license.txt create mode 100644 package/windows/win32/.gitignore create mode 100644 package/windows/win64/.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt index 02857f91d..086f054c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -299,6 +299,22 @@ if(WIN32) DESTINATION ${CMAKE_BINARY_DIR}/depends/) file(COPY ${ZLIB_DOWNLOAD_DIR}/zlib.lib DESTINATION ${CMAKE_BINARY_DIR}/depends/zlib/lib/) + + # Do the same for SDL.dll + # (DFHack doesn't require this at build time, so no need to move it to the build folder) + # TODO: remove SDL.dll from our distribution once DF moves to SDL2. we only + # continue to include it so we don't break Steam players on update by removing + # the SDL.dll that DF needs. + set(SDL_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" + ${SDL_DOWNLOAD_DIR}/SDL.dll + "1ae242c4b94cb03756a1288122a66faf") + else() + download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win32-SDL.dll" + ${SDL_DOWNLOAD_DIR}/SDL.dll + "5a09604daca6b2b5ce049d79af935d6a") + endif() endif() if(APPLE) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 418c9b371..0b9f48413 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -432,6 +432,10 @@ if(UNIX) install(TARGETS dfhooks LIBRARY DESTINATION . RUNTIME DESTINATION .) +else() + # On windows, copy SDL.dll so DF can still run. + install(PROGRAMS ${dfhack_SOURCE_DIR}/package/windows/win${DFHACK_BUILD_ARCH}/SDL.dll + DESTINATION ${DFHACK_LIBRARY_DESTINATION}) endif() # install the main lib diff --git a/package/windows/sdl license.txt b/package/windows/sdl license.txt new file mode 100644 index 000000000..e5ab03e12 --- /dev/null +++ b/package/windows/sdl license.txt @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/package/windows/win32/.gitignore b/package/windows/win32/.gitignore new file mode 100644 index 000000000..6a7461313 --- /dev/null +++ b/package/windows/win32/.gitignore @@ -0,0 +1 @@ +*.dll diff --git a/package/windows/win64/.gitignore b/package/windows/win64/.gitignore new file mode 100644 index 000000000..6a7461313 --- /dev/null +++ b/package/windows/win64/.gitignore @@ -0,0 +1 @@ +*.dll From b9d95c5a0bbc68846952c54ed91959ac55835b1f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 13 Apr 2023 18:53:11 -0700 Subject: [PATCH 0042/1234] bump version to 50.08-rc1 --- CMakeLists.txt | 6 +++--- library/xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b9f323640..bb5c428a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,9 +191,9 @@ if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl endif() # set up versioning. -set(DF_VERSION "50.07") -set(DFHACK_RELEASE "r1") -set(DFHACK_PRERELEASE FALSE) +set(DF_VERSION "50.08") +set(DFHACK_RELEASE "rc1") +set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/library/xml b/library/xml index 43a89a268..e825025d3 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 43a89a268b825fc05457678b19e551bf632dcd19 +Subproject commit e825025d399d936548c77578d4a40eb23183af0c From 52b869d908aa55410db0574610e64f69bb5502b6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 14 Apr 2023 01:22:12 -0700 Subject: [PATCH 0043/1234] don't read cur_savegame.save_dir when invalid --- library/Core.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/Core.cpp b/library/Core.cpp index b1fe2d389..e9463ec51 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2083,7 +2083,9 @@ void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event eve if (!df::global::world) return; - std::string rawFolder = "save/" + (df::global::world->cur_savegame.save_dir) + "/init"; + + std::string rawFolder = !isWorldLoaded() ? "" : + "save/" + (df::global::world->cur_savegame.save_dir) + "/init"; auto i = table.find(event); if ( i != table.end() ) { From 5ace09fad0addc0fa02ff26bd27affa573fd39b1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 14 Apr 2023 01:38:38 -0700 Subject: [PATCH 0044/1234] use the World module for the data read --- library/Core.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index e9463ec51..c3c7bb7f2 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2084,8 +2084,7 @@ void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event eve if (!df::global::world) return; - std::string rawFolder = !isWorldLoaded() ? "" : - "save/" + (df::global::world->cur_savegame.save_dir) + "/init"; + std::string rawFolder = !isWorldLoaded() ? "" : "save/" + World::ReadWorldFolder() + "/init"; auto i = table.find(event); if ( i != table.end() ) { From ce6adabbdcf50c4c0a1d071c7f874d697eaeb578 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Fri, 14 Apr 2023 05:52:24 -0500 Subject: [PATCH 0045/1234] sync library/xml to 50.08-beta --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index e825025d3..055f9b4ce 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e825025d399d936548c77578d4a40eb23183af0c +Subproject commit 055f9b4cec3bbec8e562f4774754242a14026bd2 From 051baa4e6e2ad27d0a514bbf5da68b31f25ebb96 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 15 Apr 2023 07:12:55 +0000 Subject: [PATCH 0046/1234] Auto-update submodules library/xml: master --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index e825025d3..43059670e 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e825025d399d936548c77578d4a40eb23183af0c +Subproject commit 43059670e7d3338d9a164bc23d0c41994187de9c From ef380e9e1c7b4e019b4e0b31c65cf16f234043c7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 15 Apr 2023 15:49:36 -0700 Subject: [PATCH 0047/1234] don't reset planner panel minimized state --- docs/changelog.txt | 1 + plugins/lua/buildingplan/planneroverlay.lua | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 351e13d76..975caf91f 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -38,6 +38,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes ## Misc Improvements +- `buildingplan`: minimized planner panel stays minimized until you change it again ## Documentation diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index 3e06ac79d..8f12c695f 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -729,7 +729,6 @@ function PlannerOverlay:onInput(keys) return true end self.selected = 1 - self.minimized = false self.subviews.hollow:setOption(false) self:reset() reset_counts_flag = true From af1d886a27a6f3c2cec8d3de1492c75d528aa74e Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 16 Apr 2023 03:28:37 +0000 Subject: [PATCH 0048/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index ec1a69788..7e7a1034c 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ec1a69788fd6329008672523b622fd8b390fea73 +Subproject commit 7e7a1034c502909fdbb73398865958230da67c69 From a5e2d79e39f0fbaad03e70d16eae7e95be146bbe Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 15 Apr 2023 21:05:05 -0700 Subject: [PATCH 0049/1234] remove stubs for deprecated travis scripts --- travis/authors-rst.py | 14 -------------- travis/buildmaster-rebuild-pr.py | 14 -------------- travis/check-rpc.py | 14 -------------- travis/download-df.sh | 9 --------- travis/get-df-version.sh | 9 --------- travis/lint.py | 14 -------------- travis/run-tests.py | 14 -------------- travis/script-docs.py | 14 -------------- travis/script-syntax.py | 14 -------------- 9 files changed, 116 deletions(-) delete mode 100755 travis/authors-rst.py delete mode 100755 travis/buildmaster-rebuild-pr.py delete mode 100755 travis/check-rpc.py delete mode 100755 travis/download-df.sh delete mode 100755 travis/get-df-version.sh delete mode 100755 travis/lint.py delete mode 100755 travis/run-tests.py delete mode 100755 travis/script-docs.py delete mode 100755 travis/script-syntax.py diff --git a/travis/authors-rst.py b/travis/authors-rst.py deleted file mode 100755 index cf52385b5..000000000 --- a/travis/authors-rst.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 - -import os -import subprocess -import sys - -script_name = os.path.basename(__file__) -new_script_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'ci', script_name) - -sys.stderr.write('\nNote: travis/{script_name} is deprecated. Use ci/{script_name} instead.\n\n'.format(script_name=script_name)) -sys.stderr.flush() - -p = subprocess.run([sys.executable, new_script_path] + sys.argv[1:]) -sys.exit(p.returncode) diff --git a/travis/buildmaster-rebuild-pr.py b/travis/buildmaster-rebuild-pr.py deleted file mode 100755 index cf52385b5..000000000 --- a/travis/buildmaster-rebuild-pr.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 - -import os -import subprocess -import sys - -script_name = os.path.basename(__file__) -new_script_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'ci', script_name) - -sys.stderr.write('\nNote: travis/{script_name} is deprecated. Use ci/{script_name} instead.\n\n'.format(script_name=script_name)) -sys.stderr.flush() - -p = subprocess.run([sys.executable, new_script_path] + sys.argv[1:]) -sys.exit(p.returncode) diff --git a/travis/check-rpc.py b/travis/check-rpc.py deleted file mode 100755 index cf52385b5..000000000 --- a/travis/check-rpc.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 - -import os -import subprocess -import sys - -script_name = os.path.basename(__file__) -new_script_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'ci', script_name) - -sys.stderr.write('\nNote: travis/{script_name} is deprecated. Use ci/{script_name} instead.\n\n'.format(script_name=script_name)) -sys.stderr.flush() - -p = subprocess.run([sys.executable, new_script_path] + sys.argv[1:]) -sys.exit(p.returncode) diff --git a/travis/download-df.sh b/travis/download-df.sh deleted file mode 100755 index aec2d6d99..000000000 --- a/travis/download-df.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -script_name="$(basename "$0")" -new_script_path="$(dirname "$0")/../ci/${script_name}" - -printf >&2 "\nNote: travis/%s is deprecated. Use ci/%s instead.\n\n" "${script_name}" "${script_name}" - -"${new_script_path}" "$@" -exit $? diff --git a/travis/get-df-version.sh b/travis/get-df-version.sh deleted file mode 100755 index aec2d6d99..000000000 --- a/travis/get-df-version.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -script_name="$(basename "$0")" -new_script_path="$(dirname "$0")/../ci/${script_name}" - -printf >&2 "\nNote: travis/%s is deprecated. Use ci/%s instead.\n\n" "${script_name}" "${script_name}" - -"${new_script_path}" "$@" -exit $? diff --git a/travis/lint.py b/travis/lint.py deleted file mode 100755 index cf52385b5..000000000 --- a/travis/lint.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 - -import os -import subprocess -import sys - -script_name = os.path.basename(__file__) -new_script_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'ci', script_name) - -sys.stderr.write('\nNote: travis/{script_name} is deprecated. Use ci/{script_name} instead.\n\n'.format(script_name=script_name)) -sys.stderr.flush() - -p = subprocess.run([sys.executable, new_script_path] + sys.argv[1:]) -sys.exit(p.returncode) diff --git a/travis/run-tests.py b/travis/run-tests.py deleted file mode 100755 index cf52385b5..000000000 --- a/travis/run-tests.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 - -import os -import subprocess -import sys - -script_name = os.path.basename(__file__) -new_script_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'ci', script_name) - -sys.stderr.write('\nNote: travis/{script_name} is deprecated. Use ci/{script_name} instead.\n\n'.format(script_name=script_name)) -sys.stderr.flush() - -p = subprocess.run([sys.executable, new_script_path] + sys.argv[1:]) -sys.exit(p.returncode) diff --git a/travis/script-docs.py b/travis/script-docs.py deleted file mode 100755 index cf52385b5..000000000 --- a/travis/script-docs.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 - -import os -import subprocess -import sys - -script_name = os.path.basename(__file__) -new_script_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'ci', script_name) - -sys.stderr.write('\nNote: travis/{script_name} is deprecated. Use ci/{script_name} instead.\n\n'.format(script_name=script_name)) -sys.stderr.flush() - -p = subprocess.run([sys.executable, new_script_path] + sys.argv[1:]) -sys.exit(p.returncode) diff --git a/travis/script-syntax.py b/travis/script-syntax.py deleted file mode 100755 index cf52385b5..000000000 --- a/travis/script-syntax.py +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python3 - -import os -import subprocess -import sys - -script_name = os.path.basename(__file__) -new_script_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'ci', script_name) - -sys.stderr.write('\nNote: travis/{script_name} is deprecated. Use ci/{script_name} instead.\n\n'.format(script_name=script_name)) -sys.stderr.flush() - -p = subprocess.run([sys.executable, new_script_path] + sys.argv[1:]) -sys.exit(p.returncode) From c596df2bc57585993e7544908a3c1c8643e5d8dc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 15 Apr 2023 21:30:51 -0700 Subject: [PATCH 0050/1234] update new authors from 01 Feb 2023 - 15 Apr 2023 --- docs/about/Authors.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/about/Authors.rst b/docs/about/Authors.rst index 75b9eb4f7..020ed5e76 100644 --- a/docs/about/Authors.rst +++ b/docs/about/Authors.rst @@ -45,6 +45,7 @@ cjhammel cjhammel Clayton Hughes Clément Vuchener cvuchener Corey CoreyJ87 +Cubittus Cubittus daedsidog daedsidog Dan Amlund danamlund Daniel Brooks db48x @@ -133,6 +134,7 @@ Milo Christiansen milochristiansen MithrilTuxedo MithrilTuxedo mizipzor mizipzor moversti moversti +mrrho mrrho Murad Beybalaev Erquint Myk Taylor myk002 napagokc napagokc @@ -158,6 +160,7 @@ Petr Mrázek peterix Pfhreak Pfhreak Pierre Lulé plule Pierre-David Bélanger pierredavidbelanger +PopnROFL PopnROFL potato ppaawwll ppaawwll 🐇🐇🐇🐇 Priit Laes plaes @@ -201,6 +204,7 @@ SeerSkye SeerSkye seishuuu seishuuu Seth Woodworth sethwoodworth Shim Panze Shim-Panze +silverflyone silverflyone simon Simon Jackson sizeak Simon Lees simotek @@ -235,6 +239,7 @@ ViTuRaS ViTuRaS Vjek vjek Warmist warmist Wes Malone wesQ3 +Will H TSM-EVO Will Rogers wjrogers WoosterUK WoosterUK XianMaeve XianMaeve From 67f50eafb0cee72a96b2a890023b4859232c90ed Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 15 Apr 2023 22:26:38 -0700 Subject: [PATCH 0051/1234] add alias and keybinding for toggling the keyboard cursor --- data/init/dfhack.keybindings.init | 3 +++ data/init/dfhack.tools.init | 1 + docs/changelog.txt | 1 + 3 files changed, 5 insertions(+) diff --git a/data/init/dfhack.keybindings.init b/data/init/dfhack.keybindings.init index 8ce0c3696..0fc596215 100644 --- a/data/init/dfhack.keybindings.init +++ b/data/init/dfhack.keybindings.init @@ -49,6 +49,9 @@ keybinding add Ctrl-H@dwarfmode autodump-destroy-here # apply blueprints to the map keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort +# toggle keyboard cursor +keybinding add Alt-K@dwarfmode toggle-kbd-cursor + # show information collected by dwarfmonitor #keybinding add Alt-M@dwarfmode/Default "dwarfmonitor prefs" #keybinding add Ctrl-F@dwarfmode/Default "dwarfmonitor stats" diff --git a/data/init/dfhack.tools.init b/data/init/dfhack.tools.init index aaf0cf277..8fd815559 100644 --- a/data/init/dfhack.tools.init +++ b/data/init/dfhack.tools.init @@ -144,3 +144,4 @@ enable \ alias add autounsuspend suspendmanager alias add gui/dig gui/design +alias add toggle-kbd-cursor lua "local flags4 = df.global.d_init.flags4 if flags4.KEYBOARD_CURSOR then flags4.KEYBOARD_CURSOR = false else local guidm = require('gui.dwarfmode') guidm.setCursorPos(guidm.Viewport.get():getCenter()) flags4.KEYBOARD_CURSOR = true end" diff --git a/docs/changelog.txt b/docs/changelog.txt index 351e13d76..3806dd125 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -38,6 +38,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes ## Misc Improvements +- ``toggle-kbd-cursor``: add hotkey for toggling the keyboard cursor (Alt-K) ## Documentation From 86845c5bbff2b58bd5b12f49d7184a4bafd5c36c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 16 Apr 2023 09:50:57 -0700 Subject: [PATCH 0052/1234] update author names as per feedback --- docs/about/Authors.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/about/Authors.rst b/docs/about/Authors.rst index 020ed5e76..cf74c6412 100644 --- a/docs/about/Authors.rst +++ b/docs/about/Authors.rst @@ -12,6 +12,7 @@ Name Github Other 8Z 8Z Abel abstern acwatkins acwatkins +Alex Blamey Cubittus Alexander Collins gearsix Alexander Gavrilov angavrilov ag Amber Brown hawkowl @@ -45,7 +46,6 @@ cjhammel cjhammel Clayton Hughes Clément Vuchener cvuchener Corey CoreyJ87 -Cubittus Cubittus daedsidog daedsidog Dan Amlund danamlund Daniel Brooks db48x @@ -204,7 +204,7 @@ SeerSkye SeerSkye seishuuu seishuuu Seth Woodworth sethwoodworth Shim Panze Shim-Panze -silverflyone silverflyone +Silver silverflyone simon Simon Jackson sizeak Simon Lees simotek From 1ec6d90e463cdb270f6f4828064ff5ce4ddb9b6a Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 17 Apr 2023 01:06:59 +0000 Subject: [PATCH 0053/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 7e7a1034c..726e5633f 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 7e7a1034c502909fdbb73398865958230da67c69 +Subproject commit 726e5633fd2aa1e0872a3f1553d8823505fca10e From 2dbfa37f54d74168b6f880d68c43617dadf13dd3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 16 Apr 2023 22:32:50 -0700 Subject: [PATCH 0054/1234] set version number for feedback release --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb5c428a6..239892e76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,8 +191,8 @@ if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl endif() # set up versioning. -set(DF_VERSION "50.08") -set(DFHACK_RELEASE "rc1") +set(DF_VERSION "50.07") +set(DFHACK_RELEASE "r2rc1") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From d1d521fbdb07eb72e57d2918b48d6c7cfd9a37b3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 16 Apr 2023 22:34:29 -0700 Subject: [PATCH 0055/1234] infrastructure for hiding the terminal console on startup --- docs/changelog.txt | 1 + library/Core.cpp | 9 +++++++++ library/lua/dfhack.lua | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index f7a3102cc..3bb16251c 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -40,6 +40,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - `buildingplan`: minimized planner panel stays minimized until you change it again - ``toggle-kbd-cursor``: add hotkey for toggling the keyboard cursor (Alt-K) +- `gui/control-panel`: add option for hiding the terminal console by default ## Documentation diff --git a/library/Core.cpp b/library/Core.cpp index c3c7bb7f2..4f06c3d62 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1314,6 +1314,15 @@ static void run_dfhack_init(color_ostream &out, Core *core) // load user overrides std::vector prefixes(1, "dfhack"); loadScriptFiles(core, out, prefixes, CONFIG_PATH + "init"); + + // if the option is set, hide the terminal + auto L = Lua::Core::State; + Lua::StackUnwinder top(L); + Lua::CallLuaModuleFunction(out, L, "dfhack", "getHideConsoleOnStartup", 0, 1, + Lua::DEFAULT_LUA_LAMBDA, [&](lua_State* L) { + if (lua_toboolean(L, -1)) + core->getConsole().hide(); + }, false); } // Load dfhack.init in a dedicated thread (non-interactive console mode) diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index aa33b62d6..bc543fd10 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -51,6 +51,13 @@ if dfhack.is_core_context then SC_UNPAUSED = 8 end +-- User-changeable options + +dfhack.HIDE_CONSOLE_ON_STARTUP = true +function dfhack.getHideConsoleOnStartup() + return dfhack.HIDE_CONSOLE_ON_STARTUP +end + -- Error handling safecall = dfhack.safecall From 16fbea4c1f2bd1e8eac9cbcfc6757eb659be1612 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 17 Apr 2023 05:56:19 +0000 Subject: [PATCH 0056/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 726e5633f..5fe9e423b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 726e5633fd2aa1e0872a3f1553d8823505fca10e +Subproject commit 5fe9e423bbd5cdb7c6e7e8f1051e3aa8d00c853a From a7aded65e44d95c592eb6713e2a1b9c94028c86d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 17 Apr 2023 01:04:03 -0700 Subject: [PATCH 0057/1234] match new gems category --- library/modules/Materials.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index d73b59922..7a1ef249f 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -439,6 +439,7 @@ bool MaterialInfo::matches(const df::dfhack_material_category &cat) const return true; if (cat.bits.milk && linear_index(material->reaction_product.id, std::string("CHEESE_MAT")) >= 0) return true; + TEST(gem, IS_GEM); return false; } From 77c2458900b9cc6d04b7cd9cdfaaaad4a0f7a433 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 17 Apr 2023 01:05:25 -0700 Subject: [PATCH 0058/1234] filter by gems (for windows) --- plugins/buildingplan/buildingplan.cpp | 9 +++++++++ plugins/lua/buildingplan.lua | 2 ++ plugins/lua/buildingplan/filterselection.lua | 1 + 3 files changed, 12 insertions(+) diff --git a/plugins/buildingplan/buildingplan.cpp b/plugins/buildingplan/buildingplan.cpp index 1d9f58416..e2f964a44 100644 --- a/plugins/buildingplan/buildingplan.cpp +++ b/plugins/buildingplan/buildingplan.cpp @@ -150,6 +150,7 @@ static const df::dfhack_material_category stone_cat(df::dfhack_material_category static const df::dfhack_material_category wood_cat(df::dfhack_material_category::mask_wood); static const df::dfhack_material_category metal_cat(df::dfhack_material_category::mask_metal); static const df::dfhack_material_category glass_cat(df::dfhack_material_category::mask_glass); +static const df::dfhack_material_category gem_cat(df::dfhack_material_category::mask_gem); static const df::dfhack_material_category clay_cat(df::dfhack_material_category::mask_clay); static const df::dfhack_material_category cloth_cat(df::dfhack_material_category::mask_cloth); static const df::dfhack_material_category silk_cat(df::dfhack_material_category::mask_silk); @@ -169,6 +170,9 @@ static void cache_matched(int16_t type, int32_t index) { } else if (mi.matches(glass_cat)) { DEBUG(status).print("cached glass material: %s (%d, %d)\n", mi.toString().c_str(), type, index); mat_cache.emplace(mi.toString(), std::make_pair(mi, "glass")); + } else if (mi.matches(gem_cat)) { + DEBUG(status).print("cached gem material: %s (%d, %d)\n", mi.toString().c_str(), type, index); + mat_cache.emplace(mi.toString(), std::make_pair(mi, "gem")); } else if (mi.matches(clay_cat)) { DEBUG(status).print("cached clay material: %s (%d, %d)\n", mi.toString().c_str(), type, index); mat_cache.emplace(mi.toString(), std::make_pair(mi, "clay")); @@ -800,6 +804,8 @@ static int setMaterialMaskFilter(lua_State *L) { mask |= metal_cat.whole; else if (cat == "glass") mask |= glass_cat.whole; + else if (cat == "gem") + mask |= gem_cat.whole; else if (cat == "clay") mask |= clay_cat.whole; else if (cat == "cloth") @@ -850,6 +856,7 @@ static int getMaterialMaskFilter(lua_State *L) { ret.emplace("wood", !bits || bits & wood_cat.whole); ret.emplace("metal", !bits || bits & metal_cat.whole); ret.emplace("glass", !bits || bits & glass_cat.whole); + ret.emplace("gem", !bits || bits & gem_cat.whole); ret.emplace("clay", !bits || bits & clay_cat.whole); ret.emplace("cloth", !bits || bits & cloth_cat.whole); ret.emplace("silk", !bits || bits & silk_cat.whole); @@ -897,6 +904,8 @@ static int setMaterialFilter(lua_State *L) { mask.whole |= metal_cat.whole; else if (mat.matches(glass_cat)) mask.whole |= glass_cat.whole; + else if (mat.matches(gem_cat)) + mask.whole |= gem_cat.whole; else if (mat.matches(clay_cat)) mask.whole |= clay_cat.whole; else if (mat.matches(cloth_cat)) diff --git a/plugins/lua/buildingplan.lua b/plugins/lua/buildingplan.lua index 2de467f7c..d64317eb0 100644 --- a/plugins/lua/buildingplan.lua +++ b/plugins/lua/buildingplan.lua @@ -111,6 +111,8 @@ function get_desc(filter) desc = 'Ballista part' elseif desc == 'Catapultpart' then desc = 'Catapult part' + elseif desc == 'Smallgem' then + desc = 'Small, cut gem' end return desc diff --git a/plugins/lua/buildingplan/filterselection.lua b/plugins/lua/buildingplan/filterselection.lua index 498c89c1e..968ad88d9 100644 --- a/plugins/lua/buildingplan/filterselection.lua +++ b/plugins/lua/buildingplan/filterselection.lua @@ -452,6 +452,7 @@ function QualityAndMaterialsPage:refresh() make_cat_choice('Wood', 'wood', 'CUSTOM_SHIFT_O', cats), make_cat_choice('Metal', 'metal', 'CUSTOM_SHIFT_M', cats), make_cat_choice('Glass', 'glass', 'CUSTOM_SHIFT_G', cats), + make_cat_choice('Gem', 'gem', 'CUSTOM_SHIFT_E', cats), make_cat_choice('Clay', 'clay', 'CUSTOM_SHIFT_C', cats), make_cat_choice('Cloth', 'cloth', 'CUSTOM_SHIFT_L', cats), make_cat_choice('Silk', 'silk', 'CUSTOM_SHIFT_K', cats), From b26d6a90ca9edd1b8b19185cea285eed4c03803b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 17 Apr 2023 01:06:06 -0700 Subject: [PATCH 0059/1234] update structures head --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 43059670e..1413d3c67 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 43059670e7d3338d9a164bc23d0c41994187de9c +Subproject commit 1413d3c67c5bd85e6afbef45d8b1ade6b8389ede From eb9e40a24d6023470725959f46f2d5fe3c83daf8 Mon Sep 17 00:00:00 2001 From: John Reid Date: Mon, 17 Apr 2023 10:43:14 +0200 Subject: [PATCH 0060/1234] Fix typo in Quickstart.rst Fixes a typo in Quickstart.rst: mangager -> manager --- docs/Quickstart.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst index 065ba6ecc..f4a022a9c 100644 --- a/docs/Quickstart.rst +++ b/docs/Quickstart.rst @@ -162,7 +162,7 @@ You can run them all from the launcher. 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 -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 you. Note that you could have imported the orders directly from this screen as well, using the DFHack `overlay` widget at the bottom of the manager orders panel. From e9f6695aceb9918ff56b3c8596498cd44faee033 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 17 Apr 2023 09:39:15 -0700 Subject: [PATCH 0061/1234] infrastructure for hiding armok tools --- docs/Tags.rst | 2 +- docs/changelog.txt | 3 ++- library/lua/dfhack.lua | 5 +++++ library/lua/helpdb.lua | 17 +++++++++++++++-- plugins/hotkeys.cpp | 39 +++++++++++++++++++++++++++++++-------- plugins/lua/hotkeys.lua | 13 +++++++++++++ 6 files changed, 67 insertions(+), 12 deletions(-) diff --git a/docs/Tags.rst b/docs/Tags.rst index 5ff13d632..c7b284d07 100644 --- a/docs/Tags.rst +++ b/docs/Tags.rst @@ -21,7 +21,7 @@ for the tag assignment spreadsheet. "why" tags ---------- -- `armok `: Tools that give you complete control over an aspect of the game or provide access to information that the game intentionally keeps hidden. +- `armok `: Tools that give you complete control over an aspect of the game or provide access to information that 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 `: Tools that run in the background and automatically manage routine, toilsome aspects of your fortress. - `bugfix `: Tools that fix specific bugs, either permanently or on-demand. - `design `: Tools that help you design your fort. diff --git a/docs/changelog.txt b/docs/changelog.txt index 3bb16251c..553fb3362 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -40,7 +40,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - `buildingplan`: minimized planner panel stays minimized until you change it again - ``toggle-kbd-cursor``: add hotkey for toggling the keyboard cursor (Alt-K) -- `gui/control-panel`: add option for hiding the terminal console by default +- `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 ## Documentation diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index bc543fd10..78d978147 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -58,6 +58,11 @@ function dfhack.getHideConsoleOnStartup() return dfhack.HIDE_CONSOLE_ON_STARTUP end +dfhack.HIDE_ARMOK_TOOLS = false +function dfhack.getHideArmokTools() + return dfhack.HIDE_ARMOK_TOOLS +end + -- Error handling safecall = dfhack.safecall diff --git a/library/lua/helpdb.lua b/library/lua/helpdb.lua index a7ac6226f..4ce078a22 100644 --- a/library/lua/helpdb.lua +++ b/library/lua/helpdb.lua @@ -788,7 +788,11 @@ function ls(filter_str, skip_tags, show_dev_commands, exclude_strs) table.insert(excludes, {str=argparse.stringList(exclude_strs)}) end if not show_dev_commands then - table.insert(excludes, {tag='dev'}) + local dev_tags = {'dev', 'unavailable'} + if dfhack.getHideArmokTools() then + table.insert(dev_tags, 'armok') + end + table.insert(excludes, {tag=dev_tags}) end list_entries(skip_tags, include, excludes) end @@ -813,7 +817,16 @@ function tags(tag) local skip_tags = true local include = {entry_type={ENTRY_TYPES.COMMAND}, tag=tag} - list_entries(skip_tags, include) + + local excludes = {tag={}} + if tag ~= 'unavailable' then + table.insert(excludes.tag, 'unavailable') + end + if tag ~= 'armok' and dfhack.getHideArmokTools() then + table.insert(excludes.tag, 'armok') + end + + list_entries(skip_tags, include, excludes) end return _ENV diff --git a/plugins/hotkeys.cpp b/plugins/hotkeys.cpp index 788a4c02b..136ad7a9d 100644 --- a/plugins/hotkeys.cpp +++ b/plugins/hotkeys.cpp @@ -49,7 +49,22 @@ static int cleanupHotkeys(lua_State *) { return 0; } -static void add_binding_if_valid(const string &sym, const string &cmdline, df::viewscreen *screen, bool filtermenu) { +static bool should_hide_armok(color_ostream &out, const string &cmdline) { + bool should_hide = false; + + auto L = Lua::Core::State; + Lua::StackUnwinder top(L); + Lua::CallLuaModuleFunction(out, L, "plugins.hotkeys", "should_hide_armok", 1, 1, + [&](lua_State *L){ + Lua::Push(L, cmdline); + }, [&](lua_State *L){ + should_hide = lua_toboolean(L, -1); + }); + + return should_hide; +} + +static void add_binding_if_valid(color_ostream &out, const string &sym, const string &cmdline, df::viewscreen *screen, bool filtermenu) { if (!can_invoke(cmdline, screen)) return; @@ -59,6 +74,11 @@ static void add_binding_if_valid(const string &sym, const string &cmdline, df::v return; } + if (should_hide_armok(out, cmdline)) { + DEBUG(log).print("filtering out armok keybinding\n"); + return; + } + current_bindings[sym] = cmdline; sorted_keys.push_back(sym); string keyspec = sym + "@" + MENU_SCREEN_FOCUS_STRING; @@ -67,7 +87,7 @@ static void add_binding_if_valid(const string &sym, const string &cmdline, df::v Core::getInstance().AddKeyBinding(keyspec, binding); } -static void find_active_keybindings(df::viewscreen *screen, bool filtermenu) { +static void find_active_keybindings(color_ostream &out, df::viewscreen *screen, bool filtermenu) { DEBUG(log).print("scanning for active keybindings\n"); if (valid) cleanupHotkeys(NULL); @@ -103,7 +123,7 @@ static void find_active_keybindings(df::viewscreen *screen, bool filtermenu) { string::size_type colon_pos = invoke_cmd->find(":"); // colons at location 0 are for commands like ":lua" if (colon_pos == string::npos || colon_pos == 0) { - add_binding_if_valid(sym, *invoke_cmd, screen, filtermenu); + add_binding_if_valid(out, sym, *invoke_cmd, screen, filtermenu); } else { vector tokens; @@ -111,7 +131,7 @@ static void find_active_keybindings(df::viewscreen *screen, bool filtermenu) { string focus = tokens[0].substr(1); if(Gui::matchFocusString(focus)) { auto cmdline = trim(tokens[1]); - add_binding_if_valid(sym, cmdline, screen, filtermenu); + add_binding_if_valid(out, sym, cmdline, screen, filtermenu); } } } @@ -124,7 +144,10 @@ static void find_active_keybindings(df::viewscreen *screen, bool filtermenu) { } static int getHotkeys(lua_State *L) { - find_active_keybindings(Gui::getCurViewscreen(true), true); + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + find_active_keybindings(*out, Gui::getCurViewscreen(true), true); Lua::PushVector(L, sorted_keys); Lua::Push(L, current_bindings); return 2; @@ -140,7 +163,7 @@ static void list(color_ostream &out) { DEBUG(log).print("listing active hotkeys\n"); bool was_valid = valid; if (!valid) - find_active_keybindings(Gui::getCurViewscreen(true), false); + find_active_keybindings(out, Gui::getCurViewscreen(true), false); out.print("Valid keybindings for the current focus:\n %s\n", join_strings("\n", Gui::getCurFocus(true)).c_str()); @@ -176,6 +199,8 @@ static command_result hotkeys_cmd(color_ostream &out, vector & paramete return Core::getInstance().runCommand(out, INVOKE_MENU_COMMAND ); } + CoreSuspender guard; + if (parameters[0] == "list") { list(out); return CR_OK; @@ -185,8 +210,6 @@ static command_result hotkeys_cmd(color_ostream &out, vector & paramete if (parameters.size() != 2 || parameters[0] != "invoke") return CR_WRONG_USAGE; - CoreSuspender guard; - int index = string_to_int(parameters[1], -1); if (index < 0) return CR_WRONG_USAGE; diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 8edb70073..ec5699fe4 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -5,6 +5,19 @@ local helpdb = require('helpdb') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') +local function get_command(cmdline) + local first_word = cmdline:trim():split(' +')[1] + if first_word:startswith(':') then first_word = first_word:sub(2) end + return first_word +end + +function should_hide_armok(cmdline) + local first_word = get_command(cmdline) + return dfhack.getHideArmokTools() and + helpdb.is_entry(first_word) and + helpdb.get_entry_tags(first_word).armok +end + -- ----------------- -- -- HotspotMenuWidget -- -- ----------------- -- From f6031e6a799fac2cd7d9b738e99d93d9eb5d2e7e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 17 Apr 2023 13:04:42 -0700 Subject: [PATCH 0062/1234] refactor existing logic to use new function --- plugins/lua/hotkeys.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index ec5699fe4..b162f0c08 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -12,10 +12,10 @@ local function get_command(cmdline) end function should_hide_armok(cmdline) - local first_word = get_command(cmdline) + local command = get_command(cmdline) return dfhack.getHideArmokTools() and - helpdb.is_entry(first_word) and - helpdb.get_entry_tags(first_word).armok + helpdb.is_entry(command) and + helpdb.get_entry_tags(command).armok end -- ----------------- -- @@ -245,10 +245,9 @@ end function Menu:onSelect(_, choice) if not choice or #self.subviews == 0 then return end - local first_word = choice.command:trim():split(' +')[1] - if first_word:startswith(':') then first_word = first_word:sub(2) end - self.subviews.help.text_to_wrap = helpdb.is_entry(first_word) and - helpdb.get_entry_short_help(first_word) or 'Command not found' + local command = get_command(choice.command) + self.subviews.help.text_to_wrap = helpdb.is_entry(command) and + helpdb.get_entry_short_help(command) or 'Command not found' self.subviews.help_panel:updateLayout() end From 3307427718814d7f6109828a9b39a95ce0b6f7aa Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 17 Apr 2023 13:29:58 -0700 Subject: [PATCH 0063/1234] update wording (thanks Ozzatron!) --- docs/Tags.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/Tags.rst b/docs/Tags.rst index c7b284d07..ded15c4c2 100644 --- a/docs/Tags.rst +++ b/docs/Tags.rst @@ -21,7 +21,9 @@ for the tag assignment spreadsheet. "why" tags ---------- -- `armok `: Tools that give you complete control over an aspect of the game or provide access to information that 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`. +- `armok `: 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 `: Tools that run in the background and automatically manage routine, toilsome aspects of your fortress. - `bugfix `: Tools that fix specific bugs, either permanently or on-demand. - `design `: Tools that help you design your fort. From c30c59c261e5c64a7573511e676a31d8d9867502 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 18 Apr 2023 07:13:59 +0000 Subject: [PATCH 0064/1234] Auto-update submodules library/xml: master scripts: master --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 1413d3c67..ae268954d 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 1413d3c67c5bd85e6afbef45d8b1ade6b8389ede +Subproject commit ae268954da3cde1c4e08f6d62273a17aae0d94da diff --git a/scripts b/scripts index 5fe9e423b..6fba9905a 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 5fe9e423bbd5cdb7c6e7e8f1051e3aa8d00c853a +Subproject commit 6fba9905a71f626ecc640fd3de988e147d16cb4e From 495c94127a47f660c5bc94ece7a080d1c3dcef68 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:19:25 +0000 Subject: [PATCH 0065/1234] Auto-update submodules depends/xlsxio: dfhack --- depends/xlsxio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/xlsxio b/depends/xlsxio index 439fdbc25..0a9945266 160000 --- a/depends/xlsxio +++ b/depends/xlsxio @@ -1 +1 @@ -Subproject commit 439fdbc259c13f23a3122e68ba35ad5a13bcd97c +Subproject commit 0a994526622c2201756e386ef98b44b193e25f06 From ed87075cb8b3875936c9823c8802d20b06f61e63 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 05:40:51 -0500 Subject: [PATCH 0066/1234] cmake minimum version 3.21 forced by this being the lowest version that supports vs 2022 --- depends/clsocket | 2 +- depends/lua/CMakeLists.txt | 2 +- library/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/depends/clsocket b/depends/clsocket index 6ed8aa464..d5e17c601 160000 --- a/depends/clsocket +++ b/depends/clsocket @@ -1 +1 @@ -Subproject commit 6ed8aa46462ea01a1122fc49422840a2facc9757 +Subproject commit d5e17c6012e7eefb0cbe3e130a56c24bd11f0094 diff --git a/depends/lua/CMakeLists.txt b/depends/lua/CMakeLists.txt index c3ff0c16f..efded915f 100644 --- a/depends/lua/CMakeLists.txt +++ b/depends/lua/CMakeLists.txt @@ -1,5 +1,5 @@ project(lua CXX) -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.21) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLUA_USE_APICHECK") diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index a3fcb8b6f..31cfb007d 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -1,5 +1,5 @@ project(dfapi) -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.21) # prevent CMake warnings about INTERFACE_LINK_LIBRARIES vs LINK_INTERFACE_LIBRARIES cmake_policy(SET CMP0022 NEW) From 649d72e658890246585e23f830b0142595c94e50 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 18 Apr 2023 08:28:00 -0700 Subject: [PATCH 0067/1234] add missed NO_LOGIC_SCREEN to the list adopt_region also kills the top viewscreen on transition --- library/lua/gui.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 64e203d3c..e425dbcf1 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -745,6 +745,7 @@ end local NO_LOGIC_SCREENS = { 'viewscreen_loadgamest', + 'viewscreen_adopt_regionst', 'viewscreen_export_regionst', 'viewscreen_choose_game_typest', 'viewscreen_worldst', From 250f05667b70e20a7e7c55fcfd8704477c0fe487 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 18 Apr 2023 15:50:59 -0700 Subject: [PATCH 0068/1234] add a warning when DT appears to be running --- docs/changelog.txt | 1 + plugins/lua/autolabor.lua | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 553fb3362..af0f208dc 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -42,6 +42,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - ``toggle-kbd-cursor``: add hotkey for toggling the keyboard cursor (Alt-K) - `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). ## Documentation diff --git a/plugins/lua/autolabor.lua b/plugins/lua/autolabor.lua index 6ef4d7279..50f39b225 100644 --- a/plugins/lua/autolabor.lua +++ b/plugins/lua/autolabor.lua @@ -10,7 +10,7 @@ AutolaborOverlay.ATTRS{ default_enabled=true, viewscreens='dwarfmode/Info/LABOR', frame={w=29, h=5}, - frame_style=gui.MEDIUM_FRAME, + frame_style=gui.THIN_FRAME, frame_background=gui.CLEAR_PEN, } @@ -18,9 +18,20 @@ function AutolaborOverlay:init() self:addviews{ widgets.Label{ frame={t=0, l=0}, - text_pen=COLOR_RED, + text_pen=COLOR_LIGHTRED, + text='DFHack autolabor is active!', + visible=isEnabled, + }, + widgets.Label{ + frame={t=0, l=0}, + text_pen=COLOR_LIGHTRED, + text='Dwarf Therapist is active!', + visible=function() return not isEnabled() end, + }, + widgets.Label{ + frame={t=1, l=0}, + text_pen=COLOR_WHITE, text={ - 'DFHack autolabor is active!', NEWLINE, 'Any changes made on this', NEWLINE, 'screen will have no effect.' }, @@ -29,7 +40,7 @@ function AutolaborOverlay:init() end function AutolaborOverlay:render(dc) - if not isEnabled() then return false end + if df.global.game_extra.external_flag ~= 1 then return end AutolaborOverlay.super.render(self, dc) end From 150708f21db8a401a8e62f98f2c6e8ba8911d416 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 05:00:36 -0500 Subject: [PATCH 0069/1234] build lanchdf with steam sdk --- .gitignore | 3 +++ CMakeLists.txt | 13 ++++++++++++ package/windows/CMakeLists.txt | 10 +++++---- package/windows/{launchdf.c => launchdf.cpp} | 22 ++++++++++++++++++-- 4 files changed, 42 insertions(+), 6 deletions(-) rename package/windows/{launchdf.c => launchdf.cpp} (76%) diff --git a/.gitignore b/.gitignore index e24f11252..a386b260a 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,6 @@ tags # external plugins /plugins/CMakeLists.custom.txt + +# steam api +depends/steam diff --git a/CMakeLists.txt b/CMakeLists.txt index 239892e76..899063d9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -312,6 +312,19 @@ if(WIN32) ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll "5a09604daca6b2b5ce049d79af935d6a") endif() + + # download Steam SDK + set (STEAMAPI_DIR ${dfhack_SOURCE_DIR}/depends/steam/) + download_file("https://partner.steamgames.com/downloads/steamworks_sdk_156.zip" + ${STEAMAPI_DIR}/steamworks_sdk_156.zip + "af5a579990dbe5ae4c1b0689260d001b") + file(ARCHIVE_EXTRACT + INPUT ${STEAMAPI_DIR}/steamworks_sdk_156.zip + DESTINATION ${STEAMAPI_DIR}) + set(STEAMAPI_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.lib") + set(STEAMAPI_SOURCE_DIR "${STEAMAPI_DIR}/sdk/public/steam") + set(STEAMAPI_SHARED_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.dll") + endif() if(APPLE) diff --git a/package/windows/CMakeLists.txt b/package/windows/CMakeLists.txt index a5877f117..42151e663 100644 --- a/package/windows/CMakeLists.txt +++ b/package/windows/CMakeLists.txt @@ -1,7 +1,9 @@ project(package_windows) if(WIN32) - add_executable(launchdf WIN32 launchdf.c) - install(TARGETS launchdf - DESTINATION ${DFHACK_DATA_DESTINATION}) -endif() + include_directories(${STEAMAPI_SOURCE_DIR}) + link_libraries(${STEAMAPI_LIBRARY}) + add_executable(launchdf WIN32 launchdf.cpp) + install(TARGETS launchdf DESTINATION ${DFHACK_DATA_DESTINATION}) + install(FILES ${STEAMAPI_SHARED_LIBRARY} DESTINATION ${DFHACK_DATA_DESTINATION}) +endif() \ No newline at end of file diff --git a/package/windows/launchdf.c b/package/windows/launchdf.cpp similarity index 76% rename from package/windows/launchdf.c rename to package/windows/launchdf.cpp index 992bf6636..804163960 100644 --- a/package/windows/launchdf.c +++ b/package/windows/launchdf.cpp @@ -1,13 +1,17 @@ #include #include +#include "steam_api.h" + +const uint32 DFHACK_STEAM_APPID = 2346660; static BOOL is_running_on_wine() { - static const char *(CDECL *pwine_get_version)(void); + typedef const char* (CDECL wine_get_version)(void); + static wine_get_version* pwine_get_version; HMODULE hntdll = GetModuleHandle("ntdll.dll"); if(!hntdll) return FALSE; - pwine_get_version = (void *)GetProcAddress(hntdll, "wine_get_version"); + pwine_get_version = (wine_get_version*) GetProcAddress(hntdll, "wine_get_version"); return !!pwine_get_version; } @@ -61,6 +65,20 @@ static BOOL launch_direct() { } int WINAPI wWinMain(HINSTANCE hi, HINSTANCE hpi, PWSTR cmd, int ns) { + + if (SteamAPI_RestartAppIfNecessary(DFHACK_STEAM_APPID)) // Replace with your App ID + { + return 1; + } + + if (!SteamAPI_Init()) + { + printf("Fatal Error - Steam must be running to play this game (SteamAPI_Init() failed).\n"); + return 1; + } + + return 0; + LPCWSTR err = is_running_on_wine() ? launch_via_steam_posix() : launch_via_steam_windows(); if (err && !launch_direct()) { From f336771284b152684cc4eb22cb6856330c649faf Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 08:21:54 -0500 Subject: [PATCH 0070/1234] launchdf rewrite this rewrites launchdf so that the dfhack launcher attempts to linger while df is running --- CMakeLists.txt | 6 +- package/windows/launchdf.cpp | 171 +++++++++++++++++++++++++++++++---- 2 files changed, 155 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 899063d9d..cf5586dfd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -314,10 +314,10 @@ if(WIN32) endif() # download Steam SDK - set (STEAMAPI_DIR ${dfhack_SOURCE_DIR}/depends/steam/) - download_file("https://partner.steamgames.com/downloads/steamworks_sdk_156.zip" + set (STEAMAPI_DIR ${dfhack_SOURCE_DIR}/depends/steam) + file(DOWNLOAD "https://partner.steamgames.com/downloads/steamworks_sdk_156.zip" ${STEAMAPI_DIR}/steamworks_sdk_156.zip - "af5a579990dbe5ae4c1b0689260d001b") + EXPECTED_HASH MD5=af5a579990dbe5ae4c1b0689260d001b) file(ARCHIVE_EXTRACT INPUT ${STEAMAPI_DIR}/steamworks_sdk_156.zip DESTINATION ${STEAMAPI_DIR}) diff --git a/package/windows/launchdf.cpp b/package/windows/launchdf.cpp index 804163960..19128ead1 100644 --- a/package/windows/launchdf.cpp +++ b/package/windows/launchdf.cpp @@ -1,8 +1,12 @@ #include #include +#include #include "steam_api.h" +#include + const uint32 DFHACK_STEAM_APPID = 2346660; +const uint32 DF_STEAM_APPID = 975370; static BOOL is_running_on_wine() { typedef const char* (CDECL wine_get_version)(void); @@ -32,7 +36,7 @@ static LPCWSTR launch_via_steam_windows() { si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); - WCHAR steamPath[1024]; + WCHAR steamPath[1024] = L""; DWORD datasize = 1024; LONG retCode = RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam", @@ -43,16 +47,24 @@ static LPCWSTR launch_via_steam_windows() { WCHAR commandLine[1024] = L"steam.exe -applaunch 975370"; - if (CreateProcessW(steamPath, commandLine, - NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0) - return L"Could not launch Dwarf Fortress"; + BOOL res = CreateProcessW(steamPath, commandLine, + NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + + if (res) + { + WaitForSingleObject(pi.hProcess, INFINITE); - return NULL; + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return NULL; + } + else + { + return L"Could not launch Dwarf Fortress"; + } } -// this method doesn't properly attribute Steam playtime metrics to DF, -// but that's better than not having DF start at all. -static BOOL launch_direct() { +static LPCWSTR launch_direct() { STARTUPINFOW si; PROCESS_INFORMATION pi; @@ -60,31 +72,152 @@ static BOOL launch_direct() { si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); - return CreateProcessW(L"Dwarf Fortress.exe", + BOOL res = CreateProcessW(L"Dwarf Fortress.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + + if (res) + { + WaitForSingleObject(pi.hProcess, INFINITE); + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return NULL; + } + + return L"Could not launch via non-steam fallback method"; +} + +DWORD findDwarfFortressProcess() +{ + PROCESSENTRY32W entry; + entry.dwSize = sizeof(PROCESSENTRY32W); + + const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); + + if (!Process32FirstW(snapshot, &entry)) + { + CloseHandle(snapshot); + return -1; + } + + do { + std::wstring executableName(entry.szExeFile); + if (executableName == L"Dwarf Fortress.exe") + { + CloseHandle(snapshot); + return entry.th32ProcessID; + } + } while (Process32NextW(snapshot, &entry)); + + CloseHandle(snapshot); + return -1; } -int WINAPI wWinMain(HINSTANCE hi, HINSTANCE hpi, PWSTR cmd, int ns) { +int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) { - if (SteamAPI_RestartAppIfNecessary(DFHACK_STEAM_APPID)) // Replace with your App ID + // initialize steam context + if (SteamAPI_RestartAppIfNecessary(DFHACK_STEAM_APPID)) { - return 1; + exit(0); } - if (!SteamAPI_Init()) + if (!SteamAPI_Init()) + { + // could not initialize steam context, attempt fallback launch + LPCWSTR err = launch_direct(); + if (err != NULL) { - printf("Fatal Error - Steam must be running to play this game (SteamAPI_Init() failed).\n"); - return 1; + MessageBoxW(NULL, err, NULL, 0); + exit(1); } + exit(0); + } - return 0; + bool wine = is_running_on_wine(); - LPCWSTR err = is_running_on_wine() ? launch_via_steam_posix() : launch_via_steam_windows(); + if (wine) + { + // attempt launch via steam client + LPCWSTR err = launch_via_steam_posix(); + + if (err != NULL) + // steam client launch failed, attempt fallback launch + err = launch_direct(); - if (err && !launch_direct()) { - MessageBoxW(NULL, err, NULL, 0); + if (err != NULL) + { + MessageBoxW(NULL, err, NULL, 0); + exit(1); + } + exit(0); + } + + // steam detected and not running in wine + + bool df_installed = SteamApps()->BIsAppInstalled(DF_STEAM_APPID); + + if (!df_installed) + { + // Steam DF is not installed. Assume DF is installed in same directory as DFHack and do a fallback launch + LPCWSTR err = launch_direct(); + + if (err != NULL) + { + MessageBoxW(NULL, err, NULL, 0); + exit(1); + } + exit(0); + } + + // obtain DF app path + + char buf[2048] = ""; + + int b = SteamApps()->GetAppInstallDir(DFHACK_STEAM_APPID, (char*)&buf, 2048); + std::string dfhack_install_folder = (b != -1) ? std::string(buf) : ""; + + int b2 = SteamApps()->GetAppInstallDir(DF_STEAM_APPID, (char*)&buf, 2048); + std::string df_install_folder = (b != -1) ? std::string(buf) : ""; + + + if (df_install_folder != dfhack_install_folder) + { + // DF and DFHack are not installed in the same library + MessageBoxW(NULL, L"DFHack and Dwarf Fortress must be installed in the same Steam library.\nAborting.", NULL, 0); exit(1); } + DWORD df_pid = findDwarfFortressProcess(); + + if (df_pid == -1) + { + LPCWSTR err = launch_via_steam_windows(); + if (err != NULL) + { + MessageBoxW(NULL, err, NULL, 0); + exit(1); + } + int counter = 0; + + do { + if (counter++ > 60) + { + MessageBoxW(NULL, L"Dwarf Fortress took too long to launch, aborting", NULL, 0); + exit(1); + } + Sleep(1000); + df_pid = findDwarfFortressProcess(); + } while (df_pid == -1); + } + + HANDLE hDF = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, df_pid); + + // in the future open an IPC connection so that we can proxy SteamAPI calls for the DFSteam module + + // this will eventuallyh need to become a loop with a WaitForMultipleObjects call + WaitForSingleObject(hDF, INFINITE); + + CloseHandle(hDF); + exit(0); } From dae549e3d1cc3dc775260c384eb3bd589981f662 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 08:47:05 -0500 Subject: [PATCH 0071/1234] fix missing end of line --- package/windows/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/windows/CMakeLists.txt b/package/windows/CMakeLists.txt index 42151e663..309613f2e 100644 --- a/package/windows/CMakeLists.txt +++ b/package/windows/CMakeLists.txt @@ -6,4 +6,4 @@ if(WIN32) add_executable(launchdf WIN32 launchdf.cpp) install(TARGETS launchdf DESTINATION ${DFHACK_DATA_DESTINATION}) install(FILES ${STEAMAPI_SHARED_LIBRARY} DESTINATION ${DFHACK_DATA_DESTINATION}) -endif() \ No newline at end of file +endif() From ea01dae88fc3cdc5d1d9673102e2bb2977ff430a Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 11:12:29 -0500 Subject: [PATCH 0072/1234] fix minor oops --- package/windows/launchdf.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package/windows/launchdf.cpp b/package/windows/launchdf.cpp index 19128ead1..a84465f53 100644 --- a/package/windows/launchdf.cpp +++ b/package/windows/launchdf.cpp @@ -173,11 +173,11 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, char buf[2048] = ""; - int b = SteamApps()->GetAppInstallDir(DFHACK_STEAM_APPID, (char*)&buf, 2048); - std::string dfhack_install_folder = (b != -1) ? std::string(buf) : ""; + int b1 = SteamApps()->GetAppInstallDir(DFHACK_STEAM_APPID, (char*)&buf, 2048); + std::string dfhack_install_folder = (b1 != -1) ? std::string(buf) : ""; int b2 = SteamApps()->GetAppInstallDir(DF_STEAM_APPID, (char*)&buf, 2048); - std::string df_install_folder = (b != -1) ? std::string(buf) : ""; + std::string df_install_folder = (b2 != -1) ? std::string(buf) : ""; if (df_install_folder != dfhack_install_folder) From 337c5eea2adb1be611afca3af7c796e6cdc1ba47 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 18:42:42 -0500 Subject: [PATCH 0073/1234] changes to build process for dflaunch only build dflaunch on steam-specific builds only download steamworks SDK when building dflaunch get steam account from environment when downloading steamworks SDK --- .github/workflows/steam.yml | 4 +++- CMakeLists.txt | 12 ------------ build/win64/generate-MSVC-steam.bat | 4 ++++ package/windows/CMakeLists.txt | 30 ++++++++++++++++++++++++----- 4 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 build/win64/generate-MSVC-steam.bat diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index aae1621af..a89249eab 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -38,7 +38,9 @@ jobs: ccache-win64-cross-msvc - name: Cross-compile win64 artifacts env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1' + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1' + steam_username: ${{ secrets.STEAM_USERNAME }} + steam_password: ${{ secrets.STEAM_PASSWORD }} run: | cd build bash -x build-win64-from-linux.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index cf5586dfd..fca548ccf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -313,18 +313,6 @@ if(WIN32) "5a09604daca6b2b5ce049d79af935d6a") endif() - # download Steam SDK - set (STEAMAPI_DIR ${dfhack_SOURCE_DIR}/depends/steam) - file(DOWNLOAD "https://partner.steamgames.com/downloads/steamworks_sdk_156.zip" - ${STEAMAPI_DIR}/steamworks_sdk_156.zip - EXPECTED_HASH MD5=af5a579990dbe5ae4c1b0689260d001b) - file(ARCHIVE_EXTRACT - INPUT ${STEAMAPI_DIR}/steamworks_sdk_156.zip - DESTINATION ${STEAMAPI_DIR}) - set(STEAMAPI_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.lib") - set(STEAMAPI_SOURCE_DIR "${STEAMAPI_DIR}/sdk/public/steam") - set(STEAMAPI_SHARED_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.dll") - endif() if(APPLE) diff --git a/build/win64/generate-MSVC-steam.bat b/build/win64/generate-MSVC-steam.bat new file mode 100644 index 000000000..007bb1c08 --- /dev/null +++ b/build/win64/generate-MSVC-steam.bat @@ -0,0 +1,4 @@ +IF EXIST DF_PATH.txt SET /P _DF_PATH= Date: Tue, 18 Apr 2023 19:14:37 -0500 Subject: [PATCH 0074/1234] make release channel parameter optional --- .github/workflows/steam.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index a89249eab..cf41f861d 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -14,7 +14,7 @@ on: release_channel: description: Release channel type: string - required: true + required: false default: beta jobs: From 5c541a8317ab2d82bf1744e7fdff2acf6a5d32b2 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 19:33:02 -0500 Subject: [PATCH 0075/1234] pass credentials into container (only when needed of course) --- build/build-win64-from-linux.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/build-win64-from-linux.sh b/build/build-win64-from-linux.sh index 11f4dbbc5..c0559a999 100755 --- a/build/build-win64-from-linux.sh +++ b/build/build-win64-from-linux.sh @@ -41,6 +41,8 @@ fi if ! docker run --rm -i -v "$srcdir":/src -v "$srcdir/build/win64-cross/":/src/build \ -e BUILDER_UID=$builder_uid \ -e CCACHE_DIR=/src/build/ccache \ + -e steam_username \ + -e steam_password \ --name dfhack-win \ ghcr.io/dfhack/build-env: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" \ From acc408c168093af1b1c51e1a1abe04d8eb97b177 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 21:52:57 -0500 Subject: [PATCH 0076/1234] change sdk download secret --- .github/workflows/steam.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index cf41f861d..71e56b662 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -39,8 +39,8 @@ jobs: - name: Cross-compile win64 artifacts env: CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1' - steam_username: ${{ secrets.STEAM_USERNAME }} - steam_password: ${{ secrets.STEAM_PASSWORD }} + steam_username: ${{ secrets.STEAM_SDK_USERNAME }} + steam_password: ${{ secrets.STEAM_SDK_PASSWORD }} run: | cd build bash -x build-win64-from-linux.sh From 93aaa5d19f1d74cf602744b5ad2dbc9bec42d19f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 18 Apr 2023 21:01:49 -0700 Subject: [PATCH 0077/1234] bump beta version to 50.07-r2rc2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fca548ccf..caf597088 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,7 +192,7 @@ endif() # set up versioning. set(DF_VERSION "50.07") -set(DFHACK_RELEASE "r2rc1") +set(DFHACK_RELEASE "r2rc2") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From c3b077d5e742a578b066d81baebc14ba094c4701 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 23:05:27 -0500 Subject: [PATCH 0078/1234] merge upstream submodules --- depends/clsocket | 2 +- depends/xlsxio | 2 +- scripts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/depends/clsocket b/depends/clsocket index d5e17c601..6ed8aa464 160000 --- a/depends/clsocket +++ b/depends/clsocket @@ -1 +1 @@ -Subproject commit d5e17c6012e7eefb0cbe3e130a56c24bd11f0094 +Subproject commit 6ed8aa46462ea01a1122fc49422840a2facc9757 diff --git a/depends/xlsxio b/depends/xlsxio index 0a9945266..439fdbc25 160000 --- a/depends/xlsxio +++ b/depends/xlsxio @@ -1 +1 @@ -Subproject commit 0a994526622c2201756e386ef98b44b193e25f06 +Subproject commit 439fdbc259c13f23a3122e68ba35ad5a13bcd97c diff --git a/scripts b/scripts index 6fba9905a..ec1a69788 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 6fba9905a71f626ecc640fd3de988e147d16cb4e +Subproject commit ec1a69788fd6329008672523b622fd8b390fea73 From ac4a068007055426d96ba64f6c4f3b0f96115ab0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 18 Apr 2023 21:08:50 -0700 Subject: [PATCH 0079/1234] add missing changelog for buildingplan --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 553fb3362..5110e24ab 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -39,6 +39,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - `buildingplan`: minimized planner panel stays minimized until you change it again +- `buildingplan`: can now filter by gems (for gem windows) - ``toggle-kbd-cursor``: add hotkey for toggling the keyboard cursor (Alt-K) - `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 From f45291780e324f3344fe5ab924147cd96119ca09 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 23:19:05 -0500 Subject: [PATCH 0080/1234] update structures --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 055f9b4ce..34bc84b11 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 055f9b4cec3bbec8e562f4774754242a14026bd2 +Subproject commit 34bc84b1125f32b2f09b20ee0561a24bc3a66e70 From eaf2efee05c719ffda8f45eae5697da486a7d71a Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 23:32:54 -0500 Subject: [PATCH 0081/1234] update dfhack version --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fca548ccf..1ac75885c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,8 +191,8 @@ if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl endif() # set up versioning. -set(DF_VERSION "50.07") -set(DFHACK_RELEASE "r2rc1") +set(DF_VERSION "50.08b1") +set(DFHACK_RELEASE "beta2") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From ae2bdfad5ff8fb4f9d530f9f1458415a45ed755e Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Wed, 19 Apr 2023 11:28:57 +0200 Subject: [PATCH 0082/1234] moved Slider class from filterselection.lua to widgets.lua --- library/lua/gui/widgets.lua | 137 ++++++++++++++++++ plugins/lua/buildingplan/filterselection.lua | 139 +------------------ 2 files changed, 138 insertions(+), 138 deletions(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index b33076cdc..eb4d53757 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -2293,4 +2293,141 @@ function TabBar:onInput(keys) end end +-------------------------------- +-- Slider +-- + +Slider = defclass(Slider, Widget) +Slider.ATTRS{ + num_stops=DEFAULT_NIL, + get_left_idx_fn=DEFAULT_NIL, + get_right_idx_fn=DEFAULT_NIL, + on_left_change=DEFAULT_NIL, + on_right_change=DEFAULT_NIL, +} + +function Slider:preinit(init_table) + init_table.frame = init_table.frame or {} + init_table.frame.h = init_table.frame.h or 1 +end + +function Slider:init() + if self.num_stops < 2 then error('too few Slider stops') end + self.is_dragging_target = nil -- 'left', 'right', or 'both' + self.is_dragging_idx = nil -- offset from leftmost dragged tile +end + +local function slider_get_width_per_idx(self) + return math.max(5, (self.frame_body.width-7) // (self.num_stops-1)) +end + +function Slider:onInput(keys) + if not keys._MOUSE_L_DOWN then return false end + local x = self:getMousePos() + if not x then return false end + local left_idx, right_idx = self.get_left_idx_fn(), self.get_right_idx_fn() + local width_per_idx = slider_get_width_per_idx(self) + local left_pos = width_per_idx*(left_idx-1) + local right_pos = width_per_idx*(right_idx-1) + 4 + if x < left_pos then + self.on_left_change(self.get_left_idx_fn() - 1) + elseif x < left_pos+3 then + self.is_dragging_target = 'left' + self.is_dragging_idx = x - left_pos + elseif x < right_pos then + self.is_dragging_target = 'both' + self.is_dragging_idx = x - left_pos + elseif x < right_pos+3 then + self.is_dragging_target = 'right' + self.is_dragging_idx = x - right_pos + else + self.on_right_change(self.get_right_idx_fn() + 1) + end + return true +end + +local function slider_do_drag(self, width_per_idx) + local x = self.frame_body:localXY(dfhack.screen.getMousePos()) + local cur_pos = x - self.is_dragging_idx + cur_pos = math.max(0, cur_pos) + cur_pos = math.min(width_per_idx*(self.num_stops-1)+7, cur_pos) + local offset = self.is_dragging_target == 'right' and -2 or 1 + local new_idx = math.max(0, cur_pos+offset)//width_per_idx + 1 + local new_left_idx, new_right_idx + if self.is_dragging_target == 'right' then + new_right_idx = new_idx + else + new_left_idx = new_idx + if self.is_dragging_target == 'both' then + new_right_idx = new_left_idx + self.get_right_idx_fn() - self.get_left_idx_fn() + if new_right_idx > self.num_stops then + return + end + end + end + if new_left_idx and new_left_idx ~= self.get_left_idx_fn() then + self.on_left_change(new_left_idx) + end + if new_right_idx and new_right_idx ~= self.get_right_idx_fn() then + self.on_right_change(new_right_idx) + end +end + +local SLIDER_LEFT_END = to_pen{ch=198, fg=COLOR_GREY, bg=COLOR_BLACK} +local SLIDER_TRACK = to_pen{ch=205, fg=COLOR_GREY, bg=COLOR_BLACK} +local SLIDER_TRACK_SELECTED = to_pen{ch=205, fg=COLOR_LIGHTGREEN, bg=COLOR_BLACK} +local SLIDER_TRACK_STOP = to_pen{ch=216, fg=COLOR_GREY, bg=COLOR_BLACK} +local SLIDER_TRACK_STOP_SELECTED = to_pen{ch=216, fg=COLOR_LIGHTGREEN, bg=COLOR_BLACK} +local SLIDER_RIGHT_END = to_pen{ch=181, fg=COLOR_GREY, bg=COLOR_BLACK} +local SLIDER_TAB_LEFT = to_pen{ch=60, fg=COLOR_BLACK, bg=COLOR_YELLOW} +local SLIDER_TAB_CENTER = to_pen{ch=9, fg=COLOR_BLACK, bg=COLOR_YELLOW} +local SLIDER_TAB_RIGHT = to_pen{ch=62, fg=COLOR_BLACK, bg=COLOR_YELLOW} + +function Slider:onRenderBody(dc, rect) + local left_idx, right_idx = self.get_left_idx_fn(), self.get_right_idx_fn() + local width_per_idx = slider_get_width_per_idx(self) + -- draw track + dc:seek(1,0) + dc:char(nil, SLIDER_LEFT_END) + dc:char(nil, SLIDER_TRACK) + for stop_idx=1,self.num_stops-1 do + local track_stop_pen = SLIDER_TRACK_STOP_SELECTED + local track_pen = SLIDER_TRACK_SELECTED + if left_idx > stop_idx or right_idx < stop_idx then + track_stop_pen = SLIDER_TRACK_STOP + track_pen = SLIDER_TRACK + elseif right_idx == stop_idx then + track_pen = SLIDER_TRACK + end + dc:char(nil, track_stop_pen) + for i=2,width_per_idx do + dc:char(nil, track_pen) + end + end + if right_idx >= self.num_stops then + dc:char(nil, SLIDER_TRACK_STOP_SELECTED) + else + dc:char(nil, SLIDER_TRACK_STOP) + end + dc:char(nil, SLIDER_TRACK) + dc:char(nil, SLIDER_RIGHT_END) + -- draw tabs + dc:seek(width_per_idx*(left_idx-1)) + dc:char(nil, SLIDER_TAB_LEFT) + dc:char(nil, SLIDER_TAB_CENTER) + dc:char(nil, SLIDER_TAB_RIGHT) + dc:seek(width_per_idx*(right_idx-1)+4) + dc:char(nil, SLIDER_TAB_LEFT) + dc:char(nil, SLIDER_TAB_CENTER) + dc:char(nil, SLIDER_TAB_RIGHT) + -- manage dragging + if self.is_dragging_target then + slider_do_drag(self, width_per_idx) + end + if df.global.enabler.mouse_lbut == 0 then + self.is_dragging_target = nil + self.is_dragging_idx = nil + end +end + return _ENV diff --git a/plugins/lua/buildingplan/filterselection.lua b/plugins/lua/buildingplan/filterselection.lua index 968ad88d9..fde80d4c8 100644 --- a/plugins/lua/buildingplan/filterselection.lua +++ b/plugins/lua/buildingplan/filterselection.lua @@ -12,143 +12,6 @@ local function get_cur_filters() uibs.building_subtype, uibs.custom_type) end --------------------------------- --- Slider --- - -Slider = defclass(Slider, widgets.Widget) -Slider.ATTRS{ - num_stops=DEFAULT_NIL, - get_left_idx_fn=DEFAULT_NIL, - get_right_idx_fn=DEFAULT_NIL, - on_left_change=DEFAULT_NIL, - on_right_change=DEFAULT_NIL, -} - -function Slider:preinit(init_table) - init_table.frame = init_table.frame or {} - init_table.frame.h = init_table.frame.h or 1 -end - -function Slider:init() - if self.num_stops < 2 then error('too few Slider stops') end - self.is_dragging_target = nil -- 'left', 'right', or 'both' - self.is_dragging_idx = nil -- offset from leftmost dragged tile -end - -local function slider_get_width_per_idx(self) - return math.max(5, (self.frame_body.width-7) // (self.num_stops-1)) -end - -function Slider:onInput(keys) - if not keys._MOUSE_L_DOWN then return false end - local x = self:getMousePos() - if not x then return false end - local left_idx, right_idx = self.get_left_idx_fn(), self.get_right_idx_fn() - local width_per_idx = slider_get_width_per_idx(self) - local left_pos = width_per_idx*(left_idx-1) - local right_pos = width_per_idx*(right_idx-1) + 4 - if x < left_pos then - self.on_left_change(self.get_left_idx_fn() - 1) - elseif x < left_pos+3 then - self.is_dragging_target = 'left' - self.is_dragging_idx = x - left_pos - elseif x < right_pos then - self.is_dragging_target = 'both' - self.is_dragging_idx = x - left_pos - elseif x < right_pos+3 then - self.is_dragging_target = 'right' - self.is_dragging_idx = x - right_pos - else - self.on_right_change(self.get_right_idx_fn() + 1) - end - return true -end - -local function slider_do_drag(self, width_per_idx) - local x = self.frame_body:localXY(dfhack.screen.getMousePos()) - local cur_pos = x - self.is_dragging_idx - cur_pos = math.max(0, cur_pos) - cur_pos = math.min(width_per_idx*(self.num_stops-1)+7, cur_pos) - local offset = self.is_dragging_target == 'right' and -2 or 1 - local new_idx = math.max(0, cur_pos+offset)//width_per_idx + 1 - local new_left_idx, new_right_idx - if self.is_dragging_target == 'right' then - new_right_idx = new_idx - else - new_left_idx = new_idx - if self.is_dragging_target == 'both' then - new_right_idx = new_left_idx + self.get_right_idx_fn() - self.get_left_idx_fn() - if new_right_idx > self.num_stops then - return - end - end - end - if new_left_idx and new_left_idx ~= self.get_left_idx_fn() then - self.on_left_change(new_left_idx) - end - if new_right_idx and new_right_idx ~= self.get_right_idx_fn() then - self.on_right_change(new_right_idx) - end -end - -local SLIDER_LEFT_END = to_pen{ch=198, fg=COLOR_GREY, bg=COLOR_BLACK} -local SLIDER_TRACK = to_pen{ch=205, fg=COLOR_GREY, bg=COLOR_BLACK} -local SLIDER_TRACK_SELECTED = to_pen{ch=205, fg=COLOR_LIGHTGREEN, bg=COLOR_BLACK} -local SLIDER_TRACK_STOP = to_pen{ch=216, fg=COLOR_GREY, bg=COLOR_BLACK} -local SLIDER_TRACK_STOP_SELECTED = to_pen{ch=216, fg=COLOR_LIGHTGREEN, bg=COLOR_BLACK} -local SLIDER_RIGHT_END = to_pen{ch=181, fg=COLOR_GREY, bg=COLOR_BLACK} -local SLIDER_TAB_LEFT = to_pen{ch=60, fg=COLOR_BLACK, bg=COLOR_YELLOW} -local SLIDER_TAB_CENTER = to_pen{ch=9, fg=COLOR_BLACK, bg=COLOR_YELLOW} -local SLIDER_TAB_RIGHT = to_pen{ch=62, fg=COLOR_BLACK, bg=COLOR_YELLOW} - -function Slider:onRenderBody(dc, rect) - local left_idx, right_idx = self.get_left_idx_fn(), self.get_right_idx_fn() - local width_per_idx = slider_get_width_per_idx(self) - -- draw track - dc:seek(1,0) - dc:char(nil, SLIDER_LEFT_END) - dc:char(nil, SLIDER_TRACK) - for stop_idx=1,self.num_stops-1 do - local track_stop_pen = SLIDER_TRACK_STOP_SELECTED - local track_pen = SLIDER_TRACK_SELECTED - if left_idx > stop_idx or right_idx < stop_idx then - track_stop_pen = SLIDER_TRACK_STOP - track_pen = SLIDER_TRACK - elseif right_idx == stop_idx then - track_pen = SLIDER_TRACK - end - dc:char(nil, track_stop_pen) - for i=2,width_per_idx do - dc:char(nil, track_pen) - end - end - if right_idx >= self.num_stops then - dc:char(nil, SLIDER_TRACK_STOP_SELECTED) - else - dc:char(nil, SLIDER_TRACK_STOP) - end - dc:char(nil, SLIDER_TRACK) - dc:char(nil, SLIDER_RIGHT_END) - -- draw tabs - dc:seek(width_per_idx*(left_idx-1)) - dc:char(nil, SLIDER_TAB_LEFT) - dc:char(nil, SLIDER_TAB_CENTER) - dc:char(nil, SLIDER_TAB_RIGHT) - dc:seek(width_per_idx*(right_idx-1)+4) - dc:char(nil, SLIDER_TAB_LEFT) - dc:char(nil, SLIDER_TAB_CENTER) - dc:char(nil, SLIDER_TAB_RIGHT) - -- manage dragging - if self.is_dragging_target then - slider_do_drag(self, width_per_idx) - end - if df.global.enabler.mouse_lbut == 0 then - self.is_dragging_target = nil - self.is_dragging_idx = nil - end -end - -------------------------------- -- QualityAndMaterialsPage -- @@ -328,7 +191,7 @@ function QualityAndMaterialsPage:init() enabled=enable_item_quality, on_change=function(val) self:set_max_quality(val+1) end, }, - Slider{ + widgets.Slider{ frame={l=0, t=6}, num_stops=7, get_left_idx_fn=function() From 1620604a8e0d73dd5e0b7528df284aedd11b8572 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Wed, 19 Apr 2023 11:38:22 +0200 Subject: [PATCH 0083/1234] added changelog entry --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 5110e24ab..809223e25 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -49,6 +49,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## API ## Lua +- `widgets`: "Slider" class has been moved from ``filterselection.lua`` into ``widgets.lua`` ## Removed From a0b259bb676f2000eff4e160ae14f4772ab2c82f Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Wed, 19 Apr 2023 11:44:27 +0200 Subject: [PATCH 0084/1234] attempt to fix changelog entry... --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 809223e25..1ad220b0d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -49,7 +49,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## API ## Lua -- `widgets`: "Slider" class has been moved from ``filterselection.lua`` into ``widgets.lua`` +- ``widgets``: "Slider" class has been moved from ``filterselection.lua`` into ``widgets.lua`` ## Removed From 98a252eab4ca6418b344ac8cbbc05a3273f056e5 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 20 Apr 2023 07:13:34 +0000 Subject: [PATCH 0085/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 6fba9905a..ad2bd2f60 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 6fba9905a71f626ecc640fd3de988e147d16cb4e +Subproject commit ad2bd2f60d1760db8ffb80cfa57f8fb868613e81 From 8371aa0b8b0b4bbb2716f22c649b2123e2680f41 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Thu, 20 Apr 2023 13:24:47 +0200 Subject: [PATCH 0086/1234] renamed Slider to RangeSlider, and added draft of Lua API.rst entry --- docs/changelog.txt | 2 +- docs/dev/Lua API.rst | 11 +++++++++ library/lua/gui/widgets.lua | 26 ++++++++++---------- plugins/lua/buildingplan/filterselection.lua | 2 +- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1ad220b0d..c6e4386b8 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -49,7 +49,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## API ## Lua -- ``widgets``: "Slider" class has been moved from ``filterselection.lua`` into ``widgets.lua`` +- ``widgets``: "Slider" class has been moved from ``filterselection.lua`` into ``widgets.lua`` and renamed to "RangeSlider" ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index e63bc8a61..212a6e891 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5130,6 +5130,17 @@ 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`` in ``TabBar`` for an example of how to construct pens. +RangeSlider class +----------------- + +This widget implements a mouse-interactable range-slider. The user can move its two handles to set minimum and maximum values to define a range. + +:num_stops: Specifies the amount of "notches" in the range slider, the places where handles can stop. +:get_left_idx_fn: The function used by the RangeSlider to determine what value to display on its left handle. +:get_right_idx_fn: The function used by the RangeSlider to determine what value to display on its right handle. +:on_left_change: Callback executed when a handle is moved leftwards. +:on_right_change: Callback executed when a handle is moved rightwards. + .. _lua-plugins: ======= diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index eb4d53757..a778df639 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -2294,11 +2294,11 @@ function TabBar:onInput(keys) end -------------------------------- --- Slider +-- RangeSlider -- -Slider = defclass(Slider, Widget) -Slider.ATTRS{ +RangeSlider = defclass(RangeSlider, Widget) +RangeSlider.ATTRS{ num_stops=DEFAULT_NIL, get_left_idx_fn=DEFAULT_NIL, get_right_idx_fn=DEFAULT_NIL, @@ -2306,27 +2306,27 @@ Slider.ATTRS{ on_right_change=DEFAULT_NIL, } -function Slider:preinit(init_table) +function RangeSlider:preinit(init_table) init_table.frame = init_table.frame or {} init_table.frame.h = init_table.frame.h or 1 end -function Slider:init() - if self.num_stops < 2 then error('too few Slider stops') end +function RangeSlider:init() + if self.num_stops < 2 then error('too few RangeSlider stops') end self.is_dragging_target = nil -- 'left', 'right', or 'both' self.is_dragging_idx = nil -- offset from leftmost dragged tile end -local function slider_get_width_per_idx(self) +local function rangeslider_get_width_per_idx(self) return math.max(5, (self.frame_body.width-7) // (self.num_stops-1)) end -function Slider:onInput(keys) +function RangeSlider:onInput(keys) if not keys._MOUSE_L_DOWN then return false end local x = self:getMousePos() if not x then return false end local left_idx, right_idx = self.get_left_idx_fn(), self.get_right_idx_fn() - local width_per_idx = slider_get_width_per_idx(self) + local width_per_idx = rangeslider_get_width_per_idx(self) local left_pos = width_per_idx*(left_idx-1) local right_pos = width_per_idx*(right_idx-1) + 4 if x < left_pos then @@ -2346,7 +2346,7 @@ function Slider:onInput(keys) return true end -local function slider_do_drag(self, width_per_idx) +local function rangeslider_do_drag(self, width_per_idx) local x = self.frame_body:localXY(dfhack.screen.getMousePos()) local cur_pos = x - self.is_dragging_idx cur_pos = math.max(0, cur_pos) @@ -2383,9 +2383,9 @@ local SLIDER_TAB_LEFT = to_pen{ch=60, fg=COLOR_BLACK, bg=COLOR_YELLOW} local SLIDER_TAB_CENTER = to_pen{ch=9, fg=COLOR_BLACK, bg=COLOR_YELLOW} local SLIDER_TAB_RIGHT = to_pen{ch=62, fg=COLOR_BLACK, bg=COLOR_YELLOW} -function Slider:onRenderBody(dc, rect) +function RangeSlider:onRenderBody(dc, rect) local left_idx, right_idx = self.get_left_idx_fn(), self.get_right_idx_fn() - local width_per_idx = slider_get_width_per_idx(self) + local width_per_idx = rangeslider_get_width_per_idx(self) -- draw track dc:seek(1,0) dc:char(nil, SLIDER_LEFT_END) @@ -2422,7 +2422,7 @@ function Slider:onRenderBody(dc, rect) dc:char(nil, SLIDER_TAB_RIGHT) -- manage dragging if self.is_dragging_target then - slider_do_drag(self, width_per_idx) + rangeslider_do_drag(self, width_per_idx) end if df.global.enabler.mouse_lbut == 0 then self.is_dragging_target = nil diff --git a/plugins/lua/buildingplan/filterselection.lua b/plugins/lua/buildingplan/filterselection.lua index fde80d4c8..4e8b98073 100644 --- a/plugins/lua/buildingplan/filterselection.lua +++ b/plugins/lua/buildingplan/filterselection.lua @@ -191,7 +191,7 @@ function QualityAndMaterialsPage:init() enabled=enable_item_quality, on_change=function(val) self:set_max_quality(val+1) end, }, - widgets.Slider{ + widgets.RangeSlider{ frame={l=0, t=6}, num_stops=7, get_left_idx_fn=function() From 1a2d5dfc8d34df66eb2a76cc1cb97ee79c17c43b Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 21 Apr 2023 07:13:33 +0000 Subject: [PATCH 0087/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index ad2bd2f60..5da969fce 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ad2bd2f60d1760db8ffb80cfa57f8fb868613e81 +Subproject commit 5da969fce69a5b9330f183cc0629798bf9907b69 From e30b86cfd2b25bd10ebe65cf2badf9fdfb1b0744 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 18 Apr 2023 10:19:25 +0000 Subject: [PATCH 0088/1234] Auto-update submodules depends/xlsxio: dfhack --- depends/xlsxio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/xlsxio b/depends/xlsxio index 439fdbc25..0a9945266 160000 --- a/depends/xlsxio +++ b/depends/xlsxio @@ -1 +1 @@ -Subproject commit 439fdbc259c13f23a3122e68ba35ad5a13bcd97c +Subproject commit 0a994526622c2201756e386ef98b44b193e25f06 From 1476e67422b426631247bc8119ff1ffa4cc3c736 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 18 Apr 2023 05:40:51 -0500 Subject: [PATCH 0089/1234] cmake minimum version 3.21 forced by this being the lowest version that supports vs 2022 --- depends/clsocket | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/clsocket b/depends/clsocket index 6ed8aa464..d5e17c601 160000 --- a/depends/clsocket +++ b/depends/clsocket @@ -1 +1 @@ -Subproject commit 6ed8aa46462ea01a1122fc49422840a2facc9757 +Subproject commit d5e17c6012e7eefb0cbe3e130a56c24bd11f0094 From 2b8b6a62e0d984746c386b519c5882b6e81a09be Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Fri, 21 Apr 2023 08:31:17 -0500 Subject: [PATCH 0090/1234] update structures --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 34bc84b11..98d5f8a55 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 34bc84b1125f32b2f09b20ee0561a24bc3a66e70 +Subproject commit 98d5f8a5553690ef71b9650b28d4aababf21ef5e From 6b86f7c69128e69dc03d07b735da5c68967759d9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 21 Apr 2023 11:20:28 -0700 Subject: [PATCH 0091/1234] planner panel is minimized by default and minimized state is now persisted across reloads --- data/dfhack-config/buildingplan.json | 5 +++ docs/changelog.txt | 2 +- plugins/lua/buildingplan/planneroverlay.lua | 40 ++++++++++++++------- 3 files changed, 34 insertions(+), 13 deletions(-) create mode 100644 data/dfhack-config/buildingplan.json diff --git a/data/dfhack-config/buildingplan.json b/data/dfhack-config/buildingplan.json new file mode 100644 index 000000000..9bb3052b7 --- /dev/null +++ b/data/dfhack-config/buildingplan.json @@ -0,0 +1,5 @@ +{ + "planner": { + "minimized": true + } +} \ No newline at end of file diff --git a/docs/changelog.txt b/docs/changelog.txt index 4794122f6..b53717dd0 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -38,7 +38,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes ## Misc Improvements -- `buildingplan`: minimized planner panel stays minimized until you change it again +- `buildingplan`: planner panel is minimized by default and now remembers minimized state - `buildingplan`: can now filter by gems (for gem windows) - ``toggle-kbd-cursor``: add hotkey for toggling the keyboard cursor (Alt-K) - `gui/control-panel`: add preference option for hiding the terminal console on startup diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index 8f12c695f..83a58ebd8 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -4,12 +4,15 @@ local itemselection = require('plugins.buildingplan.itemselection') local filterselection = require('plugins.buildingplan.filterselection') local gui = require('gui') local guidm = require('gui.dwarfmode') +local json = require('json') local overlay = require('plugins.overlay') local pens = require('plugins.buildingplan.pens') local utils = require('utils') local widgets = require('gui.widgets') require('dfhack.buildings') +config = config or json.open('dfhack-config/buildingplan.json') + local uibs = df.global.buildreq reset_counts_flag = false @@ -336,14 +339,14 @@ PlannerOverlay.ATTRS{ function PlannerOverlay:init() self.selected = 1 - self.minimized = false + self.state = ensure_key(config.data, 'planner') local main_panel = widgets.Panel{ view_id='main', frame={t=1, l=0, r=0, h=14}, frame_style=gui.INTERIOR_MEDIUM_FRAME, frame_background=gui.CLEAR_PEN, - visible=function() return not self.minimized end, + visible=self:callback('is_not_minimized'), } local minimized_panel = widgets.Panel{ @@ -355,8 +358,8 @@ function PlannerOverlay:init() {text=' show Planner ', pen=pens.MINI_TEXT_PEN, hpen=pens.MINI_TEXT_HPEN}, {text='['..string.char(31)..']', pen=pens.MINI_BUTT_PEN, hpen=pens.MINI_BUTT_HPEN}, }, - visible=function() return self.minimized end, - on_click=function() self.minimized = not self.minimized end, + visible=self:callback('is_minimized'), + on_click=self:callback('toggle_minimized'), }, widgets.Label{ frame={t=0, r=0, h=1}, @@ -364,8 +367,8 @@ function PlannerOverlay:init() {text=' hide Planner ', pen=pens.MINI_TEXT_PEN, hpen=pens.MINI_TEXT_HPEN}, {text='['..string.char(30)..']', pen=pens.MINI_BUTT_PEN, hpen=pens.MINI_BUTT_HPEN}, }, - visible=function() return not self.minimized end, - on_click=function() self.minimized = not self.minimized end, + visible=self:callback('is_not_minimized'), + on_click=self:callback('toggle_minimized'), }, }, } @@ -554,7 +557,7 @@ function PlannerOverlay:init() view_id='divider', frame={t=10, l=0, r=0, h=1}, on_render=self:callback('draw_divider_h'), - visible=function() return not self.minimized end, + visible=self:callback('is_not_minimized'), } local error_panel = widgets.ResizingPanel{ @@ -562,7 +565,7 @@ function PlannerOverlay:init() frame={t=15, l=0, r=0}, frame_style=gui.BOLD_FRAME, frame_background=gui.CLEAR_PEN, - visible=function() return not self.minimized end, + visible=self:callback('is_not_minimized'), } error_panel:addviews{ @@ -609,7 +612,7 @@ function PlannerOverlay:init() frame={t=0, l=1, w=37, h=1}, frame_inset=0, frame_background=gui.CLEAR_PEN, - visible=function() return not self.minimized end, + visible=self:callback('is_not_minimized'), subviews={ prev_next_selector, }, @@ -624,6 +627,19 @@ function PlannerOverlay:init() } end +function PlannerOverlay:is_minimized() + return self.state.minimized +end + +function PlannerOverlay:is_not_minimized() + return not self.state.minimized +end + +function PlannerOverlay:toggle_minimized() + self.state.minimized = not self.state.minimized + config:write() +end + function PlannerOverlay:draw_divider_h(dc) local x2 = dc.width -1 for x=0,x2 do @@ -735,13 +751,13 @@ function PlannerOverlay:onInput(keys) return false end if keys.CUSTOM_ALT_M then - self.minimized = not self.minimized + self:toggle_minimized() return true end if PlannerOverlay.super.onInput(self, keys) then return true end - if self.minimized then return false end + if self:is_minimized() then return false end if keys._MOUSE_L_DOWN then if is_over_options_panel() then return false end local detect_rect = copyall(self.frame_rect) @@ -837,7 +853,7 @@ function PlannerOverlay:onRenderFrame(dc, rect) uibs.building_type, uibs.building_subtype, uibs.custom_type)) end - if self.minimized then return end + if self:is_minimized() then return end local bounds = get_selected_bounds(self.saved_selection_pos, self.saved_pos) if not bounds then return end From 6d9a07355bde4816939177bd70086231398f3564 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 21 Apr 2023 11:54:38 -0700 Subject: [PATCH 0092/1234] allow filtering by yarn --- docs/changelog.txt | 2 +- plugins/buildingplan/buildingplan.cpp | 10 ++++++++++ plugins/lua/buildingplan/filterselection.lua | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 4794122f6..935b376b2 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -39,7 +39,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - `buildingplan`: minimized planner panel stays minimized until you change it again -- `buildingplan`: can now filter by gems (for gem windows) +- `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) - `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 diff --git a/plugins/buildingplan/buildingplan.cpp b/plugins/buildingplan/buildingplan.cpp index e2f964a44..05b2c0af6 100644 --- a/plugins/buildingplan/buildingplan.cpp +++ b/plugins/buildingplan/buildingplan.cpp @@ -154,6 +154,7 @@ static const df::dfhack_material_category gem_cat(df::dfhack_material_category:: static const df::dfhack_material_category clay_cat(df::dfhack_material_category::mask_clay); static const df::dfhack_material_category cloth_cat(df::dfhack_material_category::mask_cloth); static const df::dfhack_material_category silk_cat(df::dfhack_material_category::mask_silk); +static const df::dfhack_material_category yarn_cat(df::dfhack_material_category::mask_yarn); static void cache_matched(int16_t type, int32_t index) { MaterialInfo mi; @@ -182,6 +183,9 @@ static void cache_matched(int16_t type, int32_t index) { } else if (mi.matches(silk_cat)) { DEBUG(status).print("cached silk material: %s (%d, %d)\n", mi.toString().c_str(), type, index); mat_cache.emplace(mi.toString(), std::make_pair(mi, "silk")); + } else if (mi.matches(yarn_cat)) { + DEBUG(status).print("cached yarn material: %s (%d, %d)\n", mi.toString().c_str(), type, index); + mat_cache.emplace(mi.toString(), std::make_pair(mi, "yarn")); } else TRACE(status).print("not matched: %s\n", mi.toString().c_str()); @@ -208,6 +212,7 @@ static void load_material_cache() { load_organic_material_cache(df::organic_mat_category::Wood); load_organic_material_cache(df::organic_mat_category::PlantFiber); load_organic_material_cache(df::organic_mat_category::Silk); + load_organic_material_cache(df::organic_mat_category::Yarn); } static HeatSafety get_heat_safety_filter(const BuildingTypeKey &key) { @@ -812,6 +817,8 @@ static int setMaterialMaskFilter(lua_State *L) { mask |= cloth_cat.whole; else if (cat == "silk") mask |= silk_cat.whole; + else if (cat == "yarn") + mask |= yarn_cat.whole; } DEBUG(status,*out).print( "setting material mask filter for building_type=%d subtype=%d custom=%d index=%d to %x\n", @@ -860,6 +867,7 @@ static int getMaterialMaskFilter(lua_State *L) { ret.emplace("clay", !bits || bits & clay_cat.whole); ret.emplace("cloth", !bits || bits & cloth_cat.whole); ret.emplace("silk", !bits || bits & silk_cat.whole); + ret.emplace("yarn", !bits || bits & yarn_cat.whole); Lua::Push(L, ret); return 1; } @@ -912,6 +920,8 @@ static int setMaterialFilter(lua_State *L) { mask.whole |= cloth_cat.whole; else if (mat.matches(silk_cat)) mask.whole |= silk_cat.whole; + else if (mat.matches(yarn_cat)) + mask.whole |= yarn_cat.whole; } filter.setMaterialMask(mask.whole); get_item_filters(*out, key).setItemFilter(*out, filter, index); diff --git a/plugins/lua/buildingplan/filterselection.lua b/plugins/lua/buildingplan/filterselection.lua index 968ad88d9..eb364870d 100644 --- a/plugins/lua/buildingplan/filterselection.lua +++ b/plugins/lua/buildingplan/filterselection.lua @@ -456,6 +456,7 @@ function QualityAndMaterialsPage:refresh() make_cat_choice('Clay', 'clay', 'CUSTOM_SHIFT_C', cats), make_cat_choice('Cloth', 'cloth', 'CUSTOM_SHIFT_L', cats), make_cat_choice('Silk', 'silk', 'CUSTOM_SHIFT_K', cats), + make_cat_choice('Yarn', 'yarn', 'CUSTOM_SHIFT_Y', cats), } self.subviews.materials_categories:setChoices(category_choices) From c7bf7eba9062cc7c1aeb2f7a8cbd75e081deea5e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 21 Apr 2023 12:01:33 -0700 Subject: [PATCH 0093/1234] update scripts HEAD in beta branch --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index ec1a69788..5da969fce 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ec1a69788fd6329008672523b622fd8b390fea73 +Subproject commit 5da969fce69a5b9330f183cc0629798bf9907b69 From adeb872725cb6bfdcedbd4265a9c17e5d73d9745 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Sat, 22 Apr 2023 09:44:37 +0200 Subject: [PATCH 0094/1234] modified 's RangeSlider entry --- docs/dev/Lua API.rst | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 212a6e891..02484c745 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5133,13 +5133,16 @@ widget does not require direct usage of ``Tab``. RangeSlider class ----------------- -This widget implements a mouse-interactable range-slider. The user can move its two handles to set minimum and maximum values to define a range. - -:num_stops: Specifies the amount of "notches" in the range slider, the places where handles can stop. -:get_left_idx_fn: The function used by the RangeSlider to determine what value to display on its left handle. -:get_right_idx_fn: The function used by the RangeSlider to determine what value to display on its right handle. -:on_left_change: Callback executed when a handle is moved leftwards. -:on_right_change: Callback executed when a handle is moved rightwards. +This widget implements a mouse-interactable range-slider. The user 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 handles mirror the state of its two parent ``CycleHotkeyLabels``. + +: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. .. _lua-plugins: From 29741dff4b012a7a5bdbda8c9dc6f797bb56f2dc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Apr 2023 16:31:41 -0700 Subject: [PATCH 0095/1234] remove toggle-kbd-cursor alias (it's a script now) --- data/init/dfhack.tools.init | 1 - 1 file changed, 1 deletion(-) diff --git a/data/init/dfhack.tools.init b/data/init/dfhack.tools.init index 8fd815559..aaf0cf277 100644 --- a/data/init/dfhack.tools.init +++ b/data/init/dfhack.tools.init @@ -144,4 +144,3 @@ enable \ alias add autounsuspend suspendmanager alias add gui/dig gui/design -alias add toggle-kbd-cursor lua "local flags4 = df.global.d_init.flags4 if flags4.KEYBOARD_CURSOR then flags4.KEYBOARD_CURSOR = false else local guidm = require('gui.dwarfmode') guidm.setCursorPos(guidm.Viewport.get():getCenter()) flags4.KEYBOARD_CURSOR = true end" From 33142a5dfc6a0cf279570da298b62659b8ce3e07 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Apr 2023 17:26:45 -0700 Subject: [PATCH 0096/1234] add DFHack title version overlay --- docs/changelog.txt | 1 + plugins/lua/overlay.lua | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 76b9ab301..7d95d810a 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -44,6 +44,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `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 ## Documentation diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index ff8bf7c98..75dc301ad 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -562,4 +562,42 @@ function OverlayWidget:init() self.frame.h = self.frame.h or 1 end +-- ------------------- -- +-- TitleVersionOverlay -- +-- ------------------- -- + +TitleVersionOverlay = defclass(TitleVersionOverlay, OverlayWidget) +TitleVersionOverlay.ATTRS{ + default_pos={x=50, y=-2}, + default_enabled=true, + viewscreens='title', + frame={w=30, h=3}, +} + +function TitleVersionOverlay:init() + local text = {} + table.insert(text, 'DFHack ' .. dfhack.getDFHackVersion() .. + (dfhack.isPrerelease() and (' (%s)'):format(dfhack.getGitCommit():sub(1,7)) or '')) + if #dfhack.getDFHackBuildID() > 0 then + table.insert(text, NEWLINE) + table.insert(text, 'Build ID: ' .. dfhack.getDFHackBuildID()) + end + if dfhack.isPrerelease() then + table.insert(text, NEWLINE) + table.insert(text, {text='Pre-release build', pen=COLOR_LIGHTRED}) + end + + self:addviews{ + widgets.Label{ + frame={b=0, l=0}, + text=text, + text_pen=COLOR_WHITE, + }, + } +end + +OVERLAY_WIDGETS = { + title_version = TitleVersionOverlay, +} + return _ENV From b59bf72cd21c32cf551404ad87ac8a0b4c3d70c4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Apr 2023 17:31:29 -0700 Subject: [PATCH 0097/1234] turn down the title-version plugin --- docs/about/Removed.rst | 6 ++ docs/changelog.txt | 1 + docs/plugins/title-version.rst | 14 ----- plugins/CMakeLists.txt | 1 - plugins/title-version.cpp | 109 --------------------------------- 5 files changed, 7 insertions(+), 124 deletions(-) delete mode 100644 docs/plugins/title-version.rst delete mode 100644 plugins/title-version.cpp diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index a0365e621..174fc56c4 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -206,6 +206,12 @@ stocksettings Along with ``copystock``, ``loadstock`` and ``savestock``, replaced with the new `stockpiles` API. +.. _title-version: + +title-version +============= +Replaced with an `overlay`. + .. _warn-stuck-trees: warn-stuck-trees diff --git a/docs/changelog.txt b/docs/changelog.txt index 76b9ab301..fa5c15fde 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -52,6 +52,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Lua ## Removed +- `title-version`: replaced by an `overlay` widget # 50.07-r1 diff --git a/docs/plugins/title-version.rst b/docs/plugins/title-version.rst deleted file mode 100644 index 4d0ef0c0b..000000000 --- a/docs/plugins/title-version.rst +++ /dev/null @@ -1,14 +0,0 @@ -title-version -============= - -.. dfhack-tool:: - :summary: Displays the DFHack version on DF's title screen. - :tags: unavailable interface - :no-command: - -Usage ------ - -:: - - enable title-version diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 53d0296c7..97216ad50 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -162,7 +162,6 @@ dfhack_plugin(strangemood strangemood.cpp) dfhack_plugin(tailor tailor.cpp LINK_LIBRARIES lua) dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(title-folder title-folder.cpp) -#dfhack_plugin(title-version title-version.cpp) #dfhack_plugin(trackstop trackstop.cpp) #dfhack_plugin(tubefill tubefill.cpp) #add_subdirectory(tweak) diff --git a/plugins/title-version.cpp b/plugins/title-version.cpp deleted file mode 100644 index 66bb159ad..000000000 --- a/plugins/title-version.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "Core.h" -#include "Console.h" -#include "Export.h" -#include "PluginManager.h" -#include "modules/Gui.h" -#include "modules/Screen.h" -#include "VTableInterpose.h" -#include "DFHackVersion.h" - -#include "df/graphic.h" -#include "df/viewscreen_optionst.h" -#include "df/viewscreen_titlest.h" -#include "uicommon.h" - -using std::vector; -using std::string; -using namespace DFHack; - -DFHACK_PLUGIN("title-version"); -DFHACK_PLUGIN_IS_ENABLED(is_enabled); -REQUIRE_GLOBAL(gps); - -void draw_version(int start_x, int start_y) { - int x = start_x, - y = start_y; - - OutputString(COLOR_WHITE, x, y, string("DFHack ") + DFHACK_VERSION); - if (!DFHACK_IS_RELEASE) - { - OutputString(COLOR_WHITE, x, y, " (dev)"); - x = start_x; y++; - OutputString(COLOR_WHITE, x, y, "Git: "); - OutputString(COLOR_WHITE, x, y, DFHACK_GIT_DESCRIPTION); - } - if (strlen(DFHACK_BUILD_ID)) - { - x = start_x; y++; - OutputString(COLOR_WHITE, x, y, "Build ID: "); - OutputString(COLOR_WHITE, x, y, DFHACK_BUILD_ID); - } - if (DFHACK_IS_PRERELEASE) - { - x = start_x; y++; - OutputString(COLOR_LIGHTRED, x, y, "Pre-release build"); - } -} - -struct title_version_hook : df::viewscreen_titlest { - typedef df::viewscreen_titlest interpose_base; - - DEFINE_VMETHOD_INTERPOSE(void, render, ()) - { - INTERPOSE_NEXT(render)(); - if (!loading) - draw_version(0, 0); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(title_version_hook, render); - -struct options_version_hook : df::viewscreen_optionst { - typedef df::viewscreen_optionst interpose_base; - - DEFINE_VMETHOD_INTERPOSE(void, render, ()) - { - INTERPOSE_NEXT(render)(); - if (!msg_quit && !in_retire_adv && !msg_peasant && - !in_retire_dwf_abandon_adv && !in_abandon_dwf && !ending_game) - draw_version(2, gps->dimy - 6); - } -}; - -IMPLEMENT_VMETHOD_INTERPOSE(options_version_hook, render); - -DFhackCExport command_result plugin_enable (color_ostream &out, bool enable) -{ - if (!gps) - return CR_FAILURE; - - if (enable != is_enabled) - { - if (!INTERPOSE_HOOK(title_version_hook, render).apply(enable) || - !INTERPOSE_HOOK(options_version_hook, render).apply(enable)) - return CR_FAILURE; - - is_enabled = enable; - } - - return CR_OK; -} - -DFhackCExport command_result plugin_init (color_ostream &out, vector &commands) -{ - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown (color_ostream &out) -{ - INTERPOSE_HOOK(title_version_hook, render).remove(); - INTERPOSE_HOOK(options_version_hook, render).remove(); - return CR_OK; -} From 87e67987a926dab0fbe98f06541717d2214eb8d3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Apr 2023 17:41:38 -0700 Subject: [PATCH 0098/1234] add "version" alias to run the help --- data/init/dfhack.tools.init | 1 + docs/changelog.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/data/init/dfhack.tools.init b/data/init/dfhack.tools.init index 8fd815559..cdd2a63a0 100644 --- a/data/init/dfhack.tools.init +++ b/data/init/dfhack.tools.init @@ -145,3 +145,4 @@ enable \ alias add autounsuspend suspendmanager alias add gui/dig gui/design alias add toggle-kbd-cursor lua "local flags4 = df.global.d_init.flags4 if flags4.KEYBOARD_CURSOR then flags4.KEYBOARD_CURSOR = false else local guidm = require('gui.dwarfmode') guidm.setCursorPos(guidm.Viewport.get():getCenter()) flags4.KEYBOARD_CURSOR = true end" +alias add version help diff --git a/docs/changelog.txt b/docs/changelog.txt index fa5c15fde..ecc616669 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -41,6 +41,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `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). From b5459faffea36a6b579f6e7fe957f29d0d7aac72 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Apr 2023 18:20:50 -0700 Subject: [PATCH 0099/1234] format version string in help the same way --- library/Core.cpp | 2 +- library/DFHackVersion.cpp | 7 +++++-- library/include/DFHackVersion.h | 2 +- plugins/lua/overlay.lua | 4 ++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 4f06c3d62..a1e3b60e5 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -273,7 +273,7 @@ static std::string dfhack_version_desc() if (Version::is_release()) s << "(release)"; else - s << "(development build " << Version::git_description() << ")"; + s << "(git: " << Version::git_commit(true) << ")"; s << " on " << (sizeof(void*) == 8 ? "x86_64" : "x86"); if (strlen(Version::dfhack_build_id())) s << " [build ID: " << Version::dfhack_build_id() << "]"; diff --git a/library/DFHackVersion.cpp b/library/DFHackVersion.cpp index 7746ebece..42aac251e 100644 --- a/library/DFHackVersion.cpp +++ b/library/DFHackVersion.cpp @@ -1,6 +1,8 @@ #define NO_DFHACK_VERSION_MACROS #include "DFHackVersion.h" #include "git-describe.h" +#include + namespace DFHack { namespace Version { int dfhack_abi_version() @@ -27,9 +29,10 @@ namespace DFHack { { return DFHACK_GIT_DESCRIPTION; } - const char *git_commit() + const char* git_commit(bool short_hash) { - return DFHACK_GIT_COMMIT; + static std::string shorty(DFHACK_GIT_COMMIT, 0, 7); + return short_hash ? shorty.c_str() : DFHACK_GIT_COMMIT; } const char *git_xml_commit() { diff --git a/library/include/DFHackVersion.h b/library/include/DFHackVersion.h index 1b69dfe55..fbf2539bf 100644 --- a/library/include/DFHackVersion.h +++ b/library/include/DFHackVersion.h @@ -8,7 +8,7 @@ namespace DFHack { int dfhack_abi_version(); const char *git_description(); - const char *git_commit(); + const char* git_commit(bool short_hash = false); const char *git_xml_commit(); const char *git_xml_expected_commit(); bool git_xml_match(); diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index 75dc301ad..6a568fb85 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -571,13 +571,13 @@ TitleVersionOverlay.ATTRS{ default_pos={x=50, y=-2}, default_enabled=true, viewscreens='title', - frame={w=30, h=3}, + frame={w=35, h=3}, } function TitleVersionOverlay:init() local text = {} table.insert(text, 'DFHack ' .. dfhack.getDFHackVersion() .. - (dfhack.isPrerelease() and (' (%s)'):format(dfhack.getGitCommit():sub(1,7)) or '')) + (dfhack.isPrerelease() and (' (git: %s)'):format(dfhack.getGitCommit(true)) or '')) if #dfhack.getDFHackBuildID() > 0 then table.insert(text, NEWLINE) table.insert(text, 'Build ID: ' .. dfhack.getDFHackBuildID()) From 276efc981302646e2cee7b3d5c63dba245cdeeef Mon Sep 17 00:00:00 2001 From: Myk Date: Sun, 23 Apr 2023 18:40:24 -0700 Subject: [PATCH 0100/1234] Apply suggestions from code review --- docs/changelog.txt | 2 +- docs/dev/Lua API.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index c6e4386b8..e05227e0d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -49,7 +49,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## API ## Lua -- ``widgets``: "Slider" class has been moved from ``filterselection.lua`` into ``widgets.lua`` and renamed to "RangeSlider" +- ``widgets.RangeSlider``: new mouse-controlled two-headed slider widget ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 02484c745..078cec828 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5133,9 +5133,9 @@ widget does not require direct usage of ``Tab``. RangeSlider class ----------------- -This widget implements a mouse-interactable range-slider. The user can move its two handles to set minimum and maximum values +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 handles mirror the state of its two parent ``CycleHotkeyLabels``. +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) From 74e1aa70d9aea0bea57573b95797a659d236c1b1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Apr 2023 23:28:50 -0700 Subject: [PATCH 0101/1234] fix smoothing job detection --- docs/changelog.txt | 1 + plugins/dig-now.cpp | 10 +++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 3c1ed7e8f..588c1a6be 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -36,6 +36,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins ## Fixes +- `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 diff --git a/plugins/dig-now.cpp b/plugins/dig-now.cpp index be431722b..b2af2dbca 100644 --- a/plugins/dig-now.cpp +++ b/plugins/dig-now.cpp @@ -113,14 +113,10 @@ public: case job_type::CarveUpDownStaircase: td.bits.dig = tile_dig_designation::UpDownStair; break; - case job_type::DetailWall: - case job_type::DetailFloor: { - df::tiletype tt = map.tiletypeAt(job->pos); - if (tileSpecial(tt) != df::tiletype_special::SMOOTH) { - td.bits.smooth = 1; - } + case job_type::SmoothWall: + case job_type::SmoothFloor: + td.bits.smooth = 1; break; - } case job_type::CarveTrack: to.bits.carve_track_north = (job->item_category.whole >> 18) & 1; to.bits.carve_track_south = (job->item_category.whole >> 19) & 1; From 31401b2e199d31027be4fd155c4c91dc88805190 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Apr 2023 23:48:10 -0700 Subject: [PATCH 0102/1234] fixed size limit calculations for rollers --- docs/changelog.txt | 1 + plugins/lua/buildingplan/planneroverlay.lua | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 3c1ed7e8f..0080ab9c3 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -36,6 +36,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins ## Fixes +- `buildingplan`: fixed size limit calculations for rollers ## Misc Improvements - `buildingplan`: planner panel is minimized by default and now remembers minimized state diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index 83a58ebd8..803e9ae99 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -34,9 +34,10 @@ local function get_selection_size_limits() or btype == df.building_type.RoadPaved or btype == df.building_type.RoadDirt then return {w=31, h=31} - elseif btype == df.building_type.AxleHorizontal - or btype == df.building_type.Rollers then + elseif btype == df.building_type.AxleHorizontal then return uibs.direction == 1 and {w=1, h=31} or {w=31, h=1} + elseif btype == df.building_type.Rollers then + return (uibs.direction == 1 or uibs.direction == 3) and {w=31, h=1} or {w=1, h=31} end end From 5e1117473ae577e009ba4825f81dfcd981105cfd Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 24 Apr 2023 07:14:36 +0000 Subject: [PATCH 0103/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 5da969fce..68f6d354b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 5da969fce69a5b9330f183cc0629798bf9907b69 +Subproject commit 68f6d354b0d815ad0985dbe9b5faa140c980af14 From ab047af1633ed386edef49c7e329d1d34e6b4a92 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 24 Apr 2023 00:31:20 -0700 Subject: [PATCH 0104/1234] demote chatty WARN messages to DEBUG --- docs/changelog.txt | 1 + plugins/autoclothing.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 3c1ed7e8f..54d002f3e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -36,6 +36,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins ## Fixes +- `autoclothing`: eliminate game lag when there are many inventory items in the fort ## Misc Improvements - `buildingplan`: planner panel is minimized by default and now remembers minimized state diff --git a/plugins/autoclothing.cpp b/plugins/autoclothing.cpp index aa114cb84..d404960b4 100644 --- a/plugins/autoclothing.cpp +++ b/plugins/autoclothing.cpp @@ -565,7 +565,7 @@ static void find_needed_clothing_items() if (!item) { - WARN(cycle).print("autoclothing: Invalid inventory item ID: %d\n", ownedItem); + DEBUG(cycle).print("autoclothing: Invalid inventory item ID: %d\n", ownedItem); continue; } @@ -818,7 +818,7 @@ static void generate_report(color_ostream& out) auto item = Items::findItemByID(itemId); if (!item) { - WARN(cycle,out).print("autoclothing: Invalid inventory item ID: %d\n", itemId); + DEBUG(cycle, out).print("autoclothing: Invalid inventory item ID: %d\n", itemId); continue; } if (item->getWear() >= 1) From 6203894c998aef9f9aa3de7c6b85833719032618 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 24 Apr 2023 08:03:11 -0700 Subject: [PATCH 0105/1234] add title screen focus string detection --- library/modules/Gui.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 6ea0a5ff0..44642b5fa 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -84,6 +84,7 @@ using namespace DFHack; #include "df/unit.h" #include "df/unit_inventory_item.h" #include "df/viewscreen_dwarfmodest.h" +#include "df/viewscreen_titlest.h" #include "df/world.h" const size_t MAX_REPORTS_SIZE = 3000; // DF clears old reports to maintain this vector size @@ -144,6 +145,17 @@ static std::map getFocusStringsHandle ); \ static void getFocusStrings_##screen_type(std::string &baseFocus, std::vector &focusStrings, VIEWSCREEN(screen_type) *screen) +DEFINE_GET_FOCUS_STRING_HANDLER(title) +{ + if (screen->managing_mods) + focusStrings.push_back(baseFocus + "/Mods"); + else if (game->main_interface.settings.open) + focusStrings.push_back(baseFocus + "/Settings"); + + if (focusStrings.empty()) + focusStrings.push_back(baseFocus + "/Default"); +} + DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) { std::string newFocusString; From 65da8ef3c97e9c7b819c0cabf77292c69249dcfc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 24 Apr 2023 08:03:31 -0700 Subject: [PATCH 0106/1234] only display dfhack logo on base title screen to avoid overlapping important widgets on subscreens --- plugins/lua/hotkeys.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index b162f0c08..fca0f1f27 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -39,7 +39,7 @@ HotspotMenuWidget.ATTRS{ -- 'new_region', -- conflicts with vanilla panel layouts 'savegame', 'setupdwarfgame', - 'title', + 'title/Default', 'update_region', 'world' }, From 2686c8f08441088cb6d008c4728c66533e4a2f51 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 24 Apr 2023 08:04:08 -0700 Subject: [PATCH 0107/1234] move DFHack version next to logo and only display on the base title screen --- plugins/lua/overlay.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index 6a568fb85..81dde32b6 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -570,7 +570,7 @@ TitleVersionOverlay = defclass(TitleVersionOverlay, OverlayWidget) TitleVersionOverlay.ATTRS{ default_pos={x=50, y=-2}, default_enabled=true, - viewscreens='title', + viewscreens='title/Default', frame={w=35, h=3}, } @@ -589,7 +589,7 @@ function TitleVersionOverlay:init() self:addviews{ widgets.Label{ - frame={b=0, l=0}, + frame={t=0, l=0}, text=text, text_pen=COLOR_WHITE, }, From 300e891f8aa8d97fcef4493cc3ac9a0d7bfd7a0c Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 24 Apr 2023 14:15:09 -0700 Subject: [PATCH 0108/1234] Update changelog.txt --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 4429e40be..49723ab27 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -37,7 +37,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes - `buildingplan`: fixed size limit calculations for rollers -`- `dig-now`: properly detect and complete smoothing designations that have been converted into active jobs +- `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 From 4ecf125a1aa2eb1c4efe513ba1cca5bbe37278d7 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 24 Apr 2023 21:19:02 +0000 Subject: [PATCH 0109/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 68f6d354b..6b4001dc2 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 68f6d354b0d815ad0985dbe9b5faa140c980af14 +Subproject commit 6b4001dc2f9d0e662bb7d06d8ba6fcf343a656aa From 5a4dec35f1a28ad9838a951d3049924622c81166 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 24 Apr 2023 14:28:21 -0700 Subject: [PATCH 0110/1234] reorder template declarations so we can push vectors of maps --- library/include/LuaTools.h | 40 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h index b19fc31de..cab3ee9cc 100644 --- a/library/include/LuaTools.h +++ b/library/include/LuaTools.h @@ -342,26 +342,6 @@ namespace DFHack {namespace Lua { DFHACK_EXPORT void PushInterfaceKeys(lua_State *L, const std::set &keys); - template - void PushVector(lua_State *state, const T &pvec, bool addn = false) - { - lua_createtable(state,pvec.size(), addn?1:0); - - if (addn) - { - lua_pushinteger(state, pvec.size()); - lua_setfield(state, -2, "n"); - } - - for (size_t i = 0; i < pvec.size(); i++) - { - Push(state, pvec[i]); - lua_rawseti(state, -2, i+1); - } - } - - DFHACK_EXPORT void GetVector(lua_State *state, std::vector &pvec, int idx = 1); - DFHACK_EXPORT int PushPosXYZ(lua_State *state, const df::coord &pos); DFHACK_EXPORT int PushPosXY(lua_State *state, const df::coord2d &pos); @@ -412,6 +392,26 @@ namespace DFHack {namespace Lua { lua_settable(state, -3); } + template + void PushVector(lua_State *state, const T &pvec, bool addn = false) + { + lua_createtable(state,pvec.size(), addn?1:0); + + if (addn) + { + lua_pushinteger(state, pvec.size()); + lua_setfield(state, -2, "n"); + } + + for (size_t i = 0; i < pvec.size(); i++) + { + Push(state, pvec[i]); + lua_rawseti(state, -2, i+1); + } + } + + DFHACK_EXPORT void GetVector(lua_State *state, std::vector &pvec, int idx = 1); + DFHACK_EXPORT void CheckPen(lua_State *L, Screen::Pen *pen, int index, bool allow_nil = false, bool allow_color = true); DFHACK_EXPORT bool IsCoreContext(lua_State *state); From 73b5e37f678719c7f4473ebfa5263e8c743484d9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 24 Apr 2023 14:28:47 -0700 Subject: [PATCH 0111/1234] simplify loops with foreach syntax --- library/modules/Buildings.cpp | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 7694a696b..b9e61c863 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -1115,31 +1115,17 @@ static void createDesign(df::building *bld, bool rough) static int getMaxStockpileId() { - auto &vec = world->buildings.other[buildings_other_id::STOCKPILE]; int max_id = 0; - - for (size_t i = 0; i < vec.size(); i++) - { - auto bld = strict_virtual_cast(vec[i]); - if (bld) - max_id = std::max(max_id, bld->stockpile_number); - } - + for (auto bld : world->buildings.other.STOCKPILE) + max_id = std::max(max_id, bld->stockpile_number); return max_id; } static int getMaxCivzoneId() { - auto &vec = world->buildings.other[buildings_other_id::ANY_ZONE]; int max_id = 0; - - for (size_t i = 0; i < vec.size(); i++) - { - auto bld = strict_virtual_cast(vec[i]); - if (bld) - max_id = std::max(max_id, bld->zone_num); - } - + for (auto bld : world->buildings.other.ANY_ZONE) + max_id = std::max(max_id, bld->zone_num); return max_id; } From 65d7b290a3f7a859d2a75fa44e4c3109684f63b1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 24 Apr 2023 14:32:33 -0700 Subject: [PATCH 0112/1234] add ZScreenModal class for modal dialogs --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 7 +++++++ library/lua/gui.lua | 13 +++++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index a3e9c6f6c..2b3438cc5 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -55,6 +55,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Lua - ``widgets.RangeSlider``: new mouse-controlled two-headed slider widget +- ``gui.ZScreenModal``: ZScreen subclass for modal dialogs ## Removed - `title-version`: replaced by an `overlay` widget diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 078cec828..9c320fc98 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4323,6 +4323,13 @@ Here is an example skeleton for a ZScreen tool window:: 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 ------------------ diff --git a/library/lua/gui.lua b/library/lua/gui.lua index e425dbcf1..b2c90d076 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -867,8 +867,17 @@ function ZScreen:onGetSelectedPlant() return zscreen_get_any(self, 'Plant') end --------------------------- --- Framed screen object -- +-- convenience subclass for modal dialogs +ZScreenModal = defclass(ZScreenModal, ZScreen) +ZScreenModal.ATTRS{ + defocusable = false, + force_pause = true, + pass_pause = false, + pass_movement_keys = false, + pass_mouse_clicks = false, +} + +-- Framed screen object -------------------------- -- Plain grey-colored frame. From 54ea391b1daf7059eef570add6e327a2eebaa3b0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 24 Apr 2023 15:26:33 -0700 Subject: [PATCH 0113/1234] bump to 50.07-r2rc3 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index caf597088..72314ee6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,7 +192,7 @@ endif() # set up versioning. set(DF_VERSION "50.07") -set(DFHACK_RELEASE "r2rc2") +set(DFHACK_RELEASE "r2rc3") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 6c88fa6440b9282595fb2dddf7e6c5ba5bf07336 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 24 Apr 2023 16:12:37 -0700 Subject: [PATCH 0114/1234] don't output git hash on release builds --- plugins/lua/overlay.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index 81dde32b6..cf7008a40 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -577,7 +577,7 @@ TitleVersionOverlay.ATTRS{ function TitleVersionOverlay:init() local text = {} table.insert(text, 'DFHack ' .. dfhack.getDFHackVersion() .. - (dfhack.isPrerelease() and (' (git: %s)'):format(dfhack.getGitCommit(true)) or '')) + (dfhack.isRelease() and '' or (' (git: %s)'):format(dfhack.getGitCommit(true)))) if #dfhack.getDFHackBuildID() > 0 then table.insert(text, NEWLINE) table.insert(text, 'Build ID: ' .. dfhack.getDFHackBuildID()) From 4d3a4adf572dd49aab402a72bcd8bd368b0612f4 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 25 Apr 2023 07:13:39 +0000 Subject: [PATCH 0115/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 6b4001dc2..ad1998a00 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 6b4001dc2f9d0e662bb7d06d8ba6fcf343a656aa +Subproject commit ad1998a0032ce50e90d05429a4178b668c0840ba From 68a8c687eabbecbf4c39b8045340ee5f76dfdf05 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 25 Apr 2023 16:02:15 -0500 Subject: [PATCH 0116/1234] steam build workflow improvements improve cmake handling for downloading the sdk set up GHA to cache the SDK download --- .github/workflows/steam.yml | 6 ++++++ package/windows/CMakeLists.txt | 21 +++++++++++++++------ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 71e56b662..05692c680 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -36,6 +36,12 @@ jobs: restore-keys: | ccache-win64-cross-msvc-develop-${{ github.event.inputs.commit_hash }} ccache-win64-cross-msvc + - name: Restore steam SDK + uses: action/cache@v3 + with: + path: depends/steam/steamworks_sdk_156.zip + key: steam-sdk-156 + enableCrossOsArchive: true - name: Cross-compile win64 artifacts env: CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1' diff --git a/package/windows/CMakeLists.txt b/package/windows/CMakeLists.txt index b74cdfec5..d92d687c4 100644 --- a/package/windows/CMakeLists.txt +++ b/package/windows/CMakeLists.txt @@ -9,13 +9,22 @@ if(WIN32) ${STEAMAPI_DIR}/steamworks_sdk_156.zip EXPECTED_HASH MD5=af5a579990dbe5ae4c1b0689260d001b USERPWD $ENV{steam_username}:$ENV{steam_password} + STATUS STEAM_SDK_DOWNLOAD_STATUS + SHOW_PROGRESS ) - file(ARCHIVE_EXTRACT - INPUT ${STEAMAPI_DIR}/steamworks_sdk_156.zip - DESTINATION ${STEAMAPI_DIR}) - set(STEAMAPI_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.lib") - set(STEAMAPI_SOURCE_DIR "${STEAMAPI_DIR}/sdk/public/steam") - set(STEAMAPI_SHARED_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.dll") + list(GET STEAM_SDK_DOWNLOAD_STATUS 0 STEAM_SDK_DL_STATUS_CODE) + list(GET STEAM_SDK_DOWNLOAD_STATUS 1 STEAM_SDK_DL_ERROR_MESSAGE) + if (NOT (${STEAM_SDK_DL_STATUS_CODE} EQUAL 0)) + message(FATAL_ERROR "Steam SDK download: " ${STEAM_SDK_DL_ERROR_MESSAGE}) + else () + message(STATUS "Steam SDK download: " ${STEAM_SDK_DL_ERROR_MESSAGE}) + file(ARCHIVE_EXTRACT + INPUT ${STEAMAPI_DIR}/steamworks_sdk_156.zip + DESTINATION ${STEAMAPI_DIR}) + set(STEAMAPI_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.lib") + set(STEAMAPI_SOURCE_DIR "${STEAMAPI_DIR}/sdk/public/steam") + set(STEAMAPI_SHARED_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.dll") + endif() else() message(SEND_ERROR "Need to set steam_username and steam_password in environment to download Steamworks SDK") endif() From 17a798d5bc9f0b3d64930663e992275bdddf7d4a Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 25 Apr 2023 16:06:36 -0500 Subject: [PATCH 0117/1234] add missing letter --- .github/workflows/steam.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 05692c680..ca6802446 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -37,7 +37,7 @@ jobs: ccache-win64-cross-msvc-develop-${{ github.event.inputs.commit_hash }} ccache-win64-cross-msvc - name: Restore steam SDK - uses: action/cache@v3 + uses: actions/cache@v3 with: path: depends/steam/steamworks_sdk_156.zip key: steam-sdk-156 From 48ffad2f7145cfe19613bc8e1dba2a04e4bd565e Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Wed, 26 Apr 2023 01:02:38 +0200 Subject: [PATCH 0118/1234] added and attributes to --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 4 ++++ library/lua/gui/widgets.lua | 9 +++++---- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index b85c738a5..80f2797b6 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,6 +57,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Lua - ``widgets.RangeSlider``: new mouse-controlled two-headed slider widget - ``gui.ZScreenModal``: ZScreen subclass for modal dialogs +- ``widgets.CycleHotkeyLabel``: exposed `key_sep` and `val_gap` attributes for improved stylistic control. ## Removed - `title-version`: replaced by an `overlay` widget diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 9c320fc98..73538a5a3 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4912,12 +4912,16 @@ It has the following attributes: :key: The hotkey keycode to display, e.g. ``'CUSTOM_A'``. :key_back: Similar to ``key``, but will cycle backwards (optional) +:key_sep: If specified, will be used to customize how the activation key is + displayed. See ``token.key_sep`` in the ``Label`` documentation. :label: The string (or a function that returns a string) to display after the hotkey. :label_width: The number of spaces to allocate to the ``label`` (for use in aligning a column of ``CycleHotkeyLabel`` labels). :label_below: If ``true``, then the option value will apear below the label instead of to the right of it. Defaults to ``false``. +:val_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. :options: A list of strings or tables of ``{label=string or fn, value=val[, pen=pen]}``. String options use the same string for the label and value and use the default pen. The optional ``pen`` diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index a778df639..c7cde698c 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1488,6 +1488,8 @@ CycleHotkeyLabel = defclass(CycleHotkeyLabel, Label) CycleHotkeyLabel.ATTRS{ key=DEFAULT_NIL, key_back=DEFAULT_NIL, + key_sep=': ', + val_gap=1, label=DEFAULT_NIL, label_width=DEFAULT_NIL, label_below=false, @@ -1499,17 +1501,16 @@ CycleHotkeyLabel.ATTRS{ function CycleHotkeyLabel:init() self:setOption(self.initial_option) - local val_gap = 1 if self.label_below then - val_gap = 0 + (self.key_back and 1 or 0) + (self.key and 3 or 0) + self.val_gap = 0 + (self.key_back and 1 or 0) + (self.key and 3 or 0) end self:setText{ self.key_back ~= nil and {key=self.key_back, key_sep='', width=0, on_activate=self:callback('cycle', true)} or {}, - {key=self.key, key_sep=': ', text=self.label, width=self.label_width, + {key=self.key, key_sep=self.key_sep, text=self.label, width=self.label_width, on_activate=self:callback('cycle')}, self.label_below and NEWLINE or '', - {gap=val_gap, text=self:callback('getOptionLabel'), + {gap=self.val_gap, text=self:callback('getOptionLabel'), pen=self:callback('getOptionPen')}, } end From 6e1300458cf4440d3c510fb7007d0925099a9e42 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Wed, 26 Apr 2023 01:26:38 +0200 Subject: [PATCH 0119/1234] fixed some wrong quotation marks in changelog.txt that made the build thingy cry --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 80f2797b6..91f25a323 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,7 +57,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Lua - ``widgets.RangeSlider``: new mouse-controlled two-headed slider widget - ``gui.ZScreenModal``: ZScreen subclass for modal dialogs -- ``widgets.CycleHotkeyLabel``: exposed `key_sep` and `val_gap` attributes for improved stylistic control. +- ``widgets.CycleHotkeyLabel``: exposed "key_sep" and "val_gap" attributes for improved stylistic control. ## Removed - `title-version`: replaced by an `overlay` widget From ec659ca1c26bed0ee768421e29d49e3b4038b781 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Wed, 26 Apr 2023 11:26:29 +0200 Subject: [PATCH 0120/1234] added note about val_gap's behaviour when label_below == true --- docs/dev/Lua API.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 73538a5a3..37d85f7f6 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4922,6 +4922,7 @@ It has the following attributes: instead of to the right of it. Defaults to ``false``. :val_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. + Note that ``val_gap`` is ignored if ``label_below`` is set to ``true``. :options: A list of strings or tables of ``{label=string or fn, value=val[, pen=pen]}``. String options use the same string for the label and value and use the default pen. The optional ``pen`` From ba06a8f2bb1a41be61543755804999fc4fe48e33 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 26 Apr 2023 13:36:40 -0700 Subject: [PATCH 0121/1234] dump input vars in deploy output --- .github/workflows/steam.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index ca6802446..33aa16d34 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -48,6 +48,10 @@ jobs: steam_username: ${{ secrets.STEAM_SDK_USERNAME }} steam_password: ${{ secrets.STEAM_SDK_PASSWORD }} run: | + echo "commit: ${{ github.event.inputs.commit_hash }}" + echo "version: ${{ github.event.inputs.version }}" + echo "release_channel: ${{ github.event.inputs.release_channel }}" + echo cd build bash -x build-win64-from-linux.sh - name: Steam deploy From 9c447e8d45479c14d5a29113446c85360db70709 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 26 Apr 2023 14:39:13 -0700 Subject: [PATCH 0122/1234] re-add add-spatter plugin (minimal changes) --- docs/changelog.txt | 1 + docs/plugins/add-spatter.rst | 2 +- plugins/CMakeLists.txt | 2 +- plugins/add-spatter.cpp | 62 +++++++++++------------------------- 4 files changed, 21 insertions(+), 46 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 91f25a323..25391f081 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -34,6 +34,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # Future ## New Plugins +- `add-spatter`: allow mods to add poisons and magical effects to weapons ## Fixes - `autoclothing`: eliminate game lag when there are many inventory items in the fort diff --git a/docs/plugins/add-spatter.rst b/docs/plugins/add-spatter.rst index 6914690ea..2c43a88ef 100644 --- a/docs/plugins/add-spatter.rst +++ b/docs/plugins/add-spatter.rst @@ -2,7 +2,7 @@ add-spatter =========== .. dfhack-tool:: - :summary: Make tagged reactions produce contaminants. + :summary: Add poisons and magical effects to weapons. :tags: unavailable adventure fort gameplay items :no-command: diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 97216ad50..8aadd46f2 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -74,7 +74,7 @@ set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) # see instructions for adding "external" plugins at the end of this file. #dfhack_plugin(3dveins 3dveins.cpp) -#dfhack_plugin(add-spatter add-spatter.cpp) +dfhack_plugin(add-spatter add-spatter.cpp) dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua) dfhack_plugin(autochop autochop.cpp LINK_LIBRARIES lua) dfhack_plugin(autoclothing autoclothing.cpp LINK_LIBRARIES lua) diff --git a/plugins/add-spatter.cpp b/plugins/add-spatter.cpp index 451fffabf..3cfefce39 100644 --- a/plugins/add-spatter.cpp +++ b/plugins/add-spatter.cpp @@ -1,51 +1,26 @@ -#include "Core.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "df/item_liquid_miscst.h" +#include "PluginManager.h" +#include "VTableInterpose.h" + +#include "modules/Items.h" +#include "modules/Units.h" + #include "df/item_constructed.h" -#include "df/builtin_mats.h" -#include "df/world.h" #include "df/job.h" #include "df/job_item.h" #include "df/job_item_ref.h" -#include "df/plotinfost.h" -#include "df/report.h" #include "df/reaction.h" #include "df/reaction_reagent_itemst.h" #include "df/reaction_product_item_improvementst.h" -#include "df/reaction_product_improvement_flags.h" -#include "df/matter_state.h" #include "df/spatter.h" -#include "MiscUtils.h" - using std::vector; using std::string; -using std::stack; + using namespace DFHack; using namespace df::enums; DFHACK_PLUGIN("add-spatter"); DFHACK_PLUGIN_IS_ENABLED(is_enabled); -REQUIRE_GLOBAL(gps); -REQUIRE_GLOBAL(world); -REQUIRE_GLOBAL(plotinfo); typedef df::reaction_product_item_improvementst improvement_product; @@ -397,18 +372,20 @@ static void enable_hooks(bool enable) INTERPOSE_HOOK(product_hook, produce).apply(enable); } +DFhackCExport command_result plugin_load_data (color_ostream &out) { + if (find_reactions(out)) { + out.print("Detected spatter add reactions - enabling plugin.\n"); + enable_hooks(true); + } + else + enable_hooks(false); + + return CR_OK; +} + DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { switch (event) { - case SC_WORLD_LOADED: - if (find_reactions(out)) - { - out.print("Detected spatter add reactions - enabling plugin.\n"); - enable_hooks(true); - } - else - enable_hooks(false); - break; case SC_WORLD_UNLOADED: enable_hooks(false); reactions.clear(); @@ -423,9 +400,6 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) { - if (Core::getInstance().isWorldLoaded()) - plugin_onstatechange(out, SC_WORLD_LOADED); - return CR_OK; } From fef7919c080d9d58783e2ab26237450b03fc24c5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 26 Apr 2023 16:19:26 -0700 Subject: [PATCH 0123/1234] bump version to 50.08-beta4 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index beb1f28d9..d6b5d2949 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,7 +192,7 @@ endif() # set up versioning. set(DF_VERSION "50.08b1") -set(DFHACK_RELEASE "beta3") +set(DFHACK_RELEASE "beta4") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 1b8fc20ad53fded507407fe0f0a52486d626b6f5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 26 Apr 2023 21:01:21 -0700 Subject: [PATCH 0124/1234] check items for accessibility for dialogs before we only checked when doing the cycle, so if an inaccessible item were manually selected, we'd never be able to build --- docs/changelog.txt | 1 + plugins/buildingplan/buildingplan.cpp | 2 +- plugins/buildingplan/buildingplan.h | 2 +- plugins/buildingplan/buildingplan_cycle.cpp | 42 ++++++++++----------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 91f25a323..66904aa6d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -38,6 +38,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## 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 diff --git a/plugins/buildingplan/buildingplan.cpp b/plugins/buildingplan/buildingplan.cpp index 05b2c0af6..ce424f9c6 100644 --- a/plugins/buildingplan/buildingplan.cpp +++ b/plugins/buildingplan/buildingplan.cpp @@ -704,7 +704,7 @@ static int scanAvailableItems(color_ostream &out, df::building_type type, int16_ filter.setMaterials(set()); special.clear(); } - if (itemPassesScreen(item) && matchesFilters(item, jitem, heat, filter, special)) { + if (itemPassesScreen(out, item) && matchesFilters(item, jitem, heat, filter, special)) { if (item_ids) item_ids->emplace_back(item->id); if (counts) { diff --git a/plugins/buildingplan/buildingplan.h b/plugins/buildingplan/buildingplan.h index 5c4f25aa4..9bfd38731 100644 --- a/plugins/buildingplan/buildingplan.h +++ b/plugins/buildingplan/buildingplan.h @@ -54,7 +54,7 @@ void set_config_val(DFHack::PersistentDataItem &c, int index, int value); void set_config_bool(DFHack::PersistentDataItem &c, int index, bool value); std::vector getVectorIds(DFHack::color_ostream &out, const df::job_item *job_item, bool ignore_filters); -bool itemPassesScreen(df::item * item); +bool itemPassesScreen(DFHack::color_ostream& out, df::item* item); df::job_item getJobItemWithHeatSafety(const df::job_item *job_item, HeatSafety heat); bool matchesFilters(df::item * item, const df::job_item * job_item, HeatSafety heat, const ItemFilter &item_filter, const std::set &special); bool isJobReady(DFHack::color_ostream &out, const std::vector &jitems); diff --git a/plugins/buildingplan/buildingplan_cycle.cpp b/plugins/buildingplan/buildingplan_cycle.cpp index 3213e741d..45cafe474 100644 --- a/plugins/buildingplan/buildingplan_cycle.cpp +++ b/plugins/buildingplan/buildingplan_cycle.cpp @@ -43,10 +43,27 @@ struct BadFlags { } }; -bool itemPassesScreen(df::item * item) { +// This is tricky. we want to choose an item that can be brought to the job site, but that's not +// necessarily the same as job->pos. it could be many tiles off in any direction (e.g. for bridges), or +// up or down (e.g. for stairs). For now, just return if the item is on a walkable tile. +static bool isAccessible(color_ostream& out, df::item* item) { + df::coord item_pos = Items::getPosition(item); + df::map_block* block = Maps::getTileBlock(item_pos); + bool is_walkable = false; + if (block) { + uint16_t walkability_group = index_tile(block->walkable, item_pos); + is_walkable = walkability_group != 0; + TRACE(cycle, out).print("item %d in walkability_group %u at (%d,%d,%d) is %saccessible from job site\n", + item->id, walkability_group, item_pos.x, item_pos.y, item_pos.z, is_walkable ? "(probably) " : "not "); + } + return is_walkable; +} + +bool itemPassesScreen(color_ostream& out, df::item* item) { static const BadFlags bad_flags; return !(item->flags.whole & bad_flags.whole) - && !item->isAssignedToStockpile(); + && !item->isAssignedToStockpile() + && isAccessible(out, item); } df::job_item getJobItemWithHeatSafety(const df::job_item *job_item, HeatSafety heat) { @@ -165,22 +182,6 @@ static df::building * popInvalidTasks(color_ostream &out, Bucket &task_queue, return NULL; } -// This is tricky. we want to choose an item that can be brought to the job site, but that's not -// necessarily the same as job->pos. it could be many tiles off in any direction (e.g. for bridges), or -// up or down (e.g. for stairs). For now, just return if the item is on a walkable tile. -static bool isAccessibleFrom(color_ostream &out, df::item *item, df::job *job) { - df::coord item_pos = Items::getPosition(item); - df::map_block *block = Maps::getTileBlock(item_pos); - bool is_walkable = false; - if (block) { - uint16_t walkability_group = index_tile(block->walkable, item_pos); - is_walkable = walkability_group != 0; - TRACE(cycle,out).print("item %d in walkability_group %u at (%d,%d,%d) is %saccessible from job site\n", - item->id, walkability_group, item_pos.x, item_pos.y, item_pos.z, is_walkable ? "" : "not "); - } - return is_walkable; -} - static void doVector(color_ostream &out, df::job_item_vector_id vector_id, map &buckets, unordered_map &planned_buildings, @@ -195,7 +196,7 @@ static void doVector(color_ostream &out, df::job_item_vector_id vector_id, item_it != item_vector.rend(); ++item_it) { auto item = *item_it; - if (!itemPassesScreen(item)) + if (!itemPassesScreen(out, item)) continue; for (auto bucket_it = buckets.begin(); bucket_it != buckets.end(); ) { TRACE(cycle,out).print("scanning bucket: %s/%s\n", @@ -218,8 +219,7 @@ static void doVector(color_ostream &out, df::job_item_vector_id vector_id, auto filter_idx = task.second; const int rev_filter_idx = num_filters - (filter_idx+1); auto &pb = planned_buildings.at(id); - if (isAccessibleFrom(out, item, job) - && matchesFilters(item, jitems[filter_idx], pb.heat_safety, + if (matchesFilters(item, jitems[filter_idx], pb.heat_safety, pb.item_filters[rev_filter_idx], pb.specials) && Job::attachJobItem(job, item, df::job_item_ref::Hauled, filter_idx)) From fab05ca887049b1755cca86726f740764ea25a5c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 27 Apr 2023 12:59:06 -0700 Subject: [PATCH 0125/1234] fix position of title overlay; force refresh on resize --- plugins/lua/overlay.lua | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index cf7008a40..b1960989f 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -510,7 +510,7 @@ end local function _render_viewscreen_widgets(vs_name, dc) local vs_widgets = active_viewscreen_widgets[vs_name] - if not vs_widgets then return false end + if not vs_widgets then return end dc = dc or gui.Painter.new() for _,db_entry in pairs(vs_widgets) do local w = db_entry.widget @@ -518,11 +518,18 @@ local function _render_viewscreen_widgets(vs_name, dc) detect_frame_change(w, function() w:render(dc) end) end end + return dc end +local force_refresh + function render_viewscreen_widgets(vs_name) local dc = _render_viewscreen_widgets(vs_name, nil) _render_viewscreen_widgets('all', dc) + if force_refresh then + force_refresh = nil + df.global.gps.force_full_display_count = 1 + end end -- called when the DF window is resized @@ -531,6 +538,7 @@ function reposition_widgets() for _,db_entry in pairs(widget_db) do db_entry.widget:updateLayout(sr) end + force_refresh = true end -- ------------------------------------------------- -- @@ -568,7 +576,7 @@ end TitleVersionOverlay = defclass(TitleVersionOverlay, OverlayWidget) TitleVersionOverlay.ATTRS{ - default_pos={x=50, y=-2}, + default_pos={x=7, y=2}, default_enabled=true, viewscreens='title/Default', frame={w=35, h=3}, From ef140b0dd6d0a7437d5ed9f2cacb533c0bb7f484 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 27 Apr 2023 13:20:25 -0700 Subject: [PATCH 0126/1234] rename and enable plugin --- docs/plugins/{workNow.rst => work-now.rst} | 6 +++--- plugins/CMakeLists.txt | 2 +- plugins/{workNow.cpp => work-now.cpp} | 0 3 files changed, 4 insertions(+), 4 deletions(-) rename docs/plugins/{workNow.rst => work-now.rst} (90%) rename plugins/{workNow.cpp => work-now.cpp} (100%) diff --git a/docs/plugins/workNow.rst b/docs/plugins/work-now.rst similarity index 90% rename from docs/plugins/workNow.rst rename to docs/plugins/work-now.rst index cec39c667..7578500e8 100644 --- a/docs/plugins/workNow.rst +++ b/docs/plugins/work-now.rst @@ -1,9 +1,9 @@ -workNow -======= +work-now +======== .. dfhack-tool:: :summary: Reduce the time that dwarves idle after completing a job. - :tags: unavailable fort auto labors + :tags: fort auto jobs After finishing a job, dwarves will wander away for a while before picking up a new job. This plugin will automatically poke the game to assign dwarves to new diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 97216ad50..c9822ea8a 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -166,7 +166,7 @@ dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(tubefill tubefill.cpp) #add_subdirectory(tweak) #dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua) -#dfhack_plugin(workNow workNow.cpp) +dfhack_plugin(work-now work-now.cpp) dfhack_plugin(xlsxreader xlsxreader.cpp LINK_LIBRARIES lua xlsxio_read_STATIC zip expat) #dfhack_plugin(zone zone.cpp) diff --git a/plugins/workNow.cpp b/plugins/work-now.cpp similarity index 100% rename from plugins/workNow.cpp rename to plugins/work-now.cpp From 83fa87b492edd50f1cc98159bae3d12c0fcd0342 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 27 Apr 2023 14:22:45 -0700 Subject: [PATCH 0127/1234] add work-now to the build --- .../init/dfhack.control-panel-system.init | 1 + docs/changelog.txt | 1 + docs/plugins/work-now.rst | 15 +-- plugins/work-now.cpp | 92 ++++++++----------- 4 files changed, 44 insertions(+), 65 deletions(-) diff --git a/data/dfhack-config/init/dfhack.control-panel-system.init b/data/dfhack-config/init/dfhack.control-panel-system.init index 8b1431373..c1ad6a679 100644 --- a/data/dfhack-config/init/dfhack.control-panel-system.init +++ b/data/dfhack-config/init/dfhack.control-panel-system.init @@ -2,3 +2,4 @@ # Please use gui/control-panel to edit this file enable faststart +enable work-now diff --git a/docs/changelog.txt b/docs/changelog.txt index 66904aa6d..a6d72d4ce 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -34,6 +34,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # Future ## New Plugins +- `work-now`: reduce the time that dwarves are left without a task after completing a job ## Fixes - `autoclothing`: eliminate game lag when there are many inventory items in the fort diff --git a/docs/plugins/work-now.rst b/docs/plugins/work-now.rst index 7578500e8..517378d56 100644 --- a/docs/plugins/work-now.rst +++ b/docs/plugins/work-now.rst @@ -6,17 +6,12 @@ work-now :tags: fort auto jobs After finishing a job, dwarves will wander away for a while before picking up a -new job. This plugin will automatically poke the game to assign dwarves to new -tasks. +new job. This plugin will automatically poke them to pick up a new task quicker. Usage ----- -``workNow`` - Print current plugin status. -``workNow 0`` - Stop monitoring and poking. -``workNow 1`` - Poke the game to assign dwarves to tasks whenever the game is paused. -``workNow 2`` - Poke the game to assign dwarves to tasks whenever a dwarf finishes a job. +:: + + enable work-now + work-now [status] diff --git a/plugins/work-now.cpp b/plugins/work-now.cpp index 2286fee7e..bce2d9a73 100644 --- a/plugins/work-now.cpp +++ b/plugins/work-now.cpp @@ -1,92 +1,74 @@ -#include "Core.h" -#include "Console.h" -#include "Export.h" +#include "Debug.h" #include "PluginManager.h" -#include "DataDefs.h" #include "modules/EventManager.h" -#include "modules/World.h" -#include "df/global_objects.h" - -#include - -using namespace std; +using std::string; +using std::vector; using namespace DFHack; -DFHACK_PLUGIN("workNow"); +DFHACK_PLUGIN("work-now"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); REQUIRE_GLOBAL(process_jobs); REQUIRE_GLOBAL(process_dig); -static int mode = 0; +namespace DFHack { + DBG_DECLARE(worknow, log, DebugCategory::LINFO); +} -DFhackCExport command_result workNow(color_ostream& out, vector& parameters); +DFhackCExport command_result work_now(color_ostream& out, vector& parameters); -void jobCompletedHandler(color_ostream& out, void* ptr); +static void jobCompletedHandler(color_ostream& out, void* ptr); EventManager::EventHandler handler(jobCompletedHandler,1); DFhackCExport command_result plugin_init(color_ostream& out, std::vector &commands) { - if (!process_jobs || !process_dig) - return CR_FAILURE; - commands.push_back(PluginCommand( - "workNow", + "work-now", "Reduce the time that dwarves idle after completing a job.", - workNow)); + work_now)); return CR_OK; } -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) { - mode = 0; +DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { + if (enable != is_enabled) + { + if (enable) + EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, handler, plugin_self); + else + EventManager::unregister(EventManager::EventType::JOB_COMPLETED, handler, plugin_self); + + is_enabled = enable; + } + return CR_OK; } +DFhackCExport command_result plugin_shutdown ( color_ostream &out ) { + return plugin_enable(out, false); +} + DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event e) { - if ( !mode ) - return CR_OK; - if ( e == DFHack::SC_WORLD_UNLOADED ) { - mode = 0; - return CR_OK; + if (e == SC_PAUSED) { + DEBUG(log,out).print("game paused; poking idlers\n"); + *process_jobs = true; + *process_dig = true; } - if ( e != DFHack::SC_PAUSED ) - return CR_OK; - - *process_jobs = true; - *process_dig = true; return CR_OK; } -DFhackCExport command_result workNow(color_ostream& out, vector& parameters) { - if ( parameters.size() == 0 ) { - out.print("workNow status = %d\n", mode); +DFhackCExport command_result work_now(color_ostream& out, vector& parameters) { + if (parameters.empty() || parameters[0] == "status") { + out.print("work_now is %sactively poking idle dwarves.\n", is_enabled ? "" : "not "); return CR_OK; } - if ( parameters.size() > 1 ) { - return CR_WRONG_USAGE; - } - int32_t a = atoi(parameters[0].c_str()); - - if (a < 0 || a > 2) - return CR_WRONG_USAGE; - if ( a == 2 && mode != 2 ) { - EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, handler, plugin_self); - } else if ( mode == 2 && a != 2 ) { - EventManager::unregister(EventManager::EventType::JOB_COMPLETED, handler, plugin_self); - } - - mode = a; - out.print("workNow status = %d\n", mode); - - return CR_OK; + return CR_WRONG_USAGE; } -void jobCompletedHandler(color_ostream& out, void* ptr) { - if ( mode < 2 ) - return; - +static void jobCompletedHandler(color_ostream& out, void* ptr) { + DEBUG(log,out).print("job completed; poking idlers\n"); *process_jobs = true; *process_dig = true; } From 3dafdf8f24d0ab9a5e3700ec41f0334548dc7e63 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 27 Apr 2023 14:29:50 -0700 Subject: [PATCH 0128/1234] absorb old sphinx anchor --- docs/plugins/work-now.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/plugins/work-now.rst b/docs/plugins/work-now.rst index 517378d56..5eddf7c9f 100644 --- a/docs/plugins/work-now.rst +++ b/docs/plugins/work-now.rst @@ -1,3 +1,5 @@ +.. _worknow: + work-now ======== From 6b7c90b676ec51001a59da1388e3fa8e35ca52bf Mon Sep 17 00:00:00 2001 From: John Cosker Date: Thu, 27 Apr 2023 22:37:56 -0400 Subject: [PATCH 0129/1234] Working C++ and refactors --- plugins/design.cpp | 423 +++++++++++++++++------------------------ plugins/lua/design.lua | 12 +- 2 files changed, 186 insertions(+), 249 deletions(-) diff --git a/plugins/design.cpp b/plugins/design.cpp index 25f876d3e..88d40a630 100644 --- a/plugins/design.cpp +++ b/plugins/design.cpp @@ -11,6 +11,7 @@ #include "PluginManager.h" #include "df/graphic_viewportst.h" #include "df/world.h" +#include "modules/Gui.h" #include "modules/Persistence.h" #include "modules/Screen.h" #include "modules/World.h" @@ -49,8 +50,10 @@ DFhackCExport command_result plugin_init(color_ostream &out, DEBUG(status, out).print("initializing %s\n", plugin_name); // provide a configuration interface for the plugin - commands.push_back( - PluginCommand(plugin_name, "Designs stuff TBD", do_command)); + commands.push_back(PluginCommand( + plugin_name, + "Plugin to handle performance sensitive functions of gui/design", + do_command)); return CR_OK; } @@ -152,150 +155,77 @@ static command_result do_command(color_ostream &out, static int32_t do_cycle(color_ostream &out, bool force_designate) { return 0; } -// Assuming the existence of a class named Point, similar to the one in Lua -class Point { - public: - int x; - int y; +std::map PENS; - Point(int x, int y) : x(x), y(y) {} +struct DrawingPoint { + uint32_t penKey = 0; + std::pair cursor_coords; - bool operator==(const Point &other) const { - return x == other.x && y == other.y; - } + DrawingPoint() : penKey(0), cursor_coords({-1, -1}) {} }; -// Assuming the existence of a class named Color, similar to the one in Lua -class Color { - public: - // Define your color values here -}; +typedef std::map> ShapeMap; +ShapeMap arr; -// Assuming the existence of a class named Pen, similar to the one in Lua -class Pen { - public: - std::string ch; - int tile; - color_value fg; - // Define your pen properties and methods here +bool has_point(int x, int y) { + return arr.count(x) != 0 && arr.at(x).count(y) != 0; }; -class Design { - public: - std::map PENS; - - enum PEN_MASK { - NORTH = 0, - SOUTH, - EAST, - WEST, - DRAG_POINT, - MOUSEOVER, - INSHAPE, - EXTRA_POINT, - NUM_FLAGS - }; - - // Define the function similar to the Lua version - - uint32_t gen_pen_key(bool n, bool s, bool e, bool w, bool is_corner, - bool is_mouse_over, bool inshape, bool extra_point) { - std::bitset ret; - ret[NORTH] = n; - ret[SOUTH] = s; - ret[EAST] = e; - ret[WEST] = w; - ret[DRAG_POINT] = is_corner; - ret[MOUSEOVER] = is_mouse_over; - ret[INSHAPE] = inshape; - ret[EXTRA_POINT] = extra_point; - - return static_cast(ret.to_ulong()); - } - - Pen Design::get_pen(int x, int y, - const std::map> &arr); - // Define the function similar to the Lua version +// Key tuple is N, W, E, S +typedef std::tuple DirectionKey; +std::map> CURSORS_MAP = { + {{false, false, false, false}, {1, 2}}, // INSIDE + {{true, true, false, false}, {0, 1}}, // NW + {{true, false, false, false}, {1, 1}}, // NORTH + {{true, false, true, false}, {2, 1}}, // NE + {{false, true, false, false}, {0, 2}}, // WEST + {{false, false, true, false}, {2, 2}}, // EAST + {{false, true, false, true}, {0, 3}}, // SW + {{false, false, false, true}, {1, 3}}, // SOUTH + {{false, false, true, true}, {2, 3}}, // SE + {{true, true, true, false}, {3, 2}}, // N_NUB + {{true, false, true, true}, {5, 1}}, // E_NUB + {{true, true, false, true}, {3, 1}}, // W_NUB + {{false, true, true, true}, {4, 2}}, // S_NUB + {{false, true, true, false}, {3, 3}}, // VERT_NS + {{true, false, false, true}, {4, 1}}, // VERT_EW + {{true, true, true, true}, {4, 3}}, // POINT }; -Design design; - -// Add other methods and member variables needed for the class - -static int design_getPen(lua_State *L) { - std::map> arr; - if (lua_istable(L, -1)) { - // Iterate over the outer table - lua_pushnil(L); // First key - while (lua_next(L, -2) != 0) { - int x = lua_tointeger(L, -2); // Convert key to an integer - - if (lua_istable(L, -1)) { - // Iterate over the inner table - lua_pushnil(L); // First key - while (lua_next(L, -2) != 0) { - int y = lua_tointeger(L, -2); // Convert key to an integer - bool value = lua_toboolean(L, -1); - - if (value) { - if (arr.count(x) == 0) arr[x] = {}; - arr[x][y] = value; - } - lua_pop(L, 1); // Remove value, keep the key for the next iteration - } - } - lua_pop(L, 1); // Remove inner table, keep the key for the next iteration - } - } +enum PenMask { + North = 0, + South, + East, + West, + DragPoint, + MouseOver, + InShape, + ExtraPoint, + NumFlags +}; - for (auto x : arr) { - for (auto y : x.second) { - Screen::Pen cur_tile = Screen::readTile(x.first, y.first, true); - // cur_tile.tile = selected_tile_texpos; - Pen pen = design.get_pen(x.first, y.first, arr); - cur_tile.tile = pen.tile; - Screen::paintTile(cur_tile, x.first - *window_x, y.first - *window_y, - true); - } - } - return 0; +uint32_t gen_pen_key(bool n, bool s, bool e, bool w, bool is_drag_point, + bool is_mouse_over, bool inshape, bool extra_point) { + std::bitset(PenMask::NumFlags)> ret; + ret[PenMask::North] = n; + ret[PenMask::South] = s; + ret[PenMask::East] = e; + ret[PenMask::West] = w; + ret[PenMask::DragPoint] = is_drag_point; + ret[PenMask::MouseOver] = is_mouse_over; + ret[PenMask::InShape] = inshape; + ret[PenMask::ExtraPoint] = extra_point; + + return ret.to_ulong(); } -enum class CURSORS { - INSIDE, - NORTH, - N_NUB, - S_NUB, - W_NUB, - E_NUB, - NE, - NW, - WEST, - EAST, - SW, - SOUTH, - SE, - VERT_NS, - VERT_EW, - POINT -}; -std::map> CURSORS_MAP = { - {CURSORS::INSIDE, {1, 2}}, {CURSORS::NORTH, {1, 1}}, - {CURSORS::N_NUB, {3, 2}}, {CURSORS::S_NUB, {4, 2}}, - {CURSORS::W_NUB, {3, 1}}, {CURSORS::E_NUB, {5, 1}}, - {CURSORS::NE, {2, 1}}, {CURSORS::NW, {0, 1}}, - {CURSORS::WEST, {0, 2}}, {CURSORS::EAST, {2, 2}}, - {CURSORS::SW, {0, 3}}, {CURSORS::SOUTH, {1, 3}}, - {CURSORS::SE, {2, 3}}, {CURSORS::VERT_NS, {3, 3}}, - {CURSORS::VERT_EW, {4, 1}}, {CURSORS::POINT, {4, 3}}, -}; -Pen make_pen(const std::pair &direction, bool is_corner, - bool is_mouse_over, bool inshape, bool extra_point) { +Screen::Pen make_pen(const std::pair &direction, bool is_drag_point, + bool is_mouse_over, bool inshape, bool extra_point) { color_value color = COLOR_GREEN; int ycursor_mod = 0; if (!extra_point) { - if (is_corner) { + if (is_drag_point) { color = COLOR_CYAN; ycursor_mod += 6; if (is_mouse_over) { @@ -313,140 +243,141 @@ Pen make_pen(const std::pair &direction, bool is_corner, } } - Pen pen; - pen.ch = inshape ? "X" : "o"; + Screen::Pen pen; + pen.ch = inshape ? 'X' : 'o'; pen.fg = color; int selected_tile_texpos = 0; - Screen::findGraphicsTile("CURSORS", direction.first, direction.second, &selected_tile_texpos); + Screen::findGraphicsTile("CURSORS", direction.first, + direction.second + ycursor_mod, + &selected_tile_texpos); pen.tile = selected_tile_texpos; - // Assuming dfhack.screen.findGraphicsTile is replaced with a custom function - // findGraphicsTile pen.tile = findGraphicsTile("CURSORS", direction.first, - // direction.second + ycursor_mod); - return pen; } -Pen Design::get_pen(int x, int y, - const std::map> &arr) { - auto has_point = [&arr](int _x, int _y) { - return arr.count(_x) != 0 && arr.at(_x).count(_y) != 0 && arr.at(_x).at(_y); - }; - bool get_point = has_point(x, y); - - // Basic shapes are bounded by rectangles and therefore can have corner drag - // points even if they're not real points in the shape if (marks.size() >= - // shape.min_points && shape.basic_shape) { - // Point shape_top_left, shape_bot_right; - // shape.get_point_dims(shape_top_left, shape_bot_right); - - // if (x == shape_top_left.x && y == shape_top_left.y && - // shape.drag_corners.nw) { - // drag_point = true; - // } else if (x == shape_bot_right.x && y == shape_top_left.y && - // shape.drag_corners.ne) { - // drag_point = true; - // } else if (x == shape_top_left.x && y == shape_bot_right.y && - // shape.drag_corners.sw) { - // drag_point = true; - // } else if (x == shape_bot_right.x && y == shape_bot_right.y && - // shape.drag_corners.se) { - // drag_point = true; - // } - // } - - // for (const auto& mark : marks) { - // if (mark == Point(x, y)) { - // drag_point = true; - // } - // } - - // if (mirror_point && *mirror_point == Point(x, y)) { - // drag_point = true; - // } - - // // Check for an extra point - // bool extra_point = false; - // for (const auto& point : extra_points) { - // if (x == point.x && y == point.y) { - // extra_point = true; - // break; - // } - // } - - // // Show center point if both marks are set - // if ((shape.basic_shape && marks.size() == shape.max_points) || - // (!shape.basic_shape && !placing_mark.active && !marks.empty())) { - // int center_x, center_y; - // shape.get_center(center_x, center_y); - - // if (x == center_x && y == center_y) { - // extra_point = true; - // } - // } +Screen::Pen get_pen(int x, int y, ShapeMap &arr, const std::string &type = "") { bool n = false, w = false, e = false, s = false; - if (get_point) { + if (has_point(x, y)) { if (y == 0 || !has_point(x, y - 1)) n = true; if (x == 0 || !has_point(x - 1, y)) w = true; - if (!has_point(x + 1, y)) e = true; - if (!has_point(x, y + 1)) s = true; + if (!has_point(x + 1, y)) e = true; // TODO check map size + if (!has_point(x, y + 1)) s = true; // TODO check map size } - // DEBUG(status).print("jcosker %d %d %d %d\n", n, s, e, w); - // Get the bit field to use as a key for the PENS map - uint32_t pen_key = gen_pen_key(n, s, e, w, false, false, get_point, false); - // DEBUG(status).print("jcosker %zu\n", pen_key); + bool is_drag_point = type == "drag_point"; + bool is_extra = type == "extra_point"; + bool is_in_shape = has_point(x, y); + auto mouse_pos = Gui::getMousePos(); + bool mouse_over = mouse_pos.x == x && mouse_pos.y == y; + + uint32_t pen_key = + gen_pen_key(n, s, e, w, is_drag_point, mouse_over, is_in_shape, is_extra); + + if (CURSORS_MAP.count({n, w, e, s}) > 0 && has_point(x,y)) { + arr[x][y].cursor_coords = CURSORS_MAP.at({n, w, e, s}); + } if (PENS.find(pen_key) == PENS.end()) { std::pair cursor{-1, -1}; - // int cursor = -1; // Assuming -1 is an invalid cursor value - - // Determine the cursor to use based on the input parameters - // The CURSORS enum or equivalent should be defined in your code - if (get_point && !n && !w && !e && !s) - cursor = CURSORS_MAP.at(CURSORS::INSIDE); - else if (get_point && n && w && !e && !s) - cursor = CURSORS_MAP.at(CURSORS::NW); - else if (get_point && n && !w && !e && !s) - cursor = CURSORS_MAP.at(CURSORS::NORTH); - else if (get_point && n && e && !w && !s) - cursor = CURSORS_MAP.at(CURSORS::NE); - else if (get_point && !n && w && !e && !s) - cursor = CURSORS_MAP.at(CURSORS::WEST); - else if (get_point && !n && !w && e && !s) - cursor = CURSORS_MAP.at(CURSORS::EAST); - else if (get_point && !n && w && !e && s) - cursor = CURSORS_MAP.at(CURSORS::SW); - else if (get_point && !n && !w && !e && s) - cursor = CURSORS_MAP.at(CURSORS::SOUTH); - else if (get_point && !n && !w && e && s) - cursor = CURSORS_MAP.at(CURSORS::SE); - else if (get_point && n && w && e && !s) - cursor = CURSORS_MAP.at(CURSORS::N_NUB); - else if (get_point && n && !w && e && s) - cursor = CURSORS_MAP.at(CURSORS::E_NUB); - else if (get_point && n && w && !e && s) - cursor = CURSORS_MAP.at(CURSORS::W_NUB); - else if (get_point && !n && w && e && s) - cursor = CURSORS_MAP.at(CURSORS::S_NUB); - else if (get_point && !n && w && e && !s) - cursor = CURSORS_MAP.at(CURSORS::VERT_NS); - else if (get_point && n && !w && !e && s) - cursor = CURSORS_MAP.at(CURSORS::VERT_EW); - else if (get_point && n && w && e && s) - cursor = CURSORS_MAP.at(CURSORS::POINT); - // else if (drag_point && !get_point) cursor = CURSORS::INSIDE; - // else if (extra_point) cursor = CURSORS::INSIDE; - // Create the pen if the cursor is set - - DEBUG(status).print("jcosker %d, %d\n", cursor.first, cursor.second); - if (cursor.first != -1) { - PENS[pen_key] = make_pen(cursor, false, false, get_point, false); + + if (type != "") { + return make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, mouse_over, + is_in_shape, is_extra); + } + + if (CURSORS_MAP.count({n, w, e, s}) > 0) { + PENS.emplace(pen_key, + make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, + mouse_over, is_in_shape, is_extra)); + if (type == "" && has_point(x,y)) { + arr[x][y].penKey = pen_key; + } } } - // Return the pen for the caller + // DEBUG(status).print("not cached lmao\n"); return PENS.at(pen_key); } -DFHACK_PLUGIN_LUA_COMMANDS{DFHACK_LUA_COMMAND(design_getPen), DFHACK_LUA_END}; +static int design_load_shape(lua_State *L) { + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + int x = lua_tointeger(L, -2); + + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + int y = lua_tointeger(L, -2); + bool value = lua_toboolean(L, -1); + + if (value) { + arr[x][y] = DrawingPoint(); + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); + } + } + + return 0; +} + +static int design_clear_shape(lua_State *L) { + arr.clear(); + + return 0; +} + +static int design_draw_shape(lua_State *L) { + if (arr.size() == 0) { + design_load_shape(L); + } + + for (auto x : arr) { + for (auto y : x.second) { + Screen::Pen cur_tile = Screen::readTile(x.first, y.first, true); + Screen::Pen pen = get_pen(x.first, y.first, arr); + cur_tile.tile = pen.tile; + Screen::paintTile(cur_tile, x.first - *window_x, y.first - *window_y, + true); + } + } + + return 0; +} + +static int design_draw_points(lua_State *L) { + if (lua_istable(L, -1)) { + const char *str; + lua_rawgeti(L, -1, 2); + str = lua_tostring(L, -1); + lua_pop(L, 1); + + lua_rawgeti(L, -1, 1); + int n = luaL_len(L, -1); + for (int i = 1; i <= n; i++) { + lua_rawgeti(L, -1, i); + int x, y; + lua_getfield(L, -1, "y"); + y = lua_tointeger(L, -1); + lua_getfield(L, -2, "x"); + x = lua_tointeger(L, -1); + lua_pop(L, 3); + + Screen::Pen cur_tile = Screen::readTile(x, y, true); + Screen::Pen pen = get_pen(x, y, arr, str); + cur_tile.tile = pen.tile; + Screen::paintTile(cur_tile, x - *window_x, y - *window_y, true); + } + lua_pop(L, 1); + } + + return 0; +} + +DFHACK_PLUGIN_LUA_COMMANDS{DFHACK_LUA_COMMAND(design_draw_shape), + DFHACK_LUA_COMMAND(design_draw_points), + DFHACK_LUA_COMMAND(design_clear_shape), + DFHACK_LUA_END}; diff --git a/plugins/lua/design.lua b/plugins/lua/design.lua index fe916aa41..eb9dd3d9a 100644 --- a/plugins/lua/design.lua +++ b/plugins/lua/design.lua @@ -1,9 +1,15 @@ local _ENV = mkmodule('plugins.design') -view2 = {design_window = { name = "hello"}} +function draw_shape(arr) + design_draw_shape(arr) +end + +function draw_points(points_obj) + design_draw_points(points_obj) +end -function getPen(hi) - design_getPen(hi) +function clear_shape(arr) + design_clear_shape(arr) end return _ENV From f61d25bdebc3ee2b93eaf78d0e2102139a3bf907 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 29 Apr 2023 18:46:13 -0700 Subject: [PATCH 0130/1234] bump to 50.08-r1 --- CMakeLists.txt | 6 +++--- library/xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6b5d2949..4228f45cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,9 +191,9 @@ if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl endif() # set up versioning. -set(DF_VERSION "50.08b1") -set(DFHACK_RELEASE "beta4") -set(DFHACK_PRERELEASE TRUE) +set(DF_VERSION "50.08") +set(DFHACK_RELEASE "r1") +set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/library/xml b/library/xml index 98d5f8a55..113f5e40b 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 98d5f8a5553690ef71b9650b28d4aababf21ef5e +Subproject commit 113f5e40b471c67b5414380f477d1c7be9b635ee From 923f84b2f296c6a6f4fa00af37766b05fe3485e8 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 29 Apr 2023 18:58:34 -0700 Subject: [PATCH 0131/1234] bump to 50.08-r1 --- docs/changelog.txt | 20 ++++++++++++++++---- library/xml | 2 +- scripts | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 66904aa6d..e3ec3ca40 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -35,6 +35,22 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 50.08-r1 + +## New Plugins + ## Fixes - `autoclothing`: eliminate game lag when there are many inventory items in the fort - `buildingplan`: fixed size limit calculations for rollers @@ -51,10 +67,6 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - ``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 -## Documentation - -## API - ## Lua - ``widgets.RangeSlider``: new mouse-controlled two-headed slider widget - ``gui.ZScreenModal``: ZScreen subclass for modal dialogs diff --git a/library/xml b/library/xml index 113f5e40b..6a620feac 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 113f5e40b471c67b5414380f477d1c7be9b635ee +Subproject commit 6a620feacc85224742d8a97f633c9106ff7d81e8 diff --git a/scripts b/scripts index ad1998a00..70788484b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ad1998a0032ce50e90d05429a4178b668c0840ba +Subproject commit 70788484b4cf797aa71e5c6737cb77838407a677 From ffa9f79f941e1e58f591f9d45d715e7114c40a50 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 29 Apr 2023 22:30:42 -0700 Subject: [PATCH 0132/1234] rightsize ccache, protect steam sdk from eviction --- .github/workflows/build.yml | 8 ++++++++ .github/workflows/steam.yml | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f03d8b3b0..39be29f9c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,6 +72,12 @@ jobs: # - name: Download DF # run: | # sh ci/download-df.sh + - name: Restore steam SDK + uses: actions/cache@v3 + with: + path: depends/steam + key: steam-sdk-156 + enableCrossOsArchive: true - name: Configure DFHack env: CC: gcc-${{ matrix.gcc }} @@ -94,6 +100,8 @@ jobs: - name: Build DFHack run: | ninja -C build-ci install + ccache --max-size 100M + ccache --cleanup ccache --show-stats - name: Run cpp unit tests id: run_tests_cpp diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 33aa16d34..4c275e032 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -14,8 +14,8 @@ on: release_channel: description: Release channel type: string - required: false - default: beta + required: true + default: staging jobs: deploy-to-steam: @@ -34,12 +34,12 @@ jobs: 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-${{ github.event.inputs.commit_hash }} ccache-win64-cross-msvc - name: Restore steam SDK uses: actions/cache@v3 with: - path: depends/steam/steamworks_sdk_156.zip + path: depends/steam key: steam-sdk-156 enableCrossOsArchive: true - name: Cross-compile win64 artifacts From b69aff4d6eed64fe244255c7134ca65b54a3047a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 29 Apr 2023 23:19:02 -0700 Subject: [PATCH 0133/1234] reduce cache for msvc builds too; remove ruby --- .github/workflows/build.yml | 18 ++++-------------- .github/workflows/steam.yml | 3 +++ 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 39be29f9c..034c8c7cf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -100,7 +100,7 @@ jobs: - name: Build DFHack run: | ninja -C build-ci install - ccache --max-size 100M + ccache --max-size 200M ccache --cleanup ccache --show-stats - name: Run cpp unit tests @@ -155,6 +155,9 @@ jobs: run: | cd build bash -x build-win64-from-linux.sh + ccache -d build/win64-cross/ccache --max-size 200M + ccache -d build/win64-cross/ccache --cleanup + ccache -d build/win64-cross/ccache --show-stats - name: Format artifact name id: artifactname run: | @@ -182,11 +185,6 @@ jobs: - 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: runs-on: ubuntu-22.04 @@ -195,10 +193,6 @@ jobs: uses: actions/setup-python@v4 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 @@ -223,10 +217,6 @@ jobs: 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: runs-on: ubuntu-latest diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 4c275e032..057ba3fd5 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -54,6 +54,9 @@ jobs: echo cd build bash -x build-win64-from-linux.sh + ccache -d build/win64-cross/ccache --max-size 200M + ccache -d build/win64-cross/ccache --cleanup + ccache -d build/win64-cross/ccache --show-stats - name: Steam deploy uses: game-ci/steam-deploy@v2 with: From 17a423bcd2eaae7c823e94e94da295597e32824d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 29 Apr 2023 23:31:44 -0700 Subject: [PATCH 0134/1234] ensure msvc builds have ccache --- .github/workflows/build.yml | 4 ++++ .github/workflows/steam.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 034c8c7cf..a8495cf8a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -136,6 +136,10 @@ jobs: name: Build MSVC 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: diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 057ba3fd5..dda9b1618 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -22,6 +22,10 @@ jobs: name: Deploy to Steam 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: From 7aa5692fef32fa88dff776f801db90cb091d7db8 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 29 Apr 2023 23:46:06 -0700 Subject: [PATCH 0135/1234] reduce linux ccache size; fix msvc ccache path --- .github/workflows/build.yml | 8 ++++---- .github/workflows/steam.yml | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a8495cf8a..131c21743 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -100,7 +100,7 @@ jobs: - name: Build DFHack run: | ninja -C build-ci install - ccache --max-size 200M + ccache --max-size 50M ccache --cleanup ccache --show-stats - name: Run cpp unit tests @@ -159,9 +159,9 @@ jobs: run: | cd build bash -x build-win64-from-linux.sh - ccache -d build/win64-cross/ccache --max-size 200M - ccache -d build/win64-cross/ccache --cleanup - ccache -d build/win64-cross/ccache --show-stats + ccache -d win64-cross/ccache --max-size 200M + ccache -d win64-cross/ccache --cleanup + ccache -d win64-cross/ccache --show-stats - name: Format artifact name id: artifactname run: | diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index dda9b1618..5210b3a11 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -58,9 +58,9 @@ jobs: echo cd build bash -x build-win64-from-linux.sh - ccache -d build/win64-cross/ccache --max-size 200M - ccache -d build/win64-cross/ccache --cleanup - ccache -d build/win64-cross/ccache --show-stats + ccache -d win64-cross/ccache --max-size 200M + ccache -d win64-cross/ccache --cleanup + ccache -d win64-cross/ccache --show-stats - name: Steam deploy uses: game-ci/steam-deploy@v2 with: From cfcb1cd937fc2f513ffde0a81ab2357bce517cb5 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Sun, 30 Apr 2023 10:18:15 +0200 Subject: [PATCH 0136/1234] make val_sep useful if label_below == true --- docs/dev/Lua API.rst | 4 ++-- library/lua/gui/widgets.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 37d85f7f6..8ebb752c9 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4918,11 +4918,11 @@ It has the following attributes: hotkey. :label_width: The number of spaces to allocate to the ``label`` (for use in aligning a column of ``CycleHotkeyLabel`` labels). -:label_below: If ``true``, then the option value will 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``. :val_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. - Note that ``val_gap`` is ignored if ``label_below`` is set to ``true``. + If ``label_below`` == ``true``, negative values will shift the value leftwards. :options: A list of strings or tables of ``{label=string or fn, value=val[, pen=pen]}``. String options use the same string for the label and value and use the default pen. The optional ``pen`` diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index c7cde698c..210b71f7b 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1502,7 +1502,7 @@ function CycleHotkeyLabel:init() self:setOption(self.initial_option) if self.label_below then - self.val_gap = 0 + (self.key_back and 1 or 0) + (self.key and 3 or 0) + self.val_gap = self.val_gap + (self.key_back and 1 or 0) + (self.key and 2 or 0) end self:setText{ From 0d6c5869f49f7cdec4443c0754c6fdc45e27182b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 30 Apr 2023 16:40:03 -0700 Subject: [PATCH 0137/1234] fix logo disappearing when hovered on title screen --- docs/changelog.txt | 1 + plugins/lua/overlay.lua | 25 +++++++++++++------------ plugins/overlay.cpp | 3 ++- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index e3ec3ca40..d0855dbc8 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -36,6 +36,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins ## Fixes +- `hotkeys`: DFHack logo no longer disappears when hovered on the title screen ## Misc Improvements diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index b1960989f..84c2b4f96 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -447,7 +447,7 @@ function update_hotspot_widgets() end end -local function matches_focus_strings(db_entry, vs_name) +local function matches_focus_strings(db_entry, vs_name, vs) if not db_entry.focus_strings then return true end local matched = true local simple_vs_name = simplify_viewscreen_name(vs_name) @@ -465,9 +465,10 @@ end local function _update_viewscreen_widgets(vs_name, vs, now_ms) local vs_widgets = active_viewscreen_widgets[vs_name] if not vs_widgets then return end + local is_all = vs_name == 'all' now_ms = now_ms or dfhack.getTickCount() for name,db_entry in pairs(vs_widgets) do - if matches_focus_strings(db_entry, vs_name) and + if (is_all or matches_focus_strings(db_entry, vs_name, vs)) and do_update(name, db_entry, now_ms, vs) then return end @@ -483,12 +484,12 @@ function update_viewscreen_widgets(vs_name, vs) end end -local function _feed_viewscreen_widgets(vs_name, keys) +local function _feed_viewscreen_widgets(vs_name, vs, keys) local vs_widgets = active_viewscreen_widgets[vs_name] if not vs_widgets then return false end for _,db_entry in pairs(vs_widgets) do local w = db_entry.widget - if matches_focus_strings(db_entry, vs_name) and + if (not vs or matches_focus_strings(db_entry, vs_name, vs)) and detect_frame_change(w, function() return w:onInput(keys) end) then return true end @@ -496,9 +497,9 @@ local function _feed_viewscreen_widgets(vs_name, keys) return false end -function feed_viewscreen_widgets(vs_name, keys) - if not _feed_viewscreen_widgets(vs_name, keys) and - not _feed_viewscreen_widgets('all', keys) then +function feed_viewscreen_widgets(vs_name, vs, keys) + if not _feed_viewscreen_widgets(vs_name, vs, keys) and + not _feed_viewscreen_widgets('all', nil, keys) then return false end gui.markMouseClicksHandled(keys) @@ -508,13 +509,13 @@ function feed_viewscreen_widgets(vs_name, keys) return true end -local function _render_viewscreen_widgets(vs_name, dc) +local function _render_viewscreen_widgets(vs_name, vs, dc) local vs_widgets = active_viewscreen_widgets[vs_name] if not vs_widgets then return end dc = dc or gui.Painter.new() for _,db_entry in pairs(vs_widgets) do local w = db_entry.widget - if matches_focus_strings(db_entry, vs_name) then + if not vs or matches_focus_strings(db_entry, vs_name, vs) then detect_frame_change(w, function() w:render(dc) end) end end @@ -523,9 +524,9 @@ end local force_refresh -function render_viewscreen_widgets(vs_name) - local dc = _render_viewscreen_widgets(vs_name, nil) - _render_viewscreen_widgets('all', dc) +function render_viewscreen_widgets(vs_name, vs) + local dc = _render_viewscreen_widgets(vs_name, vs, nil) + _render_viewscreen_widgets('all', nil, dc) if force_refresh then force_refresh = nil df.global.gps.force_full_display_count = 1 diff --git a/plugins/overlay.cpp b/plugins/overlay.cpp index 8e27c8308..c02c960ba 100644 --- a/plugins/overlay.cpp +++ b/plugins/overlay.cpp @@ -72,9 +72,10 @@ struct viewscreen_overlay : T { bool input_is_handled = false; // don't send input to the overlays if there is a modal dialog up if (!world->status.popups.size()) - call_overlay_lua(NULL, "feed_viewscreen_widgets", 2, 1, + call_overlay_lua(NULL, "feed_viewscreen_widgets", 3, 1, [&](lua_State *L) { Lua::Push(L, T::_identity.getName()); + Lua::Push(L, this); Lua::PushInterfaceKeys(L, *input); }, [&](lua_State *L) { input_is_handled = lua_toboolean(L, -1); From 3f51f24f9161ecc3417b52acc6244822e9f0a44b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 30 Apr 2023 17:12:43 -0700 Subject: [PATCH 0138/1234] fix errors when dragging a scrollbar and the mouse leaves the window --- library/lua/gui/widgets.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index c7cde698c..7eeb00f1f 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -836,7 +836,9 @@ function Scrollbar:update(top_elem, elems_per_page, num_elems) end local function scrollbar_do_drag(scrollbar) - local _,y = scrollbar.frame_body:localXY(dfhack.screen.getMousePos()) + local x,y = dfhack.screen.getMousePos() + if not y then return end + x,y = scrollbar.frame_body:localXY(x, y) local cur_pos = y - scrollbar.is_dragging local max_top = scrollbar.num_elems - scrollbar.elems_per_page + 1 local max_pos = scrollbar_get_max_pos_and_height(scrollbar) From 528dc466e2d2f6e8114282c7d23eb2e0090a66e1 Mon Sep 17 00:00:00 2001 From: John Cosker Date: Mon, 1 May 2023 14:20:53 -0400 Subject: [PATCH 0139/1234] address review comments --- plugins/CMakeLists.txt | 2 +- plugins/design.cpp | 122 ++--------------------------------------- plugins/lua/design.lua | 12 ---- 3 files changed, 6 insertions(+), 130 deletions(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index c880a89ff..943bc311c 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -77,8 +77,8 @@ set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) #dfhack_plugin(add-spatter add-spatter.cpp) dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua) dfhack_plugin(autochop autochop.cpp LINK_LIBRARIES lua) +dfhack_plugin(autoclothing autoclothing.cpp LINK_LIBRARIES lua) dfhack_plugin(design design.cpp LINK_LIBRARIES lua) -dfhack_plugin(autoclothing autoclothing.cpp) dfhack_plugin(autodump autodump.cpp) dfhack_plugin(autofarm autofarm.cpp) #dfhack_plugin(autogems autogems.cpp LINK_LIBRARIES jsoncpp_static) diff --git a/plugins/design.cpp b/plugins/design.cpp index 88d40a630..1abd61842 100644 --- a/plugins/design.cpp +++ b/plugins/design.cpp @@ -30,131 +30,19 @@ using namespace df::enums; enum ConfigValues { CONFIG_IS_ENABLED = 0, }; -namespace DFHack { -// // for configuration-related logging -DBG_DECLARE(design, status, DebugCategory::LDEBUG); -// for logging during the periodic scan -DBG_DECLARE(design, cycle, DebugCategory::LDEBUG); -} // namespace DFHack -static const std::string CONFIG_KEY = std::string(plugin_name) + "/config"; -static PersistentDataItem config; -static const int32_t CYCLE_TICKS = 1200; -static int32_t cycle_timestamp = 0; // world->frame_counter at last cycle - -static command_result do_command(color_ostream &out, - std::vector ¶meters); -static int32_t do_cycle(color_ostream &out, bool force_designate = false); - -DFhackCExport command_result plugin_init(color_ostream &out, - std::vector &commands) { - DEBUG(status, out).print("initializing %s\n", plugin_name); - - // provide a configuration interface for the plugin - commands.push_back(PluginCommand( - plugin_name, - "Plugin to handle performance sensitive functions of gui/design", - do_command)); - - return CR_OK; -} -static int get_config_val(PersistentDataItem &c, int index) { - if (!c.isValid()) return -1; - return c.ival(index); -} - -static bool get_config_bool(PersistentDataItem &c, int index) { - return get_config_val(c, index) == 1; -} - -static void set_config_val(PersistentDataItem &c, int index, int value) { - if (c.isValid()) c.ival(index) = value; +namespace DFHack { + DBG_DECLARE(pathable, log, DebugCategory::LINFO); } -static void set_config_bool(PersistentDataItem &c, int index, bool value) { - set_config_val(c, index, value ? 1 : 0); -} - -DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { - if (!Core::getInstance().isWorldLoaded()) { - out.printerr("Cannot enable %s without a loaded world.\n", plugin_name); - - return CR_FAILURE; - } - - if (enable != is_enabled) { - is_enabled = enable; - DEBUG(status, out) - .print("%s from the API; persisting\n", - is_enabled ? "enabled" : "disabled"); - set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); - if (enable) do_cycle(out, true); - } else { - DEBUG(status, out) - .print("%s from the API, but already %s; no action\n", - is_enabled ? "enabled" : "disabled", - is_enabled ? "enabled" : "disabled"); - } - return CR_OK; +DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { + return CR_OK; } DFhackCExport command_result plugin_shutdown(color_ostream &out) { - DEBUG(status, out).print("shutting down %s\n", plugin_name); - - return CR_OK; + return CR_OK; } -DFhackCExport command_result plugin_load_data(color_ostream &out) { - cycle_timestamp = 0; - config = World::GetPersistentData(CONFIG_KEY); - - if (!config.isValid()) { - DEBUG(status, out).print("no config found in this save; initializing\n"); - config = World::AddPersistentData(CONFIG_KEY); - set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); - } - - // we have to copy our enabled flag into the global plugin variable, but - // all the other state we can directly read/modify from the persistent - // data structure. - is_enabled = get_config_bool(config, CONFIG_IS_ENABLED); - DEBUG(status, out) - .print("loading persisted enabled state: %s\n", - is_enabled ? "true" : "false"); - - return CR_OK; -} - -DFhackCExport command_result plugin_onstatechange(color_ostream &out, - state_change_event event) { - if (event == DFHack::SC_WORLD_UNLOADED) { - if (is_enabled) { - DEBUG(status, out).print("world unloaded; disabling %s\n", plugin_name); - is_enabled = false; - } - } - - return CR_OK; -} - -DFhackCExport command_result plugin_onupdate(color_ostream &out) { - if (is_enabled && world->frame_counter - cycle_timestamp >= CYCLE_TICKS) { - int32_t ret = do_cycle(out); - } - - return CR_OK; -} -int selected_tile_texpos = 0; -const static bool hi = - Screen::findGraphicsTile("CURSORS", 4, 3, &selected_tile_texpos); - -static command_result do_command(color_ostream &out, - std::vector ¶meters) { - return CR_OK; -} - -static int32_t do_cycle(color_ostream &out, bool force_designate) { return 0; } - std::map PENS; struct DrawingPoint { diff --git a/plugins/lua/design.lua b/plugins/lua/design.lua index eb9dd3d9a..ec3b4c79b 100644 --- a/plugins/lua/design.lua +++ b/plugins/lua/design.lua @@ -1,15 +1,3 @@ local _ENV = mkmodule('plugins.design') -function draw_shape(arr) - design_draw_shape(arr) -end - -function draw_points(points_obj) - design_draw_points(points_obj) -end - -function clear_shape(arr) - design_clear_shape(arr) -end - return _ENV From 0eb04f1b73d61752245a4113d89183840c55cfa2 Mon Sep 17 00:00:00 2001 From: John Cosker Date: Mon, 1 May 2023 14:32:09 -0400 Subject: [PATCH 0140/1234] changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 66904aa6d..e1e45f799 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -50,6 +50,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `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 +- `gui/design`: Improved performance for drawing shapes ## Documentation From ef0c8950bd60818b5fa807609f95fc330cc5e8c0 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Tue, 2 May 2023 16:46:46 +0200 Subject: [PATCH 0141/1234] renamed val_gap to option_gap, updated docs/changelog --- docs/changelog.txt | 2 +- docs/dev/Lua API.rst | 2 +- library/lua/gui/widgets.lua | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index e3ec3ca40..792d09167 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -70,7 +70,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Lua - ``widgets.RangeSlider``: new mouse-controlled two-headed slider widget - ``gui.ZScreenModal``: ZScreen subclass for modal dialogs -- ``widgets.CycleHotkeyLabel``: exposed "key_sep" and "val_gap" attributes for improved stylistic control. +- ``widgets.CycleHotkeyLabel``: exposed "key_sep" and "option_gap" attributes for improved stylistic control. ## Removed - `title-version`: replaced by an `overlay` widget diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 8ebb752c9..85e51d11d 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4920,7 +4920,7 @@ It has the following attributes: aligning a column of ``CycleHotkeyLabel`` labels). :label_below: If ``true``, then the option value will appear below the label instead of to the right of it. Defaults to ``false``. -:val_gap: The size of the gap between the label text and the option value. +: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 diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 2e1732f11..7aa79cbc3 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1491,7 +1491,7 @@ CycleHotkeyLabel.ATTRS{ key=DEFAULT_NIL, key_back=DEFAULT_NIL, key_sep=': ', - val_gap=1, + option_gap=1, label=DEFAULT_NIL, label_width=DEFAULT_NIL, label_below=false, @@ -1504,7 +1504,7 @@ function CycleHotkeyLabel:init() self:setOption(self.initial_option) if self.label_below then - self.val_gap = self.val_gap + (self.key_back and 1 or 0) + (self.key and 2 or 0) + self.option_gap = self.option_gap + (self.key_back and 1 or 0) + (self.key and 2 or 0) end self:setText{ @@ -1512,7 +1512,7 @@ function CycleHotkeyLabel:init() {key=self.key, key_sep=self.key_sep, text=self.label, width=self.label_width, on_activate=self:callback('cycle')}, self.label_below and NEWLINE or '', - {gap=self.val_gap, text=self:callback('getOptionLabel'), + {gap=self.option_gap, text=self:callback('getOptionLabel'), pen=self:callback('getOptionPen')}, } end From c1a0d1ad8665acbbe87538518545b635050c1b54 Mon Sep 17 00:00:00 2001 From: Myk Date: Tue, 2 May 2023 09:55:35 -0700 Subject: [PATCH 0142/1234] Update changelog.txt --- docs/changelog.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index d0855dbc8..e3ec3ca40 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -36,7 +36,6 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins ## Fixes -- `hotkeys`: DFHack logo no longer disappears when hovered on the title screen ## Misc Improvements From d21a6c6432b14a12070387db1f2ca4c2003efba7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 2 May 2023 14:34:45 -0700 Subject: [PATCH 0143/1234] update symbols for 50.08 itch and classic --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 6a620feac..22d9bc0bc 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 6a620feacc85224742d8a97f633c9106ff7d81e8 +Subproject commit 22d9bc0bc1847def8a6c62893104f36262e63e98 From 8b6d20ae9e8e25feed9c851bcb68e041aaf84ece Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 3 May 2023 07:14:37 +0000 Subject: [PATCH 0144/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 70788484b..8c0624942 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 70788484b4cf797aa71e5c6737cb77838407a677 +Subproject commit 8c0624942ed11b369be805b2c0b5bc5ffd14f13d From bebf3584badfd753ed7f9ad5dd70dcf604ee9d94 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 2 May 2023 21:06:46 -0700 Subject: [PATCH 0145/1234] maybe fix terminal in foreground issue --- docs/changelog.txt | 1 + library/Console-windows.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 2b800fc42..924adbd31 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -40,6 +40,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes ## Misc Improvements +- Terminal console no longer appears in front of the game window on startup ## Documentation diff --git a/library/Console-windows.cpp b/library/Console-windows.cpp index 515d89911..dd8ce9d84 100644 --- a/library/Console-windows.cpp +++ b/library/Console-windows.cpp @@ -508,6 +508,7 @@ bool Console::init(bool) inited = true; // DOESN'T WORK - locks up DF! // ForceForegroundWindow(d->MainWindow); + SetForegroundWindow(d->MainWindow); return true; } // FIXME: looks awfully empty, doesn't it? @@ -608,6 +609,7 @@ void Console::msleep (unsigned int msec) bool Console::hide() { ShowWindow( GetConsoleWindow(), SW_HIDE ); + SetForegroundWindow(d->MainWindow); return true; } From ad5a0d41f5c4a56d955032c1e456527fe93bb5cc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 3 May 2023 14:34:48 -0700 Subject: [PATCH 0146/1234] only show the terminal if requested --- library/Console-windows.cpp | 3 +-- library/Core.cpp | 10 +++------- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/library/Console-windows.cpp b/library/Console-windows.cpp index dd8ce9d84..20d943b18 100644 --- a/library/Console-windows.cpp +++ b/library/Console-windows.cpp @@ -508,7 +508,7 @@ bool Console::init(bool) inited = true; // DOESN'T WORK - locks up DF! // ForceForegroundWindow(d->MainWindow); - SetForegroundWindow(d->MainWindow); + hide(); return true; } // FIXME: looks awfully empty, doesn't it? @@ -609,7 +609,6 @@ void Console::msleep (unsigned int msec) bool Console::hide() { ShowWindow( GetConsoleWindow(), SW_HIDE ); - SetForegroundWindow(d->MainWindow); return true; } diff --git a/library/Core.cpp b/library/Core.cpp index f1bb28925..9ff6976d5 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1304,10 +1304,6 @@ static void run_dfhack_init(color_ostream &out, Core *core) return; } - // if we're running on Steam Deck, hide the terminal by default - if (DFSteam::DFIsSteamRunningOnSteamDeck()) - core->getConsole().hide(); - // load baseline defaults core->loadScriptFile(out, CONFIG_PATH + "init/default.dfhack.init", false); @@ -1315,13 +1311,13 @@ static void run_dfhack_init(color_ostream &out, Core *core) std::vector prefixes(1, "dfhack"); loadScriptFiles(core, out, prefixes, CONFIG_PATH + "init"); - // if the option is set, hide the terminal + // show the terminal if requested auto L = Lua::Core::State; Lua::StackUnwinder top(L); Lua::CallLuaModuleFunction(out, L, "dfhack", "getHideConsoleOnStartup", 0, 1, Lua::DEFAULT_LUA_LAMBDA, [&](lua_State* L) { - if (lua_toboolean(L, -1)) - core->getConsole().hide(); + if (!lua_toboolean(L, -1)) + core->getConsole().show(); }, false); } From 8f5c454b398e2c12e223ca083a90444ad0ed5d63 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 3 May 2023 15:52:01 -0700 Subject: [PATCH 0147/1234] add focus strings for new_region --- library/modules/Gui.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 44642b5fa..d03bcce09 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -84,6 +84,7 @@ using namespace DFHack; #include "df/unit.h" #include "df/unit_inventory_item.h" #include "df/viewscreen_dwarfmodest.h" +#include "df/viewscreen_new_regionst.h" #include "df/viewscreen_titlest.h" #include "df/world.h" @@ -156,6 +157,19 @@ DEFINE_GET_FOCUS_STRING_HANDLER(title) focusStrings.push_back(baseFocus + "/Default"); } +DEFINE_GET_FOCUS_STRING_HANDLER(new_region) +{ + if (screen->doing_mods) + focusStrings.push_back(baseFocus + "/Mods"); + else if (screen->doing_simple_params) + focusStrings.push_back(baseFocus + "/Basic"); + else if (screen->doing_params) + focusStrings.push_back(baseFocus + "/Advanced"); + + if (focusStrings.empty()) + focusStrings.push_back(baseFocus); +} + DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) { std::string newFocusString; From 58e11b01cba07e3721ea1dc795b3f9258354bfc0 Mon Sep 17 00:00:00 2001 From: John Cosker Date: Wed, 3 May 2023 19:37:44 -0400 Subject: [PATCH 0148/1234] Comments --- docs/changelog.txt | 1 + plugins/design.cpp | 313 ++++++++++++++++++++++----------------------- 2 files changed, 157 insertions(+), 157 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index a7ce7c25f..0a37bb3b9 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -41,6 +41,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - Terminal console no longer appears in front of the game window on startup +- `gui/design`: Improved performance for drawing shapes ## Documentation diff --git a/plugins/design.cpp b/plugins/design.cpp index 1abd61842..37ee32cbd 100644 --- a/plugins/design.cpp +++ b/plugins/design.cpp @@ -17,7 +17,6 @@ #include "modules/World.h" DFHACK_PLUGIN("design"); -DFHACK_PLUGIN_IS_ENABLED(is_enabled); using DFHack::color_value; REQUIRE_GLOBAL(window_x); @@ -27,36 +26,37 @@ REQUIRE_GLOBAL(plotinfo); using namespace DFHack; using namespace df::enums; -enum ConfigValues { - CONFIG_IS_ENABLED = 0, -}; - namespace DFHack { - DBG_DECLARE(pathable, log, DebugCategory::LINFO); +DBG_DECLARE(design, log, DebugCategory::LINFO); } -DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { +DFhackCExport command_result plugin_init(color_ostream &out, + std::vector &commands) { return CR_OK; } -DFhackCExport command_result plugin_shutdown(color_ostream &out) { +std::map PENS; + +DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { + if (event == DFHack::SC_WORLD_UNLOADED) { + DEBUG(log,out).print("clearing PENS\n"); + PENS.clear(); + } return CR_OK; } -std::map PENS; - struct DrawingPoint { - uint32_t penKey = 0; - std::pair cursor_coords; + uint32_t penKey = 0; + std::pair cursor_coords; - DrawingPoint() : penKey(0), cursor_coords({-1, -1}) {} + DrawingPoint() : penKey(0), cursor_coords({-1, -1}) {} }; typedef std::map> ShapeMap; ShapeMap arr; bool has_point(int x, int y) { - return arr.count(x) != 0 && arr.at(x).count(y) != 0; + return arr.count(x) != 0 && arr.at(x).count(y) != 0; }; // Key tuple is N, W, E, S @@ -81,188 +81,187 @@ std::map> CURSORS_MAP = { }; enum PenMask { - North = 0, - South, - East, - West, - DragPoint, - MouseOver, - InShape, - ExtraPoint, - NumFlags + North = 0, + South, + East, + West, + DragPoint, + MouseOver, + InShape, + ExtraPoint, + NumFlags }; uint32_t gen_pen_key(bool n, bool s, bool e, bool w, bool is_drag_point, bool is_mouse_over, bool inshape, bool extra_point) { - std::bitset(PenMask::NumFlags)> ret; - ret[PenMask::North] = n; - ret[PenMask::South] = s; - ret[PenMask::East] = e; - ret[PenMask::West] = w; - ret[PenMask::DragPoint] = is_drag_point; - ret[PenMask::MouseOver] = is_mouse_over; - ret[PenMask::InShape] = inshape; - ret[PenMask::ExtraPoint] = extra_point; - - return ret.to_ulong(); + std::bitset(PenMask::NumFlags)> ret; + ret[PenMask::North] = n; + ret[PenMask::South] = s; + ret[PenMask::East] = e; + ret[PenMask::West] = w; + ret[PenMask::DragPoint] = is_drag_point; + ret[PenMask::MouseOver] = is_mouse_over; + ret[PenMask::InShape] = inshape; + ret[PenMask::ExtraPoint] = extra_point; + + return ret.to_ulong(); } Screen::Pen make_pen(const std::pair &direction, bool is_drag_point, bool is_mouse_over, bool inshape, bool extra_point) { - color_value color = COLOR_GREEN; - int ycursor_mod = 0; - - if (!extra_point) { - if (is_drag_point) { - color = COLOR_CYAN; - ycursor_mod += 6; - if (is_mouse_over) { - color = COLOR_MAGENTA; - ycursor_mod += 3; - } - } - } else { - ycursor_mod += 15; - color = COLOR_LIGHTRED; + color_value color = COLOR_GREEN; + int ycursor_mod = 0; + + if (!extra_point) { + if (is_drag_point) { + color = COLOR_CYAN; + ycursor_mod += 6; + if (is_mouse_over) { + color = COLOR_MAGENTA; + ycursor_mod += 3; + } + } + } else { + ycursor_mod += 15; + color = COLOR_LIGHTRED; - if (is_mouse_over) { - color = COLOR_RED; - ycursor_mod += 3; + if (is_mouse_over) { + color = COLOR_RED; + ycursor_mod += 3; + } } - } - - Screen::Pen pen; - pen.ch = inshape ? 'X' : 'o'; - pen.fg = color; - int selected_tile_texpos = 0; - Screen::findGraphicsTile("CURSORS", direction.first, - direction.second + ycursor_mod, - &selected_tile_texpos); - pen.tile = selected_tile_texpos; - - return pen; + + Screen::Pen pen; + pen.ch = inshape ? 'X' : 'o'; + pen.fg = color; + int selected_tile_texpos = 0; + Screen::findGraphicsTile("CURSORS", direction.first, + direction.second + ycursor_mod, + &selected_tile_texpos); + pen.tile = selected_tile_texpos; + + return pen; } Screen::Pen get_pen(int x, int y, ShapeMap &arr, const std::string &type = "") { - bool n = false, w = false, e = false, s = false; - if (has_point(x, y)) { - if (y == 0 || !has_point(x, y - 1)) n = true; - if (x == 0 || !has_point(x - 1, y)) w = true; - if (!has_point(x + 1, y)) e = true; // TODO check map size - if (!has_point(x, y + 1)) s = true; // TODO check map size - } - - bool is_drag_point = type == "drag_point"; - bool is_extra = type == "extra_point"; - bool is_in_shape = has_point(x, y); - auto mouse_pos = Gui::getMousePos(); - bool mouse_over = mouse_pos.x == x && mouse_pos.y == y; - - uint32_t pen_key = - gen_pen_key(n, s, e, w, is_drag_point, mouse_over, is_in_shape, is_extra); - - if (CURSORS_MAP.count({n, w, e, s}) > 0 && has_point(x,y)) { - arr[x][y].cursor_coords = CURSORS_MAP.at({n, w, e, s}); - } - - if (PENS.find(pen_key) == PENS.end()) { - std::pair cursor{-1, -1}; - - if (type != "") { - return make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, mouse_over, - is_in_shape, is_extra); + bool n = false, w = false, e = false, s = false; + if (has_point(x, y)) { + if (y == 0 || !has_point(x, y - 1)) n = true; + if (x == 0 || !has_point(x - 1, y)) w = true; + if (!has_point(x + 1, y)) e = true; // TODO check map size + if (!has_point(x, y + 1)) s = true; // TODO check map size + } + + bool is_drag_point = type == "drag_point"; + bool is_extra = type == "extra_point"; + bool is_in_shape = has_point(x, y); + auto mouse_pos = Gui::getMousePos(); + bool mouse_over = mouse_pos.x == x && mouse_pos.y == y; + + uint32_t pen_key = gen_pen_key(n, s, e, w, is_drag_point, mouse_over, + is_in_shape, is_extra); + + if (CURSORS_MAP.count({n, w, e, s}) > 0 && has_point(x, y)) { + arr[x][y].cursor_coords = CURSORS_MAP.at({n, w, e, s}); } - if (CURSORS_MAP.count({n, w, e, s}) > 0) { - PENS.emplace(pen_key, - make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, - mouse_over, is_in_shape, is_extra)); - if (type == "" && has_point(x,y)) { - arr[x][y].penKey = pen_key; - } + if (PENS.find(pen_key) == PENS.end()) { + std::pair cursor{-1, -1}; + + if (type != "") { + return make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, + mouse_over, is_in_shape, is_extra); + } + + if (CURSORS_MAP.count({n, w, e, s}) > 0) { + PENS.emplace(pen_key, + make_pen(CURSORS_MAP.at({n, w, e, s}), is_drag_point, + mouse_over, is_in_shape, is_extra)); + if (type == "" && has_point(x, y)) { + arr[x][y].penKey = pen_key; + } + } } - } - // DEBUG(status).print("not cached lmao\n"); - return PENS.at(pen_key); + return PENS.at(pen_key); } static int design_load_shape(lua_State *L) { - if (lua_istable(L, -1)) { - lua_pushnil(L); - while (lua_next(L, -2) != 0) { - int x = lua_tointeger(L, -2); - - if (lua_istable(L, -1)) { + if (lua_istable(L, -1)) { lua_pushnil(L); while (lua_next(L, -2) != 0) { - int y = lua_tointeger(L, -2); - bool value = lua_toboolean(L, -1); - - if (value) { - arr[x][y] = DrawingPoint(); - } - lua_pop(L, 1); + int x = lua_tointeger(L, -2); + + if (lua_istable(L, -1)) { + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + int y = lua_tointeger(L, -2); + bool value = lua_toboolean(L, -1); + + if (value) { + arr[x][y] = DrawingPoint(); + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); } - } - lua_pop(L, 1); } - } - return 0; + return 0; } static int design_clear_shape(lua_State *L) { - arr.clear(); + arr.clear(); - return 0; + return 0; } static int design_draw_shape(lua_State *L) { - if (arr.size() == 0) { - design_load_shape(L); - } - - for (auto x : arr) { - for (auto y : x.second) { - Screen::Pen cur_tile = Screen::readTile(x.first, y.first, true); - Screen::Pen pen = get_pen(x.first, y.first, arr); - cur_tile.tile = pen.tile; - Screen::paintTile(cur_tile, x.first - *window_x, y.first - *window_y, - true); + if (arr.size() == 0) { + design_load_shape(L); + } + + for (auto x : arr) { + for (auto y : x.second) { + Screen::Pen cur_tile = Screen::readTile(x.first, y.first, true); + Screen::Pen pen = get_pen(x.first, y.first, arr); + cur_tile.tile = pen.tile; + Screen::paintTile(cur_tile, x.first - *window_x, + y.first - *window_y, true); + } } - } - return 0; + return 0; } static int design_draw_points(lua_State *L) { - if (lua_istable(L, -1)) { - const char *str; - lua_rawgeti(L, -1, 2); - str = lua_tostring(L, -1); - lua_pop(L, 1); - - lua_rawgeti(L, -1, 1); - int n = luaL_len(L, -1); - for (int i = 1; i <= n; i++) { - lua_rawgeti(L, -1, i); - int x, y; - lua_getfield(L, -1, "y"); - y = lua_tointeger(L, -1); - lua_getfield(L, -2, "x"); - x = lua_tointeger(L, -1); - lua_pop(L, 3); - - Screen::Pen cur_tile = Screen::readTile(x, y, true); - Screen::Pen pen = get_pen(x, y, arr, str); - cur_tile.tile = pen.tile; - Screen::paintTile(cur_tile, x - *window_x, y - *window_y, true); + if (lua_istable(L, -1)) { + const char *str; + lua_rawgeti(L, -1, 2); + str = lua_tostring(L, -1); + lua_pop(L, 1); + + lua_rawgeti(L, -1, 1); + int n = luaL_len(L, -1); + for (int i = 1; i <= n; i++) { + lua_rawgeti(L, -1, i); + int x, y; + lua_getfield(L, -1, "y"); + y = lua_tointeger(L, -1); + lua_getfield(L, -2, "x"); + x = lua_tointeger(L, -1); + lua_pop(L, 3); + + Screen::Pen cur_tile = Screen::readTile(x, y, true); + Screen::Pen pen = get_pen(x, y, arr, str); + cur_tile.tile = pen.tile; + Screen::paintTile(cur_tile, x - *window_x, y - *window_y, true); + } + lua_pop(L, 1); } - lua_pop(L, 1); - } - return 0; + return 0; } DFHACK_PLUGIN_LUA_COMMANDS{DFHACK_LUA_COMMAND(design_draw_shape), From aa0721edee40396c3aa11ec933f3beacdb85bc3d Mon Sep 17 00:00:00 2001 From: John Cosker Date: Wed, 3 May 2023 20:01:17 -0400 Subject: [PATCH 0149/1234] Changelog --- docs/changelog.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0a37bb3b9..f6524dc58 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -68,7 +68,6 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `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 -- `gui/design`: Improved performance for drawing shapes ## Lua - ``widgets.RangeSlider``: new mouse-controlled two-headed slider widget From 07c8f035c7c133da150edeccead7dc4bc3dcda2b Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 4 May 2023 07:14:05 +0000 Subject: [PATCH 0150/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 8c0624942..43a74b6c8 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 8c0624942ed11b369be805b2c0b5bc5ffd14f13d +Subproject commit 43a74b6c8679807a24028d56c1b157b28af59e73 From bfb6f3aa2eb1ed4834758f5506658955f9490579 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 5 May 2023 07:13:16 +0000 Subject: [PATCH 0151/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 43a74b6c8..54bd83727 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 43a74b6c8679807a24028d56c1b157b28af59e73 +Subproject commit 54bd83727df5f7048f5a7251b99ada1930e18ad9 From e664f4aa7b06e1bf78283773c0b1f7dc4cc61674 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 9 May 2023 21:56:07 -0400 Subject: [PATCH 0152/1234] CMake: fix find_package(Python) when inactive pyenv Python installations are present `find_package(Python)`'s default behavior is to attempt to use any `python3.x` executables it finds before `python3`. This is problematic when using tools such as pyenv, where `python3.x` executables may be present in a user's PATH but not be functional. Setting the `Python_FIND_UNVERSIONED_NAMES` hint to `FIRST` causes `python3` to be attempted first, if it exists. Note that this option was introduced in CMake 3.20: https://cmake.org/cmake/help/latest/module/FindPython.html#hints --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4228f45cd..6d1d4c562 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -376,6 +376,9 @@ endif() #### expose depends #### +# fix for pyenv: default to `python3` before `python3.x` +set(Python_FIND_UNVERSIONED_NAMES FIRST) + if(UNIX) # Rescan for pthread and zlib if the build arch changed if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_BUILD_ARCH_PREV}") From cb2db50a649ee737ea0f79c4e355cb2ec6e7c5bf Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 9 May 2023 22:13:49 -0400 Subject: [PATCH 0153/1234] Re-enable build of several plugins Likely to still work, and were probably just disabled due to v50 changes: - changeitem - createitem - deramp - flows - lair and a couple that don't access DF data at all: - luasocket - title-folder --- plugins/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 1967c370a..43b949d60 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -90,7 +90,7 @@ dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua) #dfhack_plugin(burrows burrows.cpp LINK_LIBRARIES lua) #dfhack_plugin(building-hacks building-hacks.cpp LINK_LIBRARIES lua) add_subdirectory(buildingplan) -#dfhack_plugin(changeitem changeitem.cpp) +dfhack_plugin(changeitem changeitem.cpp) dfhack_plugin(changelayer changelayer.cpp) dfhack_plugin(changevein changevein.cpp) add_subdirectory(channel-safely) @@ -98,10 +98,10 @@ dfhack_plugin(cleanconst cleanconst.cpp) dfhack_plugin(cleaners cleaners.cpp) dfhack_plugin(cleanowned cleanowned.cpp) dfhack_plugin(confirm confirm.cpp LINK_LIBRARIES lua) -#dfhack_plugin(createitem createitem.cpp) +dfhack_plugin(createitem createitem.cpp) dfhack_plugin(cursecheck cursecheck.cpp) dfhack_plugin(cxxrandom cxxrandom.cpp LINK_LIBRARIES lua) -#dfhack_plugin(deramp deramp.cpp) +dfhack_plugin(deramp deramp.cpp) dfhack_plugin(debug debug.cpp LINK_LIBRARIES jsoncpp_static) dfhack_plugin(dig dig.cpp) dfhack_plugin(dig-now dig-now.cpp LINK_LIBRARIES lua) @@ -117,7 +117,7 @@ dfhack_plugin(faststart faststart.cpp) dfhack_plugin(filltraffic filltraffic.cpp) #dfhack_plugin(fix-unit-occupancy fix-unit-occupancy.cpp) #dfhack_plugin(fixveins fixveins.cpp) -#dfhack_plugin(flows flows.cpp) +dfhack_plugin(flows flows.cpp) #dfhack_plugin(follow follow.cpp) #dfhack_plugin(forceequip forceequip.cpp) #dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp) @@ -126,9 +126,9 @@ dfhack_plugin(hotkeys hotkeys.cpp LINK_LIBRARIES lua) #dfhack_plugin(infiniteSky infiniteSky.cpp) #dfhack_plugin(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) #dfhack_plugin(jobutils jobutils.cpp) -#dfhack_plugin(lair lair.cpp) +dfhack_plugin(lair lair.cpp) dfhack_plugin(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua) -#dfhack_plugin(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) +dfhack_plugin(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) #dfhack_plugin(manipulator manipulator.cpp) #dfhack_plugin(map-render map-render.cpp LINK_LIBRARIES lua) dfhack_plugin(misery misery.cpp LINK_LIBRARIES lua) @@ -162,7 +162,7 @@ add_subdirectory(stockpiles) dfhack_plugin(strangemood strangemood.cpp) dfhack_plugin(tailor tailor.cpp LINK_LIBRARIES lua) dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) -#dfhack_plugin(title-folder title-folder.cpp) +dfhack_plugin(title-folder title-folder.cpp) #dfhack_plugin(trackstop trackstop.cpp) #dfhack_plugin(tubefill tubefill.cpp) #add_subdirectory(tweak) From f9a946190d56ac5f64c8d740b53367b95fbca8ca Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 10 May 2023 23:31:00 -0400 Subject: [PATCH 0154/1234] Disable building title-folder again Hangs when enabled in dfhack.init, at least under wine --- plugins/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 43b949d60..3ae78d320 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -162,7 +162,7 @@ add_subdirectory(stockpiles) dfhack_plugin(strangemood strangemood.cpp) dfhack_plugin(tailor tailor.cpp LINK_LIBRARIES lua) dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) -dfhack_plugin(title-folder title-folder.cpp) +#dfhack_plugin(title-folder title-folder.cpp) #dfhack_plugin(trackstop trackstop.cpp) #dfhack_plugin(tubefill tubefill.cpp) #add_subdirectory(tweak) From 94e56bf4c74e46f8b6d50c9ea051255f8308d59e Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 10 May 2023 23:49:02 -0400 Subject: [PATCH 0155/1234] Update changelog and docs for readded plugins Also mark reinstated plugins in the changelog, including for previous v50 releases --- docs/changelog.txt | 14 ++++++++++---- docs/plugins/changeitem.rst | 4 ++-- docs/plugins/createitem.rst | 2 +- docs/plugins/deramp.rst | 2 +- docs/plugins/flows.rst | 2 +- docs/plugins/lair.rst | 2 +- docs/plugins/luasocket.rst | 2 +- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index f6524dc58..fc706cdba 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -34,8 +34,14 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # Future ## New Plugins -- `add-spatter`: allow mods to add poisons and magical effects to weapons -- `work-now`: reduce the time that dwarves are left without a task after completing a job +- `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``: reduce the time that dwarves are left without a task after completing a job ## Fixes @@ -112,8 +118,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # 50.07-beta2 ## New Plugins -- `getplants`: designate trees for chopping and shrubs for gathering according to type -- `prospector`: get stone, ore, gem, and other tile property counts in fort mode. +- `getplants`: reinstated: designate trees for chopping and shrubs for gathering according to type +- `prospector`: reinstated: get stone, ore, gem, and other tile property counts in fort mode. ## Fixes -@ `buildingplan`: filters are now properly applied to planned stairs diff --git a/docs/plugins/changeitem.rst b/docs/plugins/changeitem.rst index 788b49247..f452f6a74 100644 --- a/docs/plugins/changeitem.rst +++ b/docs/plugins/changeitem.rst @@ -2,8 +2,8 @@ changeitem ========== .. dfhack-tool:: - :summary: Change item material or base quality. - :tags: unavailable adventure fort armok items + :summary: Change item material, quality, and subtype. + :tags: adventure fort armok items By default, a change is only allowed if the existing and desired item materials are of the same subtype (for example wood -> wood, stone -> stone, etc). But diff --git a/docs/plugins/createitem.rst b/docs/plugins/createitem.rst index b287042c7..b29e41521 100644 --- a/docs/plugins/createitem.rst +++ b/docs/plugins/createitem.rst @@ -3,7 +3,7 @@ createitem .. dfhack-tool:: :summary: Create arbitrary items. - :tags: unavailable adventure fort armok items + :tags: adventure fort armok items You can create new items of any type and made of any material. A unit must be selected in-game to use this command. By default, items created are spawned at diff --git a/docs/plugins/deramp.rst b/docs/plugins/deramp.rst index 4a1f34548..fdc0f7619 100644 --- a/docs/plugins/deramp.rst +++ b/docs/plugins/deramp.rst @@ -3,7 +3,7 @@ deramp .. dfhack-tool:: :summary: Removes all ramps designated for removal from the map. - :tags: unavailable fort armok map + :tags: fort armok map It also removes any "floating" down ramps that can remain after a cave-in. diff --git a/docs/plugins/flows.rst b/docs/plugins/flows.rst index 56840d999..bbb2c6661 100644 --- a/docs/plugins/flows.rst +++ b/docs/plugins/flows.rst @@ -3,7 +3,7 @@ flows .. dfhack-tool:: :summary: Counts map blocks with flowing liquids. - :tags: unavailable fort inspection map + :tags: fort inspection map If you suspect that your magma sea leaks into HFS, you can use this tool to be sure without revealing the map. diff --git a/docs/plugins/lair.rst b/docs/plugins/lair.rst index 82c5e211c..9bded57ab 100644 --- a/docs/plugins/lair.rst +++ b/docs/plugins/lair.rst @@ -3,7 +3,7 @@ lair .. dfhack-tool:: :summary: Mark the map as a monster lair. - :tags: unavailable fort armok map + :tags: fort armok map This avoids item scatter when the fortress is abandoned. diff --git a/docs/plugins/luasocket.rst b/docs/plugins/luasocket.rst index 1aa320ed7..4b5b18540 100644 --- a/docs/plugins/luasocket.rst +++ b/docs/plugins/luasocket.rst @@ -3,7 +3,7 @@ luasocket .. dfhack-tool:: :summary: Provides a Lua API for accessing network sockets. - :tags: unavailable dev + :tags: dev :no-command: See `luasocket-api` for details. From b6723e4fdbd0a72d766d12d8322ca240632d0ba4 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 11 May 2023 00:26:19 -0400 Subject: [PATCH 0156/1234] Remove "unavailable" tag from add-spatter and channel-safely docs These plugins are currently being built --- docs/plugins/add-spatter.rst | 2 +- docs/plugins/channel-safely.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/add-spatter.rst b/docs/plugins/add-spatter.rst index 2c43a88ef..e8a39f781 100644 --- a/docs/plugins/add-spatter.rst +++ b/docs/plugins/add-spatter.rst @@ -3,7 +3,7 @@ add-spatter .. dfhack-tool:: :summary: Add poisons and magical effects to weapons. - :tags: unavailable adventure fort gameplay items + :tags: adventure fort gameplay items :no-command: Give some use to all those poisons that can be bought from caravans! The plugin diff --git a/docs/plugins/channel-safely.rst b/docs/plugins/channel-safely.rst index c24f352b0..c5dbc37f6 100644 --- a/docs/plugins/channel-safely.rst +++ b/docs/plugins/channel-safely.rst @@ -3,7 +3,7 @@ channel-safely .. dfhack-tool:: :summary: Auto-manage channel designations to keep dwarves safe. - :tags: unavailable fort auto + :tags: fort auto Multi-level channel projects can be dangerous, and managing the safety of your dwarves throughout the completion of such projects can be difficult and time From 1a703c344f810ec289a42dddba9add8277c5ff75 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 15 May 2023 17:33:57 -0700 Subject: [PATCH 0157/1234] support disabling DFHack with --disable-dfhack --- docs/Core.rst | 19 ++++++++++++++++++- docs/changelog.txt | 1 + library/Core.cpp | 30 +++++++++++++++++------------- library/Hooks.cpp | 22 +++++++++++++++++++++- library/include/Core.h | 3 ++- 5 files changed, 59 insertions(+), 16 deletions(-) diff --git a/docs/Core.rst b/docs/Core.rst index 5decd668d..62b91c19c 100644 --- a/docs/Core.rst +++ b/docs/Core.rst @@ -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 an alternative mode. The non-whitespace characters following the ``:`` are the command name, and the remaining part of the line is used verbatim as -the first argument. This is very useful for the `lua` and `rb` commands. +the first argument. This is very useful for the `lua` command. As an example, the following two command lines are exactly equivalent:: :foo a b "c d" e f @@ -306,6 +306,23 @@ the root DF folder. Note that ``script-paths.txt`` is only read at startup, but the paths can also be modified programmatically at any time through the `Lua API `. +Commandline options +=================== + +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: diff --git a/docs/changelog.txt b/docs/changelog.txt index fc706cdba..d602ed93a 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -48,6 +48,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - Terminal console no longer appears in front of the game window on startup - `gui/design`: Improved performance for drawing shapes +- ``Core``: For debugging purposes, you can now pass ``--disable-dfhack`` on the Dwarf Fortress commandline to disable DFHack for the session. ## Documentation diff --git a/library/Core.cpp b/library/Core.cpp index 9ff6976d5..256493dce 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1471,16 +1471,8 @@ std::string Core::getHackPath() #endif } -bool Core::Init() -{ - if(started) - return true; - if(errorstate) - return false; - - // Lock the CoreSuspendMutex until the thread exits or call Core::Shutdown - // Core::Update will temporary unlock when there is any commands queued - MainThread::suspend().lock(); +bool Core::InitMainThread() { + Filesystem::init(); // Re-route stdout and stderr again - DF seems to set up stdout and // stderr.txt on Windows as of 0.43.05. Also, log before switching files to @@ -1496,8 +1488,6 @@ bool Core::Init() if (!freopen("stderr.log", "w", stderr)) std::cerr << "Could not redirect stderr to stderr.log" << std::endl; - Filesystem::init(); - std::cerr << "DFHack build: " << Version::git_description() << "\n" << "Starting with working directory: " << Filesystem::getcwd() << std::endl; @@ -1566,6 +1556,20 @@ bool Core::Init() // Init global object pointers df::global::InitGlobals(); + return true; +} + +bool Core::InitSimulationThread() +{ + if(started) + return true; + if(errorstate) + return false; + + // Lock the CoreSuspendMutex until the thread exits or call Core::Shutdown + // Core::Update will temporary unlock when there is any commands queued + MainThread::suspend().lock(); + std::cerr << "Initializing Console.\n"; // init the console. bool is_text_mode = (init && init->display.flag.is_set(init_display_flags::TEXT)); @@ -1965,7 +1969,7 @@ int Core::Update() if(!started) { // Initialize the core - Init(); + InitSimulationThread(); if(errorstate) return -1; } diff --git a/library/Hooks.cpp b/library/Hooks.cpp index c241e4875..1976d60d7 100644 --- a/library/Hooks.cpp +++ b/library/Hooks.cpp @@ -1,31 +1,49 @@ #include "Core.h" #include "Export.h" +#include "df/gamest.h" + +static bool disabled = false; + // called from the main thread before the simulation thread is started // and the main event loop is initiated DFhackCExport void dfhooks_init() { - // TODO: initialize things we need to do while still in the main thread + if (!DFHack::Core::getInstance().InitMainThread() || !df::global::game) + return; + const std::string & cmdline = df::global::game->command_line.original; + if (cmdline.find("--disable-dfhack") != std::string::npos) { + fprintf(stdout, "dfhack: --disable-dfhack specified on commandline; disabling\n"); + disabled = true; + } } // called from the main thread after the main event loops exits DFhackCExport void dfhooks_shutdown() { + if (disabled) + return; DFHack::Core::getInstance().Shutdown(); } // called from the simulation thread in the main event loop DFhackCExport void dfhooks_update() { + if (disabled) + return; DFHack::Core::getInstance().Update(); } // called from the simulation thread just before adding the macro // recording/playback overlay DFhackCExport void dfhooks_prerender() { + if (disabled) + return; // TODO: render overlay widgets that are not attached to a viewscreen } // called from the main thread for each SDL event. if true is returned, then // the event has been consumed and further processing shouldn't happen DFhackCExport bool dfhooks_sdl_event(SDL::Event* event) { + if (disabled) + return false; return DFHack::Core::getInstance().DFH_SDL_Event(event); } @@ -34,5 +52,7 @@ DFhackCExport bool dfhooks_sdl_event(SDL::Event* event) { // if true is returned, then the event has been consumed and further processing // shouldn't happen DFhackCExport bool dfhooks_ncurses_key(int key) { + if (disabled) + return false; return DFHack::Core::getInstance().DFH_ncurses_key(key); } diff --git a/library/include/Core.h b/library/include/Core.h index 386769fcb..696be4ead 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -191,7 +191,8 @@ namespace DFHack struct Private; std::unique_ptr d; - bool Init(); + bool InitMainThread(); + bool InitSimulationThread(); int Update (void); int Shutdown (void); bool DFH_SDL_Event(SDL::Event* event); From 910b7c2ae945b4babe2b7304b0500ea2f189dcfb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 15 May 2023 17:52:20 -0700 Subject: [PATCH 0158/1234] fix autolabor warning appearing on inappropriate screens --- docs/changelog.txt | 1 + plugins/lua/autolabor.lua | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fc706cdba..9b6868540 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -44,6 +44,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `work-now`: reinstated, renamed from ``workNow``: reduce the time that dwarves are left without a task after completing a job ## Fixes +- `autolabor`: work detail override warning now only appears on the work details screen ## Misc Improvements - Terminal console no longer appears in front of the game window on startup diff --git a/plugins/lua/autolabor.lua b/plugins/lua/autolabor.lua index 50f39b225..a468b30e1 100644 --- a/plugins/lua/autolabor.lua +++ b/plugins/lua/autolabor.lua @@ -8,9 +8,9 @@ AutolaborOverlay = defclass(AutolaborOverlay, overlay.OverlayWidget) AutolaborOverlay.ATTRS{ default_pos={x=7,y=-13}, default_enabled=true, - viewscreens='dwarfmode/Info/LABOR', + viewscreens='dwarfmode/Info/LABOR/WORK_DETAILS', frame={w=29, h=5}, - frame_style=gui.THIN_FRAME, + frame_style=gui.MEDIUM_FRAME, frame_background=gui.CLEAR_PEN, } From 9f997eaade3776997379a440af0018c6980aa8f2 Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 15 May 2023 17:54:45 -0700 Subject: [PATCH 0159/1234] Update docs/changelog.txt Co-authored-by: Alan --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index d602ed93a..529eebfff 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -48,7 +48,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - Terminal console no longer appears in front of the game window on startup - `gui/design`: Improved performance for drawing shapes -- ``Core``: For debugging purposes, you can now pass ``--disable-dfhack`` on the Dwarf Fortress commandline to disable DFHack for the session. +- Core: For debugging purposes, you can now pass ``--disable-dfhack`` on the Dwarf Fortress commandline to disable DFHack for the session. ## Documentation From a62993b90b6c21f0f1f93dbd685e3fd19f158b73 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 15 May 2023 18:15:46 -0700 Subject: [PATCH 0160/1234] add DFHACK_DISABLE env var --- docs/Core.rst | 5 +++++ library/Hooks.cpp | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/docs/Core.rst b/docs/Core.rst index 62b91c19c..0e333702f 100644 --- a/docs/Core.rst +++ b/docs/Core.rst @@ -336,6 +336,11 @@ on UNIX-like systems: DFHACK_SOME_VAR=1 ./dfhack +- ``DFHACK_DISABLE``: if set, DFHack will not initialize, not even to redirect + :file:`stdout.txt` or :file:`stderr.txt`. This is provided as an alternative + to the ``--disable-dfhack`` commandline parameter above for when environment + variables are more convenient. + - ``DFHACK_PORT``: the port to use for the RPC server (used by ``dfhack-run`` and `remotefortressreader` among others) instead of the default ``5000``. As with the default, if this port cannot be used, the server is not started. diff --git a/library/Hooks.cpp b/library/Hooks.cpp index 1976d60d7..4e339e768 100644 --- a/library/Hooks.cpp +++ b/library/Hooks.cpp @@ -8,6 +8,13 @@ static bool disabled = false; // called from the main thread before the simulation thread is started // and the main event loop is initiated DFhackCExport void dfhooks_init() { + if (getenv("DFHACK_DISABLE")) { + fprintf(stdout, "dfhack: DFHACK_DISABLE detected in environment; disabling\n"); + disabled = true; + return; + } + + // we need to init DF globals before we can check the commandline if (!DFHack::Core::getInstance().InitMainThread() || !df::global::game) return; const std::string & cmdline = df::global::game->command_line.original; From b845ea15b8050758797c0694380dc163106d85d5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 15 May 2023 18:34:43 -0700 Subject: [PATCH 0161/1234] update changelog --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 529eebfff..80d07eff4 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -48,7 +48,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - Terminal console no longer appears in front of the game window on startup - `gui/design`: Improved performance for drawing shapes -- Core: For debugging purposes, you can now pass ``--disable-dfhack`` on the Dwarf Fortress commandline to disable DFHack for the session. +- Core: For debugging purposes, you can now pass ``--disable-dfhack`` on the Dwarf Fortress commandline or specify ``DFHACK_DISABLE=1`` in the environment to disable DFHack for the current session. ## Documentation From 6b2c805d5f813b193f959758afdb5431f42fedc9 Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 15 May 2023 22:12:12 -0700 Subject: [PATCH 0162/1234] Update docs/Core.rst Co-authored-by: Alan --- docs/Core.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Core.rst b/docs/Core.rst index 0e333702f..763858b61 100644 --- a/docs/Core.rst +++ b/docs/Core.rst @@ -337,7 +337,7 @@ on UNIX-like systems: DFHACK_SOME_VAR=1 ./dfhack - ``DFHACK_DISABLE``: if set, DFHack will not initialize, not even to redirect - :file:`stdout.txt` or :file:`stderr.txt`. This is provided as an alternative + 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. From 81918a89a33d55f2ebdea2e6fe6e66fb3b59410e Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 16 May 2023 07:13:50 +0000 Subject: [PATCH 0163/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 54bd83727..1ec3602f9 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 54bd83727df5f7048f5a7251b99ada1930e18ad9 +Subproject commit 1ec3602f9d896c9dc76b26b3be845a5aa7544093 From f05fe333071a4d28cfdc643047376fa8a9bb24c6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 16 May 2023 11:26:47 -0700 Subject: [PATCH 0164/1234] fix crash on malformed json (again) --- docs/changelog.txt | 1 + library/RemoteClient.cpp | 6 +++++- library/RemoteServer.cpp | 19 +++++++++++-------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fc706cdba..50d015c4d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -44,6 +44,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `work-now`: reinstated, renamed from ``workNow``: reduce the time that dwarves are left without a task after completing a job ## Fixes +- RemoteServer: fix crash on malformed json in ``dfhack-config/remote-server.json`` ## Misc Improvements - Terminal console no longer appears in front of the game window on startup diff --git a/library/RemoteClient.cpp b/library/RemoteClient.cpp index 6a8becaae..0aa68eb51 100644 --- a/library/RemoteClient.cpp +++ b/library/RemoteClient.cpp @@ -150,7 +150,11 @@ int RemoteClient::GetDefaultPort() if (in_file) { Json::Value config; - in_file >> config; + try { + in_file >> config; + } catch (const std::exception & e) { + std::cerr << "Error reading remote server config file: " << filename << ": " << e.what() << std::endl; + } in_file.close(); if (config.isMember("port")) { port = config["port"].asInt(); diff --git a/library/RemoteServer.cpp b/library/RemoteServer.cpp index 734b80702..77510d63a 100644 --- a/library/RemoteServer.cpp +++ b/library/RemoteServer.cpp @@ -420,17 +420,20 @@ ServerMainImpl::ServerMainImpl(std::promise promise, int port) : Json::Value configJson; - std::ifstream inFile(filename, std::ios_base::in); - bool allow_remote = false; - if (inFile.is_open()) - { - inFile >> configJson; - inFile.close(); - - allow_remote = configJson.get("allow_remote", "false").asBool(); + std::ifstream inFile(filename, std::ios_base::in); + try { + if (inFile.is_open()) + { + inFile >> configJson; + allow_remote = configJson.get("allow_remote", "false").asBool(); + } + } catch (const std::exception & e) { + std::cerr << "Error reading remote server config file: " << filename << ": " << e.what() << std::endl; + std::cerr << "Reverting to remote server config to defaults" << std::endl; } + inFile.close(); // rewrite/normalize config file configJson["allow_remote"] = allow_remote; From a76bed0ed511848484bfeb0d3b94a0a8ac9af211 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 16 May 2023 11:41:28 -0700 Subject: [PATCH 0165/1234] rename overlay.reload to overlay.rescan --- docs/changelog.txt | 1 + docs/dev/overlay-dev-guide.rst | 4 ++-- plugins/lua/overlay.lua | 4 ++-- plugins/overlay.cpp | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fc706cdba..4fab1aa28 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -54,6 +54,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## API ## 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. ## Removed diff --git a/docs/dev/overlay-dev-guide.rst b/docs/dev/overlay-dev-guide.rst index 1a53e7f65..4ec226d30 100644 --- a/docs/dev/overlay-dev-guide.rst +++ b/docs/dev/overlay-dev-guide.rst @@ -183,7 +183,7 @@ Scripts #. If the script is not in your `script-paths`, install your script (see the `modding-guide` for help setting up a dev environment so that you don't need to reinstall your scripts after every edit). -#. Call ``:lua require('plugins.overlay').reload()`` to reload your overlay +#. Call ``:lua require('plugins.overlay').rescan()`` to reload your overlay widget Plugins @@ -194,7 +194,7 @@ Plugins :file:`hack/lua/plugins/` #. If you have changed the compiled plugin, `reload` it #. If you have changed the lua code, run ``:lua reload('plugins.mypluginname')`` -#. Call ``:lua require('plugins.overlay').reload()`` to reload your overlay +#. Call ``:lua require('plugins.overlay').rescan()`` to reload your overlay widget Troubleshooting diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index 84c2b4f96..9f41cb035 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -292,7 +292,7 @@ local function load_widgets(env_name, env) end -- called directly from cpp on plugin enable -function reload() +function rescan() reset() for _,plugin in ipairs(dfhack.internal.listPlugins()) do @@ -317,7 +317,7 @@ dfhack.onStateChange[GLOBAL_KEY] = function(sc) return end -- pick up widgets from active mods - reload() + rescan() end local function dump_widget_config(name, widget) diff --git a/plugins/overlay.cpp b/plugins/overlay.cpp index c02c960ba..784e17129 100644 --- a/plugins/overlay.cpp +++ b/plugins/overlay.cpp @@ -128,7 +128,7 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { if (enable) { screenSize = Screen::getWindowSize(); - call_overlay_lua(&out, "reload"); + call_overlay_lua(&out, "rescan"); } DEBUG(control).print("%sing interpose hooks\n", enable ? "enabl" : "disabl"); From 217be6b58d16004192ed3191d9154ee87be11586 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 16 May 2023 12:36:58 -0700 Subject: [PATCH 0166/1234] make full text search configurable for list filters --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 8 ++++++++ library/lua/gui/widgets.lua | 19 ++++++++++++------- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fc706cdba..f301a1055 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -47,6 +47,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - Terminal console no longer appears in front of the game window on startup +- `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 ## Documentation diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 85e51d11d..6215fd250 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5106,6 +5106,14 @@ The widget implements: 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 with a command like:: + + :lua require('gui.widgets').FILTER_FULL_TEXT=true + TabBar class ------------ diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 7aa79cbc3..e5d808903 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1932,6 +1932,8 @@ end -- Filtered List -- ------------------- +FILTER_FULL_TEXT = false + FilteredList = defclass(FilteredList, Widget) FilteredList.ATTRS { @@ -2102,19 +2104,22 @@ function FilteredList:setFilter(filter, pos) end for _,key in ipairs(tokens) do key = key:escape_pattern() - -- start matches at non-space or non-punctuation. this allows - -- punctuation itself to be matched if that is useful (e.g. - -- filenames or parameter names) if key ~= '' then if not self.case_sensitive then search_key = string.lower(search_key) key = string.lower(key) end - if not search_key:match('%f[^%p\x00]'..key) and - not search_key:match('%f[^%s\x00]'..key) then - ok = false - break + -- the separate checks for non-space or non-punctuation allows + -- punctuation itself to be matched if that is useful (e.g. + -- filenames or parameter names) + if not FILTER_FULL_TEXT and not search_key:match('%f[^%p\x00]'..key) + and not search_key:match('%f[^%s\x00]'..key) then + ok = false + break + elseif FILTER_FULL_TEXT and not search_key:find(key) then + ok = false + break end end end From b6b65d4bf69a564b2ac2b02c0cf782080b17e42b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 16 May 2023 15:37:00 -0700 Subject: [PATCH 0167/1234] update library military orders move preference for silver below steel leather cloaks -> silk cloaks leather shield -> wood shield adjust target quantities for archer uniforms --- data/orders/military.json | 410 +- .../military_include_artifact_materials.json | 4971 ----------------- docs/plugins/orders.rst | 16 +- 3 files changed, 198 insertions(+), 5199 deletions(-) delete mode 100644 data/orders/military_include_artifact_materials.json diff --git a/data/orders/military.json b/data/orders/military.json index 0e53747b6..abf2675f9 100644 --- a/data/orders/military.json +++ b/data/orders/military.json @@ -92,15 +92,16 @@ [ { "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", + "flags" : + [ + "silk" + ], + "item_type" : "CLOTH", + "min_dimension" : 10000, "value" : 10 }, { "condition" : "AtMost", - "flags" : - [ - "leather" - ], "item_subtype" : "ITEM_ARMOR_CLOAK", "item_type" : "ARMOR", "value" : 10 @@ -110,7 +111,7 @@ "job" : "MakeArmor", "material_category" : [ - "leather" + "silk" ] }, { @@ -152,25 +153,21 @@ [ { "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 25 + "item_type" : "WOOD", + "value" : 50 }, { "condition" : "AtMost", - "flags" : - [ - "leather" - ], "item_subtype" : "ITEM_SHIELD_SHIELD", "item_type" : "SHIELD", - "value" : 1 + "value" : 10 } ], "item_subtype" : "ITEM_SHIELD_SHIELD", "job" : "MakeShield", "material_category" : [ - "leather" + "wood" ] }, { @@ -191,7 +188,7 @@ "condition" : "AtMost", "item_subtype" : "ITEM_ARMOR_LEATHER", "item_type" : "ARMOR", - "value" : 1 + "value" : 10 } ], "item_subtype" : "ITEM_ARMOR_LEATHER", @@ -223,7 +220,7 @@ ], "item_subtype" : "ITEM_HELM_HELM", "item_type" : "HELM", - "value" : 1 + "value" : 10 } ], "item_subtype" : "ITEM_HELM_HELM", @@ -255,7 +252,7 @@ ], "item_subtype" : "ITEM_SHOES_BOOTS", "item_type" : "SHOES", - "value" : 2 + "value" : 20 } ], "item_subtype" : "ITEM_SHOES_BOOTS", @@ -287,7 +284,7 @@ ], "item_subtype" : "ITEM_PANTS_LEGGINGS", "item_type" : "PANTS", - "value" : 1 + "value" : 10 } ], "item_subtype" : "ITEM_PANTS_LEGGINGS", @@ -319,7 +316,7 @@ ], "item_subtype" : "ITEM_GLOVES_GLOVES", "item_type" : "GLOVES", - "value" : 2 + "value" : 20 } ], "item_subtype" : "ITEM_GLOVES_GLOVES", @@ -571,37 +568,6 @@ "is_active" : false, "is_validated" : false, "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:NATIVE_PLATINUM", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 10 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:NATIVE_PLATINUM" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 19, - "is_active" : false, - "is_validated" : false, - "item_conditions" : [ { "condition" : "AtLeast", @@ -629,7 +595,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 20, + "id" : 19, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -660,7 +626,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 21, + "id" : 20, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -691,7 +657,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 22, + "id" : 21, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -722,7 +688,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 23, + "id" : 22, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -759,7 +725,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 24, + "id" : 23, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -808,7 +774,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 25, + "id" : 24, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -845,7 +811,7 @@ "amount_left" : 4, "amount_total" : 4, "frequency" : "Daily", - "id" : 26, + "id" : 25, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -888,7 +854,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 27, + "id" : 26, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -924,7 +890,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 28, + "id" : 27, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -967,7 +933,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 29, + "id" : 28, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1015,7 +981,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 30, + "id" : 29, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1070,79 +1036,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 35, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "job" : "MakeWeapon", - "material" : "INORGANIC:SILVER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 35, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:SILVER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 37, + "id" : 30, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1175,7 +1069,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 38, + "id" : 31, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1208,7 +1102,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 39, + "id" : 32, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1241,7 +1135,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 40, + "id" : 33, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1274,7 +1168,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 41, + "id" : 34, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1307,7 +1201,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 42, + "id" : 35, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1347,7 +1241,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 43, + "id" : 36, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1387,7 +1281,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 44, + "id" : 37, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1404,12 +1298,6 @@ "material" : "COAL", "value" : 100 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, { "condition" : "AtMost", "item_subtype" : "ITEM_WEAPON_MACE", @@ -1426,7 +1314,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 45, + "id" : 38, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1443,12 +1331,6 @@ "material" : "COAL", "value" : 100 }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, { "condition" : "AtMost", "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", @@ -1465,7 +1347,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 46, + "id" : 39, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1498,7 +1380,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 47, + "id" : 40, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1531,7 +1413,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 48, + "id" : 41, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1564,7 +1446,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 49, + "id" : 42, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1597,7 +1479,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 50, + "id" : 43, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1630,7 +1512,103 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 51, + "id" : 44, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_MACE", + "job" : "MakeWeapon", + "material" : "INORGANIC:SILVER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 45, + "is_active" : false, + "is_validated" : false, + "item_conditions" : + [ + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "INORGANIC:SILVER", + "value" : 5 + }, + { + "condition" : "AtLeast", + "item_type" : "BAR", + "material" : "COAL", + "value" : 100 + }, + { + "condition" : "LessThan", + "item_type" : "BOULDER", + "reaction_class" : "FLUX", + "value" : 5 + }, + { + "condition" : "AtMost", + "flags" : + [ + "metal" + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "item_type" : "WEAPON", + "value" : 10 + }, + { + "condition" : "LessThan", + "item_type" : "BAR", + "material" : "INORGANIC:STEEL", + "value" : 10 + } + ], + "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", + "job" : "MakeWeapon", + "material" : "INORGANIC:SILVER" + }, + { + "amount_left" : 1, + "amount_total" : 1, + "frequency" : "Daily", + "id" : 46, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1678,7 +1656,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 52, + "id" : 47, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1726,7 +1704,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 53, + "id" : 48, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1774,7 +1752,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 54, + "id" : 49, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1822,7 +1800,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 55, + "id" : 50, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1870,7 +1848,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 56, + "id" : 51, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1928,7 +1906,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 57, + "id" : 52, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -1986,7 +1964,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 58, + "id" : 53, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2040,7 +2018,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 59, + "id" : 54, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2094,7 +2072,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 60, + "id" : 55, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2142,7 +2120,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 61, + "id" : 56, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2190,7 +2168,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 62, + "id" : 57, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2238,7 +2216,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 63, + "id" : 58, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2286,7 +2264,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 64, + "id" : 59, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2334,7 +2312,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 79, + "id" : 74, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2382,7 +2360,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 80, + "id" : 75, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2430,7 +2408,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 81, + "id" : 76, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2478,7 +2456,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 82, + "id" : 77, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2526,7 +2504,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 83, + "id" : 78, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2574,7 +2552,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 84, + "id" : 79, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2632,7 +2610,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 85, + "id" : 80, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2690,7 +2668,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 72, + "id" : 67, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2735,7 +2713,7 @@ "item_type" : "BAR", "material" : "INORGANIC:SILVER", "value" : 5 - }, + } ], "item_subtype" : "ITEM_WEAPON_MACE", "job" : "MakeWeapon", @@ -2745,7 +2723,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 87, + "id" : 82, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2799,7 +2777,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 88, + "id" : 83, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2847,7 +2825,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 89, + "id" : 84, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2895,7 +2873,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 90, + "id" : 85, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2943,7 +2921,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 91, + "id" : 86, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -2991,7 +2969,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 92, + "id" : 87, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3039,7 +3017,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 79, + "id" : 74, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3093,7 +3071,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 80, + "id" : 75, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3147,7 +3125,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 81, + "id" : 76, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3201,7 +3179,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 82, + "id" : 77, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3255,7 +3233,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 83, + "id" : 78, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3309,7 +3287,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 84, + "id" : 79, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3373,7 +3351,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 85, + "id" : 80, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3437,7 +3415,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 86, + "id" : 81, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3497,7 +3475,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 87, + "id" : 82, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3557,7 +3535,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 88, + "id" : 83, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3611,7 +3589,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 89, + "id" : 84, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3665,7 +3643,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 90, + "id" : 85, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3719,7 +3697,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 91, + "id" : 86, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3773,7 +3751,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 92, + "id" : 87, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3827,7 +3805,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 93, + "id" : 88, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3887,7 +3865,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 94, + "id" : 89, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -3947,7 +3925,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 95, + "id" : 90, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4007,7 +3985,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 96, + "id" : 91, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4067,7 +4045,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 97, + "id" : 92, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4127,7 +4105,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 98, + "id" : 93, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4197,7 +4175,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 99, + "id" : 94, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4267,7 +4245,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 100, + "id" : 95, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4333,7 +4311,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 101, + "id" : 96, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4399,7 +4377,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 102, + "id" : 97, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4459,7 +4437,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 103, + "id" : 98, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4519,7 +4497,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 104, + "id" : 99, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4579,7 +4557,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 105, + "id" : 100, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -4639,7 +4617,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 106, + "id" : 101, "is_active" : false, "is_validated" : false, "item_conditions" : diff --git a/data/orders/military_include_artifact_materials.json b/data/orders/military_include_artifact_materials.json deleted file mode 100644 index 536b2cd7a..000000000 --- a/data/orders/military_include_artifact_materials.json +++ /dev/null @@ -1,4971 +0,0 @@ -[ - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 0, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 10 - }, - { - "condition" : "AtMost", - "item_type" : "BACKPACK", - "value" : 10 - } - ], - "job" : "MakeBackpack", - "material_category" : - [ - "leather" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 1, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 10 - }, - { - "condition" : "AtMost", - "flags" : - [ - "leather" - ], - "item_type" : "FLASK", - "value" : 10 - } - ], - "job" : "MakeFlask", - "material_category" : - [ - "leather" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 2, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 10 - }, - { - "condition" : "AtMost", - "item_type" : "QUIVER", - "value" : 10 - } - ], - "job" : "MakeQuiver", - "material_category" : - [ - "leather" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 3, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 10 - }, - { - "condition" : "AtMost", - "flags" : - [ - "leather" - ], - "item_subtype" : "ITEM_ARMOR_CLOAK", - "item_type" : "ARMOR", - "value" : 10 - } - ], - "item_subtype" : "ITEM_ARMOR_CLOAK", - "job" : "MakeArmor", - "material_category" : - [ - "leather" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 4, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "WOOD", - "value" : 50 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "job" : "MakeWeapon", - "material_category" : - [ - "wood" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 5, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 25 - }, - { - "condition" : "AtMost", - "flags" : - [ - "leather" - ], - "item_subtype" : "ITEM_SHIELD_SHIELD", - "item_type" : "SHIELD", - "value" : 1 - } - ], - "item_subtype" : "ITEM_SHIELD_SHIELD", - "job" : "MakeShield", - "material_category" : - [ - "leather" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 6, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 25 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_ARMOR_LEATHER", - "item_type" : "ARMOR", - "value" : 1 - } - ], - "item_subtype" : "ITEM_ARMOR_LEATHER", - "job" : "MakeArmor", - "material_category" : - [ - "leather" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 7, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 25 - }, - { - "condition" : "AtMost", - "flags" : - [ - "leather" - ], - "item_subtype" : "ITEM_HELM_HELM", - "item_type" : "HELM", - "value" : 1 - } - ], - "item_subtype" : "ITEM_HELM_HELM", - "job" : "MakeHelm", - "material_category" : - [ - "leather" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 8, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 25 - }, - { - "condition" : "AtMost", - "flags" : - [ - "leather" - ], - "item_subtype" : "ITEM_SHOES_BOOTS", - "item_type" : "SHOES", - "value" : 2 - } - ], - "item_subtype" : "ITEM_SHOES_BOOTS", - "job" : "MakeShoes", - "material_category" : - [ - "leather" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 9, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 25 - }, - { - "condition" : "AtMost", - "flags" : - [ - "leather" - ], - "item_subtype" : "ITEM_PANTS_LEGGINGS", - "item_type" : "PANTS", - "value" : 1 - } - ], - "item_subtype" : "ITEM_PANTS_LEGGINGS", - "job" : "MakePants", - "material_category" : - [ - "leather" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 10, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "SKIN_TANNED", - "value" : 25 - }, - { - "condition" : "AtMost", - "flags" : - [ - "leather" - ], - "item_subtype" : "ITEM_GLOVES_GLOVES", - "item_type" : "GLOVES", - "value" : 2 - } - ], - "item_subtype" : "ITEM_GLOVES_GLOVES", - "job" : "MakeGloves", - "material_category" : - [ - "leather" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 11, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "flags" : - [ - "unrotten", - "bone", - "body_part" - ], - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "bone" - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "item_type" : "AMMO", - "value" : 1000 - } - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "job" : "MakeAmmo", - "material_category" : - [ - "bone" - ] - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 12, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "WOOD", - "value" : 150 - }, - { - "condition" : "AtMost", - "flags" : - [ - "bone" - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "item_type" : "AMMO", - "value" : 200 - }, - { - "condition" : "AtMost", - "flags" : - [ - "plant" - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "item_type" : "AMMO", - "value" : 1000 - } - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "job" : "MakeAmmo", - "material_category" : - [ - "wood" - ] - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 13, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:CASSITERITE", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:TIN", - "value" : 20 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:CASSITERITE" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 14, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:HEMATITE", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 40 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:HEMATITE" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 15, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:HORN_SILVER", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 10 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:HORN_SILVER" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 16, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:LIMONITE", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 40 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:LIMONITE" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 17, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:NATIVE_COPPER", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 40 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:NATIVE_COPPER" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 18, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:NATIVE_PLATINUM", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 10 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:NATIVE_PLATINUM" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 19, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:NATIVE_SILVER", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 10 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:NATIVE_SILVER" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 20, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:MAGNETITE", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 40 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:MAGNETITE" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 21, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:MALACHITE", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 40 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:MALACHITE" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 22, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "material" : "INORGANIC:TETRAHEDRITE", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 40 - } - ], - "job" : "SmeltOre", - "material" : "INORGANIC:TETRAHEDRITE" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 23, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "bearing" : "TIN", - "condition" : "AtLeast", - "item_type" : "BOULDER", - "value" : 5 - }, - { - "bearing" : "COPPER", - "condition" : "AtLeast", - "item_type" : "BOULDER", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 40 - } - ], - "job" : "CustomReaction", - "reaction" : "BRONZE_MAKING" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 24, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:TIN", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 40 - }, - { - "bearing" : "TIN", - "condition" : "AtMost", - "item_type" : "BOULDER", - "value" : 5 - }, - { - "bearing" : "COPPER", - "condition" : "AtMost", - "item_type" : "BOULDER", - "value" : 5 - } - ], - "job" : "CustomReaction", - "reaction" : "BRONZE_MAKING2" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 25, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:PIG_IRON", - "value" : 10 - } - ], - "job" : "CustomReaction", - "reaction" : "PIG_IRON_MAKING" - }, - { - "amount_left" : 4, - "amount_total" : 4, - "frequency" : "Daily", - "id" : 26, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:PIG_IRON", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 40 - } - ], - "job" : "CustomReaction", - "reaction" : "STEEL_MAKING" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 27, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "item_type" : "AMMO", - "value" : 1000 - } - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "job" : "MakeAmmo", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 28, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "min_dimension" : 150, - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "item_type" : "AMMO", - "value" : 1000 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "job" : "MakeAmmo", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 29, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "item_type" : "AMMO", - "value" : 1000 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "job" : "MakeAmmo", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 30, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "min_dimension" : 150, - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "item_type" : "AMMO", - "value" : 1000 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 20 - } - ], - "item_subtype" : "ITEM_AMMO_BOLTS", - "job" : "MakeAmmo", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 31, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_MACE", - "item_type" : "WEAPON", - "material" : "INORGANIC:PLATINUM", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "job" : "MakeWeapon", - "material" : "INORGANIC:PLATINUM" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 32, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "item_type" : "WEAPON", - "material" : "INORGANIC:PLATINUM", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:PLATINUM" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 64, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "item_type" : "WEAPON", - "material" : "INORGANIC:PLATINUM", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "job" : "MakeWeapon", - "material" : "INORGANIC:PLATINUM" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 35, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "job" : "MakeWeapon", - "material" : "INORGANIC:SILVER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 35, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:SILVER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 64, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "job" : "MakeWeapon", - "material" : "INORGANIC:SILVER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 37, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_SHIELD_SHIELD", - "item_type" : "SHIELD", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_SHIELD_SHIELD", - "job" : "MakeShield", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 38, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "job" : "MakeArmor", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 39, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_HELM_HELM", - "item_type" : "HELM", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_HELM_HELM", - "job" : "MakeHelm", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 40, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_SHOES_BOOTS", - "item_type" : "SHOES", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_SHOES_BOOTS", - "job" : "MakeShoes", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 41, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_GLOVES_GAUNTLETS", - "item_type" : "GLOVES", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_GLOVES_GAUNTLETS", - "job" : "MakeGloves", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 42, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_PANTS_GREAVES", - "item_type" : "PANTS", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "material" : "INORGANIC:STEEL", - "value" : 5 - } - ], - "item_subtype" : "ITEM_PANTS_GREAVES", - "job" : "MakePants", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 43, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_ARMOR_BREASTPLATE", - "item_type" : "ARMOR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "material" : "INORGANIC:STEEL", - "value" : 5 - } - ], - "item_subtype" : "ITEM_ARMOR_BREASTPLATE", - "job" : "MakeArmor", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 44, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_MACE", - "item_type" : "WEAPON", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "job" : "MakeWeapon", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 45, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "item_type" : "WEAPON", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 46, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_SPEAR", - "item_type" : "WEAPON", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_SPEAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 47, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", - "item_type" : "WEAPON", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", - "job" : "MakeWeapon", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 48, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", - "item_type" : "WEAPON", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", - "job" : "MakeWeapon", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 49, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_PICK", - "item_type" : "WEAPON", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_PICK", - "job" : "MakeWeapon", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 50, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "item_type" : "WEAPON", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - } - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "job" : "MakeWeapon", - "material" : "INORGANIC:STEEL" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 51, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_SHIELD_SHIELD", - "item_type" : "SHIELD", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_SHIELD_SHIELD", - "job" : "MakeShield", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 52, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "job" : "MakeArmor", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 53, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_HELM_HELM", - "item_type" : "HELM", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_HELM_HELM", - "job" : "MakeHelm", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 54, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_SHOES_BOOTS", - "item_type" : "SHOES", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_SHOES_BOOTS", - "job" : "MakeShoes", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 55, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_GLOVES_GAUNTLETS", - "item_type" : "GLOVES", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_GLOVES_GAUNTLETS", - "job" : "MakeGloves", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 56, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_PANTS_GREAVES", - "item_type" : "PANTS", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 5 - } - ], - "item_subtype" : "ITEM_PANTS_GREAVES", - "job" : "MakePants", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 57, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_BREASTPLATE", - "item_type" : "ARMOR", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 5 - } - ], - "item_subtype" : "ITEM_ARMOR_BREASTPLATE", - "job" : "MakeArmor", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 58, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "job" : "MakeWeapon", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 59, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 60, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_SPEAR", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_SPEAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 61, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", - "job" : "MakeWeapon", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 62, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", - "job" : "MakeWeapon", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 63, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 30 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_PICK", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 - } - ], - "item_subtype" : "ITEM_WEAPON_PICK", - "job" : "MakeWeapon", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 64, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 30 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BOULDER", - "reaction_class" : "FLUX", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "job" : "MakeWeapon", - "material" : "INORGANIC:IRON" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 79, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_SHIELD_SHIELD", - "item_type" : "SHIELD", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_SHIELD_SHIELD", - "job" : "MakeShield", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 80, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "job" : "MakeArmor", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 81, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_HELM_HELM", - "item_type" : "HELM", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_HELM_HELM", - "job" : "MakeHelm", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 82, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_SHOES_BOOTS", - "item_type" : "SHOES", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_SHOES_BOOTS", - "job" : "MakeShoes", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 83, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_GLOVES_GAUNTLETS", - "item_type" : "GLOVES", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - } - ], - "item_subtype" : "ITEM_GLOVES_GAUNTLETS", - "job" : "MakeGloves", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 84, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_PANTS_GREAVES", - "item_type" : "PANTS", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 5 - } - ], - "item_subtype" : "ITEM_PANTS_GREAVES", - "job" : "MakePants", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 85, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_BREASTPLATE", - "item_type" : "ARMOR", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 5 - } - ], - "item_subtype" : "ITEM_ARMOR_BREASTPLATE", - "job" : "MakeArmor", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 72, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "min_dimension" : 150, - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - } - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "job" : "MakeWeapon", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 87, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 88, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_SPEAR", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_SPEAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 89, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", - "job" : "MakeWeapon", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 90, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", - "job" : "MakeWeapon", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 91, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 30 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_PICK", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 - } - ], - "item_subtype" : "ITEM_WEAPON_PICK", - "job" : "MakeWeapon", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 92, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 30 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "job" : "MakeWeapon", - "material" : "INORGANIC:BISMUTH_BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 79, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_SHIELD_SHIELD", - "item_type" : "SHIELD", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_SHIELD_SHIELD", - "job" : "MakeShield", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 80, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "job" : "MakeArmor", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 81, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_HELM_HELM", - "item_type" : "HELM", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_HELM_HELM", - "job" : "MakeHelm", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 82, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_SHOES_BOOTS", - "item_type" : "SHOES", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_SHOES_BOOTS", - "job" : "MakeShoes", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 83, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_GLOVES_GAUNTLETS", - "item_type" : "GLOVES", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_GLOVES_GAUNTLETS", - "job" : "MakeGloves", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 84, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_PANTS_GREAVES", - "item_type" : "PANTS", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_PANTS_GREAVES", - "job" : "MakePants", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 85, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_BREASTPLATE", - "item_type" : "ARMOR", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "AtLeast", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_ARMOR_BREASTPLATE", - "job" : "MakeArmor", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 86, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "job" : "MakeWeapon", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 87, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 88, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_SPEAR", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_SPEAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 89, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", - "job" : "MakeWeapon", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 90, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", - "job" : "MakeWeapon", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 91, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 30 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_PICK", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 30 - } - ], - "item_subtype" : "ITEM_WEAPON_PICK", - "job" : "MakeWeapon", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 92, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 30 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 30 - } - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "job" : "MakeWeapon", - "material" : "INORGANIC:BRONZE" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 93, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_SHIELD_SHIELD", - "item_type" : "SHIELD", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_SHIELD_SHIELD", - "job" : "MakeShield", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 94, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "job" : "MakeArmor", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 95, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_HELM_HELM", - "item_type" : "HELM", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_HELM_HELM", - "job" : "MakeHelm", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 96, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_SHOES_BOOTS", - "item_type" : "SHOES", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_SHOES_BOOTS", - "job" : "MakeShoes", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 97, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_GLOVES_GAUNTLETS", - "item_type" : "GLOVES", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - } - ], - "item_subtype" : "ITEM_GLOVES_GAUNTLETS", - "job" : "MakeGloves", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 98, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_PANTS_GREAVES", - "item_type" : "PANTS", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 5 - } - ], - "item_subtype" : "ITEM_PANTS_GREAVES", - "job" : "MakePants", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 99, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 20 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_BREASTPLATE", - "item_type" : "ARMOR", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 20 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 20 - }, - { - "condition" : "AtLeast", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_ARMOR_MAIL_SHIRT", - "item_type" : "ARMOR", - "value" : 5 - } - ], - "item_subtype" : "ITEM_ARMOR_BREASTPLATE", - "job" : "MakeArmor", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 100, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_MACE", - "job" : "MakeWeapon", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 101, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "item_type" : "WEAPON", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_HAMMER_WAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 102, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_SPEAR", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_SPEAR", - "job" : "MakeWeapon", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 103, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_SWORD_SHORT", - "job" : "MakeWeapon", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 104, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 10 - } - ], - "item_subtype" : "ITEM_WEAPON_AXE_BATTLE", - "job" : "MakeWeapon", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 105, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 10 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_PICK", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 30 - } - ], - "item_subtype" : "ITEM_WEAPON_PICK", - "job" : "MakeWeapon", - "material" : "INORGANIC:COPPER" - }, - { - "amount_left" : 1, - "amount_total" : 1, - "frequency" : "Daily", - "id" : 106, - "is_active" : false, - "is_validated" : false, - "item_conditions" : - [ - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "INORGANIC:COPPER", - "value" : 30 - }, - { - "condition" : "AtLeast", - "item_type" : "BAR", - "material" : "COAL", - "value" : 100 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BRONZE", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:IRON", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:STEEL", - "value" : 30 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:SILVER", - "value" : 5 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:PLATINUM", - "value" : 5 - }, - { - "condition" : "AtMost", - "flags" : - [ - "metal" - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "item_type" : "WEAPON", - "value" : 10 - }, - { - "condition" : "LessThan", - "item_type" : "BAR", - "material" : "INORGANIC:BISMUTH_BRONZE", - "value" : 30 - } - ], - "item_subtype" : "ITEM_WEAPON_CROSSBOW", - "job" : "MakeWeapon", - "material" : "INORGANIC:COPPER" - } -] diff --git a/docs/plugins/orders.rst b/docs/plugins/orders.rst index 08e05c6ca..7082d2434 100644 --- a/docs/plugins/orders.rst +++ b/docs/plugins/orders.rst @@ -104,13 +104,15 @@ Orders are missing for plaster powder until DF :bug:`11803` is fixed. This collection adds high-volume smelting jobs for military-grade metal ores and produces weapons and armor: -- leather backpacks/waterskins/cloaks/quivers/armor +- leather backpacks/waterskins/quivers/armor +- silk cloaks - bone/wooden bolts - smelting for platinum, silver, steel, bronze, bismuth bronze, and copper (and their dependencies) - bronze/bismuth bronze/copper bolts -- silver/steel/iron/bismuth bronze/bronze/copper weapons and armor, +- steel/silver/iron/bismuth bronze/bronze/copper weapons and armor, with checks to ensure only the best available materials are being used +- wooden shields (if metal isn't available) If you set a stockpile to take weapons and armor of less than masterwork quality and turn on `automelt` (like what `dreamfort` provides on its industry level), @@ -120,16 +122,6 @@ Make sure you have a lot of fuel (or magma forges and furnaces) before you turn This file should only be imported, of course, if you need to equip a military. -:source:`library/military_include_artifact_materials ` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -As above, but this collection will also allow creation of platinum blunt weapons. -Normally these are only created by artifact moods, work orders can't be created -manually for them. - -- platinum/silver/steel/iron/bismuth bronze/bronze/copper weapons and armor, - with checks to ensure only the best available materials are being used - :source:`library/smelting ` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From f43bfed7f21406429fd53976d1fc2f8cf90d1a9c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 16 May 2023 15:53:11 -0700 Subject: [PATCH 0168/1234] remove easy meals; add bins; document jugs --- data/orders/basic.json | 99 ++++++++++++++++++++--------------------- docs/plugins/orders.rst | 7 ++- 2 files changed, 54 insertions(+), 52 deletions(-) diff --git a/data/orders/basic.json b/data/orders/basic.json index 16b05e0ba..8e271ba04 100644 --- a/data/orders/basic.json +++ b/data/orders/basic.json @@ -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_total" : 10, "frequency" : "Daily", - "id" : 1, + "id" : 0, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -47,7 +25,7 @@ "unrotten", "cookable" ], - "value" : 500 + "value" : 80 }, { "condition" : "AtMost", @@ -57,15 +35,6 @@ ], "item_type" : "FOOD", "value" : 3500 - }, - { - "condition" : "AtLeast", - "flags" : - [ - "unrotten" - ], - "item_type" : "FOOD", - "value" : 400 } ], "job" : "PrepareMeal", @@ -75,7 +44,7 @@ "amount_left" : 2, "amount_total" : 2, "frequency" : "Daily", - "id" : 2, + "id" : 1, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -112,7 +81,7 @@ "amount_left" : 2, "amount_total" : 2, "frequency" : "Daily", - "id" : 3, + "id" : 2, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -149,7 +118,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 4, + "id" : 3, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -170,7 +139,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 5, + "id" : 4, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -205,7 +174,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 6, + "id" : 5, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -237,7 +206,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 7, + "id" : 6, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -268,7 +237,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 8, + "id" : 7, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -290,7 +259,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 9, + "id" : 8, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -322,7 +291,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 10, + "id" : 9, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -353,7 +322,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 11, + "id" : 10, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -386,7 +355,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 12, + "id" : 11, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -426,7 +395,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 13, + "id" : 12, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -452,7 +421,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 14, + "id" : 13, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -487,7 +456,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 15, + "id" : 14, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -522,7 +491,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 16, + "id" : 15, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -557,7 +526,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 17, + "id" : 16, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -587,7 +556,7 @@ "amount_left" : 1, "amount_total" : 1, "frequency" : "Daily", - "id" : 18, + "id" : 17, "is_active" : false, "is_validated" : false, "item_conditions" : @@ -618,6 +587,36 @@ "job" : "MakeTool", "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_total" : 1, diff --git a/docs/plugins/orders.rst b/docs/plugins/orders.rst index 7082d2434..46a004081 100644 --- a/docs/plugins/orders.rst +++ b/docs/plugins/orders.rst @@ -67,7 +67,7 @@ This collection of orders handles basic fort necessities: - prepared meals and food products (and by-products like oil) - booze/mead - thread/cloth/dye -- pots/jugs/buckets/mugs +- pots/bins/jugs/buckets/mugs - bags of leather, cloth, silk, and yarn - crafts, totems, and shleggings from otherwise unusable by-products - mechanisms/cages @@ -80,7 +80,10 @@ This collection of orders handles basic fort necessities: You should import it as soon as you have enough dwarves to perform the tasks. Right after the first migration wave is usually a good time. -Armok's note: shleggings? Yes, `shleggings `__. +Note that the jugs are specifically made out of wood. This is so, as long as you don't may any other "Tools" out of wood, you can have a stockpile just for jugs by restricting a finished goods stockpile to only take wooden tools. + +Armok's additional note: "shleggings? Yes, +`shleggings `__." :source:`library/furnace ` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From 04b1b0f84d69ae41890aeda7d71d36eac0e69eb9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 16 May 2023 16:04:33 -0700 Subject: [PATCH 0169/1234] update changelog --- docs/changelog.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index fc706cdba..f2cbeb0af 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -46,6 +46,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes ## Misc Improvements +- `orders`: update orders in orders library for prepared meals, bins, archer uniforms, and weapons - Terminal console no longer appears in front of the game window on startup - `gui/design`: Improved performance for drawing shapes @@ -56,6 +57,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Lua ## 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 From 368a9fbc2eec722c1eaf47ffe99ab3c17a89732e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 16 May 2023 16:34:22 -0700 Subject: [PATCH 0170/1234] update dreamfort traffic patterns --- data/blueprints/dreamfort.csv | 223 ++++++++++++++++++++++++++++------ docs/changelog.txt | 1 + 2 files changed, 184 insertions(+), 40 deletions(-) diff --git a/data/blueprints/dreamfort.csv b/data/blueprints/dreamfort.csv index c5566920b..66ce693b8 100644 --- a/data/blueprints/dreamfort.csv +++ b/data/blueprints/dreamfort.csv @@ -1890,7 +1890,7 @@ Workshops: - 1x Dyer - 1x Loom - 1x Clothier -"" + "" Manual steps you have to take: - Assign minecarts to your quantum stockpile hauling routes @@ -1954,9 +1954,46 @@ Industry Walkthrough: "#meta label(industry2) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) build workshops and stockpiles, configure stockpiles" +traffic/industry_traffic build/industry_build place/industry_place query/industry_query +#dig label(industry_traffic) start(18; 18; central stairs) hidden() + + +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh +,,,,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh +,,,,oh,`,`,`,`,`,`,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,,,oh,`,`,`,`,`,`,oh,ol,ol,ol,oh,oh,oh,oh,oh,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,,,oh,`,`,`,`,`,`,oh,ol,ol,ol,oh,oh,`,oh,oh,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,,,oh,`,`,`,`,`,`,oh,ol,ol,ol,oh,oh,`,oh,oh,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,,,oh,`,`,`,`,`,`,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,,,oh,`,`,`,`,`,`,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh,oh,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,,,`,,`,,,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,oh,oh,oh,oh,oh,oh,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,oh,oh,oh,oh,oh,oh,` +,,`,ol,ol,ol,oh,oh,oh,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,oh,oh,oh,ol,ol,ol,` +,,`,ol,ol,ol,oh,`,`,`,`,`,`,`,,`,,`,,`,,`,`,`,`,`,`,`,oh,ol,ol,ol,` +,,`,ol,ol,ol,oh,oh,oh,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,oh,oh,oh,ol,ol,ol,` +,,`,oh,oh,oh,oh,oh,oh,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,oh,oh,oh,oh,oh,oh,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,,,`,,`,,,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,ol,ol,ol,ol,ol,ol,ol,ol,ol,oh,oh,oh,`,`,`,`,`,oh,oh,oh,ol,ol,ol,ol,ol,ol,ol,ol,ol,` +,,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh,oh,` +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,oh,oh,`,oh,oh,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,,,oh,oh,oh,oh,oh,oh,oh,oh,ol,ol,ol,`,oh,`,oh,`,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,`,`,`,`,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,ol,ol,ol,`,ol,ol,ol,oh,`,`,`,`,`,`,oh +,,,,`,`,`,`,`,`,`,oh,ol,ol,ol,`,ol,ol,ol,`,ol,ol,ol,oh,oh,oh,oh,oh,oh,oh,oh +,,,,,,,,,,,oh,ol,ol,ol,oh,ol,ol,ol,oh,ol,ol,ol,oh +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` + + #build label(industry_build) start(18; 18) hidden() @@ -2052,7 +2089,7 @@ query/industry_query ,,~,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,` ,,~,`,`,`,`,`,`,"{givename name=""wood feeder""}",~,"{givename name=""goods feeder""}",nocontainers,~,,`,`,`,`,`,,craftrefuse,,,,~,`,`,`,`,`,`,` ,,t{Right 5}{Down}&,`,`,`,`,`,`,~,~,{tallow}{permitwax},~,~,`,`,,,,`,`,"{givename name=""cloth/bones feeder""}",g{Up 3}{Right 5}&,~,~,~,`,`,`,`,`,`,` -,,`,`,~,`,`,"{quantum name=""goods/wood quantum""}g{Up 13}{Right 10}&","{quantumstop name=""Goods/Wood quantum"" sp_links=""{sp_link move={Right} move_back={Left}}{sp_link move=""""{Right 5}"""" move_back=""""{Left 5}""""}{sp_link move=""""{Down}{Right 5}"""" move_back=""""{Left 5}{Up}""""}""}{givename name=""goods/wood dumper""}",~,~,{forbidcrafts}{forbidgoblets},~,~,,`,,`,,`,,nocontainers,~,~,~,~,"{quantumstopfromwest name=""Clothier/Bones quantum""}{givename name=""cloth/bones dumper""}","{quantum name=""cloth/bones quantum""}g{Up 4}&",`,`,~,`,` +,,`,`,~,`,`,"{quantum name=""goods/wood quantum""}g{Up 13}{Right 10}&","{quantumstop name=""Goods/Wood quantum"" sp_links=""{sp_link move={Right} move_back={Left}}{sp_link move=""""{Right 5}"""" move_back=""""{Left 5}""""}{sp_link move=""""{Down}{Right 5}"""" move_back=""""{Left 5}{Up}""""}""}{givename name=""goods/wood dumper""}",~,~,{forbidcrafts}{forbidgoblets},~,~,,`,,`,,`,,nocontainers,~,~,~,~,"{quantumstopfromwest name=""Clothier/Bones quantum""}{givename name=""cloth/bones dumper""}","{quantum name=""cloth/bones quantum""}g{Up 4}{Right 3}&",`,`,~,`,` ,,miscliquid,`,`,`,`,`,`,~,~,"{givename name=""furniture feeder""}",~,~,`,`,,,,`,`,forbidadamantinethread,~,~,~,~,`,`,`,`,`,`,` ,,"{givename name=""miscliquid""}",`,`,`,`,`,`,~,~,forbidsand,~,~,,`,`,`,`,`,,dye,~,~,~,~,`,`,`,`,`,`,` ,,~,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,` @@ -2206,6 +2243,7 @@ Services Walkthrough: "#meta label(services2) start(central stairs) message(Remember to enqueue manager orders for this blueprint. Once furniture has been placed, continue with /services3.) dining hall anchors, stockpiles, hospital, garbage dump" +traffic/services_traffic zones/services_zones build/services_build place/services_place @@ -2221,6 +2259,108 @@ build2/services_build2 build3/services_build3 place_jail/services_place_jail query_jail/services_query_jail +#dig label(services_traffic) start(18; 18) hidden() keep lollygaggers out of the cisterns + +,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,,or,,or,or,or +,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,or,or,or,or,or,or +,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,,or,,or,or,or +,,ol,,,,ol,,,,ol,,,,,,,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,,or,,or,or,or,,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,,or,,or,or,or,,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,,,,or,,,,,,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,,,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,,or,,or,,or +,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,,,or,,or,,,,,or,,or,,or,,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,oh,oh,oh,oh,oh,,,,or,or,or,or,or,or,or,or,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,or,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,`,,oh,`,`,`,oh,,`,,oh,oh,oh,`,oh,or,or,or,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,or,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,oh,oh,oh,oh,oh,,,,or,or,or,or,or,or,or,or,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,,,or,,,,,,or,,or,,or,,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,,,,,,,,,or,,or,,or,,or +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh +,,,,oh,oh,,oh,oh +,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh +,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh + +#> + +,,,,,,,,,,,,,or,or,or,,or,,or,or,or +,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or +,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,or,or,or,,or,,or,or,or +,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or +,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,or +,,,,,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or,or +,,,,,,,,,,,,,,,,,or,,,,,,,,,or +,,,,,,,,,,,,,,,,,or,,,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,or,or,or +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,or,or,or +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,or,or,or,,,,or,or,or + + + +,,,,,,,,,,,,,or,or,or,,,,or,or,or + + + + + + + + + +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,or,or,or +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,` + +#> + +,,,,,,,,,,,,,,or,or,,,,or,or + + + +,,,,,,,,,,,,,,or,or,,,,or,or + + + + + + + + + +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,or,or +,,,,,,,,,,,,,,,`,`,`,`,` +,,,,,,,,,,,,,,,`,`,`,`,` + "#zone label(services_zones) start(18; 18) hidden() message(If you'd like to fill your wells via bucket brigade, activate the inactive pond zones one level down from where the wells will be built.) garbage dump, hospital, and pond zones" ,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` @@ -2575,42 +2715,6 @@ query_jail/services_query_jail ,,,,,,,,,,,,,,,`,`,`,`,` ,,,,,,,,,,,,,,,`,`,`,`,` -#dig label(services_traffic) start(18; 18) hidden() promote the tavern as the place to eat - -,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,,or,,or,or,or -,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,or,or,or,or,or,or -,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,,or,,or,or,or -,,ol,,,,ol,,,,ol,,,,,,,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,,or,,or,or,or,,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,,or,,or,or,or,,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,,,,or,,,,,,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,,,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,,or,,or,,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,,,or,,or,,,,,or,,or,,or,,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,oh,oh,oh,oh,oh,,,,or,or,or,or,or,or,or,or,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,or,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,`,,oh,`,`,`,oh,,`,,oh,oh,oh,`,oh,or,or,or,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,or,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,oh,oh,oh,oh,oh,,,,or,or,or,or,or,or,or,or,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,,,`,,,,,,or,,or,,or,,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,,,,,,,,,or,,or,,or,,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,,,,oh,oh,,oh,oh -,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh - "#build label(services_build3) start(18; 18) hidden() jail, statues" ,~,~,~,,~,~,~,,~,~,~,,t,l,b,,`,,t,l,b @@ -2946,8 +3050,47 @@ Apartments Walkthrough: ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -"#build label(suites2) start(18; 18; central ramp) message(Remember to enqueue manager orders for this blueprint. -bedrooms are left unconfigured so you can assign them to specific nobles)" +"#meta label(suites2) start(central ramp) message(Remember to enqueue manager orders for this blueprint. +bedrooms are left unconfigured so you can assign them to specific nobles.) build furniture and set traffic patterns" +traffic_suites/suites_traffic +build_suites/suites_build +#dig label(suites_traffic) start(18; 18; central ramp) hidden() + +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,,,,or,,,,,,or,,,,`,,`,,,,or,,,,,,or,,,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,,,or,,,,,,or,,,,`,`,`,,,,or,,,,,,or,,,,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,,,,or,,,,,,or,,,,`,`,`,,,,or,,,,,,or,,,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,,,or,,,,,,or,,,,`,,`,,,,or,,,,,,or,,,,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` + +#build label(suites_build) start(18; 18; central ramp) hidden() ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` diff --git a/docs/changelog.txt b/docs/changelog.txt index fc706cdba..75050ff73 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -48,6 +48,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - Terminal console no longer appears in front of the game window on startup - `gui/design`: Improved performance for drawing shapes +- Dreamfort: improve traffic patterns throughout the fortress (stockpiles and zones are still not working, pending updates in `quickfort`) ## Documentation From 11361975f903e4cb424b95e4b9e5497ef45df991 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 16 May 2023 17:12:44 -0700 Subject: [PATCH 0171/1234] look up texpos values instead of assuming they're constant --- docs/changelog.txt | 1 + library/lua/gui.lua | 2 +- library/lua/gui/widgets.lua | 43 +++++++++++++++++++------------------ library/modules/Screen.cpp | 2 +- plugins/pathable.cpp | 6 ++++-- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fc706cdba..14c2d7620 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -44,6 +44,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `work-now`: reinstated, renamed from ``workNow``: reduce the time that dwarves are left without a task after completing a job ## Fixes +- DFHack screen backgrounds now use appropriate tiles in DF Classic ## Misc Improvements - Terminal console no longer appears in front of the game window on startup diff --git a/library/lua/gui.lua b/library/lua/gui.lua index b2c90d076..7e991e1df 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -9,7 +9,7 @@ local getval = utils.getval local to_pen = dfhack.pen.parse -CLEAR_PEN = to_pen{tile=909, ch=32, fg=0, bg=0, write_to_lower=true} +CLEAR_PEN = to_pen{tile=df.global.init.texpos_border_interior, ch=32, fg=0, bg=0, write_to_lower=true} TRANSPARENT_PEN = to_pen{tile=0, ch=0} KEEP_LOWER_PEN = to_pen{ch=32, fg=0, bg=0, keep_lower=true} diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 7aa79cbc3..5653dff94 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -853,7 +853,7 @@ local function scrollbar_is_visible(scrollbar) return scrollbar.elems_per_page < scrollbar.num_elems end -local SBSO = 922 --Scroll Bar Spritesheet Offset / change this to point to a different spritesheet (ui themes, anyone? :p) +local SBSO = df.global.init.scrollbar_texpos[0] --Scroll Bar Spritesheet Offset / change this to point to a different spritesheet (ui themes, anyone? :p) local SCROLLBAR_UP_LEFT_PEN = to_pen{tile=SBSO+0, ch=47, fg=COLOR_CYAN, bg=COLOR_BLACK} local SCROLLBAR_UP_RIGHT_PEN = to_pen{tile=SBSO+1, ch=92, fg=COLOR_CYAN, bg=COLOR_BLACK} local SCROLLBAR_DOWN_LEFT_PEN = to_pen{tile=SBSO+24, ch=92, fg=COLOR_CYAN, bg=COLOR_BLACK} @@ -2144,34 +2144,35 @@ function FilteredList:onFilterChar(char, text) return true end +local TSO = df.global.init.tabs_texpos[0] -- tab spritesheet offset local DEFAULT_ACTIVE_TAB_PENS = { text_mode_tab_pen=to_pen{fg=COLOR_YELLOW}, text_mode_label_pen=to_pen{fg=COLOR_WHITE}, - lt=to_pen{tile=1005, write_to_lower=true}, - lt2=to_pen{tile=1006, write_to_lower=true}, - t=to_pen{tile=1007, fg=COLOR_BLACK, write_to_lower=true, top_of_text=true}, - rt2=to_pen{tile=1008, write_to_lower=true}, - rt=to_pen{tile=1009, write_to_lower=true}, - lb=to_pen{tile=1015, write_to_lower=true}, - lb2=to_pen{tile=1016, write_to_lower=true}, - b=to_pen{tile=1017, fg=COLOR_BLACK, write_to_lower=true, bottom_of_text=true}, - rb2=to_pen{tile=1018, write_to_lower=true}, - rb=to_pen{tile=1019, write_to_lower=true}, + lt=to_pen{tile=TSO+5, write_to_lower=true}, + lt2=to_pen{tile=TSO+6, write_to_lower=true}, + t=to_pen{tile=TSO+7, fg=COLOR_BLACK, write_to_lower=true, top_of_text=true}, + rt2=to_pen{tile=TSO+8, write_to_lower=true}, + rt=to_pen{tile=TSO+9, write_to_lower=true}, + lb=to_pen{tile=TSO+15, write_to_lower=true}, + lb2=to_pen{tile=TSO+16, write_to_lower=true}, + b=to_pen{tile=TSO+17, fg=COLOR_BLACK, write_to_lower=true, bottom_of_text=true}, + rb2=to_pen{tile=TSO+18, write_to_lower=true}, + rb=to_pen{tile=TSO+19, write_to_lower=true}, } local DEFAULT_INACTIVE_TAB_PENS = { text_mode_tab_pen=to_pen{fg=COLOR_BROWN}, text_mode_label_pen=to_pen{fg=COLOR_DARKGREY}, - lt=to_pen{tile=1000, write_to_lower=true}, - lt2=to_pen{tile=1001, write_to_lower=true}, - t=to_pen{tile=1002, fg=COLOR_WHITE, write_to_lower=true, top_of_text=true}, - rt2=to_pen{tile=1003, write_to_lower=true}, - rt=to_pen{tile=1004, write_to_lower=true}, - lb=to_pen{tile=1010, write_to_lower=true}, - lb2=to_pen{tile=1011, write_to_lower=true}, - b=to_pen{tile=1012, fg=COLOR_WHITE, write_to_lower=true, bottom_of_text=true}, - rb2=to_pen{tile=1013, write_to_lower=true}, - rb=to_pen{tile=1014, write_to_lower=true}, + lt=to_pen{tile=TSO+0, write_to_lower=true}, + lt2=to_pen{tile=TSO+1, write_to_lower=true}, + t=to_pen{tile=TSO+2, fg=COLOR_WHITE, write_to_lower=true, top_of_text=true}, + rt2=to_pen{tile=TSO+3, write_to_lower=true}, + rt=to_pen{tile=TSO+4, write_to_lower=true}, + lb=to_pen{tile=TSO+10, write_to_lower=true}, + lb2=to_pen{tile=TSO+11, write_to_lower=true}, + b=to_pen{tile=TSO+12, fg=COLOR_WHITE, write_to_lower=true, bottom_of_text=true}, + rb2=to_pen{tile=TSO+13, write_to_lower=true}, + rb=to_pen{tile=TSO+14, write_to_lower=true}, } --------- diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index dcb18dd91..6ccf246aa 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -209,7 +209,7 @@ static bool doSetTile_default(const Pen &pen, int x, int y, bool map) } } else if (pen.ch) { screen[0] = uint8_t(pen.ch); - *texpos_lower = 909; // basic black background + *texpos_lower = df::global::init->texpos_border_interior; // basic black background } auto rgb_fg = &gps->uccolor[fg][0]; diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index dd26a712f..06394f838 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -7,6 +7,8 @@ #include "LuaTools.h" #include "PluginManager.h" +#include "df/init.h" + using namespace DFHack; DFHACK_PLUGIN("pathable"); @@ -37,8 +39,8 @@ static void paintScreen(df::coord target, bool skip_unrevealed = false) { int selected_tile_texpos = 0; Screen::findGraphicsTile("CURSORS", 4, 3, &selected_tile_texpos); - long pathable_tile_texpos = 779; - long unpathable_tile_texpos = 782; + long pathable_tile_texpos = df::global::init->load_bar_texpos[1]; + long unpathable_tile_texpos = df::global::init->load_bar_texpos[4]; long on_off_texpos = Textures::getOnOffTexposStart(); if (on_off_texpos > 0) { pathable_tile_texpos = on_off_texpos + 0; From 899422aaf8291e7028d8b30d7316b1d1f3e90704 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 16 May 2023 17:26:16 -0700 Subject: [PATCH 0172/1234] give widgets.TabBar default hotkeys --- docs/dev/Lua API.rst | 4 +++- library/lua/gui/widgets.lua | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 85e51d11d..db5a9d59c 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5113,7 +5113,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. :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 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 diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 7aa79cbc3..aa18d9fa9 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -2241,8 +2241,8 @@ TabBar.ATTRS{ active_tab_pens=DEFAULT_ACTIVE_TAB_PENS, inactive_tab_pens=DEFAULT_INACTIVE_TAB_PENS, get_pens=DEFAULT_NIL, - key=DEFAULT_NIL, - key_back=DEFAULT_NIL, + key='CUSTOM_CTRL_T', + key_back='CUSTOM_CTRL_Y', } function TabBar:init() From 1d24f812dd36ad4b43dd439e30931d1481d87416 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 17 May 2023 07:13:14 +0000 Subject: [PATCH 0173/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 1ec3602f9..2554b931b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 1ec3602f9d896c9dc76b26b3be845a5aa7544093 +Subproject commit 2554b931bfc23564de5bc7cb28eed673e82d06d3 From de2e29a2e3679b560edcec9bf7dec766bc0a43ba Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 17 May 2023 02:34:19 -0700 Subject: [PATCH 0174/1234] add github action to clean up PR caches after merge --- .github/workflows/clean-cache.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/clean-cache.yml diff --git a/.github/workflows/clean-cache.yml b/.github/workflows/clean-cache.yml new file mode 100644 index 000000000..309fae105 --- /dev/null +++ b/.github/workflows/clean-cache.yml @@ -0,0 +1,30 @@ +name: Clean up PR caches +on: + pull_request: + 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 | 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 }} From ffe8de12928e9786431947a08bbd7f63b4bc067f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 17 May 2023 11:10:20 -0700 Subject: [PATCH 0175/1234] clean caches in root context, not the PR --- .github/workflows/clean-cache.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clean-cache.yml b/.github/workflows/clean-cache.yml index 309fae105..d3e12959d 100644 --- a/.github/workflows/clean-cache.yml +++ b/.github/workflows/clean-cache.yml @@ -1,6 +1,6 @@ name: Clean up PR caches on: - pull_request: + pull_request_target: types: - closed From 9d8a825eb4af1de095f425b4286c95186442bd18 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 15 May 2023 15:17:06 -0700 Subject: [PATCH 0176/1234] adjust usage to game structure reunification --- plugins/autolabor/autolabor.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/autolabor/autolabor.cpp b/plugins/autolabor/autolabor.cpp index 53a01a6a6..72bb4d84e 100644 --- a/plugins/autolabor/autolabor.cpp +++ b/plugins/autolabor/autolabor.cpp @@ -34,8 +34,8 @@ #include #include #include +#include #include -#include #include @@ -51,7 +51,7 @@ using namespace df::enums; DFHACK_PLUGIN("autolabor"); REQUIRE_GLOBAL(plotinfo); REQUIRE_GLOBAL(world); -REQUIRE_GLOBAL(game_extra); +REQUIRE_GLOBAL(game); #define ARRAY_COUNT(array) (sizeof(array)/sizeof((array)[0])) @@ -414,7 +414,7 @@ static void enable_plugin(color_ostream &out) cleanup_state(); init_state(); - df::global::game_extra->external_flag |= 1; // shut down DF's work detail system + game->external_flag |= 1; // shut down DF's work detail system } DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) @@ -1084,7 +1084,7 @@ DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable ) enable_autolabor = false; setOptionEnabled(CF_ENABLED, false); - df::global::game_extra->external_flag &= ~1; // reenable DF's work detail system + game->external_flag &= ~1; // reenable DF's work detail system out << "Autolabor is disabled." << std::endl; } From aa6baae834537db062f05fac2846af2c818afbae Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 17 May 2023 11:14:00 -0700 Subject: [PATCH 0177/1234] update structures ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 22d9bc0bc..9891be326 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 22d9bc0bc1847def8a6c62893104f36262e63e98 +Subproject commit 9891be32663435f2fe875e27c70010d5618de735 From 5c7d9f228d47a7c1a34a099309254703fcb916e5 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 17 May 2023 18:55:27 +0000 Subject: [PATCH 0178/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 2554b931b..2a646f9c7 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 2554b931bfc23564de5bc7cb28eed673e82d06d3 +Subproject commit 2a646f9c7204253cae70bbfb5ed194182e0ac373 From 6aede45135c5b14d0c8cbfefb8540fd846d75e9c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 16 May 2023 12:05:53 -0700 Subject: [PATCH 0179/1234] add links to quickstart-guide and gui/control-panel to the title screen --- docs/changelog.txt | 1 + docs/plugins/overlay.rst | 7 +++++++ plugins/lua/overlay.lua | 17 ++++++++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index c9f9fca89..59974909e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -55,6 +55,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `gui/design`: Improved performance for drawing shapes - Dreamfort: improve traffic patterns throughout the fortress (stockpiles and zones are still not working, pending updates in `quickfort`) - Core: For debugging purposes, you can now pass ``--disable-dfhack`` on the Dwarf Fortress commandline or specify ``DFHACK_DISABLE=1`` in the environment to disable DFHack for the current session. +- `overlay`: added links to the quickstart guide and the control panel on the DF title screen ## Documentation diff --git a/docs/plugins/overlay.rst b/docs/plugins/overlay.rst index 313220fd4..fd196158f 100644 --- a/docs/plugins/overlay.rst +++ b/docs/plugins/overlay.rst @@ -66,3 +66,10 @@ For easy reference, the corners can be found at the following coordinates: :(-1, 1): top right corner :(1, -1): lower left corner :(-1, -1): lower right corner + +Overlay +------- + +The `overlay` plugin also provides a standard overlay itself: +``title_version``, which displays the DFHack version on the DF title screen, +along with quick links to `quickstart-guide` and `gui/control-panel`. diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index 9f41cb035..fda1edc95 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -580,7 +580,8 @@ TitleVersionOverlay.ATTRS{ default_pos={x=7, y=2}, default_enabled=true, viewscreens='title/Default', - frame={w=35, h=3}, + frame={w=35, h=5}, + autoarrange_subviews=1, } function TitleVersionOverlay:init() @@ -602,6 +603,20 @@ function TitleVersionOverlay:init() text=text, text_pen=COLOR_WHITE, }, + widgets.HotkeyLabel{ + frame={l=0}, + label='Quickstart guide', + auto_width=true, + key='STRING_A063', + on_activate=function() dfhack.run_script('quickstart-guide') end, + }, + widgets.HotkeyLabel{ + frame={l=0}, + label='Control panel', + auto_width=true, + key='STRING_A047', + on_activate=function() dfhack.run_script('gui/control-panel') end, + }, } end From d4f41141ef907f336c56197a9ac3be62e751eda7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 17 May 2023 16:45:35 -0700 Subject: [PATCH 0180/1234] fix game_extra reference --- plugins/lua/autolabor.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/autolabor.lua b/plugins/lua/autolabor.lua index a468b30e1..a2c0e88cd 100644 --- a/plugins/lua/autolabor.lua +++ b/plugins/lua/autolabor.lua @@ -40,7 +40,7 @@ function AutolaborOverlay:init() end function AutolaborOverlay:render(dc) - if df.global.game_extra.external_flag ~= 1 then return end + if df.global.game.external_flag ~= 1 then return end AutolaborOverlay.super.render(self, dc) end From b9afb94ba6f5405d681ccb289419bf1e72f5d02e Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 18 May 2023 07:12:59 +0000 Subject: [PATCH 0181/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 2a646f9c7..97557b923 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 2a646f9c7204253cae70bbfb5ed194182e0ac373 +Subproject commit 97557b9239a5ad8297f6a32651b78fd9dbb333ec From eb742a603dcc945a09181662c9ea9138b78f81ba Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Thu, 18 May 2023 11:22:58 +0200 Subject: [PATCH 0182/1234] renamed XYZ_FRAME to FRAME_XYZ --- library/include/modules/Textures.h | 10 ++++---- library/lua/gui.lua | 33 +++++++++++++++--------- library/modules/Textures.cpp | 40 +++++++++++++++--------------- 3 files changed, 46 insertions(+), 37 deletions(-) diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 95e628d5a..1664f6081 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -54,11 +54,11 @@ DFHACK_EXPORT long getControlPanelTexposStart(); /** * Get the first texpos for the DFHack borders. Each is a 7x3 grid. */ -DFHACK_EXPORT long getThinBordersTexposStart(); -DFHACK_EXPORT long getMediumBordersTexposStart(); -DFHACK_EXPORT long getBoldBordersTexposStart(); -DFHACK_EXPORT long getPanelBordersTexposStart(); -DFHACK_EXPORT long getWindowBordersTexposStart(); +DFHACK_EXPORT long getBorderThinTexposStart(); +DFHACK_EXPORT long getBorderMediumTexposStart(); +DFHACK_EXPORT long getBorderBoldTexposStart(); +DFHACK_EXPORT long getBorderPanelTexposStart(); +DFHACK_EXPORT long getBorderWindowTexposStart(); } } diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 7e991e1df..311edc1f3 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -905,7 +905,7 @@ local BASE_FRAME = { } local function make_frame(name, double_line) - local texpos = dfhack.textures['get'..name..'BordersTexposStart']() + local texpos = dfhack.textures['getBorder'..name..'TexposStart']() local tp = function(offset) if texpos == -1 then return nil end return texpos + offset @@ -923,17 +923,26 @@ local function make_frame(name, double_line) return frame end -WINDOW_FRAME = make_frame('Window', true) -PANEL_FRAME = make_frame('Panel', false) -MEDIUM_FRAME = make_frame('Medium', false) -BOLD_FRAME = make_frame('Bold', true) -INTERIOR_FRAME = make_frame('Thin', false) -INTERIOR_FRAME.signature_pen = false -INTERIOR_MEDIUM_FRAME = copyall(MEDIUM_FRAME) -INTERIOR_MEDIUM_FRAME.signature_pen = false +FRAME_WINDOW = make_frame('Window', true) +FRAME_PANEL = make_frame('Panel', false) +FRAME_MEDIUM = make_frame('Medium', false) +FRAME_BOLD = make_frame('Bold', true) +FRAME_INTERIOR = make_frame('Thin', false) +FRAME_INTERIOR.signature_pen = false +FRAME_INTERIOR_MEDIUM = copyall(FRAME_MEDIUM) +FRAME_INTERIOR_MEDIUM.signature_pen = false -- for compatibility with pre-steam code -GREY_LINE_FRAME = WINDOW_FRAME +GREY_LINE_FRAME = FRAME_PANEL + +-- for compatibility with deprecated frame naming scheme +WINDOW_FRAME = FRAME_WINDOW +PANEL_FRAME = FRAME_PANEL +MEDIUM_FRAME = FRAME_MEDIUM +BOLD_FRAME = FRAME_BOLD +INTERIOR_FRAME = FRAME_INTERIOR +INTERIOR_MEDIUM_FRAME = FRAME_INTERIOR_MEDIUM + function paint_frame(dc,rect,style,title,inactive,pause_forced,resizable) local pen = style.frame_pen @@ -942,8 +951,8 @@ function paint_frame(dc,rect,style,title,inactive,pause_forced,resizable) dscreen.paintTile(style.rt_frame_pen or pen, x2, y1) dscreen.paintTile(style.lb_frame_pen or pen, x1, y2) local rb_frame_pen = style.rb_frame_pen - if rb_frame_pen == WINDOW_FRAME.rb_frame_pen and not resizable then - rb_frame_pen = PANEL_FRAME.rb_frame_pen + if rb_frame_pen == FRAME_WINDOW.rb_frame_pen and not resizable then + rb_frame_pen = FRAME_PANEL.rb_frame_pen end dscreen.paintTile(rb_frame_pen or pen, x2, y2) dscreen.fillRect(style.t_frame_pen or style.h_frame_pen or pen,x1+1,y1,x2-1,y1) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index a30f879a0..40339a616 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -24,11 +24,11 @@ static long g_red_pin_texpos_start = -1; static long g_icons_texpos_start = -1; static long g_on_off_texpos_start = -1; static long g_control_panel_texpos_start = -1; -static long g_thin_borders_texpos_start = -1; -static long g_medium_borders_texpos_start = -1; -static long g_bold_borders_texpos_start = -1; -static long g_panel_borders_texpos_start = -1; -static long g_window_borders_texpos_start = -1; +static long g_border_thin_texpos_start = -1; +static long g_border_medium_texpos_start = -1; +static long g_border_bold_texpos_start = -1; +static long g_border_panel_texpos_start = -1; +static long g_border_window_texpos_start = -1; // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set @@ -132,15 +132,15 @@ void Textures::init(color_ostream &out) { g_num_dfhack_textures += load_textures(out, "hack/data/art/control-panel.png", &g_control_panel_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/border-thin.png", - &g_thin_borders_texpos_start); + &g_border_thin_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/border-medium.png", - &g_medium_borders_texpos_start); + &g_border_medium_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/border-bold.png", - &g_bold_borders_texpos_start); + &g_border_bold_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/border-panel.png", - &g_panel_borders_texpos_start); + &g_border_panel_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/border-window.png", - &g_window_borders_texpos_start); + &g_border_window_texpos_start); DEBUG(textures,out).print("loaded %ld textures\n", g_num_dfhack_textures); @@ -197,22 +197,22 @@ long Textures::getControlPanelTexposStart() { return g_control_panel_texpos_start; } -long Textures::getThinBordersTexposStart() { - return g_thin_borders_texpos_start; +long Textures::getBorderThinTexposStart() { + return g_border_thin_texpos_start; } -long Textures::getMediumBordersTexposStart() { - return g_medium_borders_texpos_start; +long Textures::getBorderMediumTexposStart() { + return g_border_medium_texpos_start; } -long Textures::getBoldBordersTexposStart() { - return g_bold_borders_texpos_start; +long Textures::getBorderBoldTexposStart() { + return g_border_bold_texpos_start; } -long Textures::getPanelBordersTexposStart() { - return g_panel_borders_texpos_start; +long Textures::getBorderPanelTexposStart() { + return g_border_panel_texpos_start; } -long Textures::getWindowBordersTexposStart() { - return g_window_borders_texpos_start; +long Textures::getBorderWindowTexposStart() { + return g_border_window_texpos_start; } From 90fe6e7ae34132a8aa1670ae6d0cb7189a1cfd6c Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Thu, 18 May 2023 11:30:21 +0200 Subject: [PATCH 0183/1234] swapped any instance of 'border' being after 'xyz', everywhere --- docs/dev/Lua API.rst | 16 ++++++++-------- library/LuaApi.cpp | 10 +++++----- plugins/lua/buildingplan/pens.lua | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 1d70647f7..6fb2aca2c 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4347,32 +4347,32 @@ A framed screen has the following attributes: There are the following predefined frame style tables: -* ``WINDOW_FRAME`` +* ``FRAME_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. -* ``MEDIUM_FRAME`` +* ``FRAME_MEDIUM`` A frame suitable for overlay widget panels. -* ``BOLD_FRAME`` +* ``FRAME_BOLD`` A frame suitable for a non-draggable panel meant to capture the user's focus, like an important notification, confirmation dialog or error message. -* ``INTERIOR_FRAME`` +* ``FRAME_INTERIOR`` A frame suitable for light interior accent elements. This frame does *not* have a visible ``DFHack`` signature on it, so it must not be used as the most 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 most external frame for a DFHack-owned UI. @@ -4509,7 +4509,7 @@ Has attributes: by 1. The attributes are identical to what is defined in the `FramedScreen class`_. When using the predefined frame styles in the ``gui`` module, remember to ``require`` the gui module and prefix the identifier with - ``gui.``, e.g. ``gui.GREY_LINE_FRAME``. + ``gui.``, e.g. ``gui.FRAME_GREY_LINE``. Has functions: diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 08903c7bd..d21ce29e5 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1716,11 +1716,11 @@ static const LuaWrapper::FunctionReg dfhack_textures_module[] = { WRAPM(Textures, getIconsTexposStart), WRAPM(Textures, getOnOffTexposStart), WRAPM(Textures, getControlPanelTexposStart), - WRAPM(Textures, getThinBordersTexposStart), - WRAPM(Textures, getMediumBordersTexposStart), - WRAPM(Textures, getBoldBordersTexposStart), - WRAPM(Textures, getPanelBordersTexposStart), - WRAPM(Textures, getWindowBordersTexposStart), + WRAPM(Textures, getBorderThinTexposStart), + WRAPM(Textures, getBorderMediumTexposStart), + WRAPM(Textures, getBorderBoldTexposStart), + WRAPM(Textures, getBorderPanelTexposStart), + WRAPM(Textures, getBorderWindowTexposStart), { NULL, NULL } }; diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index e69a4c210..c68e12eae 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -18,12 +18,12 @@ function reload_pens() GOOD_TILE_PEN = to_pen{ch='o', fg=COLOR_GREEN, tile=dfhack.screen.findGraphicsTile('CURSORS', 1, 2)} BAD_TILE_PEN = to_pen{ch='X', fg=COLOR_RED, tile=dfhack.screen.findGraphicsTile('CURSORS', 3, 0)} - local tb_texpos = dfhack.textures.getThinBordersTexposStart() + local tb_texpos = dfhack.textures.getBorderThinTexposStart() VERT_TOP_PEN = to_pen{tile=tp(tb_texpos, 10), ch=194, fg=COLOR_GREY, bg=COLOR_BLACK} VERT_MID_PEN = to_pen{tile=tp(tb_texpos, 4), ch=179, fg=COLOR_GREY, bg=COLOR_BLACK} VERT_BOT_PEN = to_pen{tile=tp(tb_texpos, 11), ch=193, fg=COLOR_GREY, bg=COLOR_BLACK} - local mb_texpos = dfhack.textures.getMediumBordersTexposStart() + local mb_texpos = dfhack.textures.getBorderMediumTexposStart() HORI_LEFT_PEN = to_pen{tile=tp(mb_texpos, 12), ch=195, fg=COLOR_GREY, bg=COLOR_BLACK} HORI_MID_PEN = to_pen{tile=tp(mb_texpos, 5), ch=196, fg=COLOR_GREY, bg=COLOR_BLACK} HORI_RIGHT_PEN = to_pen{tile=tp(mb_texpos, 13), ch=180, fg=COLOR_GREY, bg=COLOR_BLACK} From c52b1cc950b3e55b27050740fb3f037d45918c09 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Thu, 18 May 2023 12:46:21 +0200 Subject: [PATCH 0184/1234] reverted to just renaming FRAMES in gui.lua --- library/LuaApi.cpp | 10 ++++---- library/include/modules/Textures.h | 10 ++++---- library/lua/gui.lua | 2 +- library/modules/Textures.cpp | 40 +++++++++++++++--------------- plugins/lua/buildingplan/pens.lua | 4 +-- 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index d21ce29e5..08903c7bd 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1716,11 +1716,11 @@ static const LuaWrapper::FunctionReg dfhack_textures_module[] = { WRAPM(Textures, getIconsTexposStart), WRAPM(Textures, getOnOffTexposStart), WRAPM(Textures, getControlPanelTexposStart), - WRAPM(Textures, getBorderThinTexposStart), - WRAPM(Textures, getBorderMediumTexposStart), - WRAPM(Textures, getBorderBoldTexposStart), - WRAPM(Textures, getBorderPanelTexposStart), - WRAPM(Textures, getBorderWindowTexposStart), + WRAPM(Textures, getThinBordersTexposStart), + WRAPM(Textures, getMediumBordersTexposStart), + WRAPM(Textures, getBoldBordersTexposStart), + WRAPM(Textures, getPanelBordersTexposStart), + WRAPM(Textures, getWindowBordersTexposStart), { NULL, NULL } }; diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 1664f6081..95e628d5a 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -54,11 +54,11 @@ DFHACK_EXPORT long getControlPanelTexposStart(); /** * Get the first texpos for the DFHack borders. Each is a 7x3 grid. */ -DFHACK_EXPORT long getBorderThinTexposStart(); -DFHACK_EXPORT long getBorderMediumTexposStart(); -DFHACK_EXPORT long getBorderBoldTexposStart(); -DFHACK_EXPORT long getBorderPanelTexposStart(); -DFHACK_EXPORT long getBorderWindowTexposStart(); +DFHACK_EXPORT long getThinBordersTexposStart(); +DFHACK_EXPORT long getMediumBordersTexposStart(); +DFHACK_EXPORT long getBoldBordersTexposStart(); +DFHACK_EXPORT long getPanelBordersTexposStart(); +DFHACK_EXPORT long getWindowBordersTexposStart(); } } diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 311edc1f3..d511cd51f 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -905,7 +905,7 @@ local BASE_FRAME = { } local function make_frame(name, double_line) - local texpos = dfhack.textures['getBorder'..name..'TexposStart']() + local texpos = dfhack.textures['get'..name..'BordersTexposStart']() local tp = function(offset) if texpos == -1 then return nil end return texpos + offset diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 40339a616..a30f879a0 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -24,11 +24,11 @@ static long g_red_pin_texpos_start = -1; static long g_icons_texpos_start = -1; static long g_on_off_texpos_start = -1; static long g_control_panel_texpos_start = -1; -static long g_border_thin_texpos_start = -1; -static long g_border_medium_texpos_start = -1; -static long g_border_bold_texpos_start = -1; -static long g_border_panel_texpos_start = -1; -static long g_border_window_texpos_start = -1; +static long g_thin_borders_texpos_start = -1; +static long g_medium_borders_texpos_start = -1; +static long g_bold_borders_texpos_start = -1; +static long g_panel_borders_texpos_start = -1; +static long g_window_borders_texpos_start = -1; // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set @@ -132,15 +132,15 @@ void Textures::init(color_ostream &out) { g_num_dfhack_textures += load_textures(out, "hack/data/art/control-panel.png", &g_control_panel_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/border-thin.png", - &g_border_thin_texpos_start); + &g_thin_borders_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/border-medium.png", - &g_border_medium_texpos_start); + &g_medium_borders_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/border-bold.png", - &g_border_bold_texpos_start); + &g_bold_borders_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/border-panel.png", - &g_border_panel_texpos_start); + &g_panel_borders_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/border-window.png", - &g_border_window_texpos_start); + &g_window_borders_texpos_start); DEBUG(textures,out).print("loaded %ld textures\n", g_num_dfhack_textures); @@ -197,22 +197,22 @@ long Textures::getControlPanelTexposStart() { return g_control_panel_texpos_start; } -long Textures::getBorderThinTexposStart() { - return g_border_thin_texpos_start; +long Textures::getThinBordersTexposStart() { + return g_thin_borders_texpos_start; } -long Textures::getBorderMediumTexposStart() { - return g_border_medium_texpos_start; +long Textures::getMediumBordersTexposStart() { + return g_medium_borders_texpos_start; } -long Textures::getBorderBoldTexposStart() { - return g_border_bold_texpos_start; +long Textures::getBoldBordersTexposStart() { + return g_bold_borders_texpos_start; } -long Textures::getBorderPanelTexposStart() { - return g_border_panel_texpos_start; +long Textures::getPanelBordersTexposStart() { + return g_panel_borders_texpos_start; } -long Textures::getBorderWindowTexposStart() { - return g_border_window_texpos_start; +long Textures::getWindowBordersTexposStart() { + return g_window_borders_texpos_start; } diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index c68e12eae..e69a4c210 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -18,12 +18,12 @@ function reload_pens() GOOD_TILE_PEN = to_pen{ch='o', fg=COLOR_GREEN, tile=dfhack.screen.findGraphicsTile('CURSORS', 1, 2)} BAD_TILE_PEN = to_pen{ch='X', fg=COLOR_RED, tile=dfhack.screen.findGraphicsTile('CURSORS', 3, 0)} - local tb_texpos = dfhack.textures.getBorderThinTexposStart() + local tb_texpos = dfhack.textures.getThinBordersTexposStart() VERT_TOP_PEN = to_pen{tile=tp(tb_texpos, 10), ch=194, fg=COLOR_GREY, bg=COLOR_BLACK} VERT_MID_PEN = to_pen{tile=tp(tb_texpos, 4), ch=179, fg=COLOR_GREY, bg=COLOR_BLACK} VERT_BOT_PEN = to_pen{tile=tp(tb_texpos, 11), ch=193, fg=COLOR_GREY, bg=COLOR_BLACK} - local mb_texpos = dfhack.textures.getBorderMediumTexposStart() + local mb_texpos = dfhack.textures.getMediumBordersTexposStart() HORI_LEFT_PEN = to_pen{tile=tp(mb_texpos, 12), ch=195, fg=COLOR_GREY, bg=COLOR_BLACK} HORI_MID_PEN = to_pen{tile=tp(mb_texpos, 5), ch=196, fg=COLOR_GREY, bg=COLOR_BLACK} HORI_RIGHT_PEN = to_pen{tile=tp(mb_texpos, 13), ch=180, fg=COLOR_GREY, bg=COLOR_BLACK} From ff498fcc586c37e9464f5e682db0bcc32b4a9114 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Thu, 18 May 2023 12:50:25 +0200 Subject: [PATCH 0185/1234] fixed overly aggressive FRAME renaming in docs --- docs/dev/Lua API.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 6fb2aca2c..52ca4d935 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4509,7 +4509,7 @@ Has attributes: by 1. The attributes are identical to what is defined in the `FramedScreen class`_. When using the predefined frame styles in the ``gui`` module, remember to ``require`` the gui module and prefix the identifier with - ``gui.``, e.g. ``gui.FRAME_GREY_LINE``. + ``gui.``, e.g. ``gui.GREY_LINE_FRAME``. Has functions: From 58519890b6eda1f29b9f1dc8ddc3c03164ebe38e Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Thu, 18 May 2023 13:13:56 +0200 Subject: [PATCH 0186/1234] added changelog entry --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index c9f9fca89..cc717d0bf 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,6 +62,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## 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.lua`: 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`) ## 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. From c224a534355154173f8b73b6d44cfaa47c0e5da8 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Thu, 18 May 2023 13:21:18 +0200 Subject: [PATCH 0187/1234] fixed changelog entry... --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index cc717d0bf..4baa5e54f 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,7 +62,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## 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.lua`: 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`) +- ``gui.lua``: 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`) ## 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. From 69612bde0f76cdb0656a6b30e0850a5de966022b Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Thu, 18 May 2023 13:27:27 +0200 Subject: [PATCH 0188/1234] ATTEMPTING to fix changelog entry... --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 4baa5e54f..9495658d9 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,7 +62,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## 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.lua``: 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`) +- `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`) ## 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. From e7eb664eadde01c29e18c42ae13a80a0044d6a04 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Thu, 18 May 2023 13:29:26 +0200 Subject: [PATCH 0189/1234] ATTEMPTING to fix changelog entry... AGAIN --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 9495658d9..3d9ca0356 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,7 +62,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## 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`) +- gui.lua: 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`) ## 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. From 4cf88a1f8e68b03bf71de050a96567913aa235bb Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Thu, 18 May 2023 13:52:07 +0200 Subject: [PATCH 0190/1234] actually fixed changelog entry..? --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 3d9ca0356..c8ccdec15 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,7 +62,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## 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.lua: 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`) +- ``gui.lua``: 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``) ## 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. From afcbee48ddf1b67073993a9223e0c22a1152ffe9 Mon Sep 17 00:00:00 2001 From: TaxiService Date: Thu, 18 May 2023 19:28:30 +0200 Subject: [PATCH 0191/1234] Update docs/changelog.txt Co-authored-by: Myk --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index c8ccdec15..832a81c56 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,7 +62,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## 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.lua``: 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``) +- ``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``) ## 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. From 9928ea874abe18ca577d3214378f69259f4e4298 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 17 May 2023 17:26:33 -0700 Subject: [PATCH 0192/1234] transfer Ctrl-H keybinding to gui/autodump --- data/init/dfhack.keybindings.init | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/init/dfhack.keybindings.init b/data/init/dfhack.keybindings.init index 0fc596215..f677ca301 100644 --- a/data/init/dfhack.keybindings.init +++ b/data/init/dfhack.keybindings.init @@ -43,8 +43,8 @@ keybinding add Ctrl-C spotclean # destroy the selected item keybinding add Ctrl-K@dwarfmode autodump-destroy-item -# destroy items designated for dump in the selected tile -keybinding add Ctrl-H@dwarfmode autodump-destroy-here +# bring up the autodump UI +keybinding add Ctrl-H@dwarfmode gui/autodump # apply blueprints to the map keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort From ee5553358e536bc97be7b9f7aa82a376a3e29626 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 17 May 2023 17:28:35 -0700 Subject: [PATCH 0193/1234] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 832a81c56..64d491906 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -55,6 +55,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `gui/design`: Improved performance for drawing shapes - Dreamfort: improve traffic patterns throughout the fortress (stockpiles and zones are still not working, pending updates in `quickfort`) - Core: For debugging purposes, you can now pass ``--disable-dfhack`` on the Dwarf Fortress commandline or specify ``DFHACK_DISABLE=1`` in the environment to disable DFHack for the current session. +- `gui/autodump`: fort-mode keybinding: Ctrl-H ## Documentation From 796eb331ff4992de64e53c8021506631f178295c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 18 May 2023 11:01:16 -0700 Subject: [PATCH 0194/1234] update scripts head --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 97557b923..0f02ade81 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 97557b9239a5ad8297f6a32651b78fd9dbb333ec +Subproject commit 0f02ade81771a7c24a4bbd6cfd7969704288f94b From 73f6c66c3e484451335cb4c266031d3776cf22bb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 18 May 2023 11:13:47 -0700 Subject: [PATCH 0195/1234] bump version to 50.08-r2rc1 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d1d4c562..c1560c630 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,8 +192,8 @@ endif() # set up versioning. set(DF_VERSION "50.08") -set(DFHACK_RELEASE "r1") -set(DFHACK_PRERELEASE FALSE) +set(DFHACK_RELEASE "r2rc1") +set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 1212ee0ef8bd60cacd2b05fc8f3afb96ef1d11fb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 18 May 2023 14:06:00 -0700 Subject: [PATCH 0196/1234] retrieve steam SDK from a private repo --- .github/workflows/build.yml | 15 +++++---- .github/workflows/steam.yml | 13 ++++---- package/windows/CMakeLists.txt | 60 +++++++++++++++------------------- 3 files changed, 42 insertions(+), 46 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 131c21743..94aa49452 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,12 +72,6 @@ jobs: # - name: Download DF # run: | # sh ci/download-df.sh - - name: Restore steam SDK - uses: actions/cache@v3 - with: - path: depends/steam - key: steam-sdk-156 - enableCrossOsArchive: true - name: Configure DFHack env: CC: gcc-${{ matrix.gcc }} @@ -145,6 +139,13 @@ jobs: with: submodules: true fetch-depth: 0 + - name: Get 3rd party SDKs + uses: actions/checkout@v3 + with: + repository: DFHack/3rdparty + ref: main + token: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} + path: depends - name: Fetch ccache uses: actions/cache@v3 with: @@ -155,7 +156,7 @@ jobs: ccache-win64-cross-msvc - name: Cross-compile win64 artifacts env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1' + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1' run: | cd build bash -x build-win64-from-linux.sh diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 5210b3a11..4f785969a 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -32,6 +32,13 @@ jobs: submodules: true fetch-depth: 0 ref: ${{ github.event.inputs.commit_hash }} + - name: Get 3rd party SDKs + uses: actions/checkout@v3 + with: + repository: DFHack/3rdparty + ref: main + token: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} + path: depends - name: Fetch ccache uses: actions/cache@v3 with: @@ -40,12 +47,6 @@ jobs: restore-keys: | ccache-win64-cross-msvc-${{ github.event.inputs.commit_hash }} ccache-win64-cross-msvc - - name: Restore steam SDK - uses: actions/cache@v3 - with: - path: depends/steam - key: steam-sdk-156 - enableCrossOsArchive: true - name: Cross-compile win64 artifacts env: CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1' diff --git a/package/windows/CMakeLists.txt b/package/windows/CMakeLists.txt index d92d687c4..ad5469c6b 100644 --- a/package/windows/CMakeLists.txt +++ b/package/windows/CMakeLists.txt @@ -1,38 +1,32 @@ project(package_windows) -if(WIN32) - if (BUILD_DFLAUNCH) - if ((DEFINED ENV{steam_username}) AND (DEFINED ENV{steam_password})) - # download Steam SDK - set (STEAMAPI_DIR ${dfhack_SOURCE_DIR}/depends/steam) - file(DOWNLOAD "https://partner.steamgames.com/downloads/steamworks_sdk_156.zip" - ${STEAMAPI_DIR}/steamworks_sdk_156.zip - EXPECTED_HASH MD5=af5a579990dbe5ae4c1b0689260d001b - USERPWD $ENV{steam_username}:$ENV{steam_password} - STATUS STEAM_SDK_DOWNLOAD_STATUS - SHOW_PROGRESS - ) - list(GET STEAM_SDK_DOWNLOAD_STATUS 0 STEAM_SDK_DL_STATUS_CODE) - list(GET STEAM_SDK_DOWNLOAD_STATUS 1 STEAM_SDK_DL_ERROR_MESSAGE) - if (NOT (${STEAM_SDK_DL_STATUS_CODE} EQUAL 0)) - message(FATAL_ERROR "Steam SDK download: " ${STEAM_SDK_DL_ERROR_MESSAGE}) - else () - message(STATUS "Steam SDK download: " ${STEAM_SDK_DL_ERROR_MESSAGE}) - file(ARCHIVE_EXTRACT - INPUT ${STEAMAPI_DIR}/steamworks_sdk_156.zip - DESTINATION ${STEAMAPI_DIR}) - set(STEAMAPI_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.lib") - set(STEAMAPI_SOURCE_DIR "${STEAMAPI_DIR}/sdk/public/steam") - set(STEAMAPI_SHARED_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.dll") - endif() - else() - message(SEND_ERROR "Need to set steam_username and steam_password in environment to download Steamworks SDK") - endif() +option(BUILD_DFLAUNCH "Whether to build the Steam launcher exectuable (requires Steam SDK)." OFF) - include_directories(${STEAMAPI_SOURCE_DIR}) - link_libraries(${STEAMAPI_LIBRARY}) - add_executable(launchdf WIN32 launchdf.cpp) - install(TARGETS launchdf DESTINATION ${DFHACK_DATA_DESTINATION}) - install(FILES ${STEAMAPI_SHARED_LIBRARY} DESTINATION ${DFHACK_DATA_DESTINATION}) +if(WIN32 AND BUILD_DFLAUNCH) + # builder must manually download Steam SDK + set (STEAMAPI_DIR ${dfhack_SOURCE_DIR}/depends/steam) + set (STEAMAPI_VER 156) + set (STEAMAPI_ZIP_EXPECTED_HASH af5a579990dbe5ae4c1b0689260d001b) + set (STEAMSDK_ZIP ${STEAMAPI_DIR}/steamworks_sdk_${STEAMAPI_VER}.zip) + + set (STEAM_SDK_HASH "NOT FOUND") + file(MD5 ${STEAMSDK_ZIP} STEAM_SDK_HASH) + if (NOT (${STEAM_SDK_HASH} STREQUAL ${STEAMAPI_ZIP_EXPECTED_HASH})) + message(FATAL_ERROR "You need the Steamworks SDK at ${STEAMSDK_ZIP} to build launchdf.exe. Please disable the BUILD_DFLAUNCH CMake option or download the Steam SDK from: https://partner.steamgames.com/downloads/steamworks_sdk_${STEAMAPI_VER}.zip") + endif() + if (${STEAMSDK_ZIP} IS_NEWER_THAN ${STEAMAPI_DIR}/sdk) + file(ARCHIVE_EXTRACT + INPUT ${STEAMSDK_ZIP} + DESTINATION ${STEAMAPI_DIR}) endif() + + set(STEAMAPI_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.lib") + set(STEAMAPI_SOURCE_DIR "${STEAMAPI_DIR}/sdk/public/steam") + set(STEAMAPI_SHARED_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.dll") + + include_directories(${STEAMAPI_SOURCE_DIR}) + link_libraries(${STEAMAPI_LIBRARY}) + add_executable(launchdf WIN32 launchdf.cpp) + install(TARGETS launchdf DESTINATION ${DFHACK_DATA_DESTINATION}) + install(FILES ${STEAMAPI_SHARED_LIBRARY} DESTINATION ${DFHACK_DATA_DESTINATION}) endif() From 14bbff85376cbdf412aadde12dcc1a750c0eb57f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 18 May 2023 14:39:49 -0700 Subject: [PATCH 0197/1234] secrets can't be accessed from PRs; remove from build action --- .github/workflows/build.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 94aa49452..9aed03c17 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -139,13 +139,6 @@ jobs: with: submodules: true fetch-depth: 0 - - name: Get 3rd party SDKs - uses: actions/checkout@v3 - with: - repository: DFHack/3rdparty - ref: main - token: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} - path: depends - name: Fetch ccache uses: actions/cache@v3 with: @@ -156,7 +149,7 @@ jobs: ccache-win64-cross-msvc - name: Cross-compile win64 artifacts env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1' + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1' run: | cd build bash -x build-win64-from-linux.sh From b6ee0d5c02cb620cf6f466fa2f860abfa600ca19 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 18 May 2023 14:59:08 -0700 Subject: [PATCH 0198/1234] follow advice in actions/checkout#664 --- .github/workflows/steam.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 4f785969a..5ca1ebe8d 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -32,6 +32,7 @@ jobs: submodules: true fetch-depth: 0 ref: ${{ github.event.inputs.commit_hash }} + persist-credentials: false - name: Get 3rd party SDKs uses: actions/checkout@v3 with: From 09621809812812238057b2913766ef4141b90f8f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 18 May 2023 15:10:15 -0700 Subject: [PATCH 0199/1234] attempting as an ssh-key instead of a token --- .github/workflows/steam.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 5ca1ebe8d..7f4c58afe 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -32,13 +32,12 @@ jobs: submodules: true fetch-depth: 0 ref: ${{ github.event.inputs.commit_hash }} - persist-credentials: false - name: Get 3rd party SDKs uses: actions/checkout@v3 with: repository: DFHack/3rdparty ref: main - token: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} + ssh-key: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} path: depends - name: Fetch ccache uses: actions/cache@v3 From b2102d66fa3668eeb3e62f3ef07433553291bf7b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 18 May 2023 16:16:24 -0700 Subject: [PATCH 0200/1234] check out repo directly in steam dir so we don't bork the rest of depends --- .github/workflows/steam.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 7f4c58afe..46dd27270 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -38,7 +38,7 @@ jobs: repository: DFHack/3rdparty ref: main ssh-key: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} - path: depends + path: depends/steam - name: Fetch ccache uses: actions/cache@v3 with: From d4e8d3399b34f84b22508baf752e9139e936cdd5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 18 May 2023 16:56:22 -0700 Subject: [PATCH 0201/1234] remove cursor guard from autodump so autodump destroy can work --- docs/changelog.txt | 1 + plugins/autodump.cpp | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 64d491906..eeeaf269e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -49,6 +49,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `autolabor`: work detail override warning now only appears on the work details screen ## Misc Improvements +- `autodump`: no longer checks for a keyboard cursor before executing, so ``autodump destroy`` (which doesn't require a cursor) can still function - `orders`: update orders in orders library for prepared meals, bins, archer uniforms, and weapons - Terminal console no longer appears in front of the game window on startup - `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") diff --git a/plugins/autodump.cpp b/plugins/autodump.cpp index 2514dd91a..839b3b727 100644 --- a/plugins/autodump.cpp +++ b/plugins/autodump.cpp @@ -280,8 +280,7 @@ DFhackCExport command_result plugin_init ( color_ostream &out, vector Date: Fri, 19 May 2023 12:12:52 -0700 Subject: [PATCH 0202/1234] Update widgets.lua --- library/lua/gui/widgets.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 6610dcedb..26c949805 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1664,9 +1664,9 @@ function List:setChoices(choices, selected) -- Check if page_top needs to be adjusted if #self.choices - self.page_size < 0 then self.page_top = 1 - elseif self.selected <= math.floor(self.page_size / 2) then + elseif self.selected <= (self.page_size // 2) then self.page_top = 1 - elseif self.selected >= #self.choices - math.floor(self.page_size / 2) then + elseif self.selected >= #self.choices - (self.page_size // 2) then self.page_top = #self.choices - self.page_size + 1 end end @@ -1709,7 +1709,7 @@ local function update_list_scrollbar(list) end function List:postComputeFrame(body) - local row_count = math.floor(body.height / self.row_height) + local row_count = body.height // self.row_height self.page_size = math.max(1, row_count) local num_choices = #self.choices From 3729d7daa4ccba9b5772382df7ac35209276843d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 19 May 2023 19:41:02 -0700 Subject: [PATCH 0203/1234] encode transmitted names in utf-8 --- docs/changelog.txt | 1 + .../remotefortressreader.cpp | 34 +++++++++---------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 76105e9b5..60d858551 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -47,6 +47,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - 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 diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 061cf2698..ec478c632 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -808,8 +808,6 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage return CR_OK; } - - df::world_raws *raws = &world->raws; // df::world_history *history = &world->history; MaterialInfo mat; @@ -820,7 +818,7 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage mat_def->mutable_mat_pair()->set_mat_type(0); mat_def->mutable_mat_pair()->set_mat_index(i); mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; + mat_def->set_name(DF2UTF(mat.toString())); //find the name at cave temperature; if (size_t(raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)]) < raws->descriptors.colors.size()) { ConvertDFColorDescriptor(raws->inorganics[i]->material.state_color[GetState(&raws->inorganics[i]->material)], mat_def->mutable_state_color()); @@ -838,7 +836,7 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage mat_def->mutable_mat_pair()->set_mat_type(i); mat_def->mutable_mat_pair()->set_mat_index(j); mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; + mat_def->set_name(DF2UTF(mat.toString())); //find the name at cave temperature; if (size_t(raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])]) < raws->descriptors.colors.size()) { ConvertDFColorDescriptor(raws->mat_table.builtin[i]->state_color[GetState(raws->mat_table.builtin[i])], mat_def->mutable_state_color()); @@ -855,7 +853,7 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage mat_def->mutable_mat_pair()->set_mat_type(j + 19); mat_def->mutable_mat_pair()->set_mat_index(i); mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; + mat_def->set_name(DF2UTF(mat.toString())); //find the name at cave temperature; if (size_t(creature->material[j]->state_color[GetState(creature->material[j])]) < raws->descriptors.colors.size()) { ConvertDFColorDescriptor(creature->material[j]->state_color[GetState(creature->material[j])], mat_def->mutable_state_color()); @@ -872,7 +870,7 @@ static command_result GetMaterialList(color_ostream &stream, const EmptyMessage mat_def->mutable_mat_pair()->set_mat_type(j + 419); mat_def->mutable_mat_pair()->set_mat_index(i); mat_def->set_id(mat.getToken()); - mat_def->set_name(mat.toString()); //find the name at cave temperature; + mat_def->set_name(DF2UTF(mat.toString())); //find the name at cave temperature; if (size_t(plant->material[j]->state_color[GetState(plant->material[j])]) < raws->descriptors.colors.size()) { ConvertDFColorDescriptor(plant->material[j]->state_color[GetState(plant->material[j])], mat_def->mutable_state_color()); @@ -903,7 +901,7 @@ static command_result GetGrowthList(color_ostream &stream, const EmptyMessage *i continue; MaterialDefinition * basePlant = out->add_material_list(); basePlant->set_id(pp->id + ":BASE"); - basePlant->set_name(pp->name); + basePlant->set_name(DF2UTF(pp->name)); basePlant->mutable_mat_pair()->set_mat_type(-1); basePlant->mutable_mat_pair()->set_mat_index(i); #if DF_VERSION_INT > 40001 @@ -916,7 +914,7 @@ static command_result GetGrowthList(color_ostream &stream, const EmptyMessage *i { MaterialDefinition * out_growth = out->add_material_list(); out_growth->set_id(pp->id + ":" + growth->id + +":" + growth_locations[l]); - out_growth->set_name(growth->name); + out_growth->set_name(DF2UTF(growth->name)); out_growth->mutable_mat_pair()->set_mat_type(g * 10 + l); out_growth->mutable_mat_pair()->set_mat_index(i); } @@ -1951,8 +1949,8 @@ static command_result GetWorldMapCenter(color_ostream &stream, const EmptyMessag out->set_center_x(pos.x); out->set_center_y(pos.y); out->set_center_z(pos.z); - out->set_name(Translation::TranslateName(&(data->name), false)); - out->set_name_english(Translation::TranslateName(&(data->name), true)); + out->set_name(DF2UTF(Translation::TranslateName(&(data->name), false))); + out->set_name_english(DF2UTF(Translation::TranslateName(&(data->name), true))); out->set_cur_year(World::ReadCurrentYear()); out->set_cur_year_tick(World::ReadCurrentTick()); return CR_OK; @@ -1977,8 +1975,8 @@ static command_result GetWorldMap(color_ostream &stream, const EmptyMessage *in, int height = data->world_height; out->set_world_width(width); out->set_world_height(height); - out->set_name(Translation::TranslateName(&(data->name), false)); - out->set_name_english(Translation::TranslateName(&(data->name), true)); + out->set_name(DF2UTF(Translation::TranslateName(&(data->name), false))); + out->set_name_english(DF2UTF(Translation::TranslateName(&(data->name), true))); auto poles = data->flip_latitude; #if DF_VERSION_INT > 34011 switch (poles) @@ -2126,8 +2124,8 @@ static command_result GetWorldMapNew(color_ostream &stream, const EmptyMessage * int height = data->world_height; out->set_world_width(width); out->set_world_height(height); - out->set_name(Translation::TranslateName(&(data->name), false)); - out->set_name_english(Translation::TranslateName(&(data->name), true)); + out->set_name(DF2UTF(Translation::TranslateName(&(data->name), false))); + out->set_name_english(DF2UTF(Translation::TranslateName(&(data->name), true))); #if DF_VERSION_INT > 34011 auto poles = data->flip_latitude; switch (poles) @@ -2797,8 +2795,8 @@ static command_result GetPartialCreatureRaws(color_ostream &stream, const ListRe auto send_tissue = send_creature->add_tissues(); send_tissue->set_id(orig_tissue->id); - send_tissue->set_name(orig_tissue->tissue_name_singular); - send_tissue->set_subordinate_to_tissue(orig_tissue->subordinate_to_tissue); + send_tissue->set_name(DF2UTF(orig_tissue->tissue_name_singular)); + send_tissue->set_subordinate_to_tissue(DF2UTF(orig_tissue->subordinate_to_tissue)); CopyMat(send_tissue->mutable_material(), orig_tissue->mat_type, orig_tissue->mat_index); } @@ -2831,7 +2829,7 @@ static command_result GetPartialPlantRaws(color_ostream &stream, const ListReque plant_remote->set_index(i); plant_remote->set_id(plant_local->id); - plant_remote->set_name(plant_local->name); + plant_remote->set_name(DF2UTF(plant_local->name)); if (!plant_local->flags.is_set(df::plant_raw_flags::TREE)) plant_remote->set_tile(plant_local->tiles.shrub_tile); else @@ -2843,7 +2841,7 @@ static command_result GetPartialPlantRaws(color_ostream &stream, const ListReque TreeGrowth * growth_remote = plant_remote->add_growths(); growth_remote->set_index(j); growth_remote->set_id(growth_local->id); - growth_remote->set_name(growth_local->name); + growth_remote->set_name(DF2UTF(growth_local->name)); for (size_t k = 0; k < growth_local->prints.size(); k++) { df::plant_growth_print* print_local = growth_local->prints[k]; From 3cb13152f802ad59c3a211388d67ebde56395d14 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 20 May 2023 07:12:20 +0000 Subject: [PATCH 0204/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 0f02ade81..86b083cdf 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 0f02ade81771a7c24a4bbd6cfd7969704288f94b +Subproject commit 86b083cdf5847128e88197834eb953c1716c50a8 From a5a6b70a5186484563abb0c21c454a41c9a48841 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 19 May 2023 16:51:39 -0700 Subject: [PATCH 0205/1234] launch DFHack through steam if DF is run from steam --- library/Core.cpp | 6 +- library/include/modules/DFSteam.h | 4 +- library/modules/DFSteam.cpp | 118 +++++++++++++++++++++++++----- package/windows/launchdf.cpp | 59 ++++++++------- 4 files changed, 138 insertions(+), 49 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 256493dce..431cd2c9f 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1682,8 +1682,10 @@ bool Core::InitSimulationThread() fatal("cannot bind SDL libraries"); return false; } - if (DFSteam::init(con)) + if (DFSteam::init(con)) { std::cerr << "Found Steam.\n"; + DFSteam::launchSteamDFHackIfNecessary(con); + } std::cerr << "Initializing textures.\n"; Textures::init(con); // create mutex for syncing with interactive tasks @@ -2291,7 +2293,7 @@ int Core::Shutdown ( void ) allModules.clear(); Textures::cleanup(); DFSDL::cleanup(); - DFSteam::cleanup(); + DFSteam::cleanup(getConsole()); memset(&(s_mods), 0, sizeof(s_mods)); d.reset(); return -1; diff --git a/library/include/modules/DFSteam.h b/library/include/modules/DFSteam.h index 3144830da..e604294f8 100644 --- a/library/include/modules/DFSteam.h +++ b/library/include/modules/DFSteam.h @@ -24,9 +24,9 @@ bool init(DFHack::color_ostream& out); /** * Call this when DFHack is being unloaded. */ -void cleanup(); +void cleanup(DFHack::color_ostream& out); -DFHACK_EXPORT bool DFIsSteamRunningOnSteamDeck(); +DFHACK_EXPORT void launchSteamDFHackIfNecessary(DFHack::color_ostream& out); } } diff --git a/library/modules/DFSteam.cpp b/library/modules/DFSteam.cpp index b27cc1744..c61d996d1 100644 --- a/library/modules/DFSteam.cpp +++ b/library/modules/DFSteam.cpp @@ -12,6 +12,9 @@ DBG_DECLARE(core, dfsteam, DebugCategory::LINFO); using namespace DFHack; +static const int DFHACK_STEAM_APPID = 2346660; + +static bool g_steam_initialized = false; static DFLibrary* g_steam_handle = nullptr; static const std::vector STEAM_LIBS { "steam_api64.dll", @@ -21,8 +24,32 @@ static const std::vector STEAM_LIBS { bool (*g_SteamAPI_Init)() = nullptr; void (*g_SteamAPI_Shutdown)() = nullptr; +int (*g_SteamAPI_GetHSteamUser)() = nullptr; +bool (*g_SteamAPI_RestartAppIfNecessary)(uint32_t unOwnAppID) = nullptr; void* (*g_SteamInternal_FindOrCreateUserInterface)(int, const char*) = nullptr; -bool (*g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck)(void*) = nullptr; +bool (*g_SteamAPI_ISteamApps_BIsAppInstalled)(void *iSteamApps, uint32_t appID) = nullptr; + + +static void bind_all(color_ostream& out, DFLibrary* handle) { +#define bind(name) \ + if (!handle) { \ + g_##name = nullptr; \ + } else { \ + g_##name = (decltype(g_##name))LookupPlugin(handle, #name); \ + if (!g_##name) { \ + WARN(dfsteam, out).print("steam library function not found: " #name "\n"); \ + } \ + } + + bind(SteamAPI_Init); + bind(SteamAPI_Shutdown); + bind(SteamAPI_GetHSteamUser); + bind(SteamInternal_FindOrCreateUserInterface); + bind(SteamAPI_RestartAppIfNecessary); + bind(SteamInternal_FindOrCreateUserInterface); + bind(SteamAPI_ISteamApps_BIsAppInstalled); +#undef bind +} bool DFSteam::init(color_ostream& out) { for (auto& lib_str : STEAM_LIBS) { @@ -34,30 +61,19 @@ bool DFSteam::init(color_ostream& out) { return false; } -#define bind(handle, name) \ - g_##name = (decltype(g_##name))LookupPlugin(handle, #name); \ - if (!g_##name) { \ - WARN(dfsteam, out).print("steam library function not found: " #name "\n"); \ - } - - bind(g_steam_handle, SteamAPI_Init); - bind(g_steam_handle, SteamAPI_Shutdown); + bind_all(out, g_steam_handle); - // TODO: can we remove this initialization of the Steam API once we move to dfhooks? if (!g_SteamAPI_Init || !g_SteamAPI_Shutdown || !g_SteamAPI_Init()) { DEBUG(dfsteam, out).print("steam detected but cannot be initialized\n"); return false; } - bind(g_steam_handle, SteamInternal_FindOrCreateUserInterface); - bind(g_steam_handle, SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck); -#undef bind - DEBUG(dfsteam, out).print("steam library linked\n"); + g_steam_initialized = true; return true; } -void DFSteam::cleanup() { +void DFSteam::cleanup(color_ostream& out) { if (!g_steam_handle) return; @@ -66,16 +82,78 @@ void DFSteam::cleanup() { ClosePlugin(g_steam_handle); g_steam_handle = nullptr; + + bind_all(out, nullptr); + g_steam_initialized = false; } -bool DFSteam::DFIsSteamRunningOnSteamDeck() { - if (!g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck) +#ifdef WIN32 +#include +static bool is_running_on_wine() { + typedef const char* (CDECL wine_get_version)(void); + static wine_get_version* pwine_get_version; + HMODULE hntdll = GetModuleHandle("ntdll.dll"); + if(!hntdll) return false; - if (!g_SteamInternal_FindOrCreateUserInterface) + pwine_get_version = (wine_get_version*) GetProcAddress(hntdll, "wine_get_version"); + return !!pwine_get_version; +} + +static bool launchDFHack(color_ostream& out) { + if (is_running_on_wine()) { + DEBUG(dfsteam, out).print("not attempting to re-launch DFHack on wine\n"); return false; + } + + STARTUPINFOW si; + PROCESS_INFORMATION pi; + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); - void* SteamUtils = g_SteamInternal_FindOrCreateUserInterface(0, "SteamUtils010"); + // note that the enviornment must be explicitly zeroed out and not NULL, + // otherwise the launched process will inherit this process's environment, + // and the Steam API in the launchdf process will think it is in DF's context. + BOOL res = CreateProcessW(L"hack/launchdf.exe", + NULL, NULL, NULL, FALSE, 0, "\0", NULL, &si, &pi); + + return !!res; +} +#else +static bool launchDFHack(color_ostream& out) { + // TODO once we have a non-Windows build to work with + return false; +} +#endif + +void DFSteam::launchSteamDFHackIfNecessary(color_ostream& out) { + if (!g_steam_initialized || + !g_SteamAPI_GetHSteamUser || + !g_SteamInternal_FindOrCreateUserInterface || + !g_SteamAPI_ISteamApps_BIsAppInstalled) { + DEBUG(dfsteam, out).print("required Steam API calls are unavailable\n"); + return; + } + + if (strncmp(getenv("SteamClientLaunch"), "1", 2)) { + DEBUG(dfsteam, out).print("not launched from Steam client\n"); + return; + } + + void* iSteamApps = g_SteamInternal_FindOrCreateUserInterface(g_SteamAPI_GetHSteamUser(), "STEAMAPPS_INTERFACE_VERSION008"); + if (!iSteamApps) { + DEBUG(dfsteam, out).print("cannot obtain iSteamApps interface\n"); + return; + } + + bool isDFHackInstalled = g_SteamAPI_ISteamApps_BIsAppInstalled(iSteamApps, DFHACK_STEAM_APPID); + if (!isDFHackInstalled) { + DEBUG(dfsteam, out).print("player has not installed DFHack through Steam\n"); + return; + } - return g_SteamAPI_ISteamUtils_IsSteamRunningOnSteamDeck(SteamUtils); + bool ret = launchDFHack(out); + DEBUG(dfsteam, out).print("launching DFHack via Steam: %s\n", ret ? "successful" : "unsuccessful"); } diff --git a/package/windows/launchdf.cpp b/package/windows/launchdf.cpp index a84465f53..8e6536743 100644 --- a/package/windows/launchdf.cpp +++ b/package/windows/launchdf.cpp @@ -113,6 +113,24 @@ DWORD findDwarfFortressProcess() return -1; } +bool waitForDF() { + DWORD df_pid = findDwarfFortressProcess(); + + if (df_pid == -1) + return false; + + HANDLE hDF = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, df_pid); + + // in the future open an IPC connection so that we can proxy SteamAPI calls for the DFSteam module + + // this will eventuallyh need to become a loop with a WaitForMultipleObjects call + WaitForSingleObject(hDF, INFINITE); + + CloseHandle(hDF); + + return true; +} + int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) { // initialize steam context @@ -133,6 +151,9 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, exit(0); } + if (waitForDF()) + exit(0); + bool wine = is_running_on_wine(); if (wine) @@ -187,37 +208,25 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, exit(1); } - DWORD df_pid = findDwarfFortressProcess(); + if (waitForDF()) + exit(0); - if (df_pid == -1) + LPCWSTR err = launch_via_steam_windows(); + if (err != NULL) { - LPCWSTR err = launch_via_steam_windows(); - if (err != NULL) + MessageBoxW(NULL, err, NULL, 0); + exit(1); + } + + int counter = 0; + while (!waitForDF()) { + if (counter++ > 60) { - MessageBoxW(NULL, err, NULL, 0); + MessageBoxW(NULL, L"Dwarf Fortress took too long to launch, aborting", NULL, 0); exit(1); } - int counter = 0; - - do { - if (counter++ > 60) - { - MessageBoxW(NULL, L"Dwarf Fortress took too long to launch, aborting", NULL, 0); - exit(1); - } - Sleep(1000); - df_pid = findDwarfFortressProcess(); - } while (df_pid == -1); + Sleep(1000); } - HANDLE hDF = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, df_pid); - - // in the future open an IPC connection so that we can proxy SteamAPI calls for the DFSteam module - - // this will eventuallyh need to become a loop with a WaitForMultipleObjects call - WaitForSingleObject(hDF, INFINITE); - - CloseHandle(hDF); - exit(0); } From 8c01f3efe03918f8308029a9f4ee7141a3f38a99 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 19 May 2023 20:41:52 -0700 Subject: [PATCH 0206/1234] don't relaunch launchdf if it's already running --- library/modules/DFSteam.cpp | 31 +++++++++++++++++++++++++++++++ package/windows/launchdf.cpp | 6 +++--- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/library/modules/DFSteam.cpp b/library/modules/DFSteam.cpp index c61d996d1..289c22e27 100644 --- a/library/modules/DFSteam.cpp +++ b/library/modules/DFSteam.cpp @@ -88,7 +88,9 @@ void DFSteam::cleanup(color_ostream& out) { } #ifdef WIN32 +#include #include +#include static bool is_running_on_wine() { typedef const char* (CDECL wine_get_version)(void); static wine_get_version* pwine_get_version; @@ -100,12 +102,41 @@ static bool is_running_on_wine() { return !!pwine_get_version; } +static DWORD findProcess(LPWSTR name) { + PROCESSENTRY32W entry; + entry.dwSize = sizeof(PROCESSENTRY32W); + + const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); + + if (!Process32FirstW(snapshot, &entry)) { + CloseHandle(snapshot); + return -1; + } + + do { + std::wstring executableName(entry.szExeFile); + if (executableName == name) { + CloseHandle(snapshot); + return entry.th32ProcessID; + } + } + while (Process32NextW(snapshot, &entry)); + + CloseHandle(snapshot); + return -1; +} + static bool launchDFHack(color_ostream& out) { if (is_running_on_wine()) { DEBUG(dfsteam, out).print("not attempting to re-launch DFHack on wine\n"); return false; } + if (findProcess(L"launchdf.exe") != -1) { + DEBUG(dfsteam, out).print("launchdf.exe already running\n"); + return true; + } + STARTUPINFOW si; PROCESS_INFORMATION pi; diff --git a/package/windows/launchdf.cpp b/package/windows/launchdf.cpp index 8e6536743..f9ed11f66 100644 --- a/package/windows/launchdf.cpp +++ b/package/windows/launchdf.cpp @@ -139,6 +139,9 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, exit(0); } + if (waitForDF()) + exit(0); + if (!SteamAPI_Init()) { // could not initialize steam context, attempt fallback launch @@ -151,9 +154,6 @@ int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, exit(0); } - if (waitForDF()) - exit(0); - bool wine = is_running_on_wine(); if (wine) From 9dffba68431c70d84a0951519540ec8e7802ecbc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 20 May 2023 04:38:03 -0700 Subject: [PATCH 0207/1234] amend #2914 so lists don't jump around on resize --- library/lua/gui/widgets.lua | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 26c949805..5c8094d28 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1664,9 +1664,7 @@ function List:setChoices(choices, selected) -- Check if page_top needs to be adjusted if #self.choices - self.page_size < 0 then self.page_top = 1 - elseif self.selected <= (self.page_size // 2) then - self.page_top = 1 - elseif self.selected >= #self.choices - (self.page_size // 2) then + elseif self.page_top > #self.choices - self.page_size + 1 then self.page_top = #self.choices - self.page_size + 1 end end @@ -1719,14 +1717,8 @@ function List:postComputeFrame(body) return end - local max_page_top = math.max(1, num_choices - row_count + 1) - - if self.selected > num_choices - row_count then - self.page_top = max_page_top - elseif self.selected < self.page_top then - self.page_top = self.selected - else - self.page_top = math.max(1, self.selected - row_count + 1) + if self.page_top > num_choices - self.page_size + 1 then + self.page_top = math.max(1, num_choices - self.page_size + 1) end update_list_scrollbar(self) From c782873f868099fab121038ec6bf8999604d7b5d Mon Sep 17 00:00:00 2001 From: Myk Date: Sat, 20 May 2023 04:58:08 -0700 Subject: [PATCH 0208/1234] Update changelog.txt --- docs/changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 60d858551..fdd9ca795 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -64,6 +64,9 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## API +## Internal +- ``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``) From 8d73385aaf5babc6a47b8c0ab0b1539d4fe77ed7 Mon Sep 17 00:00:00 2001 From: Myk Date: Sat, 20 May 2023 05:01:07 -0700 Subject: [PATCH 0209/1234] Update changelog.txt --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fdd9ca795..2e5b482f0 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -64,7 +64,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## API -## Internal +## Internals - ``dfhack.internal``: added memory analysis functions: ``msizeAddress``, ``getHeapState``, ``heapTakeSnapshot``, ``isAddressInHeap``, ``isAddressActiveInHeap``, ``isAddressUsedAfterFreeInHeap``, ``getAddressSizeInHeap``, and ``getRootAddressOfHeapObject`` ## Lua From af1ba12031928fea804f016c86812fcc3c10a688 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 21 May 2023 07:12:22 +0000 Subject: [PATCH 0210/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 86b083cdf..40e517eb8 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 86b083cdf5847128e88197834eb953c1716c50a8 +Subproject commit 40e517eb844779b4ac1ba6fe6d226f2d613d0b8c From d06118ad8ef99927b31487fec2f6f7cb5a761bd3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 20 May 2023 16:00:59 -0700 Subject: [PATCH 0211/1234] support recording stockpiles in blueprints --- docs/changelog.txt | 3 ++- plugins/blueprint.cpp | 26 +++++++++----------------- plugins/lua/blueprint.lua | 12 ++++++------ plugins/lua/stockpiles.lua | 4 ++-- 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 2e5b482f0..df00cf34a 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -55,7 +55,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Terminal console no longer appears in front of the game window on startup - `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 (stockpiles and zones are still not working, pending updates in `quickfort`) +- 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: For debugging purposes, you can now pass ``--disable-dfhack`` on the Dwarf Fortress commandline or specify ``DFHACK_DISABLE=1`` in the environment to disable DFHack for the current session. - `overlay`: added links to the quickstart guide and the control panel on the DF title screen - `gui/autodump`: fort-mode keybinding: Ctrl-H diff --git a/plugins/blueprint.cpp b/plugins/blueprint.cpp index 39847935d..d5a06cc5c 100644 --- a/plugins/blueprint.cpp +++ b/plugins/blueprint.cpp @@ -99,9 +99,9 @@ struct blueprint_options { bool construct = false; bool build = false; bool place = false; - bool zone = false; - bool query = false; - bool rooms = false; + // bool zone = false; + // bool query = false; + // bool rooms = false; static struct_identity _identity; }; @@ -125,9 +125,9 @@ static const struct_field_info blueprint_options_fields[] = { { struct_field_info::PRIMITIVE, "construct", offsetof(blueprint_options, construct), &df::identity_traits::identity, 0, 0 }, { struct_field_info::PRIMITIVE, "build", offsetof(blueprint_options, build), &df::identity_traits::identity, 0, 0 }, { struct_field_info::PRIMITIVE, "place", offsetof(blueprint_options, place), &df::identity_traits::identity, 0, 0 }, - { struct_field_info::PRIMITIVE, "zone", offsetof(blueprint_options, zone), &df::identity_traits::identity, 0, 0 }, - { struct_field_info::PRIMITIVE, "query", offsetof(blueprint_options, query), &df::identity_traits::identity, 0, 0 }, - { struct_field_info::PRIMITIVE, "rooms", offsetof(blueprint_options, rooms), &df::identity_traits::identity, 0, 0 }, + // { struct_field_info::PRIMITIVE, "zone", offsetof(blueprint_options, zone), &df::identity_traits::identity, 0, 0 }, + // { struct_field_info::PRIMITIVE, "query", offsetof(blueprint_options, query), &df::identity_traits::identity, 0, 0 }, + // { struct_field_info::PRIMITIVE, "rooms", offsetof(blueprint_options, rooms), &df::identity_traits::identity, 0, 0 }, { struct_field_info::END } }; struct_identity blueprint_options::_identity(sizeof(blueprint_options), &df::allocator_fn, NULL, "blueprint_options", NULL, blueprint_options_fields); @@ -855,7 +855,6 @@ static const char * get_tile_build(const df::coord &pos, return add_expansion_syntax(ctx, keys); } -/* TODO: understand how this changes for v50 static const char * get_place_keys(const tile_context &ctx) { df::building_stockpilest* sp = virtual_cast(ctx.b); @@ -908,6 +907,7 @@ static const char * get_tile_place(const df::coord &pos, return add_expansion_syntax(ctx, get_place_keys(ctx)); } +/* TODO: understand how this changes for v50 static bool hospital_maximums_eq(const df::hospital_supplies &a, const df::hospital_supplies &b) { return a.max_thread == b.max_thread && @@ -1333,23 +1333,15 @@ static bool do_transform(color_ostream &out, get_tile_construct, ensure_building); add_processor(processors, opts, "build", "build", opts.build, get_tile_build, ensure_building); -/* TODO: understand how this changes for v50 add_processor(processors, opts, "place", "place", opts.place, get_tile_place, ensure_building); +/* TODO: understand how this changes for v50 add_processor(processors, opts, "zone", "zone", opts.zone, get_tile_zone); add_processor(processors, opts, "query", "query", opts.query, get_tile_query, ensure_building); add_processor(processors, opts, "query", "rooms", opts.rooms, get_tile_rooms, ensure_building); -*/ if (opts.place) - out.printerr("'place' blueprints are not yet supported for the current version of DF\n"); - if (opts.zone) - out.printerr("'zone' blueprints are not yet supported for the current version of DF\n"); - if (opts.query) - out.printerr("'query' blueprints are not yet supported for the current version of DF\n"); - if (opts.rooms) - out.printerr("'rooms' blueprints are not yet supported for the current version of DF\n"); - +*/ if (processors.empty()) { out.printerr("no phases requested! nothing to do!\n"); return false; diff --git a/plugins/lua/blueprint.lua b/plugins/lua/blueprint.lua index 375cfc1b4..57dee31fc 100644 --- a/plugins/lua/blueprint.lua +++ b/plugins/lua/blueprint.lua @@ -9,17 +9,17 @@ local valid_phase_list = { 'construct', 'build', 'place', - 'zone', - 'query', - 'rooms', + -- 'zone', + -- 'query', + -- 'rooms', } valid_phases = utils.invert(valid_phase_list) local meta_phase_list = { 'build', 'place', - 'zone', - 'query', + -- 'zone', + -- 'query', } meta_phases = utils.invert(meta_phase_list) @@ -167,7 +167,7 @@ end function parse_commandline(opts, ...) local positionals = process_args(opts, {...}) - if opts.help then return end + if not positionals or opts.help then return end local width, height = tonumber(positionals[1]), tonumber(positionals[2]) if is_bad_dim(width) or is_bad_dim(height) then diff --git a/plugins/lua/stockpiles.lua b/plugins/lua/stockpiles.lua index 9e17cbe2b..379f2185a 100644 --- a/plugins/lua/stockpiles.lua +++ b/plugins/lua/stockpiles.lua @@ -81,7 +81,7 @@ local included_elements = { types=8, } -local function export_stockpile(name, opts) +function export_stockpile(name, opts) assert_safe_name(name) name = STOCKPILES_DIR .. '/' .. name @@ -101,7 +101,7 @@ local function export_stockpile(name, opts) stockpiles_export(name, get_sp_id(opts), includedElements) end -local function import_stockpile(name, opts) +function import_stockpile(name, opts) local is_library = false if name:startswith('library/') then name = name:sub(9) From 848556158bd3ffd198cfb98099a0ee247efbe424 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 21 May 2023 09:45:37 -0700 Subject: [PATCH 0212/1234] update HEADs --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 9891be326..c0ae38c0c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9891be32663435f2fe875e27c70010d5618de735 +Subproject commit c0ae38c0c60f5c12112d89bfd8facb7a0359fba2 diff --git a/scripts b/scripts index 40e517eb8..c96ffb334 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 40e517eb844779b4ac1ba6fe6d226f2d613d0b8c +Subproject commit c96ffb334e87a7c6098426bdbefca8ae8b51b748 From 6c9c44c71a97075dc9fef3886062fe6081bdcf57 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 21 May 2023 10:34:17 -0700 Subject: [PATCH 0213/1234] "develop" works as a ref; makes good default --- .github/workflows/steam.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 46dd27270..90f046b40 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -4,11 +4,12 @@ on: workflow_dispatch: inputs: commit_hash: - description: Commit hash + description: Branch or commit hash type: string required: true + default: develop version: - description: Version + description: Version or build description type: string required: true release_channel: From eeebce7e0f03c98289f41bc66ea11065d9ef3495 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 22 May 2023 07:13:59 +0000 Subject: [PATCH 0214/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index c96ffb334..d305ede50 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit c96ffb334e87a7c6098426bdbefca8ae8b51b748 +Subproject commit d305ede5067e9f8bb1cfeab6d746ac39a659a590 From 9e4c71318008e5fd364f24c8e836e53b7bad73d7 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 23 May 2023 07:13:27 +0000 Subject: [PATCH 0215/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index d305ede50..596b4e32a 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit d305ede5067e9f8bb1cfeab6d746ac39a659a590 +Subproject commit 596b4e32a72ee6ef71445ffae94988c8896d0805 From f3ce8059606ad1f2e65e31deea691f7c5cec5c4e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 23 May 2023 12:26:44 -0700 Subject: [PATCH 0216/1234] scroll mouse wheel to focus window under cursor --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 10 +++++----- library/lua/gui.lua | 16 +++++++++++----- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index df00cf34a..ab8ca1439 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -60,6 +60,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Core: For debugging purposes, you can now pass ``--disable-dfhack`` on the Dwarf Fortress commandline or specify ``DFHACK_DISABLE=1`` in the environment to disable DFHack for the current session. - `overlay`: added links to the quickstart guide and the control panel on the DF title screen - `gui/autodump`: fort-mode keybinding: Ctrl-H +- 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 ## Documentation diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 1c1d75358..44304a54e 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4240,11 +4240,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 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 -visible element of a non-focused ZScreen, that ZScreen will be given focus. This -allows multiple DFHack GUI tools to be usable at the same time. If the mouse is -clicked away from the ZScreen widgets, that ZScreen loses focus. If no ZScreen -has focus, all input is passed directly through to the first underlying +If multiple ZScreens are visible and the player scrolls or left/right clicks on +a visible element of a non-focused ZScreen, that ZScreen will be given focus. +This allows multiple DFHack GUI tools to be usable at the same time. If the +mouse is clicked away from the ZScreen widgets, that ZScreen loses focus. If no +ZScreen has focus, all input is passed directly through to the first underlying non-ZScreen viewscreen. For a ZScreen with keyboard focus, if :kbd:`Esc` or the right mouse button is diff --git a/library/lua/gui.lua b/library/lua/gui.lua index d511cd51f..9d9d39a8e 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -787,7 +787,9 @@ end function ZScreen:onInput(keys) local has_mouse = self:isMouseOver() if not self:hasFocus() then - if (keys._MOUSE_L_DOWN or keys._MOUSE_R_DOWN) and has_mouse then + if has_mouse and + (keys._MOUSE_L_DOWN or keys._MOUSE_R_DOWN or + keys.CONTEXT_SCROLL_UP or keys.CONTEXT_SCROLL_DOWN) then self:raise() else self:sendInputToParent(keys) @@ -818,10 +820,14 @@ function ZScreen:onInput(keys) end local passit = self.pass_pause and keys.D_PAUSE if not passit and self.pass_mouse_clicks then - for key in pairs(MOUSE_KEYS) do - if keys[key] then - passit = true - break + if keys.CONTEXT_SCROLL_UP or keys.CONTEXT_SCROLL_DOWN then + passit = true + else + for key in pairs(MOUSE_KEYS) do + if keys[key] then + passit = true + break + end end end end From 6f49a0eb3dc4055ca5b77fd7d040d25f6a4fbbad Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 23 May 2023 15:17:01 -0700 Subject: [PATCH 0217/1234] allow dragging by frame edge for non-resizable windows --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 4 ++-- library/lua/gui/widgets.lua | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index df00cf34a..c21facea1 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -59,6 +59,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `gui/blueprint`: recording of stockpile layouts and categories is now supported. note that detailed stockpile configurations will *not* be saved (yet) - Core: For debugging purposes, you can now pass ``--disable-dfhack`` on the Dwarf Fortress commandline or specify ``DFHACK_DISABLE=1`` in the environment to disable DFHack for the current session. - `overlay`: added 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 ## Documentation diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 1c1d75358..538fa08d8 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4503,7 +4503,7 @@ Has attributes: Called from ``postComputeFrame``. * ``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'``) * ``on_drag_begin = function()`` (default: ``nil``) * ``on_drag_end = function(bool)`` (default: ``nil``) @@ -4511,7 +4511,7 @@ Has attributes: If ``draggable`` is set to ``true``, then the above attributes come into play when the panel is dragged around the screen, either with the mouse or the keyboard. ``drag_anchors`` sets which parts of the panel can be clicked on - with the left mouse button to start dragging. ``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 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 diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 5c8094d28..a58ac228c 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -87,7 +87,7 @@ Panel.ATTRS { function Panel:init(args) if not self.drag_anchors then - self.drag_anchors = {title=true, frame=false, body=true} + self.drag_anchors = {title=true, frame=not self.resizable, body=true} end if not self.resize_anchors then self.resize_anchors = {t=false, l=true, r=true, b=true} From f6d9af5725ee15fcdc3a2527413f451ad8522ab6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 23 May 2023 15:20:09 -0700 Subject: [PATCH 0218/1234] also set focus on shift-scrolling --- library/lua/gui.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 9d9d39a8e..e22ddae20 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -789,7 +789,8 @@ function ZScreen:onInput(keys) if not self:hasFocus() then if has_mouse and (keys._MOUSE_L_DOWN or keys._MOUSE_R_DOWN or - keys.CONTEXT_SCROLL_UP or keys.CONTEXT_SCROLL_DOWN) then + keys.CONTEXT_SCROLL_UP or keys.CONTEXT_SCROLL_DOWN or + keys.CONTEXT_SCROLL_PAGEUP or keys.CONTEXT_SCROLL_PAGEDOWN) then self:raise() else self:sendInputToParent(keys) @@ -820,7 +821,8 @@ function ZScreen:onInput(keys) end local passit = self.pass_pause and keys.D_PAUSE if not passit and self.pass_mouse_clicks then - if keys.CONTEXT_SCROLL_UP or keys.CONTEXT_SCROLL_DOWN then + if keys.CONTEXT_SCROLL_UP or keys.CONTEXT_SCROLL_DOWN or + keys.CONTEXT_SCROLL_PAGEUP or keys.CONTEXT_SCROLL_PAGEDOWN then passit = true else for key in pairs(MOUSE_KEYS) do From 4ba2c807b2b63ba8dccde08a759b289fc5795e73 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 23 May 2023 22:26:06 +0000 Subject: [PATCH 0219/1234] Auto-update submodules library/xml: master scripts: master --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index c0ae38c0c..c0bf8aa61 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit c0ae38c0c60f5c12112d89bfd8facb7a0359fba2 +Subproject commit c0bf8aa6166b8e7a9672fd67edccfa4e78c945cd diff --git a/scripts b/scripts index 596b4e32a..d9a4d888e 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 596b4e32a72ee6ef71445ffae94988c8896d0805 +Subproject commit d9a4d888e3af40ef2f1f8765c8b4d45532129dc4 From 44340dfb75759eac7102465158cea0b2864133f9 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 24 May 2023 07:12:57 +0000 Subject: [PATCH 0220/1234] Auto-update submodules library/xml: master scripts: master plugins/stonesense: master --- library/xml | 2 +- plugins/stonesense | 2 +- scripts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/xml b/library/xml index c0bf8aa61..29801b004 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit c0bf8aa6166b8e7a9672fd67edccfa4e78c945cd +Subproject commit 29801b0043b884d04a7e63a995258ebf2b67cbaf diff --git a/plugins/stonesense b/plugins/stonesense index b7073b664..8a407a048 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit b7073b664310b909989ebe68de36a164e452825a +Subproject commit 8a407a0485d63ce399314afd2f0c623a7dfa4dfa diff --git a/scripts b/scripts index d9a4d888e..04e1e09a7 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit d9a4d888e3af40ef2f1f8765c8b4d45532129dc4 +Subproject commit 04e1e09a75e4ce3d9b7a2b98ab99a0cb45eff3b9 From 87775317a525bcbdede9d9d6b48e458a9faff5ef Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 24 May 2023 12:41:02 -0700 Subject: [PATCH 0221/1234] don't throw if json is unreadable just act like the file didn't exist (unless strict is set) --- docs/changelog.txt | 1 + library/lua/json.lua | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index df00cf34a..42ce711eb 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -51,6 +51,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## 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 CTD) - `orders`: update orders in orders library for prepared meals, bins, archer uniforms, and weapons - Terminal console no longer appears in front of the game window on startup - `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") diff --git a/library/lua/json.lua b/library/lua/json.lua index 2b4b3a66a..6ba8483dd 100644 --- a/library/lua/json.lua +++ b/library/lua/json.lua @@ -59,7 +59,13 @@ function _file:read(strict) end else self.exists = true - self.data = decode_file(self.path) + local ok, err = pcall(function() self.data = decode_file(self.path) end) + if not ok then + if strict then + error(('cannot decode file: %s: %s'):format(self.path, err)) + end + self.data = {} + end end return self.data end From a9843912bec83bf2607928ee150d09638c7c7433 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 25 May 2023 07:13:13 +0000 Subject: [PATCH 0222/1234] Auto-update submodules scripts: master plugins/stonesense: master --- plugins/stonesense | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/stonesense b/plugins/stonesense index 8a407a048..d7fa20079 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 8a407a0485d63ce399314afd2f0c623a7dfa4dfa +Subproject commit d7fa20079e89cc6516a0f5406a5ad112436066bb diff --git a/scripts b/scripts index 04e1e09a7..439356811 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 04e1e09a75e4ce3d9b7a2b98ab99a0cb45eff3b9 +Subproject commit 4393568117eaa5b74872c4d98e07dee1d58f3e48 From 732e042a543d618da913deaf1aa9907a6d8ecd6a Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 26 May 2023 00:57:44 +0000 Subject: [PATCH 0223/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 439356811..a26e72b6e 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 4393568117eaa5b74872c4d98e07dee1d58f3e48 +Subproject commit a26e72b6e1da16d6fcaadc71518314fb8aaae193 From 27ee0ae3960625bd4fd1c25136344dd52b05f5eb Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 27 May 2023 07:12:17 +0000 Subject: [PATCH 0224/1234] Auto-update submodules library/xml: master --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 29801b004..1cc81c0fa 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 29801b0043b884d04a7e63a995258ebf2b67cbaf +Subproject commit 1cc81c0faf7aa9fd1c18fbc6ef8b2298f31ab1f9 From 0918fbb0041e74765624aea4625c33bf38d8ac97 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 27 May 2023 03:16:51 -0700 Subject: [PATCH 0225/1234] add ensure_keys utility function --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 5 +++++ library/lua/dfhack.lua | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index c193442c6..b2ee30767 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -74,6 +74,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## 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. diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 9f0a40ba8..e5167a531 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3019,6 +3019,11 @@ environment by the mandatory init file dfhack.lua: set to the value of ``default_value``, which defaults to ``{}`` if not set. The new or existing value of ``t[key]`` is then returned. +* ``ensure_keys(t, key...)`` + + Walks a series of keys, creating any missing keys as empty tables. The new or + existing table from the last specified key is returned from the function. + .. _lua-string: String class extensions diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 78d978147..8ea5e9dac 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -404,6 +404,14 @@ function ensure_key(t, key, default_value) return t[key] end +function ensure_keys(t, key, ...) + t = ensure_key(t, key) + if select('#', ...) > 0 then + return ensure_keys(t, ...) + end + return t +end + -- String class extentions -- prefix is a literal string, not a pattern From 8b3eef699f4d2d6d5776ca4156085afd4220356c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 27 May 2023 05:37:31 -0700 Subject: [PATCH 0226/1234] adjust findCivzonesAt to v50 semantics --- library/modules/Buildings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index b9e61c863..dca8010da 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -465,7 +465,7 @@ bool Buildings::findCivzonesAt(std::vector *pvec, df::coord pos) { pvec->clear(); - for (df::building_civzonest* zone : world->buildings.other.ACTIVITY_ZONE) + for (df::building_civzonest* zone : world->buildings.other.ANY_ZONE) { if (pos.z != zone->z) continue; From dbcba3d548a8b8e18eb8ba385f243a38413354dd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 28 May 2023 02:26:06 -0700 Subject: [PATCH 0227/1234] refactor to allow interacting with route stop settings --- plugins/lua/stockpiles.lua | 18 +- plugins/stockpiles/StockpileSerializer.cpp | 456 +++++++++++---------- plugins/stockpiles/StockpileSerializer.h | 54 ++- plugins/stockpiles/stockpiles.cpp | 48 +++ 4 files changed, 342 insertions(+), 234 deletions(-) diff --git a/plugins/lua/stockpiles.lua b/plugins/lua/stockpiles.lua index 379f2185a..3e127de4d 100644 --- a/plugins/lua/stockpiles.lua +++ b/plugins/lua/stockpiles.lua @@ -101,7 +101,7 @@ function export_stockpile(name, opts) stockpiles_export(name, get_sp_id(opts), includedElements) end -function import_stockpile(name, opts) +local function normalize_name(name) local is_library = false if name:startswith('library/') then name = name:sub(9) @@ -109,11 +109,19 @@ function import_stockpile(name, opts) end assert_safe_name(name) if not is_library and dfhack.filesystem.exists(STOCKPILES_DIR .. '/' .. name .. '.dfstock') then - name = STOCKPILES_DIR .. '/' .. name - else - name = STOCKPILES_LIBRARY_DIR .. '/' .. name + return STOCKPILES_DIR .. '/' .. name end - stockpiles_import(name, get_sp_id(opts), opts.mode, table.concat(opts.filters, ',')) + return STOCKPILES_LIBRARY_DIR .. '/' .. name +end + +function import_stockpile(name, opts) + name = normalize_name(name) + stockpiles_import(name, get_sp_id(opts), opts.mode, table.concat(opts.filters or {}, ',')) +end + +function import_route(name, route_id, stop_id, mode, filters) + name = normalize_name(name) + stockpiles_route_import(name, route_id, stop_id, mode, table.concat(filters or {}, ',')) end local valid_includes = {general=true, categories=true, types=true} diff --git a/plugins/stockpiles/StockpileSerializer.cpp b/plugins/stockpiles/StockpileSerializer.cpp index 529e402bd..fcb0cee3e 100644 --- a/plugins/stockpiles/StockpileSerializer.cpp +++ b/plugins/stockpiles/StockpileSerializer.cpp @@ -150,12 +150,17 @@ static struct OtherMatsWeaponsArmor { } } mOtherMatsWeaponsArmor; +StockpileSettingsSerializer::StockpileSettingsSerializer(df::stockpile_settings *settings) + : mSettings(settings) { } + +StockpileSettingsSerializer::~StockpileSettingsSerializer() { } + StockpileSerializer::StockpileSerializer(df::building_stockpilest* stockpile) - : mPile(stockpile) { } + : StockpileSettingsSerializer(&stockpile->settings), mPile(stockpile) { } StockpileSerializer::~StockpileSerializer() { } -bool StockpileSerializer::serialize_to_ostream(std::ostream* output, uint32_t includedElements) { +bool StockpileSettingsSerializer::serialize_to_ostream(std::ostream* output, uint32_t includedElements) { if (output->fail()) return false; mBuffer.Clear(); @@ -168,7 +173,7 @@ bool StockpileSerializer::serialize_to_ostream(std::ostream* output, uint32_t in return output->good(); } -bool StockpileSerializer::serialize_to_file(const string& file, uint32_t includedElements) { +bool StockpileSettingsSerializer::serialize_to_file(const string& file, uint32_t includedElements) { std::fstream output(file, std::ios::out | std::ios::binary | std::ios::trunc); if (output.fail()) { WARN(log).print("ERROR: failed to open file for writing: '%s'\n", @@ -178,7 +183,7 @@ bool StockpileSerializer::serialize_to_file(const string& file, uint32_t include return serialize_to_ostream(&output, includedElements); } -bool StockpileSerializer::parse_from_istream(std::istream* input, DeserializeMode mode, const vector& filters) { +bool StockpileSettingsSerializer::parse_from_istream(std::istream* input, DeserializeMode mode, const vector& filters) { if (input->fail()) return false; mBuffer.Clear(); @@ -190,7 +195,7 @@ bool StockpileSerializer::parse_from_istream(std::istream* input, DeserializeMod return res; } -bool StockpileSerializer::unserialize_from_file(const string& file, DeserializeMode mode, const vector& filters) { +bool StockpileSettingsSerializer::unserialize_from_file(const string& file, DeserializeMode mode, const vector& filters) { std::fstream input(file, std::ios::in | std::ios::binary); if (input.fail()) { WARN(log).print("failed to open file for reading: '%s'\n", @@ -655,9 +660,7 @@ static void write_cat(const char *name, bool include_types, uint32_t cat_flags, } } -void StockpileSerializer::write(uint32_t includedElements) { - if (includedElements & INCLUDED_ELEMENTS_CONTAINERS) - write_containers(); +void StockpileSettingsSerializer::write(uint32_t includedElements) { if (includedElements & INCLUDED_ELEMENTS_GENERAL) write_general(); @@ -665,100 +668,106 @@ void StockpileSerializer::write(uint32_t includedElements) { return; DEBUG(log).print("GROUP SET %s\n", - bitfield_to_string(mPile->settings.flags).c_str()); + bitfield_to_string(mSettings->flags).c_str()); bool include_types = 0 != (includedElements & INCLUDED_ELEMENTS_TYPES); write_cat("ammo", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_ammo, + mSettings->flags.whole, + mSettings->flags.mask_ammo, std::bind(&StockpileSettings::mutable_ammo, &mBuffer), - std::bind(&StockpileSerializer::write_ammo, this, _1)); + std::bind(&StockpileSettingsSerializer::write_ammo, this, _1)); write_cat("animals", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_animals, + mSettings->flags.whole, + mSettings->flags.mask_animals, std::bind(&StockpileSettings::mutable_animals, &mBuffer), - std::bind(&StockpileSerializer::write_animals, this, _1)); + std::bind(&StockpileSettingsSerializer::write_animals, this, _1)); write_cat("armor", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_armor, + mSettings->flags.whole, + mSettings->flags.mask_armor, std::bind(&StockpileSettings::mutable_armor, &mBuffer), - std::bind(&StockpileSerializer::write_armor, this, _1)); + std::bind(&StockpileSettingsSerializer::write_armor, this, _1)); write_cat("bars_blocks", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_bars_blocks, + mSettings->flags.whole, + mSettings->flags.mask_bars_blocks, std::bind(&StockpileSettings::mutable_barsblocks, &mBuffer), - std::bind(&StockpileSerializer::write_bars_blocks, this, _1)); + std::bind(&StockpileSettingsSerializer::write_bars_blocks, this, _1)); write_cat("cloth", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_cloth, + mSettings->flags.whole, + mSettings->flags.mask_cloth, std::bind(&StockpileSettings::mutable_cloth, &mBuffer), - std::bind(&StockpileSerializer::write_cloth, this, _1)); + std::bind(&StockpileSettingsSerializer::write_cloth, this, _1)); write_cat("coin", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_coins, + mSettings->flags.whole, + mSettings->flags.mask_coins, std::bind(&StockpileSettings::mutable_coin, &mBuffer), - std::bind(&StockpileSerializer::write_coins, this, _1)); + std::bind(&StockpileSettingsSerializer::write_coins, this, _1)); write_cat("finished_goods", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_finished_goods, + mSettings->flags.whole, + mSettings->flags.mask_finished_goods, std::bind(&StockpileSettings::mutable_finished_goods, &mBuffer), - std::bind(&StockpileSerializer::write_finished_goods, this, _1)); + std::bind(&StockpileSettingsSerializer::write_finished_goods, this, _1)); write_cat("food", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_food, + mSettings->flags.whole, + mSettings->flags.mask_food, std::bind(&StockpileSettings::mutable_food, &mBuffer), - std::bind(&StockpileSerializer::write_food, this, _1)); + std::bind(&StockpileSettingsSerializer::write_food, this, _1)); write_cat("furniture", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_furniture, + mSettings->flags.whole, + mSettings->flags.mask_furniture, std::bind(&StockpileSettings::mutable_furniture, &mBuffer), - std::bind(&StockpileSerializer::write_furniture, this, _1)); + std::bind(&StockpileSettingsSerializer::write_furniture, this, _1)); write_cat("gems", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_gems, + mSettings->flags.whole, + mSettings->flags.mask_gems, std::bind(&StockpileSettings::mutable_gems, &mBuffer), - std::bind(&StockpileSerializer::write_gems, this, _1)); + std::bind(&StockpileSettingsSerializer::write_gems, this, _1)); write_cat("leather", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_leather, + mSettings->flags.whole, + mSettings->flags.mask_leather, std::bind(&StockpileSettings::mutable_leather, &mBuffer), - std::bind(&StockpileSerializer::write_leather, this, _1)); + std::bind(&StockpileSettingsSerializer::write_leather, this, _1)); write_cat("corpses", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_corpses, + mSettings->flags.whole, + mSettings->flags.mask_corpses, std::bind(&StockpileSettings::mutable_corpses_v50, &mBuffer), - std::bind(&StockpileSerializer::write_corpses, this, _1)); + std::bind(&StockpileSettingsSerializer::write_corpses, this, _1)); write_cat("refuse", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_refuse, + mSettings->flags.whole, + mSettings->flags.mask_refuse, std::bind(&StockpileSettings::mutable_refuse, &mBuffer), - std::bind(&StockpileSerializer::write_refuse, this, _1)); + std::bind(&StockpileSettingsSerializer::write_refuse, this, _1)); write_cat("sheet", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_sheet, + mSettings->flags.whole, + mSettings->flags.mask_sheet, std::bind(&StockpileSettings::mutable_sheet, &mBuffer), - std::bind(&StockpileSerializer::write_sheet, this, _1)); + std::bind(&StockpileSettingsSerializer::write_sheet, this, _1)); write_cat("stone", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_stone, + mSettings->flags.whole, + mSettings->flags.mask_stone, std::bind(&StockpileSettings::mutable_stone, &mBuffer), - std::bind(&StockpileSerializer::write_stone, this, _1)); + std::bind(&StockpileSettingsSerializer::write_stone, this, _1)); write_cat("weapons", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_weapons, + mSettings->flags.whole, + mSettings->flags.mask_weapons, std::bind(&StockpileSettings::mutable_weapons, &mBuffer), - std::bind(&StockpileSerializer::write_weapons, this, _1)); + std::bind(&StockpileSettingsSerializer::write_weapons, this, _1)); write_cat("wood", include_types, - mPile->settings.flags.whole, - mPile->settings.flags.mask_wood, + mSettings->flags.whole, + mSettings->flags.mask_wood, std::bind(&StockpileSettings::mutable_wood, &mBuffer), - std::bind(&StockpileSerializer::write_wood, this, _1)); + std::bind(&StockpileSettingsSerializer::write_wood, this, _1)); } -void StockpileSerializer::read(DeserializeMode mode, const vector& filters) { +void StockpileSerializer::write(uint32_t includedElements) { + if (includedElements & INCLUDED_ELEMENTS_CONTAINERS) + write_containers(); + + StockpileSettingsSerializer::write(includedElements); +} + +void StockpileSettingsSerializer::read(DeserializeMode mode, const vector& filters) { DEBUG(log).print("==READ==\n"); - read_containers(mode); read_general(mode); read_ammo(mode, filters); read_animals(mode, filters); @@ -786,6 +795,11 @@ void StockpileSerializer::read(DeserializeMode mode, const vector& filte read_wood(mode, filters); } +void StockpileSerializer::read(DeserializeMode mode, const vector& filters) { + read_containers(mode); + StockpileSettingsSerializer::read(mode, filters); +} + void StockpileSerializer::write_containers() { DEBUG(log).print("writing container settings\n"); mBuffer.set_max_bins(mPile->max_bins); @@ -854,53 +868,61 @@ void StockpileSerializer::read_containers(DeserializeMode mode) { mPile->max_wheelbarrows); } -void StockpileSerializer::write_general() { +void StockpileSettingsSerializer::write_general() { DEBUG(log).print("writing general settings\n"); + mBuffer.set_allow_inorganic(mSettings->allow_inorganic); + mBuffer.set_allow_organic(mSettings->allow_organic); +} + +void StockpileSerializer::write_general() { + StockpileSettingsSerializer::write_general(); mBuffer.set_use_links_only(mPile->use_links_only); - mBuffer.set_allow_inorganic(mPile->settings.allow_inorganic); - mBuffer.set_allow_organic(mPile->settings.allow_organic); } -void StockpileSerializer::read_general(DeserializeMode mode) { - read_elem("use_links_only", mode, - std::bind(&StockpileSettings::has_use_links_only, mBuffer), - std::bind(&StockpileSettings::use_links_only, mBuffer), - mPile->use_links_only); +void StockpileSettingsSerializer::read_general(DeserializeMode mode) { read_elem("allow_inorganic", mode, std::bind(&StockpileSettings::has_allow_inorganic, mBuffer), std::bind(&StockpileSettings::allow_inorganic, mBuffer), - mPile->settings.allow_inorganic); + mSettings->allow_inorganic); read_elem("allow_organic", mode, std::bind(&StockpileSettings::has_allow_organic, mBuffer), std::bind(&StockpileSettings::allow_organic, mBuffer), - mPile->settings.allow_organic); + mSettings->allow_organic); +} + +void StockpileSerializer::read_general(DeserializeMode mode) { + StockpileSettingsSerializer::read_general(mode); + read_elem("use_links_only", mode, + std::bind(&StockpileSettings::has_use_links_only, mBuffer), + std::bind(&StockpileSettings::use_links_only, mBuffer), + mPile->use_links_only); } static bool ammo_mat_is_allowed(const MaterialInfo& mi) { return mi.isValid() && mi.material && mi.material->flags.is_set(material_flags::IS_METAL); } -bool StockpileSerializer::write_ammo(StockpileSettings::AmmoSet* ammo) { +bool StockpileSettingsSerializer::write_ammo(StockpileSettings::AmmoSet* ammo) { bool all = serialize_list_itemdef( [&](const string& token) { ammo->add_type(token); }, - mPile->settings.ammo.type, + mSettings->ammo.type, vector(world->raws.itemdefs.ammo.begin(), world->raws.itemdefs.ammo.end()), item_type::AMMO); all = serialize_list_material( ammo_mat_is_allowed, [&](const string& token) { ammo->add_mats(token); }, - mPile->settings.ammo.mats) && all; + mSettings->ammo.mats) && all; - if (mPile->settings.ammo.other_mats.size() > 2) { + if (mSettings->ammo.other_mats.size() > 2) { WARN(log).print("ammo other materials > 2: %zd\n", - mPile->settings.ammo.other_mats.size()); + mSettings->ammo.other_mats.size()); } size_t num_other_mats = std::min(size_t(2), - mPile->settings.ammo.other_mats.size()); + mSettings->ammo.other_mats.size()); for (size_t i = 0; i < num_other_mats; ++i) { - if (!mPile->settings.ammo.other_mats.at(i)) { + if (!mSettings->ammo.other_mats.at(i)) { all = false; continue; } @@ -911,22 +933,22 @@ bool StockpileSerializer::write_ammo(StockpileSettings::AmmoSet* ammo) { all = serialize_list_quality( [&](const string& token) { ammo->add_quality_core(token); }, - mPile->settings.ammo.quality_core) && all; + mSettings->ammo.quality_core) && all; all = serialize_list_quality( [&](const string& token) { ammo->add_quality_total(token); }, - mPile->settings.ammo.quality_total) && all; + mSettings->ammo.quality_total) && all; return all; } -void StockpileSerializer::read_ammo(DeserializeMode mode, const vector& filters) { - auto & pammo = mPile->settings.ammo; +void StockpileSettingsSerializer::read_ammo(DeserializeMode mode, const vector& filters) { + auto & pammo = mSettings->ammo; read_category("ammo", mode, std::bind(&StockpileSettings::has_ammo, mBuffer), std::bind(&StockpileSettings::ammo, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_ammo, + mSettings->flags.whole, + mSettings->flags.mask_ammo, [&]() { pammo.type.clear(); pammo.mats.clear(); @@ -970,8 +992,8 @@ void StockpileSerializer::read_ammo(DeserializeMode mode, const vector& }); } -bool StockpileSerializer::write_animals(StockpileSettings::AnimalsSet* animals) { - auto & panimals = mPile->settings.animals; +bool StockpileSettingsSerializer::write_animals(StockpileSettings::AnimalsSet* animals) { + auto & panimals = mSettings->animals; bool all = panimals.empty_cages && panimals.empty_traps; animals->set_empty_cages(panimals.empty_cages); @@ -982,13 +1004,13 @@ bool StockpileSerializer::write_animals(StockpileSettings::AnimalsSet* animals) panimals.enabled) && all; } -void StockpileSerializer::read_animals(DeserializeMode mode, const vector& filters) { - auto & panimals = mPile->settings.animals; +void StockpileSettingsSerializer::read_animals(DeserializeMode mode, const vector& filters) { + auto & panimals = mSettings->animals; read_category("animals", mode, std::bind(&StockpileSettings::has_animals, mBuffer), std::bind(&StockpileSettings::animals, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_animals, + mSettings->flags.whole, + mSettings->flags.mask_animals, [&]() { panimals.empty_cages = false; panimals.empty_traps = false; @@ -1010,9 +1032,9 @@ static bool armor_mat_is_allowed(const MaterialInfo& mi) { return mi.isValid() && mi.material && mi.material->flags.is_set(material_flags::IS_METAL); } -bool StockpileSerializer::write_armor(StockpileSettings::ArmorSet* armor) { +bool StockpileSettingsSerializer::write_armor(StockpileSettings::ArmorSet* armor) { - auto & parmor = mPile->settings.armor; + auto & parmor = mSettings->armor; bool all = parmor.unusable && parmor.usable; armor->set_unusable(parmor.unusable); @@ -1082,13 +1104,13 @@ bool StockpileSerializer::write_armor(StockpileSettings::ArmorSet* armor) { return all; } -void StockpileSerializer::read_armor(DeserializeMode mode, const vector& filters) { - auto & parmor = mPile->settings.armor; +void StockpileSettingsSerializer::read_armor(DeserializeMode mode, const vector& filters) { + auto & parmor = mSettings->armor; read_category("armor", mode, std::bind(&StockpileSettings::has_armor, mBuffer), std::bind(&StockpileSettings::armor, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_armor, + mSettings->flags.whole, + mSettings->flags.mask_armor, [&]() { parmor.unusable = false; parmor.usable = false; @@ -1160,35 +1182,35 @@ static bool blocks_mat_is_allowed(const MaterialInfo& mi) { return mi.isValid() && mi.material && (mi.material->flags.is_set(material_flags::IS_METAL) || mi.material->flags.is_set(material_flags::IS_STONE)); } -bool StockpileSerializer::write_bars_blocks(StockpileSettings::BarsBlocksSet* bars_blocks) { +bool StockpileSettingsSerializer::write_bars_blocks(StockpileSettings::BarsBlocksSet* bars_blocks) { bool all = serialize_list_material( bars_mat_is_allowed, [&](const string& token) { bars_blocks->add_bars_mats(token); }, - mPile->settings.bars_blocks.bars_mats); + mSettings->bars_blocks.bars_mats); all = serialize_list_material( blocks_mat_is_allowed, [&](const string& token) { bars_blocks->add_blocks_mats(token); }, - mPile->settings.bars_blocks.blocks_mats) && all; + mSettings->bars_blocks.blocks_mats) && all; all = serialize_list_other_mats( mOtherMatsBars.mats, [&](const string& token) { bars_blocks->add_bars_other_mats(token); }, - mPile->settings.bars_blocks.bars_other_mats) && all; + mSettings->bars_blocks.bars_other_mats) && all; all = serialize_list_other_mats( mOtherMatsBlocks.mats, [&](const string& token) { bars_blocks->add_blocks_other_mats(token); }, - mPile->settings.bars_blocks.blocks_other_mats) && all; + mSettings->bars_blocks.blocks_other_mats) && all; return all; } -void StockpileSerializer::read_bars_blocks(DeserializeMode mode, const vector& filters) { - auto & pbarsblocks = mPile->settings.bars_blocks; +void StockpileSettingsSerializer::read_bars_blocks(DeserializeMode mode, const vector& filters) { + auto & pbarsblocks = mSettings->bars_blocks; read_category("bars_blocks", mode, std::bind(&StockpileSettings::has_barsblocks, mBuffer), std::bind(&StockpileSettings::barsblocks, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_bars_blocks, + mSettings->flags.whole, + mSettings->flags.mask_bars_blocks, [&]() { pbarsblocks.bars_mats.clear(); pbarsblocks.bars_other_mats.clear(); @@ -1219,51 +1241,51 @@ void StockpileSerializer::read_bars_blocks(DeserializeMode mode, const vectoradd_thread_silk(token); }, - &mPile->settings.cloth.thread_silk, organic_mat_category::Silk) && all; + &mSettings->cloth.thread_silk, organic_mat_category::Silk) && all; all = serialize_list_organic_mat( [&](const string& token) { cloth->add_thread_plant(token); }, - &mPile->settings.cloth.thread_plant, organic_mat_category::PlantFiber) && all; + &mSettings->cloth.thread_plant, organic_mat_category::PlantFiber) && all; all = serialize_list_organic_mat( [&](const string& token) { cloth->add_thread_yarn(token); }, - &mPile->settings.cloth.thread_yarn, organic_mat_category::Yarn) && all; + &mSettings->cloth.thread_yarn, organic_mat_category::Yarn) && all; all = serialize_list_organic_mat( [&](const string& token) { cloth->add_thread_metal(token); }, - &mPile->settings.cloth.thread_metal, organic_mat_category::MetalThread) && all; + &mSettings->cloth.thread_metal, organic_mat_category::MetalThread) && all; all = serialize_list_organic_mat( [&](const string& token) { cloth->add_cloth_silk(token); }, - &mPile->settings.cloth.cloth_silk, organic_mat_category::Silk) && all; + &mSettings->cloth.cloth_silk, organic_mat_category::Silk) && all; all = serialize_list_organic_mat( [&](const string& token) { cloth->add_cloth_plant(token); }, - &mPile->settings.cloth.cloth_plant, organic_mat_category::PlantFiber) && all; + &mSettings->cloth.cloth_plant, organic_mat_category::PlantFiber) && all; all = serialize_list_organic_mat( [&](const string& token) { cloth->add_cloth_yarn(token); }, - &mPile->settings.cloth.cloth_yarn, organic_mat_category::Yarn) && all; + &mSettings->cloth.cloth_yarn, organic_mat_category::Yarn) && all; all = serialize_list_organic_mat( [&](const string& token) { cloth->add_cloth_metal(token); }, - &mPile->settings.cloth.cloth_metal, organic_mat_category::MetalThread) && all; + &mSettings->cloth.cloth_metal, organic_mat_category::MetalThread) && all; return all; } -void StockpileSerializer::read_cloth(DeserializeMode mode, const vector& filters) { - auto & pcloth = mPile->settings.cloth; +void StockpileSettingsSerializer::read_cloth(DeserializeMode mode, const vector& filters) { + auto & pcloth = mSettings->cloth; read_category("cloth", mode, std::bind(&StockpileSettings::has_cloth, mBuffer), std::bind(&StockpileSettings::cloth, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_cloth, + mSettings->flags.whole, + mSettings->flags.mask_cloth, [&]() { pcloth.thread_silk.clear(); pcloth.thread_yarn.clear(); @@ -1315,20 +1337,20 @@ static bool coins_mat_is_allowed(const MaterialInfo& mi) { return mi.isValid(); } -bool StockpileSerializer::write_coins(StockpileSettings::CoinSet* coins) { +bool StockpileSettingsSerializer::write_coins(StockpileSettings::CoinSet* coins) { return serialize_list_material( coins_mat_is_allowed, [&](const string& token) { coins->add_mats(token); }, - mPile->settings.coins.mats); + mSettings->coins.mats); } -void StockpileSerializer::read_coins(DeserializeMode mode, const vector& filters) { - auto & pcoins = mPile->settings.coins; +void StockpileSettingsSerializer::read_coins(DeserializeMode mode, const vector& filters) { + auto & pcoins = mSettings->coins; read_category("coin", mode, std::bind(&StockpileSettings::has_coin, mBuffer), std::bind(&StockpileSettings::coin, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_coins, + mSettings->flags.whole, + mSettings->flags.mask_coins, [&]() { pcoins.mats.clear(); }, @@ -1378,37 +1400,37 @@ static bool finished_goods_mat_is_allowed(const MaterialInfo& mi) { return mi.isValid() && mi.material && (mi.material->flags.is_set(material_flags::IS_GEM) || mi.material->flags.is_set(material_flags::IS_METAL) || mi.material->flags.is_set(material_flags::IS_STONE)); } -bool StockpileSerializer::write_finished_goods(StockpileSettings::FinishedGoodsSet* finished_goods) { +bool StockpileSettingsSerializer::write_finished_goods(StockpileSettings::FinishedGoodsSet* finished_goods) { bool all = serialize_list_item_type( finished_goods_type_is_allowed, [&](const string& token) { finished_goods->add_type(token); }, - mPile->settings.finished_goods.type); + mSettings->finished_goods.type); all = serialize_list_material( finished_goods_mat_is_allowed, [&](const string& token) { finished_goods->add_mats(token); }, - mPile->settings.finished_goods.mats) && all; + mSettings->finished_goods.mats) && all; all = serialize_list_other_mats( mOtherMatsFinishedGoods.mats, [&](const string& token) { finished_goods->add_other_mats(token); }, - mPile->settings.finished_goods.other_mats) && all; + mSettings->finished_goods.other_mats) && all; all = serialize_list_quality([&](const string& token) { finished_goods->add_quality_core(token); }, - mPile->settings.finished_goods.quality_core) && all; + mSettings->finished_goods.quality_core) && all; all = serialize_list_quality([&](const string& token) { finished_goods->add_quality_total(token); }, - mPile->settings.finished_goods.quality_total) && all; + mSettings->finished_goods.quality_total) && all; return all; } -void StockpileSerializer::read_finished_goods(DeserializeMode mode, const vector& filters) { - auto & pfinished_goods = mPile->settings.finished_goods; +void StockpileSettingsSerializer::read_finished_goods(DeserializeMode mode, const vector& filters) { + auto & pfinished_goods = mSettings->finished_goods; read_category("finished_goods", mode, std::bind(&StockpileSettings::has_finished_goods, mBuffer), std::bind(&StockpileSettings::finished_goods, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_finished_goods, + mSettings->flags.whole, + mSettings->flags.mask_finished_goods, [&]() { pfinished_goods.type.clear(); pfinished_goods.other_mats.clear(); @@ -1441,7 +1463,7 @@ void StockpileSerializer::read_finished_goods(DeserializeMode mode, const vector }); } -food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_category cat) { +food_pair StockpileSettingsSerializer::food_map(organic_mat_category::organic_mat_category cat) { using df::enums::organic_mat_category::organic_mat_category; switch (cat) { @@ -1451,7 +1473,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_meat(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().meat(idx); }; - return food_pair("meat", setter, &mPile->settings.food.meat, getter, mBuffer.food().meat_size()); + return food_pair("meat", setter, &mSettings->food.meat, getter, mBuffer.food().meat_size()); } case organic_mat_category::Fish: { @@ -1459,7 +1481,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_fish(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().fish(idx); }; - return food_pair("fish/prepared", setter, &mPile->settings.food.fish, getter, mBuffer.food().fish_size()); + return food_pair("fish/prepared", setter, &mSettings->food.fish, getter, mBuffer.food().fish_size()); } case organic_mat_category::UnpreparedFish: { @@ -1467,7 +1489,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_unprepared_fish(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().unprepared_fish(idx); }; - return food_pair("fish/unprepared", setter, &mPile->settings.food.unprepared_fish, getter, mBuffer.food().unprepared_fish_size()); + return food_pair("fish/unprepared", setter, &mSettings->food.unprepared_fish, getter, mBuffer.food().unprepared_fish_size()); } case organic_mat_category::Eggs: { @@ -1475,7 +1497,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_egg(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().egg(idx); }; - return food_pair("egg", setter, &mPile->settings.food.egg, getter, mBuffer.food().egg_size()); + return food_pair("egg", setter, &mSettings->food.egg, getter, mBuffer.food().egg_size()); } case organic_mat_category::Plants: { @@ -1483,7 +1505,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_plants(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().plants(idx); }; - return food_pair("plants", setter, &mPile->settings.food.plants, getter, mBuffer.food().plants_size()); + return food_pair("plants", setter, &mSettings->food.plants, getter, mBuffer.food().plants_size()); } case organic_mat_category::PlantDrink: { @@ -1491,7 +1513,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_drink_plant(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().drink_plant(idx); }; - return food_pair("drink/plant", setter, &mPile->settings.food.drink_plant, getter, mBuffer.food().drink_plant_size()); + return food_pair("drink/plant", setter, &mSettings->food.drink_plant, getter, mBuffer.food().drink_plant_size()); } case organic_mat_category::CreatureDrink: { @@ -1499,7 +1521,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_drink_animal(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().drink_animal(idx); }; - return food_pair("drink/animal", setter, &mPile->settings.food.drink_animal, getter, mBuffer.food().drink_animal_size()); + return food_pair("drink/animal", setter, &mSettings->food.drink_animal, getter, mBuffer.food().drink_animal_size()); } case organic_mat_category::PlantCheese: { @@ -1507,7 +1529,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_cheese_plant(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().cheese_plant(idx); }; - return food_pair("cheese/plant", setter, &mPile->settings.food.cheese_plant, getter, mBuffer.food().cheese_plant_size()); + return food_pair("cheese/plant", setter, &mSettings->food.cheese_plant, getter, mBuffer.food().cheese_plant_size()); } case organic_mat_category::CreatureCheese: { @@ -1515,7 +1537,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_cheese_animal(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().cheese_animal(idx); }; - return food_pair("cheese/animal", setter, &mPile->settings.food.cheese_animal, getter, mBuffer.food().cheese_animal_size()); + return food_pair("cheese/animal", setter, &mSettings->food.cheese_animal, getter, mBuffer.food().cheese_animal_size()); } case organic_mat_category::Seed: { @@ -1523,7 +1545,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_seeds(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().seeds(idx); }; - return food_pair("seeds", setter, &mPile->settings.food.seeds, getter, mBuffer.food().seeds_size()); + return food_pair("seeds", setter, &mSettings->food.seeds, getter, mBuffer.food().seeds_size()); } case organic_mat_category::Leaf: { @@ -1531,7 +1553,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_leaves(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().leaves(idx); }; - return food_pair("leaves", setter, &mPile->settings.food.leaves, getter, mBuffer.food().leaves_size()); + return food_pair("leaves", setter, &mSettings->food.leaves, getter, mBuffer.food().leaves_size()); } case organic_mat_category::PlantPowder: { @@ -1539,7 +1561,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_powder_plant(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().powder_plant(idx); }; - return food_pair("powder/plant", setter, &mPile->settings.food.powder_plant, getter, mBuffer.food().powder_plant_size()); + return food_pair("powder/plant", setter, &mSettings->food.powder_plant, getter, mBuffer.food().powder_plant_size()); } case organic_mat_category::CreaturePowder: { @@ -1547,7 +1569,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_powder_creature(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().powder_creature(idx); }; - return food_pair("powder/animal", setter, &mPile->settings.food.powder_creature, getter, mBuffer.food().powder_creature_size()); + return food_pair("powder/animal", setter, &mSettings->food.powder_creature, getter, mBuffer.food().powder_creature_size()); } case organic_mat_category::Glob: { @@ -1555,7 +1577,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_glob(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().glob(idx); }; - return food_pair("glob", setter, &mPile->settings.food.glob, getter, mBuffer.food().glob_size()); + return food_pair("glob", setter, &mSettings->food.glob, getter, mBuffer.food().glob_size()); } case organic_mat_category::PlantLiquid: { @@ -1563,7 +1585,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_liquid_plant(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().liquid_plant(idx); }; - return food_pair("liquid/plant", setter, &mPile->settings.food.liquid_plant, getter, mBuffer.food().liquid_plant_size()); + return food_pair("liquid/plant", setter, &mSettings->food.liquid_plant, getter, mBuffer.food().liquid_plant_size()); } case organic_mat_category::CreatureLiquid: { @@ -1571,7 +1593,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_liquid_animal(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().liquid_animal(idx); }; - return food_pair("liquid/animal", setter, &mPile->settings.food.liquid_animal, getter, mBuffer.food().liquid_animal_size()); + return food_pair("liquid/animal", setter, &mSettings->food.liquid_animal, getter, mBuffer.food().liquid_animal_size()); } case organic_mat_category::MiscLiquid: { @@ -1579,7 +1601,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_liquid_misc(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().liquid_misc(idx); }; - return food_pair("liquid/misc", setter, &mPile->settings.food.liquid_misc, getter, mBuffer.food().liquid_misc_size()); + return food_pair("liquid/misc", setter, &mSettings->food.liquid_misc, getter, mBuffer.food().liquid_misc_size()); } case organic_mat_category::Paste: @@ -1588,7 +1610,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_glob_paste(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().glob_paste(idx); }; - return food_pair("paste", setter, &mPile->settings.food.glob_paste, getter, mBuffer.food().glob_paste_size()); + return food_pair("paste", setter, &mSettings->food.glob_paste, getter, mBuffer.food().glob_paste_size()); } case organic_mat_category::Pressed: { @@ -1596,7 +1618,7 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego mBuffer.mutable_food()->add_glob_pressed(id); }; FuncReadImport getter = [&](size_t idx) -> string { return mBuffer.food().glob_pressed(idx); }; - return food_pair("pressed", setter, &mPile->settings.food.glob_pressed, getter, mBuffer.food().glob_pressed_size()); + return food_pair("pressed", setter, &mSettings->food.glob_pressed, getter, mBuffer.food().glob_pressed_size()); } case organic_mat_category::Leather: case organic_mat_category::Silk: @@ -1623,8 +1645,8 @@ food_pair StockpileSerializer::food_map(organic_mat_category::organic_mat_catego return food_pair(); } -bool StockpileSerializer::write_food(StockpileSettings::FoodSet* food) { - auto & pfood = mPile->settings.food; +bool StockpileSettingsSerializer::write_food(StockpileSettings::FoodSet* food) { + auto & pfood = mSettings->food; bool all = pfood.prepared_meals; food->set_prepared_meals(pfood.prepared_meals); @@ -1642,16 +1664,16 @@ bool StockpileSerializer::write_food(StockpileSettings::FoodSet* food) { return all; } -void StockpileSerializer::read_food(DeserializeMode mode, const vector& filters) { +void StockpileSettingsSerializer::read_food(DeserializeMode mode, const vector& filters) { using df::enums::organic_mat_category::organic_mat_category; using traits = df::enum_traits; - auto & pfood = mPile->settings.food; + auto & pfood = mSettings->food; read_category("food", mode, std::bind(&StockpileSettings::has_food, mBuffer), std::bind(&StockpileSettings::food, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_food, + mSettings->flags.whole, + mSettings->flags.mask_food, [&]() { pfood.prepared_meals = false; for (int32_t mat_category = traits::first_item_value; mat_category < traits::last_item_value; ++mat_category) { @@ -1682,11 +1704,11 @@ static bool furniture_mat_is_allowed(const MaterialInfo& mi) { return mi.isValid() && mi.material && (mi.material->flags.is_set(material_flags::IS_METAL) || mi.material->flags.is_set(material_flags::IS_STONE)); } -bool StockpileSerializer::write_furniture(StockpileSettings::FurnitureSet* furniture) { +bool StockpileSettingsSerializer::write_furniture(StockpileSettings::FurnitureSet* furniture) { using df::enums::furniture_type::furniture_type; using type_traits = df::enum_traits; - auto & pfurniture = mPile->settings.furniture; + auto & pfurniture = mSettings->furniture; bool all = true; for (size_t i = 0; i < pfurniture.type.size(); ++i) { @@ -1717,13 +1739,13 @@ bool StockpileSerializer::write_furniture(StockpileSettings::FurnitureSet* furni return all; } -void StockpileSerializer::read_furniture(DeserializeMode mode, const vector& filters) { - auto & pfurniture = mPile->settings.furniture; +void StockpileSettingsSerializer::read_furniture(DeserializeMode mode, const vector& filters) { + auto & pfurniture = mSettings->furniture; read_category("furniture", mode, std::bind(&StockpileSettings::has_furniture, mBuffer), std::bind(&StockpileSettings::furniture, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_furniture, + mSettings->flags.whole, + mSettings->flags.mask_furniture, [&]() { pfurniture.type.clear(); pfurniture.other_mats.clear(); @@ -1786,10 +1808,10 @@ static bool gem_other_mat_is_allowed(MaterialInfo& mi) { return mi.isValid() && (mi.getToken() == "GLASS_GREEN" || mi.getToken() == "GLASS_CLEAR" || mi.getToken() == "GLASS_CRYSTAL"); } -bool StockpileSerializer::write_gems(StockpileSettings::GemsSet* gems) { +bool StockpileSettingsSerializer::write_gems(StockpileSettings::GemsSet* gems) { MaterialInfo mi; - auto & pgems = mPile->settings.gems; + auto & pgems = mSettings->gems; bool all = serialize_list_material( gem_mat_is_allowed, @@ -1830,13 +1852,13 @@ bool StockpileSerializer::write_gems(StockpileSettings::GemsSet* gems) { return all; } -void StockpileSerializer::read_gems(DeserializeMode mode, const vector& filters) { - auto & pgems = mPile->settings.gems; +void StockpileSettingsSerializer::read_gems(DeserializeMode mode, const vector& filters) { + auto & pgems = mSettings->gems; read_category("gems", mode, std::bind(&StockpileSettings::has_gems, mBuffer), std::bind(&StockpileSettings::gems, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_gems, + mSettings->flags.whole, + mSettings->flags.mask_gems, [&]() { pgems.cut_other_mats.clear(); pgems.cut_mats.clear(); @@ -1887,19 +1909,19 @@ void StockpileSerializer::read_gems(DeserializeMode mode, const vector& }); } -bool StockpileSerializer::write_leather(StockpileSettings::LeatherSet* leather) { +bool StockpileSettingsSerializer::write_leather(StockpileSettings::LeatherSet* leather) { return serialize_list_organic_mat( [&](const string& id) { leather->add_mats(id); }, - &mPile->settings.leather.mats, organic_mat_category::Leather); + &mSettings->leather.mats, organic_mat_category::Leather); } -void StockpileSerializer::read_leather(DeserializeMode mode, const vector& filters) { - auto & pleather = mPile->settings.leather; +void StockpileSettingsSerializer::read_leather(DeserializeMode mode, const vector& filters) { + auto & pleather = mSettings->leather; read_category("leather", mode, std::bind(&StockpileSettings::has_leather, mBuffer), std::bind(&StockpileSettings::leather, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_leather, + mSettings->flags.whole, + mSettings->flags.mask_leather, [&]() { pleather.mats.clear(); }, @@ -1912,19 +1934,19 @@ void StockpileSerializer::read_leather(DeserializeMode mode, const vectoradd_corpses(token); }, - mPile->settings.corpses.corpses); + mSettings->corpses.corpses); } -void StockpileSerializer::read_corpses(DeserializeMode mode, const vector& filters) { - auto & pcorpses = mPile->settings.corpses; +void StockpileSettingsSerializer::read_corpses(DeserializeMode mode, const vector& filters) { + auto & pcorpses = mSettings->corpses; read_category("corpses", mode, std::bind(&StockpileSettings::has_corpses_v50, mBuffer), std::bind(&StockpileSettings::corpses_v50, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_corpses, + mSettings->flags.whole, + mSettings->flags.mask_corpses, [&]() { pcorpses.corpses.clear(); }, @@ -1945,8 +1967,8 @@ static bool refuse_type_is_allowed(item_type::item_type type) { return true; } -bool StockpileSerializer::write_refuse(StockpileSettings::RefuseSet* refuse) { - auto & prefuse = mPile->settings.refuse; +bool StockpileSettingsSerializer::write_refuse(StockpileSettings::RefuseSet* refuse) { + auto & prefuse = mSettings->refuse; bool all = prefuse.fresh_raw_hide && prefuse.rotten_raw_hide; refuse->set_fresh_raw_hide(prefuse.fresh_raw_hide); @@ -1984,13 +2006,13 @@ bool StockpileSerializer::write_refuse(StockpileSettings::RefuseSet* refuse) { return all; } -void StockpileSerializer::read_refuse(DeserializeMode mode, const vector& filters) { - auto & prefuse = mPile->settings.refuse; +void StockpileSettingsSerializer::read_refuse(DeserializeMode mode, const vector& filters) { + auto & prefuse = mSettings->refuse; read_category("refuse", mode, std::bind(&StockpileSettings::has_refuse, mBuffer), std::bind(&StockpileSettings::refuse, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_refuse, + mSettings->flags.whole, + mSettings->flags.mask_refuse, [&]() { prefuse.fresh_raw_hide = false; prefuse.rotten_raw_hide = false; @@ -2042,25 +2064,25 @@ void StockpileSerializer::read_refuse(DeserializeMode mode, const vector } -bool StockpileSerializer::write_sheet(StockpileSettings::SheetSet* sheet) { +bool StockpileSettingsSerializer::write_sheet(StockpileSettings::SheetSet* sheet) { bool all = serialize_list_organic_mat( [&](const string& token) { sheet->add_paper(token); }, - &mPile->settings.sheet.paper, organic_mat_category::Paper); + &mSettings->sheet.paper, organic_mat_category::Paper); all = serialize_list_organic_mat( [&](const string& token) { sheet->add_parchment(token); }, - &mPile->settings.sheet.parchment, organic_mat_category::Parchment) && all; + &mSettings->sheet.parchment, organic_mat_category::Parchment) && all; return all; } -void StockpileSerializer::read_sheet(DeserializeMode mode, const vector& filters) { - auto & psheet = mPile->settings.sheet; +void StockpileSettingsSerializer::read_sheet(DeserializeMode mode, const vector& filters) { + auto & psheet = mSettings->sheet; read_category("sheet", mode, std::bind(&StockpileSettings::has_sheet, mBuffer), std::bind(&StockpileSettings::sheet, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_sheet, + mSettings->flags.whole, + mSettings->flags.mask_sheet, [&]() { psheet.paper.clear(); psheet.parchment.clear(); @@ -2086,20 +2108,20 @@ static bool stone_is_allowed(const MaterialInfo& mi) { return is_allowed_soil || is_allowed_stone; } -bool StockpileSerializer::write_stone(StockpileSettings::StoneSet* stone) { +bool StockpileSettingsSerializer::write_stone(StockpileSettings::StoneSet* stone) { return serialize_list_material( stone_is_allowed, [&](const string& token) { stone->add_mats(token); }, - mPile->settings.stone.mats); + mSettings->stone.mats); } -void StockpileSerializer::read_stone(DeserializeMode mode, const vector& filters) { - auto & pstone = mPile->settings.stone; +void StockpileSettingsSerializer::read_stone(DeserializeMode mode, const vector& filters) { + auto & pstone = mSettings->stone; read_category("stone", mode, std::bind(&StockpileSettings::has_stone, mBuffer), std::bind(&StockpileSettings::stone, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_stone, + mSettings->flags.whole, + mSettings->flags.mask_stone, [&]() { pstone.mats.clear(); }, @@ -2116,8 +2138,8 @@ static bool weapons_mat_is_allowed(const MaterialInfo& mi) { return mi.isValid() && mi.material && (mi.material->flags.is_set(material_flags::IS_METAL) || mi.material->flags.is_set(material_flags::IS_STONE)); } -bool StockpileSerializer::write_weapons(StockpileSettings::WeaponsSet* weapons) { - auto & pweapons = mPile->settings.weapons; +bool StockpileSettingsSerializer::write_weapons(StockpileSettings::WeaponsSet* weapons) { + auto & pweapons = mSettings->weapons; bool all = pweapons.unusable && pweapons.usable; weapons->set_unusable(pweapons.unusable); @@ -2156,13 +2178,13 @@ bool StockpileSerializer::write_weapons(StockpileSettings::WeaponsSet* weapons) return all; } -void StockpileSerializer::read_weapons(DeserializeMode mode, const vector& filters) { - auto & pweapons = mPile->settings.weapons; +void StockpileSettingsSerializer::read_weapons(DeserializeMode mode, const vector& filters) { + auto & pweapons = mSettings->weapons; read_category("weapons", mode, std::bind(&StockpileSettings::has_weapons, mBuffer), std::bind(&StockpileSettings::weapons, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_weapons, + mSettings->flags.whole, + mSettings->flags.mask_weapons, [&]() { pweapons.unusable = false; pweapons.usable = false; @@ -2209,10 +2231,10 @@ static bool wood_mat_is_allowed(const df::plant_raw* plant) { return plant && plant->flags.is_set(plant_raw_flags::TREE); } -bool StockpileSerializer::write_wood(StockpileSettings::WoodSet* wood) { +bool StockpileSettingsSerializer::write_wood(StockpileSettings::WoodSet* wood) { bool all = true; - for (size_t i = 0; i < mPile->settings.wood.mats.size(); ++i) { - if (!mPile->settings.wood.mats.at(i)) { + for (size_t i = 0; i < mSettings->wood.mats.size(); ++i) { + if (!mSettings->wood.mats.at(i)) { all = false; continue; } @@ -2225,13 +2247,13 @@ bool StockpileSerializer::write_wood(StockpileSettings::WoodSet* wood) { return all; } -void StockpileSerializer::read_wood(DeserializeMode mode, const vector& filters) { - auto & pwood = mPile->settings.wood; +void StockpileSettingsSerializer::read_wood(DeserializeMode mode, const vector& filters) { + auto & pwood = mSettings->wood; read_category("wood", mode, std::bind(&StockpileSettings::has_wood, mBuffer), std::bind(&StockpileSettings::wood, mBuffer), - mPile->settings.flags.whole, - mPile->settings.flags.mask_wood, + mSettings->flags.whole, + mSettings->flags.mask_wood, [&]() { pwood.mats.clear(); }, diff --git a/plugins/stockpiles/StockpileSerializer.h b/plugins/stockpiles/StockpileSerializer.h index f0e1a62e2..4798fba5e 100644 --- a/plugins/stockpiles/StockpileSerializer.h +++ b/plugins/stockpiles/StockpileSerializer.h @@ -4,6 +4,7 @@ #include "df/itemdef.h" #include "df/organic_mat_category.h" +#include "df/stockpile_settings.h" #include "proto/stockpiles.pb.h" @@ -57,14 +58,14 @@ struct food_pair { /** * Class for serializing the stockpile_settings structure into a Google protobuf */ -class StockpileSerializer { +class StockpileSettingsSerializer { public: /** - * @param stockpile stockpile to read or write settings to + * @param settings settings to read or write to */ - StockpileSerializer(df::building_stockpilest* stockpile); + StockpileSettingsSerializer(df::stockpile_settings *settings); - ~StockpileSerializer(); + ~StockpileSettingsSerializer(); /** * Since we depend on protobuf-lite, not the full lib, we copy this function from @@ -88,20 +89,20 @@ public: */ bool unserialize_from_file(const std::string& file, DeserializeMode mode, const std::vector& filters); -private: - df::building_stockpilest* mPile; +protected: dfstockpiles::StockpileSettings mBuffer; // read memory structures and serialize to protobuf - void write(uint32_t includedElements); + virtual void write(uint32_t includedElements); // parse serialized data into ui indices - void read(DeserializeMode mode, const std::vector& filters); + virtual void read(DeserializeMode mode, const std::vector& filters); - void write_containers(); - void read_containers(DeserializeMode mode); - void write_general(); - void read_general(DeserializeMode mode); + virtual void write_general(); + virtual void read_general(DeserializeMode mode); + +private: + df::stockpile_settings *mSettings; bool write_ammo(dfstockpiles::StockpileSettings::AmmoSet* ammo); void read_ammo(DeserializeMode mode, const std::vector& filters); @@ -139,3 +140,32 @@ private: bool write_wood(dfstockpiles::StockpileSettings::WoodSet* wood); void read_wood(DeserializeMode mode, const std::vector& filters); }; + +/** + * Class for serializing a stockpile into a Google protobuf + */ +class StockpileSerializer : public StockpileSettingsSerializer { +public: + /** + * @param stockpile stockpile to read or write settings to + */ + StockpileSerializer(df::building_stockpilest* stockpile); + + ~StockpileSerializer(); + +protected: + // read memory structures and serialize to protobuf + virtual void write(uint32_t includedElements); + + // parse serialized data into ui indices + virtual void read(DeserializeMode mode, const std::vector& filters); + + virtual void write_general(); + virtual void read_general(DeserializeMode mode); + +private: + df::building_stockpilest* mPile; + + void write_containers(); + void read_containers(DeserializeMode mode); +}; diff --git a/plugins/stockpiles/stockpiles.cpp b/plugins/stockpiles/stockpiles.cpp index d1ce46e9c..de57598c4 100644 --- a/plugins/stockpiles/stockpiles.cpp +++ b/plugins/stockpiles/stockpiles.cpp @@ -8,6 +8,8 @@ #include "df/building.h" #include "df/building_stockpilest.h" +#include "df/hauling_route.h" +#include "df/hauling_stop.h" #include #include @@ -147,8 +149,54 @@ static bool stockpiles_import(color_ostream& out, string fname, int id, string m return true; } +static bool stockpiles_route_import(color_ostream& out, string fname, int route_id, int stop_id, string mode_str, string filter) { + auto route = df::hauling_route::find(route_id); + if (!route) { + out.printerr("Specified hauling route not found: %d.\n", route_id); + return false; + } + + df::hauling_stop *stop = binsearch_in_vector(route->stops, &df::hauling_stop::id, stop_id); + if (!stop) { + out.printerr("Specified hauling stop not found in route %d: %d.\n", route_id, stop_id); + return false; + } + + if (!is_dfstockfile(fname)) + fname += ".dfstock"; + + if (!Filesystem::exists(fname)) { + out.printerr("ERROR: file doesn't exist: '%s'\n", fname.c_str()); + return false; + } + + DeserializeMode mode = DESERIALIZE_MODE_SET; + if (mode_str == "enable") + mode = DESERIALIZE_MODE_ENABLE; + else if (mode_str == "disable") + mode = DESERIALIZE_MODE_DISABLE; + + vector filters; + split_string(&filters, filter, ",", true); + + try { + StockpileSettingsSerializer cereal(&stop->settings); + if (!cereal.unserialize_from_file(fname, mode, filters)) { + out.printerr("deserialization failed: '%s'\n", fname.c_str()); + return false; + } + } + catch (std::exception& e) { + out.printerr("deserialization failed: protobuf exception: %s\n", e.what()); + return false; + } + + return true; +} + DFHACK_PLUGIN_LUA_FUNCTIONS { DFHACK_LUA_FUNCTION(stockpiles_export), DFHACK_LUA_FUNCTION(stockpiles_import), + DFHACK_LUA_FUNCTION(stockpiles_route_import), DFHACK_LUA_END }; From 20ce4a1612feea8998326f07cc02b7d6d8f0fc15 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 28 May 2023 02:28:45 -0700 Subject: [PATCH 0228/1234] add "everything" stockpile settings file useful for setting hauling route settings --- data/stockpiles/everything.dfstock | Bin 0 -> 82 bytes docs/plugins/stockpiles.rst | 3 +++ 2 files changed, 3 insertions(+) create mode 100644 data/stockpiles/everything.dfstock diff --git a/data/stockpiles/everything.dfstock b/data/stockpiles/everything.dfstock new file mode 100644 index 0000000000000000000000000000000000000000..c0fcb60519dbc8f39b9aab50b01767baa370a8a9 GIT binary patch literal 82 zcmd;LQeYHfUctyH#bm*##gxEk#3aDz#ALwe1*C(RG#I0RI0?wl0`iNPJQ%BhbQ2?x b(Z$G=!8n1DaRwvf4n~Gkj7%Jimp}vnsd5XU literal 0 HcmV?d00001 diff --git a/docs/plugins/stockpiles.rst b/docs/plugins/stockpiles.rst index 560ae2497..685bdcac3 100644 --- a/docs/plugins/stockpiles.rst +++ b/docs/plugins/stockpiles.rst @@ -134,6 +134,9 @@ entire category, or with a filter, any matchable subset thereof:: cat_weapons cat_wood +There is also an ``everything`` file that includes all the above categories, +including refuse and corpses. + For many of the categories, there are also flags and subcategory prefixes that you can match with filters and convenient pre-made settings files that manipulate interesting category subsets. From 760cd0cbcb02d7b7b3cd2a0b894219ac66ac95b0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 28 May 2023 05:37:29 -0700 Subject: [PATCH 0229/1234] implement tameable property filtering --- data/stockpiles/all.dfstock | Bin 0 -> 73 bytes docs/plugins/stockpiles.rst | 29 ++++++++++++++++----- plugins/stockpiles/StockpileSerializer.cpp | 11 ++++++-- 3 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 data/stockpiles/all.dfstock diff --git a/data/stockpiles/all.dfstock b/data/stockpiles/all.dfstock new file mode 100644 index 0000000000000000000000000000000000000000..eace9c53dd7de0601ca25e16759cb90993b5f4bd GIT binary patch literal 73 zcmd;LQeYHfUctyH#bm)~#3aDz#ALwe1*C(RG#I0RI0?wl0`iNPJQ%BhbQ2?x(Z$G= U!8n1DaRwvf4n~Gcj7%Ji07w%GJ^%m! literal 0 HcmV?d00001 diff --git a/docs/plugins/stockpiles.rst b/docs/plugins/stockpiles.rst index 685bdcac3..ae77e5cf2 100644 --- a/docs/plugins/stockpiles.rst +++ b/docs/plugins/stockpiles.rst @@ -134,12 +134,14 @@ entire category, or with a filter, any matchable subset thereof:: cat_weapons cat_wood -There is also an ``everything`` file that includes all the above categories, -including refuse and corpses. +In addition, there are files for ``all``, which includes all categories except +refuse and corpses (mirroring the "all" configuration in-game), and +``everything``, which really includes all categories. -For many of the categories, there are also flags and subcategory prefixes that -you can match with filters and convenient pre-made settings files that -manipulate interesting category subsets. +For many of the categories, there are also flags, subcategory prefixes, and +item properties that you can match with filters. In addition, there are +normally at least a few convenient pre-made settings files that manipulate +interesting category subsets. Ammo stockpile adjustments ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -172,6 +174,10 @@ Flags:: cages traps +Properties:: + + tameable + Settings files:: cages @@ -274,6 +280,13 @@ Notes: * ``thread`` and ``cloth`` settings files set all materials that are not adamantine. +Corpse stockpile adjustments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Properties:: + + tameable + Finished goods stockpile adjustments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -295,7 +308,7 @@ Settings files:: Example commands for a toy stockpile:: - stockpiles import cat_furniture -f mats/,other/,core/,total/ + stockpiles import cat_finished_goods -f mats/,other/,core/,total/ stockpiles import -m enable toys Food stockpile adjustments @@ -404,6 +417,10 @@ Flags and subcategory prefixes:: teeth/ horns/ +Properties:: + + tameable + Settings files:: rawhides diff --git a/plugins/stockpiles/StockpileSerializer.cpp b/plugins/stockpiles/StockpileSerializer.cpp index fcb0cee3e..b650ec618 100644 --- a/plugins/stockpiles/StockpileSerializer.cpp +++ b/plugins/stockpiles/StockpileSerializer.cpp @@ -11,6 +11,7 @@ // df #include "df/building_stockpilest.h" #include "df/creature_raw.h" +#include "df/caste_raw.h" #include "df/inorganic_raw.h" #include "df/item_quality.h" #include @@ -611,6 +612,12 @@ static bool serialize_list_creature(FuncWriteExport add_value, const vectorcaste.size() || !r->caste[0]->flags.is_set(df::enums::caste_raw_flags::PET)) + return r->name[0]; + return r->name[0] + "/tameable"; +} + static void unserialize_list_creature(const char* subcat, bool all, char val, const vector& filters, FuncReadImport read_value, int32_t list_size, vector& pile_list) { size_t num_elems = world->raws.creatures.all.size(); @@ -618,7 +625,7 @@ static void unserialize_list_creature(const char* subcat, bool all, char val, co if (all) { for (size_t idx = 0; idx < num_elems; ++idx) { auto r = find_creature(idx); - set_filter_elem(subcat, filters, val, r->name[0], r->creature_id, pile_list.at(idx)); + set_filter_elem(subcat, filters, val, get_filter_string(r), r->creature_id, pile_list.at(idx)); } return; } @@ -631,7 +638,7 @@ static void unserialize_list_creature(const char* subcat, bool all, char val, co continue; } auto r = find_creature(idx); - set_filter_elem(subcat, filters, val, r->name[0], r->creature_id, pile_list.at(idx)); + set_filter_elem(subcat, filters, val, get_filter_string(r), r->creature_id, pile_list.at(idx)); } } From 2edfe151d339f8ab4304798fb6c73fcad0888dab Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 28 May 2023 20:42:36 -0700 Subject: [PATCH 0230/1234] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index b2ee30767..4708711c1 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -63,6 +63,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Window behavior: non-resizable windows now allow dragging by their frame edges by default - `gui/autodump`: fort-mode keybinding: Ctrl-H - 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 ## Documentation From 7dad5be7dc30343b75fe9422d1a7114bfbc85593 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 29 May 2023 07:13:57 +0000 Subject: [PATCH 0231/1234] Auto-update submodules library/xml: master --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 1cc81c0fa..17e77412c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 1cc81c0faf7aa9fd1c18fbc6ef8b2298f31ab1f9 +Subproject commit 17e77412c040dab658a39a34eb0e21cb014c3824 From acca228ac87fa2db27c97912757ced0781dc58d4 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 31 May 2023 07:13:26 +0000 Subject: [PATCH 0232/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index a26e72b6e..6a746d6d5 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit a26e72b6e1da16d6fcaadc71518314fb8aaae193 +Subproject commit 6a746d6d53dcff667c9105579db0f4f1c7f7c9b0 From 974a6155c06071293f7a51bab4d902d9dae76bc3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 31 May 2023 18:48:08 -0700 Subject: [PATCH 0233/1234] reinstated Buildings.setOwner --- docs/dev/Lua API.rst | 4 ++-- library/include/modules/Buildings.h | 4 ++-- library/modules/Buildings.cpp | 29 ++++++++++++++--------------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index e5167a531..d07cb045e 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1944,9 +1944,9 @@ General 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. * ``dfhack.buildings.getSize(building)`` diff --git a/library/include/modules/Buildings.h b/library/include/modules/Buildings.h index 66745abe6..78163108e 100644 --- a/library/include/modules/Buildings.h +++ b/library/include/modules/Buildings.h @@ -108,9 +108,9 @@ DFHACK_EXPORT df::general_ref *getGeneralRef(df::building *building, df::general DFHACK_EXPORT df::specific_ref *getSpecificRef(df::building *building, df::specific_ref_type type); /** - * Sets the owner unit for the building. + * Sets the owner unit for the zone. */ -DFHACK_EXPORT bool setOwner(df::building *building, df::unit *owner); +DFHACK_EXPORT bool setOwner(df::building_civzonest *building, df::unit *owner); /** * Find the building located at the specified tile. diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index dca8010da..3d0d89c49 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -350,46 +350,45 @@ df::specific_ref *Buildings::getSpecificRef(df::building *building, df::specific return findRef(building->specific_refs, type); } -bool Buildings::setOwner(df::building *bld, df::unit *unit) +bool Buildings::setOwner(df::building_civzonest *bld, df::unit *unit) { CHECK_NULL_POINTER(bld); -/* TODO: understand how this changes for v50 - if (!bld->is_room) - return false; - if (bld->owner == unit) + + if (bld->assigned_unit == unit) return true; - if (bld->owner) + df::building * pbld = dynamic_cast(bld); + + if (bld->assigned_unit) { - auto &blist = bld->owner->owned_buildings; - vector_erase_at(blist, linear_index(blist, bld)); + auto &blist = bld->assigned_unit->owned_buildings; + vector_erase_at(blist, linear_index(blist, pbld)); - if (auto spouse = df::unit::find(bld->owner->relationship_ids[df::unit_relationship_type::Spouse])) + if (auto spouse = df::unit::find(bld->assigned_unit->relationship_ids[df::unit_relationship_type::Spouse])) { auto &blist = spouse->owned_buildings; - vector_erase_at(blist, linear_index(blist, bld)); + vector_erase_at(blist, linear_index(blist, pbld)); } } - bld->owner = unit; + bld->assigned_unit = unit; if (unit) { - bld->owner_id = unit->id; + bld->assigned_unit_id = unit->id; unit->owned_buildings.push_back(bld); if (auto spouse = df::unit::find(unit->relationship_ids[df::unit_relationship_type::Spouse])) { auto &blist = spouse->owned_buildings; - if (bld->canUseSpouseRoom() && linear_index(blist, bld) < 0) + if (bld->canUseSpouseRoom() && linear_index(blist, pbld) < 0) blist.push_back(bld); } } else { - bld->owner_id = -1; + bld->assigned_unit_id = -1; } -*/ return true; } From 5c914280c3cbfaf88fc9fb00d92b97033839081b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 1 Jun 2023 10:53:08 -0700 Subject: [PATCH 0234/1234] change dynamic_cast -> virtual_cast --- library/modules/Buildings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 3d0d89c49..78c7b00ed 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -357,7 +357,7 @@ bool Buildings::setOwner(df::building_civzonest *bld, df::unit *unit) if (bld->assigned_unit == unit) return true; - df::building * pbld = dynamic_cast(bld); + df::building * pbld = virtual_cast(bld); if (bld->assigned_unit) { From 6ba830f2cfdc72b382e319344ad6e560477b429b Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 1 Jun 2023 17:54:12 +0000 Subject: [PATCH 0235/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 6a746d6d5..6430e8ed0 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 6a746d6d53dcff667c9105579db0f4f1c7f7c9b0 +Subproject commit 6430e8ed0facbe152e98f5ff1f274febfd6b5772 From ecf82471cfc8886d2424ecb43e1ea81c487c460d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 1 Jun 2023 11:20:08 -0700 Subject: [PATCH 0236/1234] update for 50.08-r2 --- CMakeLists.txt | 4 ++-- docs/changelog.txt | 49 +++++++++++++++++++++++++++++----------------- library/xml | 2 +- scripts | 2 +- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c1560c630..3ea16ce29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,8 +192,8 @@ endif() # set up versioning. set(DF_VERSION "50.08") -set(DFHACK_RELEASE "r2rc1") -set(DFHACK_PRERELEASE TRUE) +set(DFHACK_RELEASE "r2") +set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/docs/changelog.txt b/docs/changelog.txt index 4708711c1..bd1b97e6e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -34,14 +34,32 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # Future ## 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``: reduce the time that dwarves are left without a task after completing a job + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Internals + +## Lua + +## Removed + +# 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 @@ -51,24 +69,19 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## 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 CTD) -- `orders`: update orders in orders library for prepared meals, bins, archer uniforms, and weapons -- Terminal console no longer appears in front of the game window on startup +- 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: For debugging purposes, you can now pass ``--disable-dfhack`` on the Dwarf Fortress commandline or specify ``DFHACK_DISABLE=1`` in the environment to disable DFHack for the current session. -- `overlay`: added links to the quickstart guide and the control panel on the DF title screen +- 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 +- `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 -## Documentation - -## API - ## Internals - ``dfhack.internal``: added memory analysis functions: ``msizeAddress``, ``getHeapState``, ``heapTakeSnapshot``, ``isAddressInHeap``, ``isAddressActiveInHeap``, ``isAddressUsedAfterFreeInHeap``, ``getAddressSizeInHeap``, and ``getRootAddressOfHeapObject`` diff --git a/library/xml b/library/xml index 17e77412c..51fe3ca11 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 17e77412c040dab658a39a34eb0e21cb014c3824 +Subproject commit 51fe3ca11f9587bc50ed09b768022cd9688250d8 diff --git a/scripts b/scripts index 6430e8ed0..315c7afc2 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 6430e8ed0facbe152e98f5ff1f274febfd6b5772 +Subproject commit 315c7afc20651ac0fe1700d720f71796190f198e From 4a2b97105c76998320f0c0f73b5d4c3d2a6839bc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 5 Jun 2023 14:18:55 -0700 Subject: [PATCH 0237/1234] only initialize steam if launched from steam --- docs/changelog.txt | 1 + library/modules/DFSteam.cpp | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index bd1b97e6e..c36597047 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -36,6 +36,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins ## Fixes +- Fix crash for some players when they launch DF outside of the Steam client ## Misc Improvements diff --git a/library/modules/DFSteam.cpp b/library/modules/DFSteam.cpp index 289c22e27..1fd064d56 100644 --- a/library/modules/DFSteam.cpp +++ b/library/modules/DFSteam.cpp @@ -52,6 +52,12 @@ static void bind_all(color_ostream& out, DFLibrary* handle) { } bool DFSteam::init(color_ostream& out) { + char *steam_client_launch = getenv("SteamClientLaunch"); + if (!steam_client_launch || strncmp(steam_client_launch, "1", 2) != 0) { + DEBUG(dfsteam, out).print("not launched from Steam client; not initializing steam\n"); + return false; + } + for (auto& lib_str : STEAM_LIBS) { if ((g_steam_handle = OpenPlugin(lib_str.c_str()))) break; @@ -168,11 +174,6 @@ void DFSteam::launchSteamDFHackIfNecessary(color_ostream& out) { return; } - if (strncmp(getenv("SteamClientLaunch"), "1", 2)) { - DEBUG(dfsteam, out).print("not launched from Steam client\n"); - return; - } - void* iSteamApps = g_SteamInternal_FindOrCreateUserInterface(g_SteamAPI_GetHSteamUser(), "STEAMAPPS_INTERFACE_VERSION008"); if (!iSteamApps) { DEBUG(dfsteam, out).print("cannot obtain iSteamApps interface\n"); From d8c1e64c5c7684f5508ca1e5b505d833c4f65709 Mon Sep 17 00:00:00 2001 From: UnFaventia <135673143+UnFaventia@users.noreply.github.com> Date: Tue, 6 Jun 2023 10:38:24 +1000 Subject: [PATCH 0238/1234] Update autonick.txt --- data/dfhack-config/autonick.txt | 864 ++++++++++++++++++++++++++++++++ 1 file changed, 864 insertions(+) diff --git a/data/dfhack-config/autonick.txt b/data/dfhack-config/autonick.txt index e7de79f54..2c1120888 100644 --- a/data/dfhack-config/autonick.txt +++ b/data/dfhack-config/autonick.txt @@ -24,6 +24,36 @@ Jay Crow Raven Sparrow +Platypus +House Mouse +Pangolin +Funnel Web +Weasel +Meerkats +Rat +Ant +Gopher +Fennec +Groundhog +Aardvark +Rabbit +Olm +Chipmunk +Bilbie +Vole +Nile Croc +Wombat +Worm +Gerbil +Armodillo +Thrinaxodon +Binky +Bandicoot +Bettongs +Potoroos +Antechinus +Jerboas +Numbat # colours Flash @@ -35,11 +65,435 @@ Indigo Jade Umber Silver +Bistre +Black +Black bean +Noir +Charcoal +Ebony +Eerie +Jet +Licorice +Midnight +Night +Onyx +Space +Raisin +Rich +Russ violet +Smoky +Taupe +Aero +Alice +Argent Lue +Azure +Azul +Baby blue +Berkeley +Bice +Bleu +Bondi +Brandeis Byzant +Cambridge +Carolina +Celestial +Celtic +Cerulean +Chefchaouen +Chrysler +Cobalt +Columbia +Cornflower +Sky +Delft +Denim +Dodger +Duke +Federal +Glaucous +Electrindigo +Eclipse +Ice +Illini +Klein +Jordy +Lapis Lazuli +Majorelle +Marian +Maya +Slate +Munsell +Navy +Neon blue +Oxford +Palatinate +Penn +Periwinkle +Phthalo +Picton +Poly +Powder +Prussia +Royal +Ruddy +Sapphire +Honolulu +Savoy +Silver Lake +Space cadet +Steel +Tang +Tufts +Ultramarine +Uranian +Vista +Yale +Zaffre +Auburn +Almond +Beaver +Beige +Bole +Bone +Bronze +Buff +Burgundy +Sienna +Umber +Camel +Caput mortuum +Caramel +Chamoisee +Chestnut +Chocolate +Citron +Cocoa +Coffee +Copper +Cordovan +Coyote +Desert +Drab +Dun +Earth +Ecru +Fallow +Fawn +Field +Fulvous +Goldenrod +Harvest +Khaki +Kobicha +Lion +Liver +Mahogany +Maroon +Ochre +Redwood +Rufous +Russet +Rust +Sand +Satin +Sheen +Seal +Sepia +Sinopia +Tan +Taupe +Tawny +Titian +Van Dyke +Walnut +Wenge +Wheat +Aqua +Aquamarine +Capri +Caribbean +Celeste +Cyprus +Fluorescent +Jungle +Keppel +Ice +Sea +Moonstone +Myrtle +Pacific +Pine +Robin +Skobeloff +Teal +Turquoise +Verdigris +Vivid +Zomp +Platinum +Timberwolf +Ash +Rose quartz +Cinereous +Cadet +Cool +Davys +Paynes +Glaucous +Gunmetal +Feldgrau +Apple +Asparagus +Avocado +Brunswick +Cal Poly +Castleton +Celadon +Chartreuse +Moss +Pastel +Dartmouth +Emerald +Erin +Fern +Forest +Harlequin +Honeydew +Hunter +Jade +Kelly green +Lawn +Lime +Malachite +Mantis +Mindaro +Neon +Olivine +Paris +Pear +Pigment +Pine +Pistachio +Reseda +Rifle +Sage +Screamin' +Shamrock +Bud +Amaranth +Baker-Miller +Cerise +Crimson +Carmine +Magenta +Eggplant +Fandango +Finn +Fuchsia +Haze +Mulberry +Orchid +Plum +Pizzazz +Quinacridone +Raspberry +Razzle dazzle +Rose +Shocking +Telemagenta +Aerospace +Alloy +Amber +Apricot +Atomic +Tangerine +Burnt +Butterscotch +Carrot +Champagne +Chrome +Coral +Flame +Gold +Hunyadi +Melon +Peel +Papaya +Peach +Persimmon +Princeton +Pumpkin +Rust +Safety orange +Saffron +Tangelo +Tigers Eye +Titian +Xanthous +Blush +Brilliant +Brink +Carnation +Cherry +Cordovan +Cyclamen +Dogwood +Folly +Heliotrope +Hollywood +Hot +Lavender +Mimi +Misty +Mountbatten +Orchid +Phlox +Pompadour +Puce +Raspberry +Razzmatazz +Bonbon +Quartz +Taupe +Vale +Rosewood +Rosy +Salmon +Seashell +Tea +Tickle +Thulian +Ultra +Burgundy +Byzantium +Caput mortuum +Eminence +Grape +Iris +Mardi Gras +Mauve +Mauveine +Mulberry +Murrey +Palatinate +Pale +Pomp +Power +Purpureus +Tekhelet +Thistle +Tropical +Tyrian +Wisteria +Barn +Bittersweet +Shimmer +Blood +Candy apple +Cantaloupe +Cardinal +Carmine +Chili +Cosmos +Cinnabar +Claret +Coquelicot +Cordovan +Cornell +Crimson +Falu +Brick +Engine +Folly +Garnet +Imperial +Jasper +Penn +Poppy +Redwood +Rojo +Rust +Rusty +Scarlet +Syracuse +Tomato +Turkey +Vermilion +Wine +Alabaster +Antique +Cornsilk +Latte +Cream +Eggshell +Flax +Floral +Ghost +Isabelline +Ivory +Lemon +chiffon +Linen +Navajo +Nyanza +Lace +Parchment +Pearl +Seasalt +Seashell +Vanilla +Smoke +Amber +Apricot +Arylide +Aureolin +Buff +Canary +Citron +Ecru +Gamboge +Icterine +Jonquil +Maize +Mikado +Mindaro +Mustard +Selective +Stil de grain +Straw +Sunglow +Sunset +Wheat # planets Mars Jupiter Saturn +Pluto +Neptune +Europa + +# charites +Damia +Auxesia +Cleta +Phaenna +Hegemone +Peitho +Paregoros +Pasithea +Charis +Kale +Antheia +Eudaimonia +Euthymia +Eutychia +Paidia +Pandaisia +Pannychis +Aglaea +Euphrosyne +Thalia # nature Blaze @@ -150,3 +604,413 @@ Wilder Wisdom Wyatt Zephyr + +# Gemstones +Actinolite +Nephrite +Adamite +Aegirine +Afghanite +Agrellite +Algodonite +Alunite +Amblygonite +Analcime +Anatase +Andalusite +Chiastolite +Andesine +Anglesite +Anhydrite +Annabergite +Anorthite +Antigorite +Bowenite +Apatite +Apophyllite +Aragonite +Asbestos +Astrophyllite +Augelite +Austinite +Ferro +Magnes +Mangan +Tinzenite +Azurmalachite +Azurite +Baryte +Bast +Bayldonite +Benitoite +Beryl +Aquamarine +Maxixe +Emerald +Goshenite +Golden beryl +Heliodor +Morganite +Red beryl +Beryllonite +Beudantite +Bismutot +Biotit +Bole +Boracite +Bornite +Brazilianite +Brookite +Brucite +Bustam +Bytown +Calcite +Caledonite +Canasite +Cancrin +Vishnev +Carleton +Carnall +Cassiterite +Cataplei +Cavans +Celestite +Ceruleite +Cerussite +Chabaz +Chalcopyr +Chambers +Charlesite +Charoite +Childrenite +Chiolite +Chrysoberyl +Alexandrite +Cymophane +Chromite +Chrysocolla +Cinnabar +Clinochlore +Clinohumite +Clintonite +Cobaltite +Coleman +Cordierite +Iolite +Cornwallite +Corundum +Ruby +Sapphire +Padparadscha +Covell +Creedite +Crocite +Cuprite +Danburite +Datolite +Descloiz +Diamond +Bort +Ballas +Diaspore +Dickinsonite +Diopside +Dioptase +Dolomite +Dumortier +Ekanite +Elbaite +Emerald +Trapiche +Enstatite +Bronzite +Hypersthene +Eosphorite +Epidote +Piemont +Erythrite +Esperite +Ettring +Eudialyte +Faya +Feldspar +Andesine +Albite +Anorth +Anorthoc +Amazon +Celsian +Microcline +Moonstone +Adularia +Rainbow +Ortho +Unakite +Plagioclase +Labradorite +Oligoclase +Sanidine +Sunstone +Oregon Sunstone +Rainbow Lattice +Fergusonite +Ferroaxin +Fluora +Fluorapophyl +Fluorite +Forster +Friedelite +Gadolin +Gahnite +Gahnospinel +Garnet +Pyralspite +Almandine +Pyrope +Spessartine +Ugrand +Demantoid +Melanite +Topazolita +Grossular +Hessonite +Hydrogrossular +Tsavorite +Pyrope +Rhodolite +Mali garnet +Malaia +Spessar +Umbal +Gaspe +Gayluss +Gibbsite +Glaucophane +Goeth +Goosecreek +Grandidier +Gypsum +Gyro +Halite +Hambergite +Hanksite +Hardystonite +Helenite +Hematite +Herder +Hexagonite +Hibonite +Hidden +Hodgkinsonite +Holtite +Howlite +Huebnerite +Humite +Hurlbut +Ilmenite +Inderite +Jade +Jadeite +Jasper +Jeremejevite +Kainite +Kämmerer +Kaolin +Kornerup +Kurnakov +Kyanite +Langbein +Lawsonite +Lazulite +Lazurite +Legrandite +Lepidolite +Leucite +Leucophan +Linarite +Lizardite +Londonite +Ludlamite +Ludwigite +Malachite +Maria-meionite +Werner +Marcasite +Meliphanite +Mellite +Mesolite +Milar +Millerite +Mime +Monazite +Mordenite +Mottram +Muscovite +Fuchsite +Nambul +Natrolite +Nepheline +Neptunite +Nickeline +Niccolite +Nosean +Nuumm +Olivine +Opal +Fire opal +Moss opal +Painite +Papagoite +Pargas +Parisite +Pectol +Larimar +Pentland +Peridot +Periclase +Perthite +Petal +Castor +Pezzottaite +Phena +Phosgen +Phospho +Piemontite +Realgar +Rhodizite +Rhodochros +Rhodon +Richter +Riebeck +Crocidolite +Rosasite +Rutile +Samarskite +Sanidine +Sapphirine +Sarcol +Scapol +Marialite +Meionite +Scheel +Schizol +Scorod +Selenite +Sella +Senarmon +Sepio +Meerschaum +Sérandite +Seraph +Serendibite +Serpentine +Bowen +Stich +Shattuck +Shiga +Shortite +Shung +Siderite +Silliman +Simpsonite +Sinhal +Smalt +Smithsonite +Sodalite +Hackman +Sogdian +Sperry +Spessar +Sphaler +Spinel +Ceylon +Spodumene +Triphane +Spurrite +Stauro +Strontian +Titanate +Sulfur +Bustamite +Sylvite +Taaffeita +Talc +Tantalite +Tektites +Tephroite +Thomsonite +Thaumasite +Topaz +Tourmaline +Achroite +Chrome +Dravite +Elbaite +Indicol +Olenite +Paraiba +Rossman +Rubellite +Tremol +Triphyl +Triplite +Tugtup +Turquoise +Ulex +Ussing +Vanadinite +Variscite +Vesuvianite +Californite +Villiaum +Vivianite +Vlasov +Wardite +Wavell +Welogan +Whewell +Wilkeite +Willemite +Wither +Wollastone +Wulfenite +Wurtzite +Xonot +Yugawara +Zektzer +Zeolites +Analcime +Chabaz +Steller +Stilbite +Zinc +Zinnwald +Zircon +Jacinth +Zoisite +Tanzan +Thulite +Zultan +Zany +Lapis lazuli +Desert glass +Llanite +Maw sit-sit +Obsidian +Tears +Pallas +Peridot +Soapstone +Tact +Unakite +Bauxite +Concretions +Bloodstone +Heliotrope +Eilat stone +Epidos +Glimmer +Goldstone +Hawks eye +Iddings +Lampro From b4a804ca0cc70c8bbb541a58b4a87d1d98bac463 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 5 Jun 2023 17:42:35 -0700 Subject: [PATCH 0239/1234] bump to 50.08-r3 --- CMakeLists.txt | 2 +- docs/changelog.txt | 6 +++++- library/xml | 2 +- scripts | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ea16ce29..1abc91861 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,7 +192,7 @@ endif() # set up versioning. set(DF_VERSION "50.08") -set(DFHACK_RELEASE "r2") +set(DFHACK_RELEASE "r3") set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/docs/changelog.txt b/docs/changelog.txt index c36597047..fbc74bad8 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -36,7 +36,6 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins ## Fixes -- Fix crash for some players when they launch DF outside of the Steam client ## Misc Improvements @@ -50,6 +49,11 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Removed +# 50.08-r3 + +## Fixes +- Fix crash for some players when they launch DF outside of the Steam client + # 50.08-r2 ## New Plugins diff --git a/library/xml b/library/xml index 51fe3ca11..413f1c037 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 51fe3ca11f9587bc50ed09b768022cd9688250d8 +Subproject commit 413f1c0371094a7933db0cd524ff9fad64fb0fe3 diff --git a/scripts b/scripts index 315c7afc2..c356aebcd 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 315c7afc20651ac0fe1700d720f71796190f198e +Subproject commit c356aebcde32199fa7c1d32b65ed5c96d008c1f9 From c5e68f42944df6ba0ddcec97c68fc904c28c42c8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 01:10:44 +0000 Subject: [PATCH 0240/1234] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/python-jsonschema/check-jsonschema: 0.22.0 → 0.23.1](https://github.com/python-jsonschema/check-jsonschema/compare/0.22.0...0.23.1) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c305de56c..efa59812d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: args: ['--fix=lf'] - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.22.0 + rev: 0.23.1 hooks: - id: check-github-workflows - repo: https://github.com/Lucas-C/pre-commit-hooks From 9c19b229b4628ab5e65d8ac718310195d3335fba Mon Sep 17 00:00:00 2001 From: UnFaventia <135673143+UnFaventia@users.noreply.github.com> Date: Tue, 6 Jun 2023 11:17:18 +1000 Subject: [PATCH 0241/1234] Update autonick.txt Fixed white spaces & name doubles --- data/dfhack-config/autonick.txt | 459 +++++++++++++++----------------- 1 file changed, 213 insertions(+), 246 deletions(-) diff --git a/data/dfhack-config/autonick.txt b/data/dfhack-config/autonick.txt index 2c1120888..4e24fd61e 100644 --- a/data/dfhack-config/autonick.txt +++ b/data/dfhack-config/autonick.txt @@ -66,314 +66,298 @@ Jade Umber Silver Bistre -Black +Black Black bean Noir Charcoal -Ebony +Ebony Eerie Jet Licorice Midnight -Night -Onyx -Space -Raisin +Night +Onyx +Space +Raisin Rich Russ violet Smoky -Taupe Aero -Alice -Argent Lue -Azure -Azul -Baby blue -Berkeley +Alice +Argent Lue +Azure +Azul +Baby blue +Berkeley Bice -Bleu -Bondi +Bleu +Bondi Brandeis Byzant -Cambridge -Carolina -Celestial -Celtic +Cambridge +Carolina +Celestial +Celtic Cerulean -Chefchaouen -Chrysler -Cobalt -Columbia -Cornflower -Sky -Delft -Denim -Dodger +Chefchaouen +Chrysler +Cobalt +Columbia +Cornflower +Sky +Delft +Denim +Dodger Duke Federal Glaucous Electrindigo Eclipse -Ice -Illini -Klein -Jordy +Illini +Klein +Jordy Lapis Lazuli Majorelle -Marian -Maya -Slate +Marian +Maya +Slate Munsell -Navy +Navy Neon blue Oxford -Palatinate -Penn +Palatinate +Penn Periwinkle -Phthalo -Picton +Phthalo +Picton Poly Powder Prussia -Royal -Ruddy -Sapphire -Honolulu -Savoy +Royal +Ruddy +Honolulu +Savoy Silver Lake Space cadet -Steel -Tang -Tufts +Steel +Tang +Tufts Ultramarine Uranian -Vista -Yale +Vista +Yale Zaffre Auburn Almond Beaver Beige -Bole -Bone +Bole +Bone Bronze -Buff -Burgundy -Sienna -Umber -Camel -Caput mortuum -Caramel +Burgundy +Sienna +Umber +Camel +Caput mortuum +Caramel Chamoisee -Chestnut -Chocolate -Citron -Cocoa -Coffee -Copper -Cordovan -Coyote -Desert +Chestnut +Chocolate +Citron +Cocoa +Coffee +Copper +Coyote +Desert Drab -Dun -Earth -Ecru -Fallow -Fawn -Field +Dun +Earth +Fallow +Fawn +Field Fulvous Goldenrod Harvest -Khaki -Kobicha -Lion -Liver -Mahogany -Maroon -Ochre +Khaki +Kobicha +Lion +Liver +Mahogany +Maroon +Ochre Redwood -Rufous -Russet -Rust -Sand -Satin -Sheen -Seal -Sepia +Rufous +Russet +Rust +Sand +Satin +Sheen +Seal +Sepia Sinopia -Tan -Taupe -Tawny -Titian +Tan +Taupe +Tawny +Titian Van Dyke -Walnut -Wenge -Wheat -Aqua -Aquamarine -Capri +Walnut +Wenge +Aqua +Aquamarine +Capri Caribbean -Celeste +Celeste Cyprus -Fluorescent -Jungle +Fluorescent +Jungle Keppel -Ice +Ice Sea -Moonstone -Myrtle +Myrtle Pacific -Pine -Robin +Pine +Robin Skobeloff -Teal -Turquoise -Verdigris -Vivid +Teal +Turquoise +Verdigris +Vivid Zomp Platinum Timberwolf -Ash -Rose quartz +Ash +Rose quartz Cinereous -Cadet +Cadet Cool Davys Paynes -Glaucous -Gunmetal +Glaucous +Gunmetal Feldgrau -Apple -Asparagus -Avocado -Brunswick -Cal Poly -Castleton +Apple +Asparagus +Avocado +Brunswick +Cal Poly +Castleton Celadon -Chartreuse -Moss -Pastel -Dartmouth +Chartreuse +Moss +Pastel +Dartmouth Emerald -Erin +Erin Fern Forest -Harlequin +Harlequin Honeydew Hunter -Jade -Kelly green -Lawn -Lime +Kelly green +Lawn +Lime Malachite Mantis Mindaro -Neon +Neon Olivine -Paris +Paris Pear -Pigment -Pine +Pigment Pistachio Reseda -Rifle +Rifle Sage Screamin' Shamrock Bud Amaranth -Baker-Miller +Baker-Miller Cerise -Crimson Carmine Magenta Eggplant -Fandango -Finn +Fandango +Finn Fuchsia -Haze -Mulberry -Orchid -Plum +Haze +Orchid +Plum Pizzazz Quinacridone -Raspberry -Razzle dazzle +Razzle dazzle Rose -Shocking +Shocking Telemagenta Aerospace -Alloy -Amber +Alloy +Amber Apricot -Atomic +Atomic Tangerine -Burnt +Burnt Butterscotch -Carrot +Carrot Champagne -Chrome -Coral -Flame -Gold -Hunyadi +Chrome +Coral +Flame +Gold +Hunyadi Melon Peel Papaya -Peach -Persimmon +Peach +Persimmon Princeton Pumpkin Rust Safety orange Saffron Tangelo -Tigers Eye +Tigers Eye Titian Xanthous -Blush +Blush Brilliant -Brink -Carnation -Cherry +Brink +Carnation +Cherry Cordovan Cyclamen Dogwood -Folly -Heliotrope -Hollywood -Hot +Heliotrope +Hollywood +Hot Lavender Mimi Misty -Mountbatten -Orchid -Phlox +Mountbatten +Orchid +Phlox Pompadour -Puce +Puce Raspberry Razzmatazz Bonbon Quartz -Taupe -Vale +Taupe +Vale Rosewood Rosy Salmon -Seashell -Tea +Tea Tickle Thulian Ultra Burgundy Byzantium -Caput mortuum Eminence -Grape +Grape Iris Mardi Gras -Mauve -Mauveine -Mulberry +Mauve +Mauveine +Mulberry Murrey Palatinate Pale @@ -383,16 +367,15 @@ Purpureus Tekhelet Thistle Tropical -Tyrian +Tyrian Wisteria Barn -Bittersweet +Bittersweet Shimmer Blood -Candy apple +Candy apple Cantaloupe Cardinal -Carmine Chili Cosmos Cinnabar @@ -402,65 +385,61 @@ Cordovan Cornell Crimson Falu -Brick +Brick Engine -Folly -Garnet +Folly Imperial -Jasper +Jaspar Penn Poppy -Redwood -Rojo -Rust -Rusty +Rojo +Rusty Scarlet -Syracuse +Syracuse Tomato -Turkey -Vermilion +Turkey +Vermilion Wine Alabaster -Antique +Antique Cornsilk -Latte +Latte Cream Eggshell -Flax +Flax Floral Ghost Isabelline Ivory -Lemon +Lemon chiffon -Linen -Navajo +Linen +Navajo Nyanza Lace Parchment -Pearl +Pearl Seasalt Seashell Vanilla Smoke -Amber -Apricot -Arylide +Apricot +Arylide Aureolin -Buff +Buff Canary Citron -Ecru +Ecru Gamboge Icterine Jonquil -Maize -Mikado -Mindaro +Maize +Mikado +Mindaro Mustard Selective -Stil de grain -Straw +Stil de grain +Straw Sunglow Sunset Wheat @@ -475,22 +454,22 @@ Europa # charites Damia -Auxesia -Cleta -Phaenna -Hegemone -Peitho -Paregoros -Pasithea -Charis -Kale -Antheia -Eudaimonia -Euthymia -Eutychia -Paidia -Pandaisia -Pannychis +Auxesia +Cleta +Phaenna +Hegemone +Peitho +Paregoros +Pasithea +Charis +Kale +Antheia +Eudaimonia +Euthymia +Eutychia +Paidia +Pandaisia +Pannychis Aglaea Euphrosyne Thalia @@ -619,7 +598,6 @@ Analcime Anatase Andalusite Chiastolite -Andesine Anglesite Anhydrite Annabergite @@ -677,7 +655,6 @@ Cavans Celestite Ceruleite Cerussite -Chabaz Chalcopyr Chambers Charlesite @@ -689,7 +666,6 @@ Alexandrite Cymophane Chromite Chrysocolla -Cinnabar Clinochlore Clinohumite Clintonite @@ -719,8 +695,6 @@ Dioptase Dolomite Dumortier Ekanite -Elbaite -Emerald Trapiche Enstatite Bronzite @@ -745,11 +719,10 @@ Moonstone Adularia Rainbow Ortho -Unakite +Kite Plagioclase Labradorite Oligoclase -Sanidine Sunstone Oregon Sunstone Rainbow Lattice @@ -766,7 +739,6 @@ Gahnospinel Garnet Pyralspite Almandine -Pyrope Spessartine Ugrand Demantoid @@ -780,7 +752,6 @@ Pyrope Rhodolite Mali garnet Malaia -Spessar Umbal Gaspe Gayluss @@ -832,7 +803,6 @@ Lizardite Londonite Ludlamite Ludwigite -Malachite Maria-meionite Werner Marcasite @@ -851,11 +821,10 @@ Nambul Natrolite Nepheline Neptunite -Nickeline +Nickeline Niccolite Nosean Nuumm -Olivine Opal Fire opal Moss opal @@ -866,10 +835,9 @@ Parisite Pectol Larimar Pentland -Peridot Periclase Perthite -Petal +Petal Castor Pezzottaite Phena @@ -898,7 +866,7 @@ Scorod Selenite Sella Senarmon -Sepio +Sepio Meerschaum Sérandite Seraph @@ -979,7 +947,6 @@ Xonot Yugawara Zektzer Zeolites -Analcime Chabaz Steller Stilbite From 0f224e60da2123ce45c37d4980f2e17f485a782b Mon Sep 17 00:00:00 2001 From: UnFaventia <135673143+UnFaventia@users.noreply.github.com> Date: Tue, 6 Jun 2023 11:21:44 +1000 Subject: [PATCH 0242/1234] Update changelog.txt --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index c36597047..ebefbdd4e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -82,6 +82,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `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 +- Autonick: additional nicknames based on borrowwing animals, colours, gems and minerals added ## Internals - ``dfhack.internal``: added memory analysis functions: ``msizeAddress``, ``getHeapState``, ``heapTakeSnapshot``, ``isAddressInHeap``, ``isAddressActiveInHeap``, ``isAddressUsedAfterFreeInHeap``, ``getAddressSizeInHeap``, and ``getRootAddressOfHeapObject`` From d9dab857c6756197e67523a5e746f2fc7b4092ee Mon Sep 17 00:00:00 2001 From: UnFaventia <135673143+UnFaventia@users.noreply.github.com> Date: Tue, 6 Jun 2023 12:09:53 +1000 Subject: [PATCH 0243/1234] Update autonick.txt --- data/dfhack-config/autonick.txt | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/data/dfhack-config/autonick.txt b/data/dfhack-config/autonick.txt index 4e24fd61e..12fbe65e6 100644 --- a/data/dfhack-config/autonick.txt +++ b/data/dfhack-config/autonick.txt @@ -63,7 +63,6 @@ Blue Shadow Indigo Jade -Umber Silver Bistre Black @@ -103,13 +102,11 @@ Chrysler Cobalt Columbia Cornflower -Sky Delft Denim Dodger Duke Federal -Glaucous Electrindigo Eclipse Illini @@ -153,7 +150,6 @@ Beige Bole Bone Bronze -Burgundy Sienna Umber Camel @@ -195,9 +191,7 @@ Seal Sepia Sinopia Tan -Taupe Tawny -Titian Van Dyke Walnut Wenge @@ -214,17 +208,14 @@ Ice Sea Myrtle Pacific -Pine Robin Skobeloff Teal -Turquoise Verdigris Vivid Zomp Platinum Timberwolf -Ash Rose quartz Cinereous Cadet @@ -234,7 +225,6 @@ Paynes Glaucous Gunmetal Feldgrau -Apple Asparagus Avocado Brunswick @@ -246,7 +236,6 @@ Moss Pastel Dartmouth Emerald -Erin Fern Forest Harlequin @@ -254,10 +243,8 @@ Honeydew Hunter Kelly green Lawn -Lime Malachite Mantis -Mindaro Neon Olivine Paris @@ -280,7 +267,6 @@ Fandango Finn Fuchsia Haze -Orchid Plum Pizzazz Quinacridone @@ -291,14 +277,12 @@ Telemagenta Aerospace Alloy Amber -Apricot Atomic Tangerine Burnt Butterscotch Carrot Champagne -Chrome Coral Flame Gold @@ -310,7 +294,6 @@ Peach Persimmon Princeton Pumpkin -Rust Safety orange Saffron Tangelo @@ -322,10 +305,8 @@ Brilliant Brink Carnation Cherry -Cordovan Cyclamen Dogwood -Heliotrope Hollywood Hot Lavender @@ -359,7 +340,6 @@ Mauve Mauveine Mulberry Murrey -Palatinate Pale Pomp Power @@ -390,7 +370,6 @@ Engine Folly Imperial Jaspar -Penn Poppy Rojo Rusty @@ -428,7 +407,6 @@ Arylide Aureolin Buff Canary -Citron Ecru Gamboge Icterine @@ -622,9 +600,7 @@ Bast Bayldonite Benitoite Beryl -Aquamarine Maxixe -Emerald Goshenite Golden beryl Heliodor @@ -634,7 +610,6 @@ Beryllonite Beudantite Bismutot Biotit -Bole Boracite Bornite Brazilianite @@ -780,7 +755,6 @@ Humite Hurlbut Ilmenite Inderite -Jade Jadeite Jasper Jeremejevite From 2de77d3f57615d50c205ee99b72bf602626f8088 Mon Sep 17 00:00:00 2001 From: UnFaventia <135673143+UnFaventia@users.noreply.github.com> Date: Tue, 6 Jun 2023 12:11:10 +1000 Subject: [PATCH 0244/1234] Update changelog.txt --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index ebefbdd4e..c724c9235 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -39,6 +39,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Fix crash for some players when they launch DF outside of the Steam client ## Misc Improvements +- `Autonick`: additional nicknames based on burrowing animals, colours, gems and minerals added ## Documentation @@ -82,7 +83,6 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `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 -- Autonick: additional nicknames based on borrowwing animals, colours, gems and minerals added ## Internals - ``dfhack.internal``: added memory analysis functions: ``msizeAddress``, ``getHeapState``, ``heapTakeSnapshot``, ``isAddressInHeap``, ``isAddressActiveInHeap``, ``isAddressUsedAfterFreeInHeap``, ``getAddressSizeInHeap``, and ``getRootAddressOfHeapObject`` From e50fe7eb995832ff44097e615c2432dd304b04af Mon Sep 17 00:00:00 2001 From: UnFaventia <135673143+UnFaventia@users.noreply.github.com> Date: Tue, 6 Jun 2023 12:17:53 +1000 Subject: [PATCH 0245/1234] Update changelog.txt --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 580bdc2bd..8ee4abf2c 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -38,7 +38,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes ## Misc Improvements -- `Autonick`: additional nicknames based on burrowing animals, colours, gems and minerals added +- `autonick`: additional nicknames based on burrowing animals, colours, gems and minerals added ## Documentation From efc4f277d93b323334a3015b758b16a058612be6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 6 Jun 2023 08:06:56 -0700 Subject: [PATCH 0246/1234] clear item occupancy flags for channeled tiles --- docs/changelog.txt | 1 + plugins/dig-now.cpp | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 8ee4abf2c..b010f55b5 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -36,6 +36,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins ## Fixes +- `dig-now`: clear item occupancy flags for channeled tiles that had items on them ## Misc Improvements - `autonick`: additional nicknames based on burrowing animals, colours, gems and minerals added diff --git a/plugins/dig-now.cpp b/plugins/dig-now.cpp index b2af2dbca..94d8c761f 100644 --- a/plugins/dig-now.cpp +++ b/plugins/dig-now.cpp @@ -968,10 +968,20 @@ static void post_process_dug_tiles(color_ostream &out, } if (to.bits.item) { - for (auto item : world->items.other.IN_PLAY) { - if (item->pos == pos && item->flags.bits.on_ground) - item->moveToGround( - resting_pos.x, resting_pos.y, resting_pos.z); + std::vector items; + if (auto b = Maps::ensureTileBlock(pos)) { + for (auto item_id : b->items) { + auto item = df::item::find(item_id); + if (item && item->pos == pos) + items.emplace_back(item); + } + } + if (!items.empty()) { + // fresh MapCache since tile properties are being actively changed + MapExtras::MapCache mc; + for (auto item : items) + Items::moveToGround(mc, item, resting_pos); + mc.WriteAll(); } } } From abc1a6a56965794acff928c223d3ad7ef84fafab Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 23 May 2023 17:03:36 -0700 Subject: [PATCH 0247/1234] clean up some cmake --- CMakeLists.txt | 127 +++++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 79 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1abc91861..56cfa0b95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,21 +1,19 @@ # main project file. use it from a build sub-folder, see COMPILE for details ## 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 CMP0074 NEW) project(dfhack) -if("${CMAKE_GENERATOR}" STREQUAL Ninja) - if("${CMAKE_VERSION}" VERSION_LESS 3.9) - message(WARNING "You are using an old version of CMake (${CMAKE_VERSION}) with Ninja. This may result in ninja errors - see docs/Compile.rst for more details. Upgrading your CMake version is recommended.") - endif() -endif() +# set up versioning. +set(DF_VERSION "50.08") +set(DFHACK_RELEASE "r2rc1") +set(DFHACK_PRERELEASE TRUE) -if(NOT("${CMAKE_VERSION}" VERSION_LESS 3.12)) - # make ZLIB_ROOT work in CMake >= 3.12 - # https://cmake.org/cmake/help/git-stage/policy/CMP0074.html - cmake_policy(SET CMP0074 NEW) -endif() +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)") # Set up build types if(CMAKE_CONFIGURATION_TYPES) @@ -123,7 +121,7 @@ elseif("${DFHACK_BUILD_ARCH}" STREQUAL "64") set(DFHACK_SETARCH "x86_64") add_definitions(-DDFHACK64) else() - message(SEND_ERROR "Invalid build architecture (should be 32/64): ${DFHACK_BUILD_ARCH}") + message(SEND_ERROR "Invalid build architecture (should be 32 or 64): ${DFHACK_BUILD_ARCH}") endif() if(CMAKE_CROSSCOMPILING) @@ -182,30 +180,24 @@ endif() if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl OR NOT EXISTS ${dfhack_SOURCE_DIR}/scripts/CMakeLists.txt OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/clsocket/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/jsoncpp-sub/CMakeLists.txt OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/libexpat/expat/CMakeLists.txt OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/libzip/CMakeLists.txt OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/xlsxio/CMakeLists.txt + OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/googletest/CMakeLists.txt OR NOT EXISTS ${dfhack_SOURCE_DIR}/depends/luacov/src ) - message(SEND_ERROR "One or more required submodules could not be found! Run 'git submodule update --init' from the root DFHack directory. (See the section 'Getting the Code' in docs/Compile.rst)") + message(SEND_ERROR "One or more required submodules could not be found! Run 'git submodule update --init' from the root DFHack directory. (See the section 'Getting the Code' in docs/dev/compile/Compile.rst)") endif() -# set up versioning. -set(DF_VERSION "50.08") -set(DFHACK_RELEASE "r3") -set(DFHACK_PRERELEASE FALSE) - -set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") - -set(DFHACK_ABI_VERSION 1) - -set(DFHACK_BUILD_ID "" CACHE STRING "Build ID (should be specified on command line)") +# dfhack data goes here: +set(DFHACK_DATA_DESTINATION hack) ## where to install things (after the build is done, classic 'make install' or package structure) # the dfhack libraries will be installed here: if(UNIX) # put the lib into DF/hack - set(DFHACK_LIBRARY_DESTINATION hack) + set(DFHACK_LIBRARY_DESTINATION ${DFHACK_DATA_DESTINATION}) else() # windows is crap, therefore we can't do nice things with it. leave the libs on a nasty pile... set(DFHACK_LIBRARY_DESTINATION .) @@ -213,31 +205,26 @@ endif() # external tools will be installed here: set(DFHACK_BINARY_DESTINATION .) -# dfhack data goes here: -set(DFHACK_DATA_DESTINATION hack) # plugin libs go here: -set(DFHACK_PLUGIN_DESTINATION hack/plugins) -# dfhack header files go here: -set(DFHACK_INCLUDES_DESTINATION hack/include) +set(DFHACK_PLUGIN_DESTINATION ${DFHACK_DATA_DESTINATION}/plugins) # dfhack lua files go here: -set(DFHACK_LUA_DESTINATION hack/lua) +set(DFHACK_LUA_DESTINATION ${DFHACK_DATA_DESTINATION}/lua) # the windows .lib file goes here: -set(DFHACK_DEVLIB_DESTINATION hack) +set(DFHACK_DEVLIB_DESTINATION ${DFHACK_DATA_DESTINATION}) # 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) +set(DFHACK_DEVDOC_DESTINATION ${DFHACK_DATA_DESTINATION}) # some options for the user/developer to play with -option(BUILD_LIBRARY "Build the library that goes into DF." ON) -option(BUILD_PLUGINS "Build the plugins." ON) +option(BUILD_LIBRARY "Build the DFHack library." ON) +option(BUILD_PLUGINS "Build the DFHack plugins." ON) set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) if(UNIX) ## flags for GCC # default to hidden symbols - # build 32bit # ensure compatibility with older CPUs # enable C++11 features add_definitions(-DLINUX_BUILD) @@ -254,7 +241,7 @@ if(UNIX) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -march=i686") endif() string(REPLACE "-DNDEBUG" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") - set(CMAKE_INSTALL_RPATH "hack") + set(CMAKE_INSTALL_RPATH ${DFHACK_LIBRARY_DESTINATION}) elseif(MSVC) # for msvc, tell it to always use 8-byte pointers to member functions to avoid confusion set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /vmg /vmm /MP") @@ -276,30 +263,37 @@ elseif(WIN32) add_definitions(-DWIN32) endif() -#### download depends #### +#### dependencies #### + +# fix for pyenv: default to `python3` before `python3.x` +set(Python_FIND_UNVERSIONED_NAMES FIRST) include(CMake/DownloadFile.cmake) if(WIN32) - # Download zlib on Windows - set(ZLIB_DOWNLOAD_DIR ${dfhack_SOURCE_DIR}/depends/zlib/lib/win${DFHACK_BUILD_ARCH}) - if(${DFHACK_BUILD_ARCH} STREQUAL "64") - download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-zlib.lib" - ${ZLIB_DOWNLOAD_DIR}/zlib.lib - "a3b2fc6b68efafa89b0882e354fc8418") - else() - download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win32-zlib.lib" - ${ZLIB_DOWNLOAD_DIR}/zlib.lib - "f4ebaa21d9de28566e88b1edfcdff901") + set(ZLIB_FILE win64-zlib.lib) + set(ZLIB_PATH ${CMAKE_BINARY_DIR}/depends/zlib/) + set(ZLIB_MD5 a3b2fc6b68efafa89b0882e354fc8418) + file(COPY ${dfhack_SOURCE_DIR}/depends/zlib/ DESTINATION ${ZLIB_PATH}) + download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/${ZLIB_FILE}" + ${ZLIB_PATH}${ZLIB_FILE} + ${ZLIB_MD5}) + set(ZLIB_ROOT ${ZLIB_PATH}) +else() + # Rescan for pthread and zlib if the build arch changed + if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_BUILD_ARCH_PREV}") + unset(ZLIB_LIBRARY CACHE) + unset(CMAKE_HAVE_PTHREAD_H CACHE) endif() - # Move zlib to the build folder so possible 32 and 64-bit builds - # in the same source tree don't conflict - 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/) + if(NOT APPLE AND DFHACK_BUILD_32) + set(ZLIB_ROOT /usr/lib/i386-linux-gnu) + endif() +endif() +find_package(ZLIB REQUIRED) +include_directories(${ZLIB_INCLUDE_DIRS}) +if(WIN32) # Do the same for SDL.dll # (DFHack doesn't require this at build time, so no need to move it to the build folder) # TODO: remove SDL.dll from our distribution once DF moves to SDL2. we only @@ -315,7 +309,6 @@ if(WIN32) ${SDL_DOWNLOAD_DIR}/SDL.dll "5a09604daca6b2b5ce049d79af935d6a") endif() - endif() if(APPLE) @@ -376,29 +369,6 @@ endif() #### expose depends #### -# fix for pyenv: default to `python3` before `python3.x` -set(Python_FIND_UNVERSIONED_NAMES FIRST) - -if(UNIX) - # Rescan for pthread and zlib if the build arch changed - if(NOT "${DFHACK_BUILD_ARCH}" STREQUAL "${DFHACK_BUILD_ARCH_PREV}") - unset(ZLIB_LIBRARY CACHE) - unset(CMAKE_HAVE_PTHREAD_H CACHE) - endif() -endif() - -# find and make available libz -if(NOT UNIX) # Windows - # zlib is in here so 32-bit and 64-bit builds in the same source tree are possible - set(ZLIB_ROOT ${CMAKE_BINARY_DIR}/depends/zlib/) -else() - if(NOT APPLE AND DFHACK_BUILD_32) - # 32-bit Linux - set(ZLIB_ROOT /usr/lib/i386-linux-gnu) - endif() -endif() - -find_package(ZLIB REQUIRED) include_directories(depends/protobuf) include_directories(depends/lua/include) include_directories(depends/md5) @@ -420,7 +390,6 @@ endif() include_directories(depends/lodepng) include_directories(depends/tthread) -include_directories(${ZLIB_INCLUDE_DIRS}) include_directories(depends/clsocket/src) include_directories(depends/xlsxio/include) add_subdirectory(depends) From aa3ca94de45328fb52fd00d2cc4d698e540c37cc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 23 May 2023 17:15:47 -0700 Subject: [PATCH 0248/1234] fix paths --- CMakeLists.txt | 6 +++--- depends/zlib/lib/win32/.gitignore | 1 - depends/zlib/lib/win64/.gitignore | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) delete mode 100644 depends/zlib/lib/win32/.gitignore delete mode 100644 depends/zlib/lib/win64/.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt index 56cfa0b95..50ac8f183 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -271,12 +271,12 @@ set(Python_FIND_UNVERSIONED_NAMES FIRST) include(CMake/DownloadFile.cmake) if(WIN32) - set(ZLIB_FILE win64-zlib.lib) + set(ZLIB_FILE zlib.lib) set(ZLIB_PATH ${CMAKE_BINARY_DIR}/depends/zlib/) set(ZLIB_MD5 a3b2fc6b68efafa89b0882e354fc8418) file(COPY ${dfhack_SOURCE_DIR}/depends/zlib/ DESTINATION ${ZLIB_PATH}) - download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/${ZLIB_FILE}" - ${ZLIB_PATH}${ZLIB_FILE} + download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-${ZLIB_FILE}" + ${ZLIB_PATH}lib/${ZLIB_FILE} ${ZLIB_MD5}) set(ZLIB_ROOT ${ZLIB_PATH}) else() diff --git a/depends/zlib/lib/win32/.gitignore b/depends/zlib/lib/win32/.gitignore deleted file mode 100644 index 683bf139f..000000000 --- a/depends/zlib/lib/win32/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.lib diff --git a/depends/zlib/lib/win64/.gitignore b/depends/zlib/lib/win64/.gitignore deleted file mode 100644 index 683bf139f..000000000 --- a/depends/zlib/lib/win64/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.lib From 9aecedb9e2ac5c90faab8a3623f3b25f224dce21 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 24 May 2023 03:04:33 -0700 Subject: [PATCH 0249/1234] move zlib download back to src dir --- CMakeLists.txt | 5 ++--- depends/zlib/lib/win64/.gitignore | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 depends/zlib/lib/win64/.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt index 50ac8f183..dfc8efb4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,11 +272,10 @@ include(CMake/DownloadFile.cmake) if(WIN32) set(ZLIB_FILE zlib.lib) - set(ZLIB_PATH ${CMAKE_BINARY_DIR}/depends/zlib/) + set(ZLIB_PATH ${dfhack_SOURCE_DIR}/depends/zlib/) set(ZLIB_MD5 a3b2fc6b68efafa89b0882e354fc8418) - file(COPY ${dfhack_SOURCE_DIR}/depends/zlib/ DESTINATION ${ZLIB_PATH}) download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-${ZLIB_FILE}" - ${ZLIB_PATH}lib/${ZLIB_FILE} + ${ZLIB_PATH}lib/win64/${ZLIB_FILE} ${ZLIB_MD5}) set(ZLIB_ROOT ${ZLIB_PATH}) else() diff --git a/depends/zlib/lib/win64/.gitignore b/depends/zlib/lib/win64/.gitignore new file mode 100644 index 000000000..683bf139f --- /dev/null +++ b/depends/zlib/lib/win64/.gitignore @@ -0,0 +1 @@ +*.lib From 394db656e6877d8c389b1f77acc8512b8236a2ed Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 24 May 2023 03:04:43 -0700 Subject: [PATCH 0250/1234] remove obsolete BUILD_DEVEL option and logic --- library/CMakeLists.txt | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 371d3cd14..8681c9c90 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -5,7 +5,6 @@ cmake_minimum_required(VERSION 3.21) cmake_policy(SET CMP0022 NEW) # build options -option(BUILD_DEVEL "Install/package files required for development(For SDK)." OFF) if(UNIX) option(CONSOLE_NO_CATCH "Make the console not catch 'CTRL+C' events for easier debugging." OFF) endif() @@ -459,17 +458,4 @@ install(DIRECTORY ${dfhack_SOURCE_DIR}/patches DESTINATION ${DFHACK_DATA_DESTINATION} FILES_MATCHING PATTERN "*.dif") -# Unused for so long that it's not even relevant now... -if(BUILD_DEVEL) - if(WIN32) - install(TARGETS dfhack - ARCHIVE DESTINATION ${DFHACK_DEVLIB_DESTINATION}) - endif() - # note the ending '/'. This means *contents* of the directory are installed - # without the '/', the directory itself is installed - install(DIRECTORY include/ - DESTINATION ${DFHACK_INCLUDES_DESTINATION} - FILES_MATCHING PATTERN "*.h" PATTERN "*.inc" ) -endif() - add_subdirectory(xml) From 73f8186ab7561e20f837c999fad67b5ea0423cd6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 24 May 2023 12:15:52 -0700 Subject: [PATCH 0251/1234] use standard ROOT path structure --- CMakeLists.txt | 2 +- depends/zlib/lib/{win64 => }/.gitignore | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename depends/zlib/lib/{win64 => }/.gitignore (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index dfc8efb4e..0b4c6027f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,7 +275,7 @@ if(WIN32) set(ZLIB_PATH ${dfhack_SOURCE_DIR}/depends/zlib/) set(ZLIB_MD5 a3b2fc6b68efafa89b0882e354fc8418) download_file("https://github.com/DFHack/dfhack-bin/releases/download/0.44.09/win64-${ZLIB_FILE}" - ${ZLIB_PATH}lib/win64/${ZLIB_FILE} + ${ZLIB_PATH}lib/${ZLIB_FILE} ${ZLIB_MD5}) set(ZLIB_ROOT ${ZLIB_PATH}) else() diff --git a/depends/zlib/lib/win64/.gitignore b/depends/zlib/lib/.gitignore similarity index 100% rename from depends/zlib/lib/win64/.gitignore rename to depends/zlib/lib/.gitignore From 130b42d041270ed4917c81ca3832f342bef54e6d Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 7 Jun 2023 07:13:20 +0000 Subject: [PATCH 0252/1234] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index c356aebcd..0119ab1b6 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit c356aebcde32199fa7c1d32b65ed5c96d008c1f9 +Subproject commit 0119ab1b6d540e192c77f114c5ea7f7aeab9b39a From 05db72c7b39d0fa45265e705bebaf8f6fc4d968d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 2 Jun 2023 13:15:21 -0700 Subject: [PATCH 0253/1234] add organic stockpile preset --- data/stockpiles/organic.dfstock | Bin 0 -> 9 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/stockpiles/organic.dfstock diff --git a/data/stockpiles/organic.dfstock b/data/stockpiles/organic.dfstock new file mode 100644 index 0000000000000000000000000000000000000000..70f0496ca3b21fb297da244a8ac729b839d0fe58 GIT binary patch literal 9 QcmbQh$T)+MVFx1v01D>; Date: Mon, 5 Jun 2023 04:17:13 -0700 Subject: [PATCH 0254/1234] add barrels stockpile preset --- data/stockpiles/barrels.dfstock | 2 ++ docs/plugins/stockpiles.rst | 1 + 2 files changed, 3 insertions(+) create mode 100644 data/stockpiles/barrels.dfstock diff --git a/data/stockpiles/barrels.dfstock b/data/stockpiles/barrels.dfstock new file mode 100644 index 000000000..70a723903 --- /dev/null +++ b/data/stockpiles/barrels.dfstock @@ -0,0 +1,2 @@ + +BARREL \ No newline at end of file diff --git a/docs/plugins/stockpiles.rst b/docs/plugins/stockpiles.rst index ae77e5cf2..922c3a418 100644 --- a/docs/plugins/stockpiles.rst +++ b/docs/plugins/stockpiles.rst @@ -369,6 +369,7 @@ Subcategory prefixes:: Settings files:: pots + barrels bags buckets sand From 8c1e761f867f6259152cd1dbdfd3417e3544358d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 7 Jun 2023 01:28:15 -0700 Subject: [PATCH 0255/1234] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index b010f55b5..cdfe29650 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -40,6 +40,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - `autonick`: additional nicknames based on burrowing animals, colours, gems and minerals added +- `stockpiles`: added ``barrels`` and ``organic`` stockpile presets ## Documentation From 321941385e94171142c24e1550bc797bafc8041e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 7 Jun 2023 11:57:16 -0700 Subject: [PATCH 0256/1234] add artifacts and masterworks presets --- data/stockpiles/artifacts.dfstock | Bin 0 -> 107 bytes data/stockpiles/masterworks.dfstock | Bin 0 -> 112 bytes docs/changelog.txt | 2 +- docs/plugins/stockpiles.rst | 15 +++++++++++++++ 4 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 data/stockpiles/artifacts.dfstock create mode 100644 data/stockpiles/masterworks.dfstock diff --git a/data/stockpiles/artifacts.dfstock b/data/stockpiles/artifacts.dfstock new file mode 100644 index 0000000000000000000000000000000000000000..1c7315dfe83ce1f673768a743418c10baa1124fa GIT binary patch literal 107 zcmd;L;b0J85MrLe$RNd~#Nk*}l9`s6T%yGiz!1S;#NdP^=EV@i5XF#$B$CBY#8Ac1 e#K@-w*J#1uz|h6W=LHvtU`Sv%#mI1pkpTehwHf6A literal 0 HcmV?d00001 diff --git a/data/stockpiles/masterworks.dfstock b/data/stockpiles/masterworks.dfstock new file mode 100644 index 0000000000000000000000000000000000000000..fa94c86a936d8852d061758b28f67c069c8d48c5 GIT binary patch literal 112 zcmd;L;b0J85MrLe$RNe7#Oa$@T#{OpR+^*562K6_V8q~rEa=4$#1O@hge;WBP{dHh f(8S2Eh0trk;K0zu$nS*^iC{=zIK{|tiID*Sw*(xB literal 0 HcmV?d00001 diff --git a/docs/changelog.txt b/docs/changelog.txt index cdfe29650..b15f5565e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -40,7 +40,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - `autonick`: additional nicknames based on burrowing animals, colours, gems and minerals added -- `stockpiles`: added ``barrels`` and ``organic`` stockpile presets +- `stockpiles`: added ``barrels``, ``organic``, ``artifacts``, and ``masterworks`` stockpile presets ## Documentation diff --git a/docs/plugins/stockpiles.rst b/docs/plugins/stockpiles.rst index 922c3a418..cc1f3c016 100644 --- a/docs/plugins/stockpiles.rst +++ b/docs/plugins/stockpiles.rst @@ -143,6 +143,21 @@ item properties that you can match with filters. In addition, there are normally at least a few convenient pre-made settings files that manipulate interesting category subsets. +Cross-category stockpile adjustments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Settings files:: + + artifacts + masterworks + +Example command for a meltable weapons stockpile:: + + stockpiles import cat_weapons + stockpiles import -m disable cat_weapons -f other/ + stockpiles import -m disable artifacts + stockpiles import -m disable masterworks + Ammo stockpile adjustments ~~~~~~~~~~~~~~~~~~~~~~~~~~ From 873000df806d806dfa8d7e992818e97e2bffe96c Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 8 Jun 2023 07:13:15 +0000 Subject: [PATCH 0257/1234] Auto-update submodules library/xml: master scripts: master --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index 413f1c037..1f22dd8b8 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 413f1c0371094a7933db0cd524ff9fad64fb0fe3 +Subproject commit 1f22dd8b8aa767609ea13bf1d2da8907001e0ce2 diff --git a/scripts b/scripts index 0119ab1b6..13a822532 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 0119ab1b6d540e192c77f114c5ea7f7aeab9b39a +Subproject commit 13a82253226854a5da8d01e6deeb5cc6192c770f From c98525d6683869fc72a5cbf27ea659a9fb4934b1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 7 Jun 2023 03:40:34 -0700 Subject: [PATCH 0258/1234] update dreamfort to new quickfort syntax and capabilities --- data/blueprints/dreamfort.csv | 2675 ++++++++++++++------------------- 1 file changed, 1170 insertions(+), 1505 deletions(-) diff --git a/data/blueprints/dreamfort.csv b/data/blueprints/dreamfort.csv index 66ce693b8..e93d082e3 100644 --- a/data/blueprints/dreamfort.csv +++ b/data/blueprints/dreamfort.csv @@ -1,16 +1,17 @@ #notes label(help) run me for the dreamfort walkthrough "Welcome to Dreamfort! These blueprints will help you build a functional, secure, fully self-sustaining fortress that you can use as-is or extend to build the fortress of your dreams!" "" -"It can be difficult to apply a set of blueprints that you did not write yourself. This walkthrough will guide you through the high-level steps of building Dreamfort. Run ""quickfort run library/dreamfort.csv -n /checklist"" (or, if you're looking at the online version, switch to the ""checklist"" sheet) for a compact list of the commands you'll be running. Each level also has its own mini-walkthrough with more details." +"It can be difficult to apply a set of blueprints that you did not write yourself. This walkthrough will guide you through the high-level steps of building Dreamfort. Run ""quickfort run library/dreamfort.csv -n /checklist"" (or, if you're looking at the online version, switch to the ""checklist"" sheet) for a compact list of the blueprints you'll be applying. Each level also has its own mini-walkthrough with more details." "" "The final fort will have a walled-in area on the surface for livestock, trading, aboveground farming, and military training. One z-level down is the farming level, with related workshops and vents up to the surface for miasma prevention. The farming level also has a miniature dining hall and dormitory for use until you get the services and housing levels set up." "" "Beyond those two, the other layers can be built in any order, at any z-level, according to your preference and the layout peculiarities of your embark site:" "- The industry level has a compact, but complete set of workshops and stockpiles (minus what is already provided on the farming level)." -"- The services level has dining, hospital, marksman barracks, and justice services, plus a well system. It is 4 z-levels deep." -"- The guildhall level has large, empty rooms for building libraries, temples, and guildhalls." -- The suites level has fancy rooms for your nobles. +"- The services level has dining, hospital, marksman barracks, and justice services. It has a well system and is 4 z-levels deep." +"- The guildhall level has large rooms for building libraries, temples, and guildhalls, with optional furniture layouts." +- The suites level has fancy rooms for your nobles with the furniture that they require. - The apartments levels have small but well-furnished bedrooms for your other dwarves. +- The crypt level houses your dead. "" "Run each level's ""help"" blueprint (e.g. ""quickfort run library/dreamfort.csv -n /surface_help"") for more details." "" @@ -20,25 +21,20 @@ "" "There are some tasks common to all forts that Dreamfort doesn't specifically handle for you. For example, Dreamfort sets up a barracks, but managing squads is up to you. Here are some other common tasks that may need to be done manually (or with some other tool):" - Exploratory mining for specific resources like iron -- Filling the well system with water -- Bringing magma up to the industry level to power magma forges/furnaces +"- Filling the well system with water (if you have a light aquifer, see library/aquifer_tap.csv for help with this)" +- Bringing magma up to the industry level to power magma forges/furnaces (see library/pump_stack.csv for help with this) - Manufacturing trade goods -- Assigning skilled labors to migrants (although the example professions included with DFHack will help with this) "- Custom stockpile setups to assist with, for example, encrusting only high-quality items" "" -"Dreamfort works best at an embark site that is flat and has at least one soil layer. New players should avoid embarks with aquifers if they are not prepared to deal with them. Bring picks for mining, an axe for woodcutting, and an anvil for a forge. Bring a few blocks to speed up initial workshop construction as well. That's all you really need, but see the example embark profile in the online spreadsheets for a more complete setup." +"Dreamfort works best at an embark site that is relatively flat and has at least one soil layer. New players should avoid embarks with aquifers if they are not prepared to deal with them. Bring picks for mining, an axe for woodcutting, and an anvil for a forge. Bring a few blocks to speed up initial workshop construction as well. That's all you really need, but see the example embark profile in the online spreadsheets for a more complete setup." "" -"Other DFHack commands also work very well with Dreamfort, such as autofarm, autonestbox, prioritize, seedwatch, tailor, and, of course, buildingplan. An init file that gets everything configured for you is distributed with DFHack as hack/examples/init/onMapLoad_dreamfort.init." -Put that file in your dfhack-config/init/ directory -- the same directory that has dfhack.init. +"Other DFHack tools also work very well with Dreamfort, such as autofarm and all of the other DFHack auto tools. Turn them on in the DFHack gui/control-panel." "" -"Also check out https://docs.dfhack.org/en/stable/docs/Plugins.html#professions for more information on the default labor professions that are distributed with DFHack, including suggestions on how many dwarves of each profession you are likely to need at each stage of fort maturity." +"Once you have your starting surface workshops up and running, you might want to configure buildingplan to only use blocks for constructions so it won't use your precious wood, boulders, and bars to build floors and walls. If you bring at least 7 blocks with you on embark, you can set this to be your default in the Autostart tab of gui/control-panel." "" -"Once you have your starting surface workshops up and running, you might want to configure buildingplan (in its global settings, accessible from any building placement screen, e.g.: b-a-G) to only use blocks for constructions so it won't use your precious wood, boulders, and bars to build floors and walls. If you bring at least 7 blocks with you on embark, you can even set this in your dfhack-config/init/onMapLoad.init file like this:" -on-new-fortress buildingplan set boulders false; buildingplan set logs false +"Directly after embark, run ""quickfort run library/dreamfort.csv -n /setup_help"" to get some advice on initial settings, and get started building your fort with ""quickfort run library/dreamfort.csv -n /surface1"" on the surface (see /surface_help for how to select a good spot). Read the walkthroughs for each level to understand what's going on and follow the checklist to keep track of where you are in the building process. Good luck, and have fun building an awesome Dreamfort-based fort!" "" -"Directly after embark, run ""quickfort run library/dreamfort.csv -n /setup"" with your cursor on your wagon to set settings, and get started building your fort with ""quickfort run library/dreamfort.csv -n /surface1"" on the surface (see /surface_help for how to select a good spot). Read the walkthroughs for each level to understand what's going on and follow the checklist to keep track of where you are in the building process. Good luck, and have fun building an awesome Dreamfort-based fort!" -"" -"The dreamfort.csv file distributed with DFHack is generated from online spreadsheet files. If you want to look at how these blueprints are put together, it is easier to look at the online spreadsheets than the giant .csv. You can view them at: https://drive.google.com/drive/folders/1iS90EEVqUkxTeZiiukVj1pLloZqabKuP" +"The dreamfort.csv file distributed with DFHack is generated from online spreadsheet files. If you want to look at how these blueprints are put together, it is easier to look at the online spreadsheets than the giant .csv. You can view them at: https://drive.google.com/drive/folders/1dsmvnzbOKsyFS3DCj0F8ibSnMhVHEjdV" You are welcome to copy the Dreamfort spreadsheets and make your own modifications! "" "If you like, you can download a fully built Dreamfort-based fort from https://dffd.bay12games.com/file.php?id=15434 and explore it @@ -46,105 +42,98 @@ interactively." "# The dreamfort.csv distributed with DFHack is generated with the following command: for fname in dreamfort*.xlsx; do xlsx2csv -a -p '' ""$fname""; done | sed 's/,*$//'" #notes label(checklist) command checklist -"Here is the recommended order for Dreamfort commands. You can copy/paste the command lines directly into the DFHack terminal, or, if you prefer, you can run the blueprints in the UI with gui/quickfort. See the walkthroughs (the ""help"" blueprints) for context and details. Also remember to read the messages the blueprints print out after you run them so you don't miss any important manual steps." +"Here is the recommended order for Dreamfort commands. You can either copy/paste the command lines directly into the DFHack terminal or run the blueprints in the UI with gui/quickfort. See the walkthroughs (the ""help"" blueprints) for context and details. Also remember to read the messages the blueprints print out after you run them so you don't miss any important manual steps!" "" -- Preparation (before you embark!) -- -Copy hack/examples/init/onMapLoad_dreamfort.init to your dfhack-config/init directory inside your DF installation -Optionally copy the premade Dreamfort embark profile from the online spreadsheets to the data/init/embark_profiles.txt file +Optionally copy the premade Dreamfort embark profile from the online spreadsheets to the prefs/embark_profiles.txt file. +Run gui/control-panel and enable settings on the Autostart tab. See the /setup_help notes for details. "" -- Set settings and preload initial orders -- -quickfort run library/dreamfort.csv -n /setup,# Run before making any manual adjustments to settings! Run the /setup_help blueprint for details on what this blueprint does. -"quickfort orders library/dreamfort.csv -n ""/surface2, /farming2, /surface3, /farming3, /industry2, /surface4""","# Queue up orders required to get the fort minimally functional and secure. You can remove the order for the anvil (you brought one with you, right?)." +quickfort run library/dreamfort.csv -n /setup_help,# For advice on how to do initial setup for success. +"quickfort orders library/dreamfort.csv -n ""/surface2, /farming2, /surface3, /industry2, /surface4""","# Queue up orders required to get the fort minimally functional and secure. You can remove the order for the anvil (you brought one with you, right?)." "" -- Find a good starting spot on the surface -- gui/quickfort library/dreamfort.csv -n /perimeter,# Run at embark. Don't actually apply the blueprint. Just use the preview shadow to find a good spot on the surface. "" -- Dig -- -quickfort run library/dreamfort.csv -n /surface1,# Run when you find your center tile. -quickfort run library/dreamfort.csv -n /dig_all,"# Run when you find a suitable rock layer for the industry level. It designates digging for industry, services, guildhall, suites, and apartments all in one go. This list does not include the farming level, which we'll dig in the uppermost soil layer a bit later. Note that it is more efficient for your miners if you designate your digging before they dig the central stairs past that level since the stairs are dug at a low priority. This keeps your miners focused on one level at a time. If you need to designate your levels individually due to caverns interrupting the sequence or just because it is your preference, run the level-specific dig blueprints (i.e. /industry1, /services1, /guildhall1, /suites1, and 5 levels of /apartments1) instead of running /dig_all." +quickfort run library/dreamfort.csv -n /surface1,# Run when you find your center tile. Deconstruct your wagon if it is in the way. +quickfort run library/dreamfort.csv -n /dig_all,"# Run when you find a suitable rock layer for the industry level. It designates digging for industry, services, guildhall, suites, apartments, and the crypt all in one go. This list does not include the farming level, which we'll dig in the uppermost soil layer a bit later. Note that it is more efficient for your miners if you designate your digging before they dig the central stairs past that level since the stairs are dug at a low priority. This keeps your miners focused on one level at a time. If you need to designate your levels individually due to caverns interrupting the sequence or just because it is your preference, run the level-specific dig blueprints (i.e. /industry1, /services1, /guildhall1, /suites1, 3 levels of /apartments1, and /crypt1) instead of running /dig_all." "" -- Core fort (should finish at about the third migration wave) -- quickfort run library/dreamfort.csv -n /surface2,"# Run after initial trees are cleared. If you are deconstructing the wagon now, wait until after the wagon is deconstructed so the jobs that depend on wagon contents (e.g. blocks) don't get canceled later." -quickfort run library/dreamfort.csv -n /farming1,# Run when channels are dug and the additional designated trees are cleared. +quickfort run library/dreamfort.csv -n /farming1,# Run when channels are dug and the additional designated trees on the surface are cleared. quickfort run library/dreamfort.csv -n /farming2,# Run when the farming level has been dug out. quickfort run library/dreamfort.csv -n /surface3,# Run right after /farming2. -quickfort run library/dreamfort.csv -n /farming3,# Run when furniture has been placed. quickfort run library/dreamfort.csv -n /industry2,# Run when the industry level has been dug out. -prioritize ConstructBuilding,# To get those workshops up and running ASAP. You may have to run this several times as the materials for the building construction jobs become ready. +prioritize ConstructBuilding,"# To get those workshops up and running ASAP. You may have to run this several times as the materials for the building construction jobs become ready. As industry workshops are built, you can remove the temporary workshops and stockpiles on the surface. **Be sure that there are no items attached to jobs left in the workshops before deconstructing them, otherwise you'll get canceled jobs!**" quickfort run library/dreamfort.csv -n /surface4,"# Run after the walls and floors are built on the surface. Even if /surface3 is finished before you run /industry2, though, wait until after /industry2 to run this blueprint so that surface walls, floors, and roofing don't prevent your workshops from being built (due to lack of blocks)." -"quickfort orders,run library/dreamfort.csv -n /services2",# Run when the services levels have been dug out. Feel free to remove the orders for the ropes if you already brought them with you. -orders import library/basic,"# Run after the first migration wave, so you have dorfs to do all the basic tasks. Note that this is the ""orders"" plugin, not the ""quickfort orders"" command." +"quickfort orders,run library/dreamfort.csv -n /services2","# Run when the services levels have been dug out. Feel free to remove the orders for the ropes if you already brought them with you. If you are filling your wells from an aquifer or stream, now is also a good time to start digging the plumbing." +orders import library/basic,"# Run after the first migration wave, so you have dwarves to do all the basic tasks. Note that this is the ""orders"" plugin, not the ""quickfort orders"" command." "quickfort orders,run library/dreamfort.csv -n /surface5","# Run when all marked trees on the surface are chopped down and walls and floors have been constructed, including the roof section over the future barracks." prioritize ConstructBuilding,# Run when you see the bridges ready to be built so the busy masons come and build them. -"quickfort orders,run library/dreamfort.csv -n /surface6",# Run when at least the beehives and weapon rack are constructed and you have linked all levers to their respective bridges. +"quickfort orders,run library/dreamfort.csv -n /surface6",# Run once you have linked all levers to their respective bridges. "quickfort orders,run library/dreamfort.csv -n /surface7",# Run after the surface walls are completed and any marked trees are chopped down. "" -- Plumbing -- -"This is a good time to fill your well cisterns, either with a bucket brigade or by routing water from a freshwater stream or an aquifer (see the library/aquifer_tap.csv blueprint for help with this)." -"Also consider bringing magma up to your services level so you can replace the forge and furnaces on your industry level with more powerful magma versions. This is especially important if your embark has insufficient trees to convert into charcoal. Keep in mind that moving magma is a tricky process and can take a long time. Don't forget to continue making progress through the checklist! If you choose to use magma, I suggest getting it in place before importing the military and smelting automation orders since they make heavy use of furnaces and forges." +"If you haven't done it already, this is a good time to fill your well cisterns, either with a bucket brigade or by routing water from a freshwater stream or an aquifer (see the library/aquifer_tap.csv blueprint for help with this)." +"Also consider bringing magma up to your services level so you can replace the forge and furnaces on your industry level with more powerful magma versions. This is especially important if your embark has insufficient trees to convert into charcoal. Keep in mind that moving magma is a tricky process and can take a long time. Don't forget to continue making progress through this checklist! If you choose to use magma, try to get it in place before importing the military and smelting automation orders since they make heavy use of furnaces and forges." "" -- Mature fort (third migration wave onward) -- +The order of steps in this section is less important. Feel free to reorder as per the needs of your fort. orders import library/furnace,# Automated production of basic furnace-related items. Don't forget to create a sand collection zone (or remove the sand- and glass-related orders if you have no sand). +"quickfort orders,run library/dreamfort.csv -n /guildhall2_default",# Run when the guildhall level has been dug out. "quickfort orders,run library/dreamfort.csv -n /suites2",# Run when the suites level has been dug out. -"quickfort orders,run library/dreamfort.csv -n /surface8","# Run if/when you need longer trap corridors on the surface for larger sieges, anytime after you run /surface7." +"quickfort orders,run library/dreamfort.csv -n /services3",# Run when your population grows to about 20. "quickfort orders,run library/dreamfort.csv -n /apartments2",# Run when the first apartment level has been dug out. -"quickfort orders,run library/dreamfort.csv -n /services3","# Run after the dining table and chair, weapon rack, and archery targets have been constructed. Also wait until after you complete /surface7, though, because surface defenses are more important than a grand dining hall." -"quickfort orders,run library/dreamfort.csv -n /guildhall2",# Run when the guildhall level has been dug out. -"quickfort orders,run library/dreamfort.csv -n ""/guildhall3, /guildhall4""",# Optionally run after /guildhall2 to build default furnishings and declare a library and temple. -"quickfort orders,run library/dreamfort.csv -n /apartments3",# Run when all beds have been constructed on the first apartments level. -"quickfort orders,run library/dreamfort.csv -n /farming4",# Run once you have a cache of potash. +"quickfort orders,run library/dreamfort.csv -n /crypt2",# Run when the crypt level has been dug out. +"quickfort orders,run library/dreamfort.csv -n /surface8","# Run if/when you need longer trap corridors on the surface for larger sieges, anytime after you run /surface7." +"quickfort orders,run library/dreamfort.csv -n /farming3",# Add in all the doors we couldn't afford to build earlier. orders import library/military,# Automated production of military equipment. Turn on automelt in the meltables piles on the industry level to automatically upgrade all metal military equipment to masterwork quality. These orders are optional if you are not using a military. orders import library/smelting,# Automated production of all types of metal bars. -"quickfort orders,run library/dreamfort.csv -n /services4","# Run when you need a jail, anytime after the restraints are placed from /services3." -orders import library/rockstock,# Maintains a small stock of all types of rock furniture. +"quickfort orders,run library/dreamfort.csv -n /services4",# Run when you need a full dining room and/or jail. +orders import library/rockstock,# Maintains a small stock of all types of rock furniture. Useful for filling out future guildhalls. orders import library/glassstock,# Maintains a small stock of all types of glass furniture and parts (only import if you have sand). +"quickfort orders,run library/dreamfort.csv -n /apartments2",# Repeat as needed as your fort grows. +"quickfort orders,run library/dreamfort.csv -n /crypt3",# Run when the crypt is starting to run out of space. "" --- Repeat for each remaining apartments level as needed -- -"quickfort orders,run library/dreamfort.csv -n /apartments2",# Run when the apartment level has been dug out. -"quickfort orders,run library/dreamfort.csv -n /apartments3",# Run when all beds have been constructed. -burial -pets,# Run once the coffins are placed to set them to allow for burial. - See this checklist online at https://docs.google.com/spreadsheets/d/13PVZ2h3Mm3x_G1OXQvwKd7oIR2lK4A1Ahf6Om1kFigw/edit#gid=1459509569 #notes label(setup_help) -Makes common initial adjustments to in-game settings. -"" -"The /setup blueprint is intended to be run once at the start of the game, before anything else is changed. Players are welcome to make any further customizations after this blueprint is run. Please be sure to run the /setup blueprint before making any other changes, though, so your settings are not overwritten!" -"" -The following settings are changed: -"- The manager, chief medical dwarf, broker, and bookkeeper noble roles are assigned to the first suggested dwarf. This is likely to be the expedition leader, but the game could suggest others if they have relevant skills. Bookkeeping is set to the highest precision." -"" -- Standing orders are set to: - - only farmers harvest - - gather refuse from outside (incl. vermin) - - no autoloom (so the hospital always has thread -- we'll be managing cloth production with automated orders) -"" -"- A burrow named ""Inside"" is created, but it's up to the player to define the area as the fort expands. It is intended for use in getting your civilians to safety during sieges. A military alert named ""Siege"" is also created and associated with the ""Inside"" burrow." -"" -- Military uniforms get the following modifications: - - all default uniforms set to replace clothing -" - in the ""Metal armor"" uniform, the ""metal armor"" item is removed and replaced by ""metal breastplate"" and ""metal mail shirt""" -" - in the ""Metal armor"" uniform, the ""metal legwear"" item is removed and replaced by ""metal greaves""" -"" -"All default uniforms should also have a leather cloak added, but the position of the cloak in the equipment list changes for every embark. We suggest manually adding a leather cloak to your uniforms after running the /setup blueprint." -"" -- Hotkeys are created for the 8 most interesting levels. Only the names are set -- it's up to the player to adjust them to actual locations in the (H) menu since the blueprint can't know where the levels will eventually be built. Feel free to replace any hotkeys with locations that *you* think are interesting : ) -"" -These are all set for your convenience. Nothing in Dreamfort depends on these settings staying as they are. Feel free to change any setting to your personal preference. -"" -#aliases -startnobles: n{Down 4}{togglesequence 8}{Up}s{Up}&^^ -startorders: ohrov^Wl^^ -startburrows: wa&nInside&^^ -metalarmorsetup: A{Right 2}{Down 2}&{Down}&{Left}&M{Right}{Down}&{Left}{Down}{Right}{Down}&{Left}{Down 2}L{Right}{Down 2}&{Left}{Down 3}&M{Right}{Down}&{Left 2} -startmilitary: mnr{Down}r{metalarmorsetup}{Down}racNSiege&{Right}&^ -sethotkey: {fkey}n{name}& -starthotkeys: H{sethotkey fkey={F2} name=Farming}{sethotkey fkey={F3} name=Industry}{sethotkey fkey={F4} name=Services}{sethotkey fkey={F5} name=Guildhall}{sethotkey fkey={F6} name=Quarry}{sethotkey fkey={F7} name=Cavern}{sethotkey fkey={F8} name=Magma}^ -"" -"#config label(setup) message(Please set the zoom targets of the hotkeys (the 'H' menu) according to where you actually end up digging the levels. -As you build your fort, expand the ""Inside"" burrow to include new civilian-safe areas. -Optionally, add a leather cloak to your military uniforms to enhance their protection rating. -Nothing in Dreamfort depends on these settings staying as they are. Feel free to change any setting to your personal preference.) assign nobles, set standing orders, create burrows, make adjustments to military uniforms, and set hotkey names" -{startnobles}{startorders}{startburrows}{startmilitary}{starthotkeys} +These are Dreamfort's suggestions for adjustments to settings and initial setup. +"" +"- Assign dwarves to manager, chief medical dwarf, sheriff, broker, and bookkeeper noble roles (they can all be the same dwarf)" +"" +- On the Work details screen (Labor -> Work details) + - Specialize your miners (click the hammer-lock button so it turns red) and make your miners also engravers (they'll need something to do once the mining is done) +"" +- In standing orders (Labor -> Standing orders): +" - Change ""Automatically weave all thread"" to ""No automatic weaving"" so the hospital always has thread -- we'll be managing cloth production with automated orders" +"" +"- Create a burrow named ""Inside"" and register it as a civilian alert burrow in gui/civ-alert so you can use it to get your civilians to safety during sieges. You will have to periodically expand the burrow area as the fort expands." +"" +"Beyond the bugfix tools that are enabled by default, we recommend enabling the following DFHack tools in gui/control-panel (but they are not required if you prefer to do these things manually):" +"On the ""Autostart"" tab, additionally enable:" +- autobutcher +- autobutcher target 50 50 14 2 BIRD_GOOSE +- autochop +- autofarm +- autofish +- autonestbox +- autoslab +- ban-cooking all +- buildingplan set boulders false +- buildingplan set logs false +- nestboxes +- prioritize +- seedwatch +- suspendmanager +- tailor +"Note that if you've already started your fort and have missed the ""new fort"" trigger, you can enable these tools on the ""Fort"" tab instead. You can run the one-time commands (like ban-cooking all) manually from gui/launcher." +"" +"On the ""Maintenance"" tab, enable:" +- everything +"" +"On the ""System"" tab, additionally enable:" +- work-now "#meta label(dig_all) start(central stairs on industry level) dig industry, services, guildhall, suites, and apartments levels. does not include farming." # Note that this blueprint will only work for the unified dreamfort.csv. It won't work for the individual .xlsx files (since #meta blueprints can't cross file boundaries). "" @@ -156,35 +145,35 @@ Nothing in Dreamfort depends on these settings staying as they are. Feel free to #> /suites1 #> -/apartments1 repeat(down 5) +/apartments1 repeat(down 3) +#>3 +/crypt1 #ignore -"Here are the minimal labors needed for essential tasks in getting Dreamfort up and running, along with suggestions for which dwarves to assign them to. You can enable additional labors as you wish. Skills with an asterisk (*) are especially worth putting points into on the embark preparation screen." +"Here are the most important skills for getting Dreamfort up and running, along with suggestions for how to distribute them." "" -Manager / Bookkeeper / Broker,Miner,Miner,Mason,Mason,Outdoorsdwarf,Farmer -Mechanic (*),Miner (*),Miner (*),Mason (*),Mason (*),Carpenter (*),Grower (*) -Stonecrafter,,,,,Wood Cutter (*) -Wood Cutter,,,,,Bee Keeper -Architect -Misc. labors needed for constructing workshops +Manager / Bookkeeper / Broker,Miner,Miner,Mason,Smith,Outdoorsdwarf,Farmer +Mechanic,Miner,Miner,Stonecutter,Weaponsmith,Carpenter,Stonecutter +Stonecrafting,Engraver,Engraver,Mason,Armorsmith,Wood Cutter,Planter "" -"The most time-consuming tasks in early Dreamfort are: mining, chopping down trees, and making blocks. Starting with at least two miners, two woodcutters (assuming your embark has trees), and two masons helps in keeping the fort from stalling." +"The most time-consuming tasks in early Dreamfort are: mining, chopping down trees, and making blocks. Starting with at least two miners, two woodcutters (assuming your embark has trees), and two stonecutters helps keep the fort from stalling. If you have to smooth walls to prevent a light aquifer from flooding your fort, starting with a few engravers saves a ton of time." "" We suggest bringing at least: 2 picks,for the two miners -2 battleaxes,for the two woodcutters +2 battleaxes,for two active woodcutters 1 anvil,for the forge food and seeds,as per usual 4 ropes,"for the hospital well and traction benches. you could build the ropes out of raw materials, but dwarves are usually too busy to do textile work at the start of the game." 7 blocks,for starting workshops and the temporary trade depot. necessary if you have buildingplan configured for blocks only. -many boulders,for quickly turning into more blocks. blocks are the limiting factor in the early stages. +many boulders,for quickly turning into more blocks while your miners are digging in dirt or dealing with aquifers. blocks are the limiting factor in the early stages. dogs and cats,for protection and vermin control -geese,"for bones and leather. bring at least 1 male and 2 females for the 2 early nestboxes. autobutcher settings in the included onMapLoad_dreamfort.init file are optimized for raising geese. if you prefer another bird, be sure to adjust the autobutcher settings." +geese,for bones and leather. bring at least 1 male and 2 females for the 2 early nestboxes. "" Also bring logs for beds if embarking in an area without many trees. "" See ldog's Dreamfort embark profile for a more advanced (and more thoroughly explained!) approach: https://drive.google.com/file/d/1Et42JTzeYK23iI5wrPMsFJ7lUXwVBQob/view?usp=sharing "#ignore Add these lines to the bottom of your ""data/init/embark_profiles.txt"" file to make the ""Dreamfort"" profile available in-game. Also see ldog's dreamfort embark profile for a more advanced, dwarfy approach." +[PROFILE] [TITLE:Dreamfort] [SKILL:1:STONECRAFT:1] [SKILL:1:MECHANICS:5] @@ -193,36 +182,40 @@ https://drive.google.com/file/d/1Et42JTzeYK23iI5wrPMsFJ7lUXwVBQob/view?usp=shari [SKILL:1:ORGANIZATION:1] [SKILL:1:RECORD_KEEPING:1] [SKILL:2:MINING:5] -[SKILL:2:DETAILSTONE:2] +[SKILL:2:ENGRAVE_STONE:4] [SKILL:2:SWIMMING:1] [SKILL:3:MINING:5] -[SKILL:3:DETAILSTONE:2] +[SKILL:3:ENGRAVE_STONE:4] [SKILL:3:SWIMMING:1] -[SKILL:4:MASONRY:5] -[SKILL:5:MASONRY:5] +[SKILL:4:MASONRY:2] +[SKILL:4:MILITARY_TACTICS:5] +[SKILL:4:CUT_STONE:3] +[SKILL:5:FORGE_WEAPON:5] +[SKILL:5:FORGE_ARMOR:5] [SKILL:6:WOODCUTTING:5] [SKILL:6:CARPENTRY:5] -[SKILL:7:PLANT:3] -[ITEM:2:WEAPON:ITEM_WEAPON_PICK:INORGANIC:COPPER] -[ITEM:2:WEAPON:ITEM_WEAPON_AXE_BATTLE:INORGANIC:COPPER] +[SKILL:7:PLANT:5] +[SKILL:7:CUT_STONE:5] +[ITEM:10:CLOTH:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] +[ITEM:100:WOOD:NONE:PLANT_MAT:WILLOW:WOOD] +[ITEM:30:BLOCKS:NONE:INORGANIC:QUARTZITE] +[ITEM:21:SEEDS:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:GRASS_TAIL_PIG:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:GRASS_WHEAT_CAVE:SEED] +[ITEM:21:SEEDS:NONE:PLANT_MAT:POD_SWEET:SEED] +[ITEM:20:SEEDS:NONE:PLANT_MAT:BUSH_QUARRY:SEED] +[ITEM:20:SEEDS:NONE:PLANT_MAT:MUSHROOM_CUP_DIMPLE:SEED] [ITEM:1:ANVIL:NONE:INORGANIC:IRON] -[ITEM:7:DRINK:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:DRINK] -[ITEM:26:DRINK:NONE:PLANT_MAT:GRASS_TAIL_PIG:DRINK] -[ITEM:26:DRINK:NONE:PLANT_MAT:GRASS_WHEAT_CAVE:DRINK] -[ITEM:26:DRINK:NONE:PLANT_MAT:POD_SWEET:DRINK] -[ITEM:10:SEEDS:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:SEED] -[ITEM:10:SEEDS:NONE:PLANT_MAT:GRASS_TAIL_PIG:SEED] -[ITEM:10:SEEDS:NONE:PLANT_MAT:GRASS_WHEAT_CAVE:SEED] -[ITEM:10:SEEDS:NONE:PLANT_MAT:POD_SWEET:SEED] -[ITEM:10:SEEDS:NONE:PLANT_MAT:BUSH_QUARRY:SEED] -[ITEM:10:SEEDS:NONE:PLANT_MAT:MUSHROOM_CUP_DIMPLE:SEED] -[ITEM:25:PLANT:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:STRUCTURAL] +[ITEM:2:WEAPON:ITEM_WEAPON_AXE_BATTLE:INORGANIC:COPPER] +[ITEM:2:WEAPON:ITEM_WEAPON_PICK:INORGANIC:COPPER] +[ITEM:20:DRINK:NONE:PLANT_MAT:GRASS_TAIL_PIG:DRINK] +[ITEM:20:DRINK:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:DRINK] +[ITEM:20:DRINK:NONE:PLANT_MAT:POD_SWEET:DRINK] +[ITEM:20:DRINK:NONE:PLANT_MAT:GRASS_WHEAT_CAVE:DRINK] +[ITEM:30:PLANT:NONE:PLANT_MAT:MUSHROOM_HELMET_PLUMP:STRUCTURAL] +[ITEM:45:BOULDER:NONE:INORGANIC:QUARTZITE] +[ITEM:20:THREAD:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] [ITEM:4:CHAIN:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] -[ITEM:5:CLOTH:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] -[ITEM:5:THREAD:NONE:CREATURE_MAT:SPIDER_CAVE:SILK] -[ITEM:50:WOOD:NONE:PLANT_MAT:WILLOW:WOOD] -[ITEM:40:BOULDER:NONE:INORGANIC:QUARTZITE] -[ITEM:10:BLOCKS:NONE:INORGANIC:QUARTZITE] [PET:2:DOG:FEMALE:STANDARD] [PET:1:DOG:MALE:STANDARD] [PET:2:CAT:FEMALE:STANDARD] @@ -268,7 +261,7 @@ Features: - Barracks (with prisoner processing quantum dump) - Trap-filled hallways for invaders - Optional extended trap hallways (to handle larger sieges) -- Protected trade depot +"- Protected trade depot, with separate trade goods stockpiles for organics and inorganics (for easy elven trading)" - A grid of 1x1 farm plots (intended to be managed by DFHack autofarm) "" Manual steps you have to take: @@ -279,11 +272,11 @@ Manual steps you have to take: Be sure to choose an embark site that has a flat area on the surface large enough to use these blueprints! "" Surface Walkthrough: -"1) Choose a tile for your central fortress stairs. The terrain around that tile should be perfectly flat. Trees are ok, but no slopes, rivers, or lakes. To be sure that the tile you've chosen is in a good spot, set the cursor over that tile and run ""quickfort run library/dreamfort.csv -n /perimeter"". This will show you the eventual boundaries of the fort. Some wall segments might be missing due to existing trees, but that's ok. Make sure the area within the exterior wall is flat. Run ""quickfort undo library/dreamfort.csv -n /perimeter"" to clean up." +"1) Choose a tile for your central fortress stairs. The terrain around that tile should be perfectly flat. Trees are ok, but no slopes, rivers, or lakes. To be sure that the tile you've chosen is in a good spot, run ""gui/quickfort library/dreamfort.csv -n /perimeter"". This will show you the eventual boundaries of the fort. Some wall segments might be missing due to existing trees, but that's ok. Make sure the area within the exterior wall is flat. Cancel out of the preview. You don't actually need to apply this blueprint." "" "2) With the cursor on the chosen tile, run /surface1 to clear surrounding trees and set up your pastures. Deconstruct your wagon to get it out of the way of our upcoming walls and floors. Remember to assign your dogs to the pasture around the staircase and your grazing animals to the large pasture. Your egg-layers will automatically get assigned to nestbox zones once the nestboxes are built, so you don't need to worry about them. You can let your cats roam free to chase vermin." "" -"3) Once the marked trees have been cleared, run /surface2 to setup starting workshops/stockpiles, channel out the miasma vents for the farming level, and start clearing trees from a larger area. If you haven't done it already, now is a good time to configure buildingplan to only build buildings with blocks, not logs or raw boulders. Do this by entering buildingplan's global configuration (""baG"") and ensuring the only generic building material allowed is ""blocks"". Run ""quickfort orders"" for /surface2." +"3) Once the marked trees have been cleared, run /surface2 to setup starting workshops/stockpiles, channel out the miasma vents for the farming level, and start clearing trees from a larger area. If you haven't done it already, now is a good time to configure buildingplan to only build buildings with blocks, not logs or raw boulders. Run ""quickfort orders"" for /surface2." "" "4) Once the channels are dug out and the trees are cleared, start digging the farming level one z-level down. Once you have run /farming2, come back to the surface and run /surface3 to cover the vents and build an enclosure around your central stairs. Although the vents will be covered with flooring, they will still work to prevent miasma on the farming level. Run ""quickfort orders"" for /surface3." "" @@ -291,39 +284,39 @@ Surface Walkthrough: "" "6) Once walls and floors have been constructed (including the small roof segment one z-level up over the barracks), run /surface5 to build furniture, gates, and the permanent trade depot. Remember to deconstruct the temporary trade depot once nobody is using it. Run ""quickfort orders"" for /surface5." "" -"7) Once at least the beehives and weapon rack are built, run /surface6 to configure the rooms and build the remaining walls and floors. Run ""quickfort orders"" for /surface6." +"7) Once all marked trees are cleared, run /surface6 to build the remaining walls and floors. Run ""quickfort orders"" for /surface6." "" "8) Once you have enough dwarves to do a lot of building without starving other important tasks, run /surface7 to build the roof. Run ""quickfort orders"" for /surface7." "" "9) For extra security, you can run /surface8 any time after /surface7 to extend the trap corridors. Run ""quickfort orders"" for /surface8." "" -"10) Once your industry and farming levels are set up and running, you can disassemble the surface workshops and remove the surface stockpiles. Disassembling a workshop scatters the items stored within it and cancels any pending jobs that happen to use those items. In order to avoid job cancellations, first set the surface workshops to not accept general work orders. Do this by entering query mode (""q""), selecting a workshop, entering the workshop profile (""P""), moving to work orders (right arrow), and hitting Enter. Then enter view mode (""t"") and check to see if any items in a workshop are marked with ""TSK"". Once no items in the workshop have that marker, you are free to disassemble that workshop." +"10) Once your industry and farming levels are set up and running, you can disassemble the surface workshops and remove the surface stockpiles. Disassembling a workshop scatters the items stored within it and cancels any pending jobs that happen to use those items. In order to avoid job cancellations, first set the surface workshops to not accept general work orders. Then check to see if any items in a workshop are marked as being part of an active job. Once no items in the workshop have that marker, you are free to disassemble that workshop." "" Sieges and Prisoner Processing: Here are some tips and procedures for handling seiges -- including how to clean up afterwards! "" "- Ensure your ""Inside"" burrow includes only below-ground areas and safe surface areas of your fort. In particular, don't include the ""atrium"" area (where the ""siege bait"" zone is) or the trapped hallways." "" -"- When a siege begins, set the civilian alert to ""Siege"" to ensure all your civilians stay out of danger. Immediately pull the lever to close the outer main gate. It is also wise to close the trade depot and inner main gate as well. That way, if enemies get past the traps, they'll have to go through the soldiers in your barracks." +"- When a siege begins, set your civilian alert (attach the alert to your ""Inside"" burrow if it isn't already) to ensure all your civilians stay out of danger. Immediately pull the lever to close the outer main gate. It is also wise to close the trade depot and inner main gate as well. That way, if enemies get past the traps, they'll have to go through the soldiers in your barracks." "" "- During a siege, use the levers to control how attackers path through the trapped corridors. If there are more enemies than cage traps, time your lever pulling so that the inner gates snap closed before your last cage trap is sprung. Then the remaining attackers will have to backtrack and go through the other trap-filled hallway." "" -"- If your cage traps fill up, ensure your hallways are free of uncaged attackers, then close the trap hallway outer gates and open the inner gates. Unset the civilian alert and allow your dwarves to reset all the traps -- make some extra cages in preparation for this! Then re-set the civilian alert to ""Siege"" and open the trap hallway outer gates." +"- If your cage traps fill up, ensure your hallways are free of uncaged attackers, then close the trap hallway outer gates and open the inner gates. Clear the civilian alert and allow your dwarves to reset all the traps -- make some extra cages in preparation for this! Then re-enable the civilian alert and open the trap hallway outer gates." "" "- Once the last attacker is caged, open all the gates and unset the civilian alert. Life is normal again!" "" "After a siege, you can use the caged prisoners to safely train your military. Here's how:" "" -"- Once the prisoners are hauled to the ""prisoner quantum"" stockpile, run ""unforbid all"" and ""stripcaged all"" in the DFHack console (or GUI launcher)." +"- Once the prisoners are hauled to the ""prisoner quantum"" stockpile, run ""stripcaged all"" in the DFHack gui/launcher." "" "- After all the prisoners' items have been confiscated, bring your military dwarves to the barracks (if they aren't already there)." "" -- Use the zone (i) menu to assign a group prisoners to the pasture that overlaps the prisoner quantum stockpile +- Assign a group prisoners to the pasture that overlaps the prisoner quantum stockpile "" "- Hauler dwarves will come and release prisoners one by one. Your military dwarves will immediately pounce on the released prisoner and chop them to bits, saving the hauler dwarves from being attacked. Repeat until all prisoners have been ""processed""." "" -"Only common hostile creatures are accepted by the prisoner hauling route by default. You can add additional creature types by configuring the hauling route stop in the 'h' menu. Note that generated creature types, like necromancer experiments, can't be explicitly added. You have to (at least temporarily) accept all animals to include them." -#meta label(perimeter) start(central stairs) message(Run quickfort undo on this blueprint to clean up.) show the eventual perimeter of the surface fort; useful for location scouting +"Only common hostile creatures are accepted by the prisoner hauling route by default. You can add additional creature types by configuring the hauling route stop. Note that generated creature types, like necromancer experiments, can't be explicitly added. You have to (at least temporarily) accept all animals to include them." +"#meta label(perimeter) start(central stairs) message(If you accidentally applied this blueprint to the map, run quickfort undo on this blueprint to clean up.) show the eventual perimeter of the surface fort; useful for location scouting" walls/surface_walls corridor/surface_corridor "" @@ -333,15 +326,13 @@ If your wagon is within the fort perimeter, deconstruct it to get it out of the Once the marked trees are all chopped down (if any), continue with /surface2.) clear trees and set up pastures" clear_small/surface_clear_small zones/surface_zones -name_zones/surface_name_zones #> central_stairs/central_stairs repeat(down 10) "" "#meta label(surface2) start(central stairs) message(Remember to enqueue manager orders for this blueprint. Once the channels are dug out and the marked trees are cleared, continue with /surface3.) set up starting workshops/stockpiles, channel miasma vents, and clear more trees" -build_start/surface_build_start place_start/surface_place_start -query_start/surface_query_start +build_start/surface_build_start channel/surface_channel clear/surface_clear "" @@ -357,16 +348,14 @@ pre_building/surface_pre_building "" "#meta label(surface5) start(central stairs) message(Remember to enqueue manager orders for this blueprint. Disassemble the temporary trade depot in the pasture once the new one is constructed (and no merchants are using the old one). -Once the marked trees are cleared and at least the beehives and weapon rack have been constructed, continue with /surface6.) build gates, furniture, and trade stockpile/depot" +Once the marked trees are cleared, continue with /surface6.) build gates, furniture, and trade stockpile/depot" +traffic/surface_traffic place/surface_place build/surface_build -query/surface_query -traffic/surface_traffic clear_large/surface_clear_large "" "#meta label(surface6) start(central stairs) message(Remember to enqueue manager orders for this blueprint. -Continue with /surface7 sometime after the walls are completed and any marked trees are chopped down, whenever you have enough dwarves to build the roof without starving other important construction tasks.) configure hives and barracks, build traps and remaining walls/floors" -query2/surface_query2 +Continue with /surface7 sometime after the walls are completed and any marked trees are chopped down, whenever you have enough dwarves to build the roof without starving other important construction tasks.) build traps and remaining walls/floors" walls/surface_walls floors/surface_floors traps/surface_traps @@ -384,17 +373,26 @@ roof4/surface_roof4 corridor_gates/surface_corridor_gates corridor/surface_corridor corridor_traps/surface_corridor_traps -query_corridor/surface_query_corridor -#dig label(central_stairs_odd) start(2;2) hidden() spiral stairs odd levels +#dig label(central_stairs_odd) start(2;2) hidden() carved spiral stairs odd levels `,j6,` u,`,u `,j6,` -#meta label(central_stairs_even) hidden() spiral stairs even levels +#meta label(central_stairs_even) hidden() carved spiral stairs even levels /central_stairs_odd transform(cw) -#meta label(central_stairs) two levels of spiral stairs (use --repeat down) +#meta label(central_stairs) two levels of carved spiral stairs (repeat down as needed) /central_stairs_odd #> /central_stairs_even +#build label(central_stairs_odd_constructed) start(2;2) hidden() constructed spiral stairs odd levels +`,Cd,` +Cu,`,Cu +`,Cd,` +#meta label(central_stairs_even_constructed) hidden() constructed spiral stairs even levels +/central_stairs_odd_constructed transform(cw) +#meta label(central_stairs_constructed) two levels of constructed spiral stairs (repeat down as needed) +/central_stairs_odd_constructed +#> +/central_stairs_even_constructed #dig label(surface_clear_small) start(19; 19) hidden() clear trees for starting workshops and stockpiles @@ -417,7 +415,7 @@ u,`,u ,,,`,,`,,,,,,,,,,`,t1,j,t1,j,t1,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,t1,t1,t1,t1,t1,,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,`,t1,t1,t1,t1,t1,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` ,,,`,,`,,,,,,,,,`,t1,,,,,,t1,`,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,t1,t1,,,,,,t1,t1,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,t1,t1,,t1,t1,t1,,t1,t1,,,,,,,,,`,,` @@ -435,98 +433,30 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,nmt(25x11),,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),`,,,,,,`,nt(9x5),,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,nt,nt,nt,nt,nt,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,nt,`,~,`,nt,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,nt,nt,nt,nt,nt,,,,,,,,,,,`,,` -,,,`,,`,,`,n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),n(1x1),`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,n,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,n,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#query label(surface_name_zones) start(19; 19) hidden() - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,"{namezone name=""main pasture""}",,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,"{namezone name=""nestbox1""}","{namezone name=""nestbox2""}","{namezone name=""nestbox3""}","{namezone name=""nestbox4""}","{namezone name=""nestbox5""}","{namezone name=""nestbox6""}","{namezone name=""nestbox7""}",`,,,,,,`,"{namezone name=""taming area""}",,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,"{namezone name=""guard dogs""}",,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,"{namezone name=""nestbox8""}","{namezone name=""nestbox9""}","{namezone name=""nestbox10""}","{namezone name=""nestbox11""}","{namezone name=""nestbox12""}","{namezone name=""nestbox13""}","{namezone name=""nestbox14""}",`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,"{namezone name=""siege bait""}",,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,"{namezone name=""prisoner processing""}",,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#build label(surface_build_start) start(19; 19) hidden() message(There is room to the left of the carpenter's workshop to build one more workshop of any type if you need it.) starting workshops - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,"n{name=""Main pasture""}(25x11)",,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,"t{name=""Pet training area""}(9x5)",,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,wc,,,,wr,,,,wm,,,,wt,,,,,D,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,N,N,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,"n{name=""Nestbox 1""}(1x1)","n{name=""Nestbox 2""}(1x1)","n{name=""Nestbox 3""}(1x1)","n{name=""Nestbox 4""}(1x1)","n{name=""Nestbox 5""}(1x1)","n{name=""Nestbox 6""}(1x1)","n{name=""Nestbox 7""}(1x1)",`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,"n/guarddogs{name=""Guard dogs""}(5x1)",~,~,~,~,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,n/guarddogs(5x1),~,~,~,~,,,,,,,,,,,`,,` +,,,`,,`,,`,"n{name=""Nestbox 8""}(1x1)","n{name=""Nestbox 9""}(1x1)","n{name=""Nestbox 10""}(1x1)","n{name=""Nestbox 11""}(1x1)","n{name=""Nestbox 12""}(1x1)","n{name=""Nestbox 13""}(1x1)","n{name=""Nestbox 14""}(1x1)",`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,"B{name=""Surface barracks""}(8x5)",,,,,,,,`,,,,,,,,`,"m{name=""Welcome area/wagon parking lot""}(8x5)",,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,"n{name=""Siege bait pasture""}",,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,"t{name=""Caged wildlife taming area""}(1x1)",,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,"n{name=""Prisoner processing pen""}(1x-2)",`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` ,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` ,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` @@ -537,9 +467,9 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,"gunzSpd{name=""Starting misc"" containers=0}(8x2)",,,,,,,,"hlr{name=""Starting cloth/trash"" containers=0}(8x2)",,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,f(8x4),,,,,,,,w(4x4),,,,s2(5x4),,,,,gunzSpd(4x4),,,,hlr(4x4),,,,`,,` +,,,`,,`,"f{name=""Starting food""}(8x4)",,,,,,,,"w{name=""Starting wood""}(4x4)",,,,"s2{name=""Starting stone""}:=otherstone(6x4)",,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` @@ -554,7 +484,7 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` ,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` @@ -566,29 +496,29 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway -#query label(surface_query_start) start(19; 19) hidden() config stockpiles +#build label(surface_build_start) start(19; 19) hidden() message(There is room to the left of the carpenter's workshop to build one more workshop of any type if you need it.) starting workshops ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,`,`,"D{name=""Starter trade depot""}",`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,"{givename name=""starting food""}",,,,"{givename name=""starting wood""}",,,,,"{givename name=""starting stone""}",,,,"{givename name=""starting misc""}",,,,"{givename name=""starting cloth/trash""}",`,,` -,,,`,,`,,,,,,,,,,,,,otherstone,,,,,nocontainers,,,,nocontainers,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,,,,,,,,,,`,,` +,,,`,,`,`,"wt{name=""Starter mechanic's""}",`,,`,"wc{name=""Starter carpenter""}",`,,`,"wr{name=""Starter craftsdwarf's""}",`,,`,"wm{name=""Starter stoneworker's""}",`,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,,`,N,N,,,,,,`,,,,,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` ,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` @@ -622,7 +552,7 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` ,,,`,,`,,,,,,,,,`,h1,,,,,,h1,`,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,h1,h1,,,,,,h1,h1,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,h1,h1,,h1,h1,h1,,h1,h1,,,,,,,,,`,,` @@ -656,7 +586,7 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,t1,t1 -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,t1,t1 +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,t1,t1 ,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,t1,t1 ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,t1,t1 ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,t1,t1 @@ -690,7 +620,7 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` ,,,`,,`,,,,,,,,,`,Cf,,,,,,Cf,`,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,Cf,Cf,,,,,,Cf,Cf,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,Cf,Cf,,Cf,Cf,Cf,,Cf,Cf,,,,,,,,,`,,` @@ -724,7 +654,7 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,,,,,,,,,,Cw,,H,~,H,,Cw,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,Cf,,`,`,`,,Cf,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,Cw,,,,,,Cw,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,Cw,Cw,Cf,Cw,Cf,Cw,Cw,`,`,,`,`,`,`,`,`,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,Cw,Cw,Cf,Cw,Cf,Cw,Cw,`,`,,,,,,,,`,,` ,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` @@ -792,7 +722,7 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,d,,`,`,`,,d,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,d,`,d,`,`,`,`,,`,`,`,`,`,`,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,d,`,d,`,`,`,`,,,,,,,,`,,` ,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` @@ -825,14 +755,14 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,~,~,~,~,~,~,~,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,~,~,~,~,~,~,~,Cf,Cf,Cf,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,Cf,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,~,`,~,`,`,`,`,Cf,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,Cf,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,Cf,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,Cf,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,Cf,`,,` +,,,`,,`,,`,,,,,Cf,Cf,Cf,~,~,~,~,~,~,~,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,Cf,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,Cf,`,`,`,`,~,`,~,`,`,`,`,,,,,,,,`,,` +,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,Cf,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,Cf,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,Cf,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,Cf,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` ,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` ,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` @@ -856,24 +786,24 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,Cf,,Cf,,Cf,`,,,,,,,,,,`,,` -,,,`,,`,,Cw,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,Cf,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` -,,,`,,`,,Cw,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,Cw,Cf,Cw,`,`,`,,`,,`,`,`,Cw,Cf,Cw,`,`,`,`,`,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,,,,,,~,`,,,,,,,Cf,Cf,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,Cf,Cf,Cf,Cf,Cf,~,~,,,,,,,,Cf,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,,~,~,~,,~,~,,,,,Cf,Cf,,Cf,`,,` -,,,`,,`,,Cf,,Cf,Cf,Cf,Cf,Cf,,Cf,,~,~,~,,Cf,,,Cf,,,,,,Cf,`,,` -,,,`,,`,,Cf,,Cf,Cf,Cf,Cf,Cf,`,,,~,~,~,,,`,,Cf,,,,,Cf,Cf,`,,` +,,,`,,`,,`,,,,,,,,`,Cf,,Cf,,Cf,`,Cf,Cf,,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cw,,,,,,,,,,`,`,`,,,Cf,Cf,,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cf,,,,,,,,`,,`,`,`,,`,Cf,Cf,,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,Cw,,,,,,,,,,`,`,`,,,Cf,Cf,,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,,`,,,,,,,,`,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,,Cf,Cf,Cf,Cf,Cf,,`,,` +,,,`,,`,`,`,`,`,`,Cw,Cf,Cw,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,Cf,Cf,,Cf,Cf,,,,`,~,Cf,Cf,Cf,Cf,Cf,~,`,,,,,,,,,`,,` +,,,`,,`,Cf,,,,,,,,~,~,Cf,Cf,Cf,Cf,Cf,~,~,,,,,,,,,`,,` +,,,`,,`,Cf,,,,,,,,~,~,,~,~,~,,~,~,,,,,,,,,`,,` +,,,`,,`,Cf,,,,,,Cf,,Cf,Cf,,~,~,~,,Cf,Cf,,,,,,,,,`,,` +,,,`,,`,Cf,Cf,,,,,Cf,,`,,,~,~,~,,,`,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,Cf,,,,,,,,,Cf,,,,,~,,,,,Cf,,,,,,,,,Cf,` +,,,`,Cf,Cf,,,,,,,,Cf,Cf,,,,~,,,,Cf,Cf,,,,,,,,Cf,Cf,` ,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` -#place label(surface_place) start(19; 19) hidden() remaining surface stockpiles +#dig label(surface_traffic) start(19; 19) hidden() set traffic designations @@ -890,64 +820,26 @@ Feel free to assign an unimportant animal to the pasture in the main entranceway ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,a5(9x5),,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,g(3x3),,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,c,,,,,,,`,,,,,,,,`,,c,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,or,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,`,or,or,ol,ol,ol,ol,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,ol,ol,or,ol,ol,ol,ol,ol,ol,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,ol,ol,or,,,,,ol,ol,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,ol,ol,or,,,,,ol,ol,,,,,,,,,`,,` +,,,`,,`,,,,,,,,or,`,or,or,,,,,,`,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` ,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -"#build label(surface_build) start(19; 19) hidden() message(Use autofarm to manage farm crop selection. -Remember to connect the levers to the gates once they are built.) gates, barracks, farm area, and trade area" - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,~h,`,~,~,N,N,N,N,N,`,Tl,,Tl,,Tl,`,,,,,,,,,,`,,` -,,,`,,`,~h,`,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,~h,d,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),`,,`,`,`,,`,,,,,,,,,,`,,` -,,,`,,`,~h,`,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,~h,`,N,N,N,N,N,N,N,`,Tl,Tl,Tl,Tl,Tl,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,d,`,`,`,`,,`,,`,`,`,`,d,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,gw,gw,gw,gw,gw,,`,,,,,,,h,b,`,,` -,,,`,,`,,,,,,,,,ga,ga,gw,gw,gw,gw,gw,gd,gd,,,,,,,,b,`,,` -,,,`,,`,,,,,,D,,,ga,ga,,,,,,gd,gd,,,,,a,r,,b,`,,` -,,,`,,`,,trackstopS,,,,,,,ga,ga,,,,,,gd,gd,,trackstopS,,,,,,b,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,h,b,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,gd,gd,,,,,,,,gd,gd,,,,,,,,ga,ga,,,,,,,,ga,ga,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,gw,gw,gw,gw,gw,gw,gw,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,gw,gw,gw,gw,gw,gw,gw -,,,,,,,,,,,,,,,gw,gw,gw,gw,gw,gw,gw - -#aliases -"prisoner_route_enable: {enableanimals}{cages}{permittraps}{animalsprefix}{Right}{permitsearch search="" men""}{permitsearch search=dwarves}{permitsearch search=elves}{permitsearch search=humans}{permitsearch search=kobolds}{permitsearch search=gremlins}{permitsearch search=giants}{permitsearch search=goblins}{permitsearch search=ettins}{permitsearch search=cyclopes}{permitsearch search=ogres}{permitsearch search=eyes}{permitsearch search=reachers}{permitsearch search=gorlaks}{permitsearch search=trolls}{permitsearch search=minotaurs}^" +,,,`,`,`,`,`,`,`,`,`,`,`,`,ol,ol,ol,ol,ol,ol,ol,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,ol,ol,ol,ol,ol,ol,ol +,,,,,,,,,,,,,,,ol,ol,ol,ol,ol,ol,ol -"#query label(surface_query) start(19; 19) hidden() message(Remember to assign minecarts to the trade goods and prisoner processing quantum stockpiles (run ""assign-minecarts all""). +"#place label(surface_place) start(19; 19) hidden() message(Remember to assign minecarts to the trade goods and prisoner processing quantum stockpiles (run ""assign-minecarts all""). Feel free to adjust the configuration of the ""trade goods"" feeder stockpile so it accepts the item types you want to trade away. If those items types are also accepted by other stockpiles, configure those stockpiles to give to the ""trade goods"" stockpile. -You might also want to set the ""trade goods quantum"" stockpile to Auto Trade if you have the autotrade DFHack plugin enabled.)" +You might also want to set the ""trade goods quantum"" stockpile to autotrade.) remaining surface stockpiles" @@ -958,30 +850,32 @@ You might also want to set the ""trade goods quantum"" stockpile to Auto Trade i ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,"a{name=""Pets/Prisoner feeder""}(9x5)",,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,"{givename name=""trade depo gate""}",,"{givename name=""inner main gate""}",,"{givename name=""barracks gate""}",`,"{givename name=""prison/training area""}",,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,"c{name=""Organic trade goods quantum"" quantum=true}:+all",,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,`,`,`,,,"g{name=""Trade goods"" containers=0}:-cat_finished_goods/type/,core/artifact+crafts(2x3)",,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,"{givename name=""left outer gate""}","{givename name=""left inner gate""}","{givename name=""outer main gate""}","{givename name=""right inner gate""}","{givename name=""right outer gate""}",`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,nocontainers,crafts,,,,,,,`,,,,"{givename name=""inner main gate""}",,,,`,,,,,,,,,`,,` -,,,`,,`,"{givename name=""trade goods""}",,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,{forbidmasterworkfinishedgoods}{forbidartifactfinishedgoods},,,,,,,,"{givename name=""trade depo gate""}",,,,,,,,"{givename name=""barracks gate""}",,,,,,,,,`,,` -,,,`,,`,,"{quantumstopfromnorth name=""Trade Goods quantum""}",,,,,,,,,,,,,,,,,"{quantumstop name=""Prisoner/Cage quantum"" move={Up 5} move_back={Down 5} route_enable={prisoner_route_enable}}{givename name=""prisoner/cage dumper""}",,,,,,,`,,` -,,,`,,`,,"{quantum name=""trade goods quantum""}",,,,,,,`,,,,,,,,`,,"{quantum name=""prisoner/cage quantum"" quantum_enable={enableanimals}}",,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,"c{name=""Inorganic trade goods quantum"" quantum=true}:+all-organic",,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,"a{name=""Prisoner/cage quantum"" quantum=true}",,`,,,,,,,,`,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,"{givename name=""left outer gate""}",,,,,,,,,"{givename name=""left inner gate""}",,,,,,,,"{givename name=""right inner gate""}",,,,,,,,,"{givename name=""right outer gate""}",,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,"{givename name=""outer main gate""}",,,,`,`,`,`,`,`,`,`,`,`,`,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` -#dig label(surface_traffic) start(19; 19) hidden() set traffic designations +#aliases +"#build label(surface_build) start(19; 19) hidden() message(Use autofarm to manage farm crop selection. +Remember to connect the levers to the gates once they are built.) gates, barracks, farm area, and trade area" @@ -998,22 +892,22 @@ You might also want to set the ""trade goods quantum"" stockpile to Auto Trade i ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,or,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,ol,ol,ol,ol,ol,,`,or,,,,,,,,`,,` -,,,`,,`,,,,,,,,,ol,ol,ol,ol,ol,ol,ol,ol,ol,or,,,,,,,,`,,` -,,,`,,`,,,,,,,,,ol,ol,,,,,,ol,ol,or,,,,,,,,`,,` -,,,`,,`,,,,,,,,,ol,ol,,,,,,ol,ol,or,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,or,,,,,,,,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,~,~,N,N,N,N,N,`,"Tl{name=""Barracks gate""}",,"Tl{name=""Inner main gate""}",,"Tl{name=""Trade depo gate""}",`,"trackstopE{name=""Organic trade goods dumper"" take_from=""Trade goods"" route=""Organic trade goods quantum""}",,,~,~,~,~,~,,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),,,`,`,`,,,,,,~,~,~,~,~,,`,,` +,,,`,,`,"~h{name=""reserved for splitting"" do_install=true}(1x1)",d,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),`,,`,`,`,,`,,,,~,~,D,~,~,,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),p(1x1),,,`,`,`,,,,,,~,~,~,~,~,,`,,` +,,,`,,`,~h{do_install=true do_gather=true}(1x1),`,N,N,N,N,N,N,N,`,"Tl{name=""Left outer gate""}(1x1)","Tl{name=""Left inner gate""}(1x1)","Tl{name=""Outer main gate""}(1x1)","Tl{name=""Right inner gate""}(1x1)","Tl{name=""Right outer gate""}(1x1)",`,"trackstopE{name=""Inorganic trade goods dumper"" take_from=""Trade goods,Organic trade goods quantum"" route=""Inorganic trade goods quantum""}:-organic",,,~,~,~,~,~,,`,,` +,,,`,,`,`,`,`,`,`,`,d,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,b,h,,a,r,,,,`,,"gw{name=""Inner main gate""}",gw,gw,gw,gw,,`,,,,,,,,,`,,` +,,,`,,`,b,,,,,,,,"ga{name=""Barracks gate""}",ga,gw,gw,gw,gw,gw,"gd{name=""Trade depo gate""}",gd,,,,,,,,,`,,` +,,,`,,`,b,,,,,,,,ga,ga,,,,,,gd,gd,,,,,,,,,`,,` +,,,`,,`,b,,,,,,"trackstopS{name=""Prisoner/cage dumper"" take_from=""Pets/Prisoner feeder"" route=""Prisoner/cage quantum""}:-cat_animals/tameable",,ga,ga,,,,,,gd,gd,,,,,,,,,`,,` +,,,`,,`,b,h,,,,,,,`,,,,,,,,`,s,,s,,,s,,s,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,ol,ol,ol,ol,ol,ol,ol,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,ol,ol,ol,ol,ol,ol,ol -,,,,,,,,,,,,,,,ol,ol,ol,ol,ol,ol,ol +,,,`,"gd{name=""Left outer gate""}",gd,,,,,,,,"gd{name=""Left inner gate""}",gd,,,,,,,,"ga{name=""Right inner gate""}",ga,,,,,,,,"ga{name=""Right outer gate""}",ga,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,"gw{name=""Outer main gate""}",gw,gw,gw,gw,gw,gw,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,gw,gw,gw,gw,gw,gw,gw +,,,,,,,,,,,,,,,gw,gw,gw,gw,gw,gw,gw #dig label(surface_clear_large) start(19; 19) hidden() clear wider area of trees t1(37x33) @@ -1031,51 +925,17 @@ t1(37x33) ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,,`,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,`,,`,~,`,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` ,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#query label(surface_query2) start(19; 19) hidden() - - - -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,cg,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,cg,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,c,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` -,,,`,,`,cg,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,cg,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,r&,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` ,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` @@ -1105,7 +965,7 @@ t1(37x33) ,,,`,,Cw,,,,,,,,,,~,,`,`,`,,~,,,,,,,,,,Cw,,` ,,,`,,Cw,,~,,,,,,,,,,`,`,`,,,,,,,,,,,,Cw,,` ,,,`,,Cw,,Cw,,,,,,,,~,,,,,,~,,,,,,,,,,Cw,,` -,,,`,,Cw,Cw,Cw,Cw,Cw,Cw,~,,~,Cw,~,~,,~,,~,~,Cw,~,,~,Cw,Cw,Cw,Cw,Cw,Cw,,` +,,,`,,Cw,Cw,Cw,Cw,Cw,Cw,~,,~,Cw,~,~,,~,,~,~,Cw,Cw,,,,,,,,Cw,,` ,,,`,,Cw,,,,,,,,,Cw,,,,,,,,Cw,,,,,,,,,Cw,,` ,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` ,,,`,,Cw,,,,,,,,,,,,,,,,,,,,,,,,,,Cw,,` @@ -1134,17 +994,17 @@ t1(37x33) ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,~,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,~,Cf,~,Cf,~,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,~,Cf,Cf,Cf,Cf,Cf,~,,,,,,,,,,`,,` -,,,`,,`,,~,,,,,,,,`,Cf,`,Cf,`,Cf,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,~,Cf,Cf,Cf,Cf,Cf,~,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,~,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,~,~,~,~,~,~,~,~,~,~,Cf,~,~,~,Cf,~,~,Cf,Cf,Cf,Cf,~,~,Cf,~,`,,` -,,,`,,`,Cf,~,Cf,~,~,~,~,~,~,~,Cf,~,~,~,Cf,~,~,Cf,~,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,Cf,~,Cf,~,~,~,~,~,`,Cf,Cf,~,~,~,Cf,Cf,`,Cf,~,Cf,Cf,Cf,Cf,~,~,`,,` +,,,`,,`,,`,,,,,,,,`,~,Cf,~,Cf,~,`,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,`,,,,,,,,~,Cf,Cf,Cf,Cf,Cf,~,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,~,,,,,,,,`,Cf,`,Cf,`,Cf,`,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,`,,,,,,,,~,Cf,Cf,Cf,Cf,Cf,~,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,~,~,Cf,~,~,~,~,~,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,Cf,~,~,Cf,Cf,Cf,`,~,~,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,Cf,~,~,~,Cf,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,Cf,Cf,Cf,Cf,Cf,~,Cf,~,~,Cf,~,~,~,Cf,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,Cf,Cf,Cf,Cf,~,Cf,`,Cf,Cf,~,~,~,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,,` ,,,`,~,,,,,,,,,,,Cf,Cf,Cf,~,Cf,Cf,Cf,,,,,,,,,,,~,` ,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` @@ -1153,8 +1013,8 @@ t1(37x33) #build label(surface_traps) start(19; 19) hidden() -,,,,,Tc,Tc,,,,,,,,,,,,,,,,,,,,,,,,Tc,Tc -,,,,,Tc,Tc,,,,,,,,,,,,,,,,,,,,,,,,Tc,Tc +,,,,,Tc,,,,,,,,,,,,,,,,,,,,,,,,,,Tc +,,,,,Tc,,,,,,,,,,,,,,,,,,,,,,,,,,Tc ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` @@ -1173,7 +1033,7 @@ t1(37x33) ,,,`,,`,,,,,,,,,,`,,`,`,`,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` ,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` @@ -1205,14 +1065,14 @@ t1(37x33) ,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,~,~,~,~,~,~,~,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,~,~,~,~,~,~,~,~,~,~,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,~,~,~,~,~,`,,,~,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,~,~,~,~,~,~,~,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,~,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,~,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,~,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,~,`,,` +,,,`,,`,,`,,,,,~,~,~,~,~,~,~,~,~,~,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,~,,,`,~,~,~,~,~,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,,,,,,,,`,,` +,,,`,,`,~,~,~,~,~,~,~,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,~,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,~,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,~,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,~,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` ,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` ,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` @@ -1239,14 +1099,14 @@ t1(37x33) ,,,`,,`,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` ,,,`,,`,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` ,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` -,,,`,,`,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,~,~,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,`,,` -,,,`,,`,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,~,Cf,Cf,Cf,Cf,Cf,Cf,`,,` -,,,`,,`,`,`,`,`,`,`,Cf,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,~,~,~,~,~,~,~,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` -,,,`,,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,~,`,,` +,,,`,,`,Cf,`,Cf,Cf,Cf,Cf,~,~,~,~,~,~,~,~,~,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,Cf,`,Cf,Cf,Cf,Cf,~,Cf,Cf,`,~,~,~,~,~,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,~,~,~,~,~,~,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` +,,,`,,`,~,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,,` ,,,`,,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,Cf,,` ,,,`,`,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,`,` @@ -1275,7 +1135,7 @@ t1(37x33) ,,,`,,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` ,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` ,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,~,~,~,~,~,~,`,,` ,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` ,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` ,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` @@ -1309,7 +1169,7 @@ t1(37x33) ,,,`,,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` ,,,`,,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` ,,,`,,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,,` -,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,,` +,,,`,,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,~,~,~,~,~,~,`,,` ,,,`,,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,,` ,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` ,,,`,,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,,` @@ -1321,10 +1181,10 @@ t1(37x33) -#build label(surface_corridor_gates) start(19; 19) hidden() gates for the longer trap hallways +#build label(surface_corridor_gates) start(19; 19) hidden() message(Remember to connect the levers to the new external trap gates.) gates for the longer trap hallways -,,,,gx,,,,,,,,,,,,,,,,,,,,,,,,,,,,gx +,,,,"gx{name=""Left trap gate""}",,,,,,,,,,,,,,,,,,,,,,,,,,,,"gx{name=""Right trap gate""}" ,,,`,gx,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,gx,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` @@ -1340,10 +1200,10 @@ t1(37x33) ,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,Tl,`,`,`,Tl,`,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,"Tl{name=""Left trap gate""}",`,`,`,"Tl{name=""Right trap gate""}",`,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` ,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` ,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` @@ -1377,7 +1237,7 @@ t1(37x33) ,,,Cw,,`,,,,,,,,,,`,~,`,`,`,~,`,,,,,,,,,,`,,Cw ,,,Cw,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,Cw ,,,Cw,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,Cw -,,,Cw,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,Cw +,,,Cw,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,Cw ,,,Cw,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,Cw ,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw ,,,Cw,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,Cw @@ -1411,7 +1271,7 @@ t1(37x33) ,,,`,Cf,`,~,~,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,Cf,` ,,,`,Cf,`,~,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` ,,,`,Cf,`,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,`,~,~,~,~,~,~,~,~,~,`,Cf,` -,,,`,Cf,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,`,`,`,`,`,`,`,Cf,` +,,,`,Cf,`,`,`,`,`,`,`,~,`,`,`,`,~,`,~,`,`,`,`,~,~,~,~,~,~,~,`,Cf,` ,,,`,Cf,`,~,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,`,~,~,~,~,~,~,~,~,`,Cf,` ,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` ,,,`,Cf,`,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,~,`,Cf,` @@ -1426,8 +1286,8 @@ t1(37x33) #build label(surface_corridor_traps) start(19; 19) hidden() traps for the longer trap hallways -,,,,~,,,,,,,,,,,,,,,,,,,,,,,,,,,,~ -,,,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,~,` +,,Tc,Tc,~,,,,,,,,,,,,,,,,,,,,,,,,,,,,~,Tc,Tc +,,Tc,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,Tc ,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` ,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` ,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` @@ -1445,7 +1305,7 @@ t1(37x33) ,,,`,Tc,`,,,,,,,,,,`,~,`,`,`,~,`,,,,,,,,,,`,Tc,` ,,,`,Tc,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,Tc,` ,,,`,Tc,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,Tc,` -,,,`,Tc,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,Tc,` +,,,`,Tc,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,Tc,` ,,,`,Tc,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,Tc,` ,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` ,,,`,Tc,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,Tc,` @@ -1453,42 +1313,8 @@ t1(37x33) ,,,`,Tc,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,Tc,` ,,,`,Tc,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,Tc,` ,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - - - -#query label(surface_query_corridor) start(19; 19) hidden() (Remember to connect the levers to the new external trap gates.) configure barracks and name outer levers/gates - - - -,,,`,"{givename name=""left trap gate""}",`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,"{givename name=""right trap gate""}",` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,`,"{givename name=""left trap gate""}",`,`,`,"{givename name=""right trap gate""}",`,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,,,`,`,`,,,,,,,,,,,,`,,` -,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,`,`,`,`,`,`,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` -,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` -,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` - +,,Tc,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,Tc +,,Tc,Tc,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Tc,Tc #notes label(farming_help) @@ -1497,7 +1323,7 @@ Screenshot: https://drive.google.com/file/d/1fBC3G5Y888l4tVe5REAyAd_zeojADVme "" Features: - Pairs with the surface blueprints for vents that prevent miasma -- Farm plots (intended to be managed by DFHack autofarm) +- Farm plots (can be managed by DFHack autofarm) - Plentiful food storage - Refuse/corpse quantum stockpile - Small dormitory and dining room for post-embark needs @@ -1514,25 +1340,21 @@ Workshops: - Screw Press "" Manual steps you have to take: -- Check to make sure the lower office is assigned to your manager and assign the upper office to your bookkeeper (if different from your manager) "- Assign a minecart to your refuse quantum stockpile hauling route (you can run ""assign-minecarts all"" at the DFHack prompt to do this)" -"- If the industry level is already built, configure the jugs, pots, and bags stockpiles to take from the ""Goods"" quantum stockpile (the one on the left) on the industry level" "" Farming Walkthrough: "1) Wait until you have channeled the miasma vents and cleared trees on the surface before digging out the farming level on the z-level below the surface, otherwise you will end up with extra ramps on the farming level and unprotected holes through the surface when you later chop down trees growing above empty space." "" -"2) Start digging with /farming1 and get started on manufacturing furniture by running ""quickfort orders"" on /farming2 and /farming3." +"2) Start digging with /farming1 and get started on manufacturing furniture by running ""quickfort orders"" on /farming2" "" -"3) Once the level is dug out, run /farming2 to build workshops, stockpiles, and the furniture we need to anchor the rooms. Remember to assign a minecart to the newly-designated quantum refuse dump. There are also jugs, pots, and bags stockpiles on this level that should be configured to ""take"" from the industry level stockpile once we get the industry level built." +"3) Once the level is dug out, run /farming2 to designate zones, build workshops and stockpiles, and place furniture. Remember to assign a minecart to the newly-designated quantum refuse dump." "" -"4) When the furniture is in place, run /farming3 to designate your starter dining room and dormitory and build the farm plots and remaining furniture. The blueprint also attempts to assign the lower office to your manager, but double-check this assignment in case your dwarves are in an unexpected order." +"4) Once your fort has enough free time to build the remaining doors, run /farming3. Run ""quickfort orders"" for /farming3." "" -"5) Once your fort has enough free time to build the remaining doors, run /farming4. This will also enable seasonal fertilization for your farm plots. Run ""quickfort orders"" for /farming4." -"" -"6) You can disassemble the dining room and dormitory once the services and apartments levels are up and running, if you like." +"5) You can disassemble the dining room and dormitory once the services and apartments levels are up and running, if you like." "#dig label(farming1) start(16; 18; central stairs) message(Once the area is dug out, continue with /farming2.)" -# this level is dug at priority 2 since it is dug in soil. it's worth the miner's time to stop digging the industry level and -# quickly dig out this one. +# this level is dug at priority 2 since it is dug in soil. it's worth the miner's time to +# stop digging the industry level and quickly dig out this one. ,,,,,,,,,2,2,2,,2,2,2,2,2,,2,2,2,2 ,,,,,,,,,2,2,2,,2,2,2,2,2,,2,2,2,2 ,,,,,,,,,2,2,2,,2,2,2,2,2,,2,2,2,2 @@ -1563,35 +1385,29 @@ Farming Walkthrough: "#meta label(farming2) start(central stairs) message(Remember to enqueue manager orders for this blueprint. Once furniture has been placed, continue with /farming3.) workshops, stockpiles, and important furniture" -build/farming_build +zone/farming_zone place/farming_place +build/farming_build traffic/farming_traffic -query_stockpiles/farming_query_stockpiles -link_stockpiles/farming_link -"" -#meta label(farming3) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) configure rooms and build farm plots and more furniture -query_rooms/farming_rooms -build2/farming_build2 "" -#meta label(farming4) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) configure farm plots and build remaining furniture -query_plots/farming_query_plots -build3/farming_build3 -#build label(farming_build) start(16; 18) hidden() workshops and important furniture +#meta label(farming3) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) build remaining doors +doors/farming_doors +#zone label(farming_zone) start(16; 18) hidden() rooms -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,c,t,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,t,c +,,,,,,,,,T{pets=true}(1x1),`,`,,`,`,`,`,`,,"h{name=""Starter dining hall""}(4x6)",,,` +,,,,,,,,,T{pets=true}(1x1),`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,,,T{pets=true}(1x1),`,`,,`,`,`,`,`,,`,`,`,` ,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,c,t,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,b +,,,,,,,"o{name=""Manager's office"" assigned_unit=manager}(3x1)",,`,,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,` +,,,,,,,"o{name=""Bookkeeper's office"" assigned_unit=bookkeeper}(3x1)",,`,,`,,`,`,`,`,`,,` +,,,,,,,,,,,`,,`,`,`,`,`,,`,,"D{name=""Starter dormitory""}(3x3)",,` ,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,`,` -,,,,,,`,wl,`,`,,`,,`,`,`,`,`,,`,,`,`,` +,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,` ,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` -,,wq,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,wp,`,`,`,`,ww,`,`,`,`,,,`,,`,,,`,`,`,wu,`,`,`,wz,` +,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` ,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` ,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` ,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` @@ -1602,40 +1418,71 @@ build3/farming_build3 ,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,wh,`,,`,`,`,,`,wn,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,trackstopS,,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` ,,,,,,,,,,,,,,,` -#place label(farming_place) start(16; 18) hidden() stockpiles +"#place label(farming_place) start(16; 18) hidden() message(remember to assign a minecart to the refuse quantum stockpile (run ""assign-minecarts all"")" -,,,,,,,,,`,`,`,,`,`,`,f10(1x9),b(1x12),,f(4x2),,,` +,,,,,,,,,`,`,`,,`,`,`,"c{name=""Seeds"" barrels=10 links_only=true take_from=""Starting food""}:+seeds(1x9)","c{name=""Potash""}:+potash(1x12)",,"c{name=""booze"" barrels=-1 take_from=""Starting food""}:+booze(4x2)",,,` ,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` ,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` ,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,f(3x2),,` +,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,"c{name=""Prepared food"" take_from=""Starting food""}:+preparedmeals(3x2)",,` ,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,` ,,,,,,,`,`,`,,`,,`,`,`,`,`,,` ,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,` -,,,,,,`,`,`,u,,`,,`,`,`,`,`,,`,`,`,`,` -,,,,,,`,`,`,u,,`,,f(4x3),,,`,`,,`,,`,`,` -,,,u,u,,`,`,`,u,,`,,`,`,`,`,`,,` -,,`,u,u,,`,`,`,u,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,g,g,`,`,`,`,u,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,g,g,,`,`,`,u,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,,,,,,`,`,`,"u{name=""Pots"" take_from=""Starting misc""}:-cat_furniture/type+pots(1x4)",,`,,`,`,`,`,`,,`,`,`,`,` +,,,,,,`,`,`,~,,`,,"c{name=""Seeds feeder"" give_to=""Seeds"" take_from=""Starting food""}:+seeds(4x3)",,,,`,,`,,`,`,` +,,,"u{name=""Bags"" take_from=""Starting misc""}:-cat_furniture/type+bags(2x2)",~,,`,`,`,~,,`,,`,`,`,`,`,,` +,,`,~,~,,`,`,`,~,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,`,"c{name=""Jugs"" take_from=""Starting misc""}:+cat_finished_goods/core,total+woodtools(2x2)",~,`,`,`,`,"u{name=""Barrels"" take_from=""Starting misc,Starting food""}:-cat_furniture/type+barrels(1x2)",`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` +,,,~,~,,`,`,`,~,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` +,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` +,,"c{name=""Plants"" barrels=-1 take_from=""Starting food""}:+plants",c,c,c,c,c,c,c,c,c,,`,`,~,`,`,,"c{name=""Cookable food"" barrels=-1 take_from=""Starting food""}:+cat_food/meat/,fish/prepared/,egg/,cheese/,leaves/,powder/,glob/,liquid/plant/,paste/,pressed/,milk,royal_jelly-dye-cat_food/tallow,thread,liquid/misc/",c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,c,c,`,`,`,`,`,`,`,c,c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,c,c,,`,`,`,`,`,,c,c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,c,,,,`,,`,,,,c,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,,,c,`,`,`,`,`,c,,,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,c,,"c{name=""Unprepared fish"" take_from=""Starting food""}:+unpreparedfish",c,,,`,,,"c{name=""Rawhides"" take_from=""Starting cloth/trash""}:+rawhides",c,,c,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,,c,c,,"c{name=""Refuse feeder"" give_to=""Rawhides"" take_from=""Starting cloth/trash""}:+cat_refuse/type(1x3)","y{name=""Corpse feeder"" take_from=""Starting cloth/trash""}:+cat_refuse/corpses,bodyparts(2x3)",~,,c,c,,,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,`,`,`,,~,~,~,,`,`,`,,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,`,`,`,,~,~,~,,`,`,`,,c,c,c,c,c,c,c +,,c,c,c,c,c,c,c,,`,`,`,,,`,,,`,`,`,,c,c,c,c,c,c,c +,,,,,,,,,,,,,,,"ry{name=""Refuse/corpse quantum"" give_to=""Rawhides"" quantum=true}" + + +#build label(farming_build) start(16; 18) hidden() workshops and important furniture + + +,,,,,,,,,n,`,`,,p{seasonal_fertilize=true}(3x1),,,`,`,,`,`,`,` +,,,,,,,,,n,`,`,,p{seasonal_fertilize=true}(3x1),,,`,`,,`,`,`,` +,,,,,,,,,n,`,`,,p{seasonal_fertilize=true}(3x1),,,`,`,,c,t,t,c +,,,,,,,,,,,`,,p{seasonal_fertilize=true}(3x1),,,`,`,,c,t,t,c +,,,,,,,t,c,`,,`,,p{seasonal_fertilize=true}(3x1),,,`,`,,`,`,`,` +,,,,,,,`,`,`,`,`,,p{seasonal_fertilize=true}(3x1),,,`,`,,`,`,`,` +,,,,,,,t,c,`,,`,,p{seasonal_fertilize=true}(3x1),,,`,`,,` +,,,,,,,,,,,`,,p{seasonal_fertilize=true}(3x1),,,`,`,,`,,b,b,b +,,,,,,`,`,`,`,,`,,p{seasonal_fertilize=true}(3x1),,,`,`,,`,`,`,`,h +,,,,,,`,wl,`,`,,`,,`,`,`,`,`,,`,,b,b,b +,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` +,,wq,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` +,,wp,`,`,`,`,ww,`,`,`,`,,,`,,`,,,`,`,`,wu,`,`,`,wz,` +,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` ,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,f,f,f,f,f,f,f,f,f,f,,`,`,~,`,`,,f,f,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,f,f,f,`,`,`,`,`,`,`,f,f,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,f,f,f,,`,`,`,`,`,,f,f,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,f,f,,,,`,,`,,,,f,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,f,,,f,`,`,`,`,`,r,,,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,f,,f,f,,,`,,,r,r,,f,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,,,f,f,,r(2x3),,ry2(1x3),,r,r,,,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,,`,`,`,,`,`,`,,`,`,`,,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,,`,`,`,,`,`,`,,`,`,`,,f,f,f,f,f,f,f -,,f,f,f,f,f,f,f,,`,`,`,,,`,,,`,`,`,,f,f,f,f,f,f,f -,,,,,,,,,,,,,,,ry +,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,,`,d,`,`,`,d,`,,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,,`,`,,,d,,,`,`,,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,wh,`,,`,`,`,,`,wn,`,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,`,`,`,,,"trackstopS{name=""Refuse/corpse dumper"" take_from=""Refuse feeder,Corpse feeder"" route=""Refuse/corpse quantum""}",,,`,`,`,,`,`,`,`,`,`,` +,,,,,,,,,,,,,,,` #dig label(farming_traffic) start(16; 18) hidden() keep hungry dwarves away from the crops and food stores so they prefer the prepared meals @@ -1652,181 +1499,24 @@ build3/farming_build3 ,,,,,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,ol,ol,ol,ol ,,,,,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,,ol,ol,ol ,,,ol,ol,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol -,,ol,ol,ol,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,,ol,ol,ol,,ol,ol,ol -,,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,or,,or,,,ol,ol,ol,ol,ol,ol,ol,ol,ol -,,,ol,ol,,ol,ol,ol,ol,,ol,ol,ol,ol,ol,ol,ol,ol,ol,,ol,ol,ol,,ol,ol,ol +,,ol,ol,ol,,ol,ol,ol,ol,,ol,,or,or,or,or,or,,ol,,or,or,or,,or,or,or +,,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,or,,or,,,ol,or,or,or,or,ol,or,or,or +,,,ol,ol,,ol,ol,ol,ol,,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,,or,or,or ,,,,or,,,or,,,,,,ol,`,`,`,ol,,,,,or,,,,or ,,or,or,or,or,or,or,or,or,or,or,,ol,`,~,`,ol,,or,or,or,or,or,or,or,or,or,or ,,or,or,or,or,or,or,or,or,or,or,or,ol,`,`,`,ol,or,or,or,or,or,or,or,or,or,or,or ,,or,or,or,or,or,or,or,or,or,or,,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,or -,,or,or,or,or,or,or,or,or,or,,,,ol,,ol,,,,or,or,or,or,or,or,or,or,or -,,or,or,or,or,or,or,or,or,,,ol,ol,ol,ol,ol,ol,ol,,,or,or,or,or,or,or,or,or -,,or,or,or,or,or,or,or,or,,ol,ol,,,ol,,,ol,ol,,or,or,or,or,or,or,or,or -,,or,or,or,or,or,or,or,,,ol,ol,,ol,ol,ol,,ol,ol,,,or,or,or,or,or,or,or -,,or,or,or,or,or,or,or,,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,or,or,or,or -,,or,or,or,or,or,or,or,,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,or,or,or,or -,,or,or,or,or,or,or,or,,ol,ol,ol,,,ol,,,ol,ol,ol,,or,or,or,or,or,or,or -,,,,,,,,,,,,,,,ol - +,,or,or,or,or,or,or,or,or,or,,,,or,,or,,,,or,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,,,or,or,or,or,or,or,or,,,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,or,,or,or,,,or,,,or,or,,or,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,,or,or,,or,or,or,,or,or,,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or,or,or,or,or +,,or,or,or,or,or,or,or,,or,or,or,,,or,,,or,or,or,,or,or,or,or,or,or,or +,,,,,,,,,,,,,,,or -"#query label(farming_query_stockpiles) start(16; 18) hidden() message(remember to: -- assign a minecart to the refuse quantum stockpile (run ""assign-minecarts all"") -- if the industry level is already built, configure the jugs, pots, and bags stockpiles to take from the ""Goods"" quantum stockpile on the industry level) config stockpiles" - -,,,,,,,,,`,`,`,,`,`,`,seeds,potash,,booze,,,` -,,,,,,,,,`,`,`,,`,`,`,linksonly,nocontainers,,"{givename name=""booze""}",`,`,` -,,,,,,,,,`,`,`,,`,`,`,"{givename name=""seeds""}","{givename name=""potash""}",,`,`,`,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,preparedfood -,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,"{givename name=""prepared food""}",`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,` -,,,,,,`,`,`,pots,,`,,`,`,`,`,`,,`,`,`,`,` -,,,,,,`,`,`,"{givename name=""pots""}",,`,,seeds,nocontainers,"{givename name=""seeds feeder""}",give2up,`,,`,,`,`,` -,,,bags,,,`,`,`,`,,`,,`,`,`,`,`,,` -,,`,nocontainers,"{givename name=""bags""}",,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,woodentools,,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,nocontainers,"{givename name=""jugs""}",,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,plants,,,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,,,,,,,"{givename name=""cookable food""}" -,,`,,,,"{givename name=""plants""}",`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,forbidplants,,,,,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,forbidtallow,,,,,`,` -,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,forbiddye,,,,`,`,` -,,`,`,`,`,`,`,`,`,,,unpreparedfish,,,,,,rawhides,,,`,forbidunpreparedfish,,,,,,` -,,`,`,`,`,`,`,`,`,,`,nocontainers,,,`,,,"{givename name=""rawhides""}",`,,`,forbidmiscliquid,,,,,,` -,,`,`,`,`,`,`,`,,,`,"{givename name=""unprepared fish""}",,forbidcraftrefuse,"{givename name=""refuse feeder""}",corpses,,t{Left 3}{Down 4}&,`,,,forbidpreparedfood,,,,,,` -,,`,`,`,`,`,`,`,,`,`,`,,forbidcorpses,"{give move=""{Right 3}{Up}""}","{givename name=""corpse feeder""}",,`,`,`,,forbidbooze,,,,,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,forbidseeds,,,,,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,"{quantumstop name=""Refuse/Corpse quantum"" sp_links=""{sp_link move={Up} move_back={Down}}{sp_link move=""""{Right}{Up}"""" move_back=""""{Down}{Left}""""}""}{givename name=""refuse/corpse dumper""}",,,`,`,`,,forbidwax,,,,`,`,` -,,,,,,,,,,,,,,,"{quantum name=""refuse/corpse quantum""}" - - -#query label(farming_link) start(16; 18) hidden() set farming stockpiles to take from starting surface stockpiles - - -,,,,,,,,,`,`,`,,`,`,`,t{Down 6}{Left 10}<&,`,,t{Down 6}{Left 13}<&,`,`,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,t{Down 2}{Left 14}<&,`,` -,,,,,,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,` -,,,,,,`,`,`,t{Up 2}{Right 11}<&,,`,,`,`,`,`,`,,`,`,`,`,` -,,,,,,`,`,`,`,,`,,t{Up 3}{Left 7}<&,`,`,`,`,,`,,`,`,` -,,,t{Up 4}{Right 17}<&,`,,`,`,`,`,,`,,`,`,`,`,`,,` -,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,t{Up 6}{Right 17}<&,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,t{Up 9}{Right 4}<&,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,t{Up 9}{Left 13}<&,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,,t{Up 13}{Left 6}<&,`,`,`,`,`,`,,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,,t{Up 15}{Right 10}<&,`,`,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,` - - -#query label(farming_rooms) start(16; 18) hidden() message(Check to ensure the lower office got assigned to your manager and assign the upper office to your bookkeeper (if different from your manager).) configure rooms - - -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,r&a+&,,,,`,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,r+&h -,,,,,,,,,,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,r&a+&,,,`,`,,`,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,`,`,`,`,`,,` -,,,,,,,,,,,`,,`,`,`,`,`,,`,,`,`,r&d -,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,`,` -,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,` -,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` -,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,` - - -"#build label(farming_build2) start(16; 18) hidden() farm plots, remaining furniture, and important doors" - - -,,,,,,,,,`,`,`,,p(3x1),,,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,p(3x1),,,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,p(3x1),,,`,`,,c,t,~,~ -,,,,,,,,,,,`,,p(3x1),,,`,`,,c,t,t,c -,,,,,,,`,`,`,,`,,p(3x1),,,`,`,,`,`,`,` -,,,,,,,`,`,`,`,`,,p(3x1),,,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,p(3x1),,,`,`,,` -,,,,,,,,,,,`,,p(3x1),,,`,`,,`,,b,b,~ -,,,,,,`,`,`,`,,`,,p(3x1),,,`,`,,`,`,`,`,h -,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,b,b,b -,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` -,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,,`,d,`,`,`,d,`,,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,`,`,,,d,,,`,`,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,` - - -#query label(farming_query_plots) start(16; 18) hidden() configure farm plots for seasonal fertilization - - -,,,,,,,,,`,`,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,,,`,`,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,,,,,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,`,`,,s,`,`,`,`,,`,`,`,` -,,,,,,,`,`,`,,`,,s,`,`,`,`,,` -,,,,,,,,,,,`,,s,`,`,`,`,,`,,`,`,` -,,,,,,`,`,`,`,,`,,s,`,`,`,`,,`,`,`,`,` -,,,,,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,` -,,,`,`,,`,`,`,`,,`,,`,`,`,`,`,,` -,,`,`,`,,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,` -,,,`,`,,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,,`,`,` -,,,,`,,,`,,,,,,`,`,`,`,`,,,,,`,,,,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,,,,`,,`,,,,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,,`,`,,,`,,,`,`,,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,,`,`,`,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,`,`,,,`,,,`,`,`,,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,` - - -#build label(farming_build3) start(16; 18) hidden() remaining doors +#build label(farming_doors) start(16; 18) hidden() remaining doors ,,,,,,,,,`,`,`,,`,`,`,`,`,,`,`,`,` @@ -1862,18 +1552,18 @@ Sets up workshops for all non-farming industries Screenshot: https://drive.google.com/file/d/1emMaHHCaUPcdRbkLQqvr-0ZCs2tdM5X7 "" Features: -- Space-efficient layout for all workshops +- Compact layout that covers all workshops - Manager orders that automate basic fortress maintenance "- Space available underneath the forge and smelters for magma, allowing the starting forge and smelters to be eventually replaced by magma versions." - Quantum stockpiles for compact storage with separate stockpiles for: - A reserve of uncut gems for strange moods that the jeweler's workshop cannot take from -"- Wood, steel bars, and coal so you can see at a glance if you're low on stock" -- Items that cannot be quantum stockpiled (e.g. lye and sand bags) +"- Wood, iron bars, steel bars, flux, and coal so you can see at a glance if you're low on stock" +"- Items that cannot be quantum stockpiled (e.g. lye, dye, and sand bags)" - Meltable weapons and armor "" Workshops: -- 2x Mason +- 2x Stonecutter - 4x Craftsdwarf - 1x Jeweler - 1x Mechanic @@ -1890,33 +1580,29 @@ Workshops: - 1x Dyer - 1x Loom - 1x Clothier - "" Manual steps you have to take: -- Assign minecarts to your quantum stockpile hauling routes -"- Give from the ""Goods"" quantum stockpile to the jugs, pots, and bags stockpiles on the farming level" +- Assign minecarts to your quantum stockpile hauling routes. "" Optional manual steps you can take: -- Restrict the Mechanic's workshop to only allow skilled workers so unskilled trap-resetters won't be tasked to build mechanisms. -"- Restrict the Craftsdwarf's workshops to only allow labors that take from the adjacent stockpiles. That is, only allow Woodcrafting for the Craftsdwarf's workshop on the left near the wood stockpile, Stonecrafting and Strand Extraction for the Craftsdwarf's workshop near the Mason's workshops, and Bonecrafting for one of the Craftsdwarf's workshop near the Clothier's workshop. The last Craftdwarf's workshop can hold all the remaining labors, or it can be a secondary workshop for a labor that you want more dwarves working on." "- To encourage your masons to concentrate on building blocks and other high-volume orders, it helps to set one of your Mason's workshops to service a maximum of 2 manager orders at a time." "- Once you have enough haulers, you can increase the rate of stone and ore hauling jobs by building more wheelbarrows and adding them to the stone and ore feeder stockpiles." -"- If desired, set one or both stockpiles in the bottom left to auto-melt. This results in melting all weapons and armor that are inferior to masterwork. This is great for upgrading your military, but it takes a *lot* of fuel unless you have first replaced the forge and smelters with magma versions. If you enable automelt and you don't have magma forges and magma smelters, be sure to be in a heavily forested area, enable auto-chop, and keep your coal stocks high." +"- If desired, set one or both stockpiles in the bottom left to auto-melt. This results in melting all weapons and armor that are inferior to masterwork. This is great for upgrading your military, but it takes a *lot* of fuel unless you have first replaced the forge and smelters with magma versions. If you enable automelt and you don't have magma forges and magma smelters, be sure to be in a heavily forested area, set up autochop, and keep your coal stocks high." "" Industry Walkthrough: -"1) Start digging out /industry1 as soon as you find a stone layer at least two layers beneath the surface so the boulders can be used by your starting workshops. The services level is intended to be dug beneath this one, and there is space on that level to route magma underneath your furnaces so you can replace the furnaces on this level with magma-powered equivalents." +"1) Start digging out /industry1 as soon as you find a non-aquifer stone layer at least two layers beneath the surface so the boulders can be used by your starting workshops. The services level is intended to be dug beneath this one, and there is space on that level to route magma underneath your furnaces so you can replace the furnaces on this level with magma-powered equivalents." "" -"2) Queue up manufacturing by running ""quickfort orders"" on /industry2. You brought an anvil with you (right??), so you can remove the unneeded anvil work order from the manager orders screen (j-m). Note that stockpiles that accept containers may claim the barrels you need to build the Dyer's Workshop and Ashery. If you see those two buildings not being constructed, build a few extra barrels or run combine-plants and combine-drinks to free up some existing ones." +"2) Queue up manufacturing by running ""quickfort orders"" on /industry2. You brought an anvil with you (right??), so you can remove the unneeded anvil work order from the manager orders screen. Note that stockpiles that accept containers may claim the barrels you need to build the Dyer's Workshop and Ashery. If you see those two buildings not being constructed, build a few extra barrels or run combine all to free up some existing ones." "" -"3) Once the area is dug out, run /industry2. Remember to assign minecarts to to your quantum stockpile hauling routes, and if the farming level is already built, give from the ""Goods"" quantum stockpile (the one on the left) to the jugs, pots, and bags stockpiles on the farming level." +"3) Once the area is dug out, run /industry2. Remember to assign minecarts to to your quantum stockpile hauling routes." "" -"4) Once you have enough dwarves to do maintenance tasks (that is, after the first or second migration wave), run ""orders import library/basic"" to use the provided basic.json to take care of your fort's basic needs, such as food, booze, and raw material processing." +"4) Once you have enough dwarves to do maintenance tasks (that is, after the first or second migration wave), run ""orders import library/basic"" to use the provided manager orders to take care of your fort's basic needs, such as food, booze, and raw material processing." "" "5) If you want to automatically melt goblinite and other low-quality weapons and armor, mark the south-east stockpiles for auto-melt. If you don't have a high density of trees to make into charcoal, though, be sure to route magma to the level beneath this one and replace the forge and furnaces with magma equivalents." "" "6) Once you have magma furnaces (or abundant fuel) and more dwarves, run ""orders import library/furnace"", ""orders import library/military"", and ""orders import library/smelting"" to import the remaining fort automation orders. The military orders are optional if you are not planning to have a military, of course." "" -"7) At any time, feel free to build extra workshops or designate custom stockpiles in the unused space in the top and bottom right. The space is there for you to use!" +"7) At any time, feel free to build extra workshops or designate custom stockpiles in the remaining open space. The space is there for you to use! Note the area in the bottom right can be used for additional magma-powered furnaces and workshops since there is space reserved for magma in those spots in the level beneath." "#dig label(industry1) start(18; 18; central stairs) message(Once the area is dug out, continue with /industry2.)" @@ -1953,12 +1639,12 @@ Industry Walkthrough: ,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d -"#meta label(industry2) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) build workshops and stockpiles, configure stockpiles" +#meta label(industry2) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) workshops and stockpiles traffic/industry_traffic -build/industry_build place/industry_place -query/industry_query -#dig label(industry_traffic) start(18; 18; central stairs) hidden() +build/industry_build +build2/industry_build2 +#dig label(industry_traffic) start(18; 18; central stairs) hidden() traffic patterns ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` @@ -1994,117 +1680,115 @@ query/industry_query ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -#build label(industry_build) start(18; 18) hidden() +"#place label(industry_place) start(18; 18) hidden() message(remember to: +- assign minecarts to to your quantum stockpile hauling routes (use ""assign-minecarts all"") +- if you want to automatically melt goblinite and other low-quality weapons and armor, mark the south-east stockpiles for auto-melt +- once you have enough dwarves, run ""orders import library/basic"" to automate your fort's basic needs (see /industry_help for more info on this file)) industry stockpiles" + + +,,,,,,,,,,,"e{name=""Rough gems for moods"" containers=0 take_from=""Stoneworker quantum,Gem feeder""}:=roughgems",e,e,e,e,e,e,e,e,e,e,e,e +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"se{name=""Stoneworker quantum"" quantum=true}",`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,"s10{name=""Stone feeder""}:=otherstone(5x4)",,,~,~,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,` +,,"w{name=""Wood"" take_from=""Goods/wood quantum,Wood feeder""}",`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,"c{name=""Dye"" barrels=-1 }:+dye" +,,w,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,`,`,`,`,`,`,"e{name=""Gem feeder"" containers=0}(5x1)",,,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,"w{name=""Wood feeder""}(2x5)",,"g{name=""Goods feeder"" containers=0}:+cat_food/tallow+wax-crafts-goblets(3x3)",,`,,`,`,`,`,`,,"hlS{name=""Cloth/bones feeder"" containers=0}:+cat_refuse/skulls/,bones/,hair/,shells/,teeth/,horns/-adamantinethread(5x5)",,,~,~,`,`,`,`,`,`,c +,,w,`,`,`,`,`,`,~,~,~,~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c +,,`,`,`,`,`,"c{name=""Goods/wood quantum"" quantum=true give_to=Pots,Barrels,Jugs,Bags}:+all",`,~,~,~,~,~,,`,,`,,`,,~,~,~,~,~,`,"r{name=""Cloth/bones quantum"" quantum=true}:+all",`,`,`,`,c +,,"c{name=""Lye"" barrels=2}:+miscliquid",`,`,`,`,`,`,~,~,"u2{name=""Furniture feeder""}:-sand(3x2)",~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,~,~,~,~,~,,`,`,`,`,`,,~,~,~,~,~,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,`,"bnpdz{name=""Bar/military feeder"" containers=0}:-potash+adamantinethread(5x3)",,,,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,c,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,c +,,,,"pd{name=""Meltable steel/bronze"" take_from=""Metalworker quantum,Bar/military feeder""}:-cat_weapons/mats/,other/,core/masterful,core/artifact-cat_armor/mats/,other/,core/masterful,core/artifact+bronzeweapons+bronzearmor+steelweapons+steelarmor(7x3)",,,~,~,~,~,`,`,`,`,"s5{name=""Ore/clay feeder""}:-otherstone(5x2)",,,~,~,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,"c{name=""Coal"" containers=0 take_from=""Metalworker quantum,Bar/military feeder""}:+coal",`,"c{name=""Metalworker quantum"" quantum=true}:+all",`,"c{name=""Iron"" containers=0 take_from=""Metalworker quantum,Bar/military feeder""}:+ironbars",`,`,`,`,`,`,`,`,`,`,` +,,,,"pd{name=""Other meltables"" take_from=""Metalworker quantum,Bar/military feeder""}:-cat_weapons/other/,core/masterful,core/artifact-cat_armor/other/,core/masterful,core/artifact-bronzeweapons-bronzearmor-steelweapons-steelarmor(7x3)",,,~,~,~,~,`,`,`,`,c,"c{name=Flux take_from=""Metalworker quantum,Ore/clay feeder""}:+flux(3x1)",,,c,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,c,`,`,`,c,`,`,`,`,`,`,`,`,`,`,` +,,,,~,~,~,~,~,~,~,`,`,`,`,c,`,`,`,c,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,"u{name=""Sand bags""}:-cat_furniture/type+sand",u,u,u,u,u,`,"c{name=""Steel"" containers=0 take_from=""Metalworker quantum,Bar/military feeder""}:+steelbars",c,c,c,c,c + + +#build label(industry_build) start(18; 18) hidden() workshops to build first ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,wj,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,wr,`,`,`,`,`,`,`,wt,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,trackstopN,`,`,`,`,`,`,`,`,ws,`,`,`,` -,,,,`,`,wS,`,`,wb,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,"wr{name=""Stone craftsdwarf""}",`,`,`,`,`,`,`,wt,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"trackstopN{name=""Stone/gem dumper"" take_from=""Stone feeder,Gem feeder"" route=""Stone/gem quantum""}",`,`,`,`,`,`,`,`,~,`,`,`,` +,,,,`,`,~,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,wm,`,`,`,`,`,`,`,wm,`,`,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,wy,`,`,ew,`,`,ew,`,`,`,`,`,`,`,`,`,`,`,`,`,wk,`,`,wo,`,`,wd,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,,,d,,d,,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,~,`,`,~,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,~,`,`,~,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,~,,~,,,`,`,`,`,`,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,d,`,,,,`,d,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,wc,`,`,`,trackstopW,`,`,`,`,`,,`,,`,,`,,`,`,`,`,`,trackstopE,`,`,`,we,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,d,`,,,,`,d,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,,,,`,~,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,wc,`,`,`,"trackstopW{name=""Goods/wood dumper"" take_from=""Wood feeder,Goods feeder,Furniture feeder"" route=""Goods/wood quantum""}",`,`,`,`,`,,`,,`,,`,,`,`,`,`,`,"trackstopE{name=""Cloth/bones dumper"" take_from=""Cloth/bones feeder"" route=""Cloth/bones quantum""}",`,`,`,~,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,~,`,,,,`,~,`,`,`,`,`,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,,,d,,d,,,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,wr,`,`,ew,`,`,ew,`,`,`,`,`,`,`,`,`,`,`,`,`,wr,`,`,wr,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,~,,~,,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,~,`,`,~,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,~,`,`,`,`,` ,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,trackstopS,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"trackstopS{name=""Metalworker dumper"" take_from=""Bar/military feeder,Ore/clay feeder"" route=""Metalworker quantum""}",`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,eg,`,`,`,wf,`,`,`,ek,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,~,`,`,`,~,`,`,`,`,`,`,`,`,` ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -#place label(industry_place) start(18; 18) hidden() +#build label(industry_build2) start(18; 18) hidden() remaining workshops -,,,,,,,,,,,e,e,e,e,e,e,e,e,e,e,e,e,e ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"wj{name=""Encruster"" take_from=""Goods/wood quantum,Stoneworker quantum,Gem feeder""}",`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,ws,`,`,`,` +,,,,`,`,wS,`,`,wb,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,wy,`,`,ew,`,`,ew,`,`,`,`,`,`,`,`,`,`,`,`,`,wk,`,`,wo,`,`,"wd{take_from=""Cloth/bones feeder,Cloth/bones quantum,Dye""}",`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,d,,d,,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,d,`,,,,`,d,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,~,`,`,`,~,`,`,`,`,`,,`,,`,,`,,`,`,`,`,`,~,`,`,`,we,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,d,`,,,,`,d,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,,,d,,d,,,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,"wr{name=""Wood craftsdwarf""}",`,`,ew,`,`,ew,`,`,`,`,`,`,`,`,`,`,`,`,`,"wr{name=""Misc craftsdwarf""}",`,`,"wr{name=""Bone craftsdwarf""}",`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,c,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,s4(5x4),,,~,~,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,`,`,`,`,`,`,e(5x1),,,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,w(2x5),,fg(3x3),,`,,`,`,`,`,`,,frhlS(5x5),,,~,~,`,`,`,`,`,`,` -,,w,`,`,`,`,`,`,~,~,~,~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,` -,,`,`,`,`,`,c,`,~,~,~,~,~,,`,,`,,`,,~,~,~,~,~,`,r,`,`,`,`,` -,,f3,`,`,`,`,`,`,~,~,u2(3x2),~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,` -,,f3,`,`,`,`,`,`,~,~,~,~,~,,`,`,`,`,`,,~,~,~,~,~,`,`,`,`,`,`,` -,,f3,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,` -,,f3,`,`,`,`,`,`,`,`,`,`,`,`,bnpdhz(5x3),,,,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,f3,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,f3,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,pd(7x3),,,~,~,~,~,`,`,`,`,s2(5x2),,,~,~,`,`,`,`,`,`,`,`,`,`,` -,,,,~,~,~,~,~,~,~,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,` -,,,,~,~,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,b,`,c,`,b,`,`,`,`,`,`,`,`,`,`,` -,,,,pd(7x3),,,~,~,~,~,`,`,`,`,b,s,s,s,b,`,`,`,`,`,`,`,`,`,`,` -,,,,~,~,~,~,~,~,~,`,`,`,`,b,`,`,`,b,`,`,`,`,`,`,`,`,`,`,` -,,,,~,~,~,~,~,~,~,`,`,`,`,b,`,`,`,b,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,u,u,u,u,u,u,`,b,b,b,b,b,b - - -"#query label(industry_query) start(18; 18) hidden() message(remember to: -- assign minecarts to to your quantum stockpile hauling routes (use ""assign-minecarts all"") -- if the farming level is already built, give from the ""Goods"" quantum stockpile to the jugs, pots, and bags stockpiles on the farming level -- if you want to automatically melt goblinite and other low-quality weapons and armor, mark the south-east stockpiles for auto-melt -- once you have enough dwarves, run ""orders import library/basic"" to automate your fort's basic needs (see /industry_help for more info on this file) -- optionally, restrict the labors for your Craftsdwarf's and Mechanic's workshops as per the guidance in /industry_help)" - - -,,,,,,,,,,,roughgems,,,,nocontainers,"{givename name=""rough gems for moods""}",t{Down 5}&,,,,,~,~ -,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,"{givename name=""stone craftsdwarf""}",`,`,`,"{quantum name=""stoneworker quantum""}g{Up 3}&",`,`,`,~,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"{quantumstop name=""Stoneworker quantum"" sp_links=""{sp_link move={Down} move_back={Up}}{sp_link move=""""{Down 5}"""" move_back=""""{Up 5}""""}""}{givename name=""stoneworker dumper""}",`,`,`,`,`,`,`,`,~,`,`,`,` -,,,,`,`,~,`,`,~,`,`,`,`,`,otherstone,,,,~,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,~,`,"{givename name=""stone feeder""}",~,~,~,~,`,~,`,`,`,`,`,`,`,`,` -,,"{givename name=""wood""}",`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,~,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,~,`,~,`,`,~,`,`,~,`,`,`,`,nocontainers,"{givename name=""gem feeder""}",~,~,~,`,`,`,`,~,`,`,~,`,`,~,`,` -,,~,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,` -,,~,`,`,`,`,`,`,"{givename name=""wood feeder""}",~,"{givename name=""goods feeder""}",nocontainers,~,,`,`,`,`,`,,craftrefuse,,,,~,`,`,`,`,`,`,` -,,t{Right 5}{Down}&,`,`,`,`,`,`,~,~,{tallow}{permitwax},~,~,`,`,,,,`,`,"{givename name=""cloth/bones feeder""}",g{Up 3}{Right 5}&,~,~,~,`,`,`,`,`,`,` -,,`,`,~,`,`,"{quantum name=""goods/wood quantum""}g{Up 13}{Right 10}&","{quantumstop name=""Goods/Wood quantum"" sp_links=""{sp_link move={Right} move_back={Left}}{sp_link move=""""{Right 5}"""" move_back=""""{Left 5}""""}{sp_link move=""""{Down}{Right 5}"""" move_back=""""{Left 5}{Up}""""}""}{givename name=""goods/wood dumper""}",~,~,{forbidcrafts}{forbidgoblets},~,~,,`,,`,,`,,nocontainers,~,~,~,~,"{quantumstopfromwest name=""Clothier/Bones quantum""}{givename name=""cloth/bones dumper""}","{quantum name=""cloth/bones quantum""}g{Up 4}{Right 3}&",`,`,~,`,` -,,miscliquid,`,`,`,`,`,`,~,~,"{givename name=""furniture feeder""}",~,~,`,`,,,,`,`,forbidadamantinethread,~,~,~,~,`,`,`,`,`,`,` -,,"{givename name=""miscliquid""}",`,`,`,`,`,`,~,~,forbidsand,~,~,,`,`,`,`,`,,dye,~,~,~,~,`,`,`,`,`,`,` -,,~,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,` -,,~,`,"{givename name=""wood craftsdwarf""}",`,`,~,`,`,~,`,`,`,`,forbidpotash,nocontainers,"{givename name=""bar/military feeder""}",~,~,`,`,`,`,"{givename name=""misc craftsdwarf""}",`,`,"{givename name=""bone craftsdwarf""}",`,`,`,`,` -,,~,`,`,`,`,`,`,`,`,`,`,`,`,adamantinethread,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,~,`,`,`,`,`,`,`,`,`,`,`,`,~,~,~,~,~,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,nocontainers,t{Right 12}{Up 3}&,t{Right 11}{Down 3}&,"{givename name=""meltable steel/brnze""}",,,,`,`,~,`,forbidotherstone,,,,,`,~,`,`,`,`,`,`,`,`,` -,,,,{bronzeweapons}{permitsteelweapons}{forbidmasterworkweapons}{forbidartifactweapons},,,,,,,`,`,`,`,"{givename name=""ore/clay feeder""}",~,~,~,~,`,`,`,`,`,`,`,`,`,`,` -,,,,{bronzearmor}{permitsteelarmor}{forbidmasterworkarmor}{forbidartifactarmor},,,,,,,`,`,`,`,`,`,"{quantumstop name=""Metalworker quantum"" sp_links=""{sp_link move={Up} move_back={Down}}{sp_link move=""""{Up 5}"""" move_back=""""{Down 5}""""}""}{givename name=""metalworker dumper""}",`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,~,`,t{Right 2}&,`,"{quantum name=""metalworker quantum""}",`,t{Left 2}&,`,~,`,`,`,`,`,`,`,`,` -,,,,nocontainers,t{Right 12}{Up 7}&,t{Right 11}{Up 1}&,"{givename name=""other meltables""}",,,,`,`,`,`,coal,flux,t{Up}&,"{givename name=""flux""}",ironbars,`,`,`,`,`,`,`,`,`,`,` -,,,,{metalweapons}{forbidbronzeweapons}{forbidsteelweapons}{forbidmasterworkweapons}{forbidartifactweapons},,,,,,,`,`,`,`,"{givename name=""coal""}",`,`,`,"{givename name=""iron""}",`,`,`,`,`,`,`,`,`,`,` -,,,,{metalarmor}{forbidbronzearmor}{forbidsteelarmor}{forbidmasterworkarmor}{forbidartifactarmor},,,,,,,`,`,~,`,nocontainers,`,~,`,nocontainers,`,~,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,eg,`,`,`,wf,`,`,`,ek,`,`,`,`,`,`,`,`,` +,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,sand,"{givename name=""sand bags""}",nocontainers,~,~,~,`,t{Up 5}{Left}&,,,nocontainers,steelbars,"{givename name=""steel""}" #notes label(services_help) @@ -2113,53 +1797,55 @@ Screenshot: https://drive.google.com/file/d/13vDIkTVOZGkM84tYf4O5nmRs4VZdE1gh "" Features: - Spacious dining room/tavern (tavern is restricted to residents-only by default) -- Prepared food and drink stockpiles +- Large prepared food and drink stockpiles - Well cistern system (bring your own water) -- Hospital with a well for washing +- Hospital (also restricted to residents by default) with a well for washing +- Well-appointed jail cells +- Bolt-recycling archery range for your marksdwarves +- Interrogation room for your Captain of the Guard - Garbage dump - Empty space for magma to power forges and smelters in the industry level above "" -Note the hospital also has animal training enabled so it can be used with the dwarfvet plugin if it's enabled. +Note the hospital is attached to an animal training zone so it can be used with the dwarfvet plugin if it's enabled. "" Manual steps you have to take: -"- If you want to tavern to attract visitors, change the restriction in the (l)ocation menu." -"- Fill the cisterns with water, either with a bucket brigade or by plumbing flowing water. Fill so that there are two z-levels of 7-depth water to prevent muddiness. If you want to fill with buckets, designate a pond zone on the level below the main floor. If you feel adventurous and are experienced with water pressure, you can instead route (depressurized!) water to the second-to-bottom level (the one above the up staircases)." +"- If you want to tavern to attract visitors, change the restriction in the location configuration screen." +"- Fill the cisterns with water, either with a bucket brigade or by plumbing flowing water. Fill so that there are two z-levels of 7-depth water to prevent muddiness. If you want to fill with buckets, you can use the pre-designated pond zones on the level below the main floor. If you feel adventurous and are experienced with water pressure, you can instead route (depressurized!) water to the second-to-bottom level (the one above the up staircases)." "- If you are filling the wells with a bucket brigade and at least one well is already constructed, you'll run into issues with the dwarves stealing water from one well to fill another. Temporarily deconstruct the wells or temporarily build grates beneath the wells to block the buckets to avoid this issue. Remember to rebuild the wells or remove the grates afterwards, though!" -- Assign the office to the right of the barracks to your Sheriff/Captain of the Guard to use it as an interrogation room. "" Services Walkthrough: -1) Start this level when your fort grows to about 50 dwarves so everyone has a place to eat. +1) Start this level when your fort grows to about 30 dwarves so everyone has a place to eat. "" -2) Start digging with /services1. Note that this digs out the main level and three levels below for the wells. +2) Start digging with /services1. Note that this digs out the main level and three levels below for the well cisterns. "" -"3) Once the area is dug out, set up important furniture, stockpiles, hospital zone and garbage dump zone with /services2. Run ""quickfort orders"" for /services2." +"3) Once the area is dug out, set up zones/locations and start populating the rooms with /services2. Run ""quickfort orders"" for /services2." "" -"4) When the table and chair have been placed in the dining room, the beds are placed in the rented rooms, and the weapon rack and archery targets are constructed in the barracks, run /services3 to build the rest of the furniture and configure your dining room/tavern and barracks. Run ""quickfort orders"" for /services3." +4) Fill the wells with either bucket brigades or by carefully routing flowing water. "" -5) Fill the wells with either bucket brigades or by carefully routing flowing water. +"5) When your fort has grown some more, or you start needing a jail cell, run /services3 to extend the rooms a bit more. Run ""quickfort orders"" for /services3." "" -"6) When your fort is mature enough to need jail cells, run /services4 to set those up, anytime after the restraints are built in the jail cell block. You also get some decorative statues to increase the value of your dining hall. Assign the office to the right of the barracks to your Sheriff/Captain of the Guard to use it as an interrogation room. Run ""quickfort orders"" for /services4." +"6) When your fort is more mature and you need to expand the rooms, run /services4 to finish everything up. If you didn't have a Sheriff/Captain of the Guard to automatically assign to the interrogation room when you ran /services2, you can manually assign the office now. Run ""quickfort orders"" for /services4." "#dig label(services1) start(18; 18; central stairs) message(Once the area is dug out, continue with /services2.)" -,d,d,d,,d,d,d,,d,d,d,,d,h,d,,j,,d,h,d -,d,d,d,,d,d,d,,d,d,d,,d,d,d,d,d,d,d,d,d -,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,,d,d,d -,,d,,,,d,,,,d,,,,,,,d -,d,d,d,d,d,d,d,d,d,d,d,,d,h,d,,d,,d,h,d,,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,,d,,d,d,d,,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,,,,,,d,,,,,,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,,,,d -,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,,d,d,d,,d,d,d,,d,h,d,,d,h,d,,d,h,d,,d,h,d,,d,h,d +,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d +,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d +,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d +,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,,,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,h,h,h,h,h,h,h,h,h,h,,d,,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,,d,,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,,j,,d,d,d,d,d ,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d ,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,,d,,d,,d,,d ,d,d,d,d,d,d,d,d,d,d,d,,,,,d,,d,,,,,d,,d,,d,,d -,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,d,d,,,,d,d,d,d,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,,d,,d,`,`,`,d,,d,,d,d,d,h,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,d,d,,,,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,d,d,,,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,h,d,d,d,d,d,,d,,d,`,`,`,d,,d,,d,d,d,h,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,d,d,,,,d,,d,,d,,d ,d,d,d,d,d,d,d,d,d,d,d,,,,,,d,,,,,,d,,d,,d,,d ,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,,,d,,d,,d,,d ,d,d,d,d,d,d,d,d,d,d,d @@ -2177,33 +1863,33 @@ Services Walkthrough: #> -,,,,,,,,,,,,,j5,h5,j,,u,,j,h5,j5 -,,,,,,,,,,,,,5,5,5,5,d,5,5,5,5 -,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,j5,h5,j,,d,,j,h5,j5 -,,,,,,,,,,,,,5,5,5,5,d,5,5,5,5 -,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,d -,,,,,,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d -,,,,,,,,,,,,,,,,,6,,,,,,,,,d -,,,,,,,,,,,,,,,,,d,,,,,,,,,d -,,,,,,,,,,,,,,,d,d,d,d,d,,,,,,,d -,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,5,5,5 -,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,j,h5,j5 +,,,,,,,,,,,,,j5,h5,j,,j5,h5,j,,j5,h5,j,,j5,h5,j,,j5,h5,j +,,,,,,,,,,,,,5,5,5,,5,5,5,,5,5,5,,5,5,5,,5,5,5 +,,,,,,,,,,,,,,d,,,,d,,,,d,,,,d,,,,d +,,,,,,,,,,,,,,d,,,,d,,,,d,,,,d,,,,d +,,,,,,,,,,,,,,d,,,,d,,,,d,,,,d,,,,d +,,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,,,d,,,,,,,,,,,,,,,,,,,,d +,,,,,,d,,,,,,,,,,,,,,,,,,,,d +,,,,,,d,,,,,,,,,,,,,,,,,,,,d +,,,,,,d,,,,,,,,,,,,,,,,,,,,d +,,,,,,d,,,,,,,,,,,,,,,,,,u,d,d +,,,,,,d,,,,,,,,,,,,,,,,,,,,d +,,,,,,d,,,,,,,,,,,,,,,,,,,,d +,,,,,,d,,,,,,,,,,,,,,,,,,,,d +,,,,,,d,,,,,,,,,d,d,d,d,d,,,,,,,d +,,,,,5,5,5,,,,,,,,d,`,`,`,d,,,,,,5,5,5 +,,,,,j5,h5,j,,,,,,,,d,`,`,`,d,,,,,,j5,h5,j ,,,,,,,,,,,,,,,d,`,`,`,d ,,,,,,,,,,,,,,,d,d,d,d,d #> -,,,,,,,,,,,,,u5,h5,i,,,,i,h5,u5 +,,,,,,,,,,,,,u5,h5,i,,u5,h5,i,,u5,h5,i,,u5,h5,i,,u5,h5,i + -,,,,,,,,,,,,,u5,h5,i,,,,i,h5,u5 @@ -2215,17 +1901,17 @@ Services Walkthrough: ,,,,,,,,,,,,,,,d,d,d,d,d ,,,,,,,,,,,,,,,d,`,`,`,d -,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,i,h5,u5 +,,,,,u5,h5,i,,,,,,,,d,`,`,`,d,,,,,,u5,h5,i ,,,,,,,,,,,,,,,d,`,`,`,d ,,,,,,,,,,,,,,,d,d,d,d,d #> -,,,,,,,,,,,,,,d,u,,,,u,d +,,,,,,,,,,,,,,d,u,,,d,u,,,d,u,,,d,u,,,d,u + -,,,,,,,,,,,,,,d,u,,,,u,d @@ -2237,93 +1923,88 @@ Services Walkthrough: ,,,,,,,,,,,,,,,d,d,d,d,d ,,,,,,,,,,,,,,,d,`,`,`,d -,,,,,,,,,,,,,,,d,`,`,`,d,,,,,,u,d +,,,,,,d,u,,,,,,,,d,`,`,`,d,,,,,,,d,u ,,,,,,,,,,,,,,,d,`,`,`,d ,,,,,,,,,,,,,,,d,d,d,d,d -"#meta label(services2) start(central stairs) message(Remember to enqueue manager orders for this blueprint. -Once furniture has been placed, continue with /services3.) dining hall anchors, stockpiles, hospital, garbage dump" +"#meta label(services2) start(central stairs) message(Once furniture has been built, continue with /services3.) zones and minimally functional hospital and dining hall" traffic/services_traffic zones/services_zones -build/services_build place/services_place -name_zones/services_name_zones -query_stockpiles/services_query_stockpiles +build/services_build "" -"#meta label(services3) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) configure dining room/tavern, build dining hall and hospital furniture" -query_dining/services_query_dining -query_rented_rooms/services_query_rented_rooms +"#meta label(services3) start(central stairs) message(Once furniture has been built, continue with /services4.) expand furnishings" +place2/services_place2 build2/services_build2 "" -#meta label(services4) start(central stairs) message(Remember to enqueue manager orders for this blueprint.) declare and furnish jail and build decorative furniture +#meta label(services4) start(central stairs) complete furnishings +place3/services_place3 build3/services_build3 -place_jail/services_place_jail -query_jail/services_query_jail -#dig label(services_traffic) start(18; 18) hidden() keep lollygaggers out of the cisterns - -,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,,or,,or,or,or -,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,or,or,or,or,or,or -,ol,ol,ol,,ol,ol,ol,,ol,ol,ol,,or,or,or,,or,,or,or,or -,,ol,,,,ol,,,,ol,,,,,,,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,,or,,or,or,or,,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,,or,,or,or,or,,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,,,,or,,,,,,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,,,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,or,or,or,or,or,or,or,or,or,,or,,or,,or,,or -,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,ol,,,,,or,,or,,,,,or,,or,,or,,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,oh,oh,oh,oh,oh,,,,or,or,or,or,or,or,or,or,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,or,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,`,,oh,`,`,`,oh,,`,,oh,oh,oh,`,oh,or,or,or,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,or,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,oh,oh,oh,oh,oh,,,,or,or,or,or,or,or,or,or,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,,,or,,,,,,or,,or,,or,,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,,,,,,,,,,,,or,,or,,or,,or -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh -,,,,oh,oh,,oh,oh -,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh -,oh,oh,oh,oh,oh,,oh,oh,oh,oh,oh +#dig label(services_traffic) start(18; 18) hidden() keep lollygaggers out of the cisterns and justice areas + +,`,`,`,,`,`,`,,`,`,`,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,`,`,`,,`,`,`,,`,`,`,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,`,`,`,,`,`,`,,`,`,`,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,,`,,,,`,,,,`,,,,or,,,,or,,,,or,,,,or,,,,or +,`,`,`,`,`,`,`,`,`,`,`,,,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,or,,or,,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,or,or,or,or,or,or,or,or,or,,or,,or,,or,,or +,`,`,`,`,`,`,`,`,`,`,`,,,,,or,,or,,,,,or,,or,,or,,or +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,or,,or,,or,,or +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,ol,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,oh,oh,oh,oh,oh,ol,or +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,ol,or,or,or,or +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,or,,or,,or,,or +,`,`,`,`,`,`,`,`,`,`,`,,,,,,or,,,,,,or,,or,,or,,or +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,or,,or,,or,,or +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` +,`,`,`,`,`,,`,`,`,`,` #> -,,,,,,,,,,,,,or,or,or,,or,,or,or,or -,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or -,,,,,,,,,,,,,,,,,or -,,,,,,,,,,,,,,,,,or -,,,,,,,,,,,,,or,or,or,,or,,or,or,or -,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or -,,,,,,,,,,,,,,,,,or -,,,,,,,,,,,,,,,,,or -,,,,,,,,,,,,,,,,,or -,,,,,,,,,,,,,,,,,or -,,,,,,,,,,,,,,,,,or -,,,,,,,,,,,,,,,,,or,or,or,or,or,or,or,or,or,or -,,,,,,,,,,,,,,,,,or,,,,,,,,,or -,,,,,,,,,,,,,,,,,or,,,,,,,,,or -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,or -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,or,or,or -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,or,or,or +,,,,,,,,,,,,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,,,,,,,,,,,,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or +,,,,,,,,,,,,,,or,,,,or,,,,or,,,,or,,,,or +,,,,,,,,,,,,,,or,,,,or,,,,or,,,,or,,,,or +,,,,,,,,,,,,,,or,,,,or,,,,or,,,,or,,,,or +,,,,,,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or,or +,,,,,,or,,,,,,,,,,,,,,,,,,,,or +,,,,,,or,,,,,,,,,,,,,,,,,,,,or +,,,,,,or,,,,,,,,,,,,,,,,,,,,or +,,,,,,or,,,,,,,,,,,,,,,,,,,,or +,,,,,,or,,,,,,,,,,,,,,,,,,or,or,or +,,,,,,or,,,,,,,,,,,,,,,,,,,,or +,,,,,,or,,,,,,,,,,,,,,,,,,,,or +,,,,,,or,,,,,,,,,,,,,,,,,,,,or +,,,,,,or,,,,,,,,,`,`,`,`,`,,,,,,,or +,,,,,or,or,or,,,,,,,,`,`,`,`,`,,,,,,or,or,or +,,,,,or,or,or,,,,,,,,`,`,`,`,`,,,,,,or,or,or ,,,,,,,,,,,,,,,`,`,`,`,` ,,,,,,,,,,,,,,,`,`,`,`,` #> -,,,,,,,,,,,,,or,or,or,,,,or,or,or +,,,,,,,,,,,,,or,or,or,,or,or,or,,or,or,or,,or,or,or,,or,or,or + -,,,,,,,,,,,,,or,or,or,,,,or,or,or @@ -2335,17 +2016,17 @@ query_jail/services_query_jail ,,,,,,,,,,,,,,,`,`,`,`,` ,,,,,,,,,,,,,,,`,`,`,`,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,or,or,or +,,,,,or,or,or,,,,,,,,`,`,`,`,`,,,,,,or,or,or ,,,,,,,,,,,,,,,`,`,`,`,` ,,,,,,,,,,,,,,,`,`,`,`,` #> -,,,,,,,,,,,,,,or,or,,,,or,or +,,,,,,,,,,,,,,or,or,,,or,or,,,or,or,,,or,or,,,or,or + -,,,,,,,,,,,,,,or,or,,,,or,or @@ -2357,33 +2038,33 @@ query_jail/services_query_jail ,,,,,,,,,,,,,,,`,`,`,`,` ,,,,,,,,,,,,,,,`,`,`,`,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,or,or +,,,,,,or,or,,,,,,,,`,`,`,`,`,,,,,,,or,or ,,,,,,,,,,,,,,,`,`,`,`,` ,,,,,,,,,,,,,,,`,`,`,`,` -"#zone label(services_zones) start(18; 18) hidden() message(If you'd like to fill your wells via bucket brigade, activate the inactive pond zones one level down from where the wells will be built.) garbage dump, hospital, and pond zones" - -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,,`,,,,`,,,,`,,,,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,ht,ht,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,,,,,,d,,,,,ht,ht,ht,ht,ht,ht,ht,ht,ht,ht -,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,ht,ht,ht,ht,ht,ht,ht,ht,ht +"#zone label(services_zones) start(18; 18) hidden() message(If you'd like to fill your wells via bucket brigade, activate the inactive pond zones one level down from where the wells will be built.) garbage dump, hospital, taverrn, barracks, archery range, and pond zones" +,,,,,,,,,,,,"j{name=""Jail 1""}(5x5)",,,,"j{name=""Jail 2""}(5x5)",,,,"j{name=""Jail 3""}(5x5)",,,,"j{name=""Jail 4""}(5x5)",,,,"j{name=""Jail 5""}(5x5)" +,"b{location=tavern/bigpub name=""Rented room 1""}(1x3)","b{location=tavern/bigpub name=""Rented room 2""}(1x3)","b{location=tavern/bigpub name=""Rented room 3""}(1x3)",,"b{location=tavern/bigpub name=""Rented room 4""}(1x3)","b{location=tavern/bigpub name=""Rented room 5""}(1x3)","b{location=tavern/bigpub name=""Rented room 6""}(1x3)",,"b{location=tavern/bigpub name=""Rented room 7""}(1x3)","b{location=tavern/bigpub name=""Rented room 8""}(1x3)","b{location=tavern/bigpub name=""Rented room 9""}(1x3)",,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +"h{location=tavern/bigpub allow=residents name=""Grand hall tavern""}(13x31)",,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,`,"o{name=""Interrogation room"" assigned_unit=sheriff}(7x7)" +,`,`,`,`,`,`,`,`,`,`,`,,"B{name=""Marksdwarf barracks""}a{name=""Shooting gallery"" shoot_from=""south""}",Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba +,`,`,`,`,`,`,`,`,`,`,`,,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,Ba,,m{location=hospital name=Hospital allow=residents},,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,m,m,m,m,m,m,m,m,m,m +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,m,m,m,m,m,m,m +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,m,m,m,m,m,m,m,m,m,m +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,,,"d{name=""Garbage dump""}",,,,,,m,,m,,m,,m +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,m,,m,,m,,m ,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,` @@ -2399,84 +2080,48 @@ query_jail/services_query_jail #> -,,,,,,,,,,,,,`,apPf,`,,`,,`,apPf,` -,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,`,apPf,`,,`,,`,apPf,` -,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,`,,,,,,,,,` -,,,,,,,,,,,,,,,,,`,,,,,,,,,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,`,`,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,`,apPf,` +,,,,,,,,,,,,,`,"p{name=""Jail 1 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 2 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 3 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 4 cistern"" pond=true active=false}",`,,`,"p{name=""Jail 5 cistern"" pond=true active=false}",` +,,,,,,,,,,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,,,,,,,,,`,,,,`,,,,`,,,,`,,,,` +,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,,,`,,,,,,,,,,,,,,,,,,,,` +,,,,,,`,,,,,,,,,,,,,,,,,,,,` +,,,,,,`,,,,,,,,,,,,,,,,,,,,` +,,,,,,`,,,,,,,,,,,,,,,,,,,,` +,,,,,,`,,,,,,,,,,,,,,,,,,`,`,` +,,,,,,`,,,,,,,,,,,,,,,,,,,,` +,,,,,,`,,,,,,,,,,,,,,,,,,,,` +,,,,,,`,,,,,,,,,,,,,,,,,,,,` +,,,,,,`,,,,,,,,,`,`,`,`,`,,,,,,,` +,,,,,`,`,`,,,,,,,,`,`,`,`,`,,,,,,`,`,` +,,,,,`,"p{name=""Tavern cistern"" pond=true active=false}",`,,,,,,,,`,`,`,`,`,,,,,,`,"p{name=""Hospital cistern"" pond=true active=false}",` ,,,,,,,,,,,,,,,`,`,`,`,` ,,,,,,,,,,,,,,,`,`,`,`,` -#build label(services_build) start(18; 18) hidden() build basic hospital and dining room anchor - -,b,b,b,,b,b,b,,b,b,b,,`,`,`,,`,,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,,`,,,,`,,,,`,,,,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,d,,,,,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,A,A,A,`,A,A,A,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,r,`,`,`,`,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,d,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,trackstopN,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,b -,`,`,`,`,`,`,`,`,`,`,`,,,,,d,,d,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,t,`,`,`,`,R -,`,`,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,h -,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,l,`,`,`,`,R -,`,`,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,t,c,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,R -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,h,`,`,`,`,` -,,,,`,`,,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` - #place label(services_place) start(18; 18) hidden() -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,,`,,,,`,,,,`,,,,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,c,`,`,`,`,`,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,"z{name=""Training quantum"" quantum=true}",`,`,`,`,`,,`,,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,z(7x1),,,`,`,`,`,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,"z{name=""Training bolts feeder"" containers=0 take_from=""Metalworker quantum""}:-cat_ammo/type/,mats/,other/+bolts+woodammo+boneammo(9x1)",,,,,,,,`,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,c,,,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,"c{name=""Garbage dump"" links_only=true}",,,,,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,` @@ -2485,41 +2130,42 @@ query_jail/services_query_jail ,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,,`,` -,f(5x5),,,`,`,,f(5x5),,,`,` +,"c{name=""Prepared food"" barrels=-1}:+preparedmeals(5x5)",,,,`,,"c{name=""Booze"" barrels=-1}:+booze(5x5)",,,,` ,`,`,`,`,`,,`,`,`,`,` ,`,`,`,`,`,,`,`,`,`,` ,`,`,`,`,`,,`,`,`,`,` ,`,`,`,`,`,,`,`,`,`,` -#query label(services_name_zones) start(18; 18) hidden() - -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,,`,,,,`,,,,`,,,,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,"{namezone name=""hospital""}" -,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,"{namezone name=""garbage dump""}" +"#build label(services_build) start(18; 18) hidden() message(Remember to enqueue manager orders for this blueprint. +Assign a minecart to the training ammo quantum dump with ""assign-minecarts all"") build basic hospital, dining room, and barracks" + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,A,A,A,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,h,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,b,`,`,`,"trackstopN{name=""Training bolts dumper"" take_from=""Training bolts feeder"" route=""Training bolts quantum""}",`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,b +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,d +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,t,`,`,d,R +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,l,`,`,h +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,d,R +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,` +,`,`,`,`,`,`,c,t,t,c,` +,`,`,`,`,`,`,c,t,t,c,` +,`,`,`,`,`,`,c,t,t,c,` +,`,`,`,`,`,`,c,t,t,c,` ,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,h,`,`,`,`,` ,,,,`,`,,`,` ,`,`,`,`,`,,`,`,`,`,` ,`,`,`,`,`,,`,`,`,`,` @@ -2527,50 +2173,28 @@ query_jail/services_query_jail ,`,`,`,`,`,,`,`,`,`,` ,`,`,`,`,`,,`,`,`,`,` -#> - -,,,,,,,,,,,,,`,"{namezone name=""jail3 well""}",`,,`,,`,"{namezone name=""jail4 well""}",` -,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,`,"{namezone name=""jail1 well""}",`,,`,,`,"{namezone name=""jail2 well""}",` -,,,,,,,,,,,,,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,`,,,,,,,,,` -,,,,,,,,,,,,,,,,,`,,,,,,,,,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,`,`,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,`,"{namezone name=""hospital well""}",` -,,,,,,,,,,,,,,,`,`,`,`,` -,,,,,,,,,,,,,,,`,`,`,`,` - -"#query label(services_query_stockpiles) start(18; 18) hidden() message(Configure the training ammo stockpile to take from the metalworker quantum on the industry level. Assign a minecart to the training ammo quantum dump with ""assign-minecarts all"") configure stockpiles" - -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,,`,,,,`,,,,`,,,,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,"{quantum name=""training quantum""}",`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,"{quantumstopfromsouth name=""Training quantum""}{givename name=""training dumper""}",`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,nocontainers,{bolts}{forbidmetalbolts}{forbidartifactammo},"{givename name=""training bolts""}",`,`,`,`,`,,`,,`,,`,,` +#place label(services_place2) start(18; 18) hidden() jail food and booze + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,"c{name=""Jail food"" take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,~,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,~,~,~,~,~,~,~,~,~,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,"{givename name=""garbage dump""}" +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,~,,,,,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,` @@ -2579,41 +2203,41 @@ query_jail/services_query_jail ,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,,`,` -,preparedfood,"{givename name=""prepared food""}",`,`,`,,booze,"{givename name=""booze""}",`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` - -"#query label(services_query_dining) start(18; 18) hidden() message(The tavern is restricted to residents only by default. If you'd like your tavern to attract vistors, please go to the (l)ocation menu and change the restriction.) set up dining room/tavern and barracks" - -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,,`,,,,`,,,,`,,,,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,r+&w,r+&w,r+&w,`,r+&w,r+&w,r+&w,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,r{+ 2}&,,,`,`,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,"r{+ 12}&h{givename name=""grand hall""}lai^l{Up}r^q",,,,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,` +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ + +#build label(services_build2) start(18; 18) hidden() message(Remember to enqueue manager orders for this blueprint.) expand each room + +,`,b,`,,`,b,`,,`,b,`,,`,`,`,,`,`,`,,t,l,b,,`,`,`,,`,`,` +,`,h,`,,`,h,`,,`,h,`,,`,`,`,,`,`,`,,c,v,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,d,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,A,A,A,~,~,~,A,A,A,A,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,c,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,t,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,c,`,` +,`,`,`,`,`,`,`,`,`,`,`,,~,`,`,`,`,`,`,`,h,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,~,`,`,`,~,`,`,`,b +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,b,,b,,b,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,d,,d,,d,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,~,~ +,`,`,`,`,`,l,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,~,`,`,~ +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,~,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,` +,`,c,t,t,c,`,~,~,~,~,` +,`,c,t,t,c,`,~,~,~,~,` +,`,c,t,t,c,`,~,~,~,~,` +,`,c,t,t,c,`,~,~,~,~,` ,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` +,h,`,`,`,`,~,`,`,`,`,h ,,,,`,`,,`,` ,`,`,`,`,`,,`,`,`,`,` ,`,`,`,`,`,,`,`,`,`,` @@ -2621,28 +2245,28 @@ query_jail/services_query_jail ,`,`,`,`,`,,`,`,`,`,` ,`,`,`,`,`,,`,`,`,`,` -#query label(services_query_rented_rooms) start(18; 18) hidden() attach rented rooms to tavern - -,r&l-&,r&l-&,r&l-&,,r&l-&,r&l-&,r&l-&,,r&l-&,r&l-&,r&l-&,,`,`,`,,`,,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,,`,,,,`,,,,`,,,,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` +#place label(services_place3) start(18; 18) hidden() remaining jail food and booze + +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,`,`,`,,`,`,`,,`,`,`,,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,~,,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)",,`,`,"c{name=""Jail booze"" barrels=-1 take_from=""Booze""}:+booze(1x2)" +,`,`,`,,`,`,`,,`,`,`,,"c{name=""Jail food"" take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,"c{name=""Jail food"" take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,~,`,`,,"c{name=""Jail food"" take_from=""Prepared food""}:+preparedmeals(2x1)",,`,,"c{name=""Jail food"" take_from=""Prepared food""}:+preparedmeals(2x1)",,` +,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,~,`,`,`,`,`,,`,,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,~,~,~,~,~,~,~,~,~,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,~,,,,,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,` ,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,` @@ -2651,172 +2275,42 @@ query_jail/services_query_jail ,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` - -"#build label(services_build2) start(18; 18) hidden() build rest of hospital and dining room, doors, prep for jail" - -,~,~,~,,~,~,~,,~,~,~,,`,`,`,,`,,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,v,`,d,`,d,`,v,` -,f,`,h,,f,`,h,,f,`,h,,`,`,`,,`,,`,`,` -,,d,,,,d,,,,d,,,,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,v,`,d,`,d,`,v,`,,`,`,c,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,~,,,,,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,b,~,~,~,`,~,~,~,h,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,b,`,`,`,~,`,`,`,`,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,b,`,`,`,`,`,`,`,`,~,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,b,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,b,`,`,`,`,`,`,`,a,,b,,b,,b,,~ -,`,`,`,`,`,`,`,`,`,`,`,,,,,~,,~,,,,,d,,d,,d,,d -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,~,`,`,`,d,~ -,`,c,t,t,c,`,c,t,t,c,`,~,`,d,`,`,`,`,`,d,`,d,`,`,`,`,`,`,~ -,`,c,t,t,c,`,c,t,t,c,`,,`,,`,`,`,`,`,,`,,`,`,`,~,`,`,`,d,~ -,`,c,t,t,c,`,c,t,t,c,`,~,`,d,`,`,`,`,`,d,`,d,`,`,`,`,`,`,f -,`,c,t,~,~,`,c,t,t,c,`,,,,`,`,`,`,`,,,,`,`,`,t,`,`,`,d,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ +,~,~,~,~,~,,~,~,~,~,~ + +#build label(services_build3) start(18; 18) hidden() message(Remember to enqueue manager orders for this blueprint.) finalize furniture + +,b,~,b,,b,~,b,,b,~,b,,t,l,b,,t,l,b,,~,~,~,,t,l,b,,t,l,b +,h,~,h,,h,~,h,,h,~,h,,c,v,`,,c,v,`,,~,~,`,,c,v,`,,c,v,` +,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` +,,d,,,,d,,,,d,,,,d,,,,d,,,,~,,,,d,,,,d +,`,`,`,s,`,`,`,s,`,`,`,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,,` +,s,`,`,`,`,`,`,`,`,`,s,,~,~,~,~,~,~,~,~,~,~,,`,,j,`,`,`,j +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,,`,,`,`,~,`,` +,s,`,`,`,`,`,`,`,`,`,s,,`,`,`,`,`,`,`,`,`,`,,`,,j,`,~,`,j +,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,d,`,d,`,`,~,`,` +,s,`,`,`,`,`,`,`,`,`,s,,~,h,h,`,`,`,h,h,~,`,,`,,j,`,`,`,j +,`,`,`,`,`,`,`,`,`,`,`,,~,b,b,`,~,`,b,b,~ +,s,`,`,`,`,`,`,`,`,`,s,,`,`,`,`,`,`,`,`,`,,~,,~,,~,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,,d,,d,,,,,~,,~,,~,,~ +,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,,`,,`,,` +,`,`,`,`,`,`,`,`,`,`,`,d,`,d,`,`,`,`,`,d,`,d,`,`,`,`,`,~,`,`,~,~ +,`,c,t,`,`,~,`,`,t,c,`,,s,,`,`,`,`,`,,s,,`,`,`,~,`,`,~ +,`,c,t,`,`,`,`,`,t,c,`,d,`,d,`,`,`,`,`,d,`,d,`,`,`,`,`,t,`,`,~,~ +,`,c,t,t,c,`,c,t,t,c,`,,,,`,`,`,`,`,,,,`,,`,,`,,` ,`,c,t,t,c,`,c,t,t,c,`,,,,,,`,,,,,,d,,d,,d,,d ,`,c,t,t,c,`,c,t,t,c,`,,,,,,,,,,,,b,,b,,b,,b -,`,c,t,t,c,`,c,t,t,c,` -,`,c,t,t,c,`,c,t,t,c,` -,`,c,t,t,c,`,c,t,t,c,` -,`,c,t,t,c,`,c,t,t,c,` -,`,`,`,`,`,`,`,`,`,`,` -,h,`,`,`,`,~,`,`,`,`,h -,,,,d,d,,d,d -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` - -#> - -,,,,,,,,,,,,,`,`,`,,`,,`,`,` -,,,,,,,,,,,,,`,`,`,d,`,d,`,`,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,`,`,`,,`,,`,`,` -,,,,,,,,,,,,,`,`,`,d,`,d,`,`,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,` -,,,,,,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,` -,,,,,,,,,,,,,,,,,`,,,,,,,,,` -,,,,,,,,,,,,,,,,,d,,,,,,,,,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,,d -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,`,`,` -,,,,,,,,,,,,,,,`,`,`,`,`,,,,,,`,`,` -,,,,,,,,,,,,,,,`,`,`,`,` -,,,,,,,,,,,,,,,`,`,`,`,` - -"#build label(services_build3) start(18; 18) hidden() jail, statues" - -,~,~,~,,~,~,~,,~,~,~,,t,l,b,,`,,t,l,b -,`,`,`,,`,`,`,,`,`,`,,c,~,`,~,`,~,c,~,` -,~,`,~,,~,`,~,,~,`,~,,`,`,`,,`,,`,`,` -,,~,,,,~,,,,~,,,,,,,` -,`,`,`,s,`,`,`,s,`,`,`,,t,l,b,,`,,t,l,b,,j,`,`,`,j -,`,`,`,`,`,`,`,`,`,`,`,,c,~,`,~,`,~,c,~,`,,`,`,~,`,` -,s,`,`,`,`,`,`,`,`,`,s,,`,`,`,,`,,`,`,`,,v,`,t,`,v -,`,`,`,`,`,`,`,`,`,`,`,,,,,,~,,,,,,`,`,c,`,` -,s,`,`,`,`,`,`,`,`,`,s,,~,~,~,~,`,~,~,~,~,,j,`,`,`,j -,`,`,`,`,`,`,`,`,`,`,`,,~,`,`,`,~,`,`,`,`,,,,d -,s,`,`,`,`,`,`,`,`,`,s,,~,`,`,`,`,`,`,`,`,~,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,~,`,`,`,`,`,`,`,` -,s,`,`,`,`,`,`,`,`,`,s,,~,`,`,`,`,`,`,`,~,,~,,~,,~,,~ -,`,`,`,`,`,`,`,`,`,`,`,,,,,~,,~,,,,,~,,~,,~,,~ -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,s,`,~,`,`,`,~,~ -,`,~,~,~,~,`,~,~,~,~,`,~,`,~,`,`,`,`,`,~,`,~,`,`,`,`,`,`,~ -,`,~,~,~,~,`,~,~,~,~,`,,s,,`,`,`,`,`,,s,,`,`,`,~,`,`,`,~,~ -,`,~,~,~,~,`,~,~,~,~,`,~,`,~,`,`,`,`,`,~,`,~,`,`,`,`,`,`,~ -,`,~,~,~,~,`,~,~,~,~,`,,,,`,`,`,`,`,,,,`,s,`,~,`,`,`,~,~ -,`,~,~,~,~,`,~,~,~,~,`,,,,,,`,,,,,,~,,~,,~,,~ -,`,~,~,~,~,`,~,~,~,~,`,,,,,,,,,,,,~,,~,,~,,~ ,`,~,~,~,~,`,~,~,~,~,` ,`,~,~,~,~,`,~,~,~,~,` ,`,~,~,~,~,`,~,~,~,~,` ,`,~,~,~,~,`,~,~,~,~,` ,`,`,`,`,`,`,`,`,`,`,` ,~,`,s,`,`,~,`,`,s,`,~ -,,,,~,~,,~,~ -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` - -#place label(services_place_jail) start(18; 18) hidden() - -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,`,f(1x2),`,`,`,`,`,f(1x2) -,`,`,`,,`,`,`,,`,`,`,,f(2x1),`,`,,`,,f(2x1),`,` -,,`,,,,`,,,,`,,,,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,f(1x2),`,`,`,`,`,f(1x2),,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,f(2x1),`,`,,`,,f(2x1),`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,,`,`,`,`,` - -#query label(services_query_jail) start(18; 18) hidden() message(Assign the office to the right of the barracks to your Sheriff/Captain of the Guard to use it as your interrogation room) set up barracks and jail - -,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,,`,`,` -,`,`,`,,`,`,`,,`,`,`,,`,"r--&j{givename name=""jail3""}","{booze}{givename name=""booze""}",`,`,`,`,"r--&j{givename name=""jail4""}","{booze}{givename name=""booze""}" -,`,`,`,,`,`,`,,`,`,`,,"{preparedfood}{givename name=""prepared food""}",t{Down 4}&,t{Down 4}&,,`,,"{preparedfood}{givename name=""prepared food""}",t{Down 4}&,t{Down 4}& -,,`,,,,`,,,,`,,,,,,,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,,`,,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,"r--&j{givename name=""jail1""}","{booze}{givename name=""booze""}",`,`,`,`,"r--&j{givename name=""jail2""}","{booze}{givename name=""booze""}",,`,`,"r+&{givename name=""sheriff's office""}",`,` -,`,`,`,`,`,`,`,`,`,`,`,,"{preparedfood}{givename name=""prepared food""}",t{Down 22}{Left 10}&,t{Down 22}{Left 4}&,,`,,"{preparedfood}{givename name=""prepared food""}",t{Left 6}&,t{Left 6}&,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,,,"{givename name=""interrogation""}" -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,`,`,`,`,`,`,`,`,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,`,,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,,,`,,`,,`,,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,,`,` +,,,,d,d,,d,d ,`,`,`,`,`,,`,`,`,`,` ,`,`,`,`,`,,`,`,`,`,` ,`,`,`,`,`,,`,`,`,`,` @@ -2828,14 +2322,14 @@ query_jail/services_query_jail Screenshot: https://drive.google.com/file/d/17jHiCKeZm6FSS-CI4V0r0GJZh09nzcO_ "" Features: -"- Big rooms, optionally pre-furnished. Double-thick walls to ensure engravings add value to the ""correct"" side. Declare locations from the pre-created meeting zones as needed." +"- Big rooms, optionally pre-furnished. Double-thick walls to ensure engravings add maximum value. Declare locations from the pre-created meeting zones as needed." "" Guildhall Walkthrough: 1) Dig out the rooms with /guildhall1. "" -"2) Once the area is dug out, pre-create the zones and add doors and a few statues with /guildhall2. Run ""quickfort orders"" for /guildhall2." +"2) Once the area is dug out, choose a /guildhall2 variant based on your needs. For your first copy of this level, you probably want /guildhall2_default, which includes temple and library zones. For later copies you probably want to create all locations yourself, so you should choose /guildhall2_no_locations if you want the default furnishings or /guildhall2_custom for a full blank slate. Run ""quickfort orders"" for your chosen variant." "" -"3) Furnish individual rooms manually, or get default furnishings for a variety of room types by running /guildhall3. If you use the default furnishings, also run ""quickfort orders"" for /guildhall3. Declare appropriate locations from the pre-created zones as you need guildhalls, libraries, and temples. If you'd like a ""no specific diety"" temple declared for the top room and a library declared for the bottom room, run /guildhall4. Both locations will be ""Residents only"" by default, but you can change this in the (l)ocation menu if you want them to attract visitors. If you need more rooms, you can dig another /guildhall1 in an unused z-level." +"Note that the default temple and library are created ""Residents only"", but you can change this in the location configuration screen if you want them to attract visitors. If you need more rooms, you can dig another /guildhall1 in an unused z-level." "#dig label(guildhall1) start(15; 15; central stairs) message(Once the area is dug out, continue with /guildhall2.)" @@ -2866,33 +2360,44 @@ Guildhall Walkthrough: ,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d -#meta label(guildhall2) +#meta label(guildhall2_default) furnished with default temple and library +locations/guildhall_locations doors/guildhall_doors +furnish/guildhall_furnish +"" +#meta label(guildhall2_no_locations) fully furnished and zoned but no locations zones/guildhall_zones -"#build label(guildhall_doors) start(15; 15; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint. -Smooth/engrave tiles, furnish rooms, and declare locations as required.) build doors" - +doors/guildhall_doors +furnish/guildhall_furnish +"" +#meta label(guildhall2_custom) only zones and doors +zones/guildhall_zones +doors/guildhall_doors +"" +"" +"#zone label(guildhall_locations) start(15; 15; central stairs) hidden() message(The library and temple are restricted to residents only by default. If you'd like them to attract vistors, please go to the location screen and change the restrictions.) declare a library and temple" +,m(9x9),,,,,,,,,"m{location=temple name=""All-inclusive temple"" allow=residents}(9x9)",,,,,,,,,m(9x9) ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,~,`,`,`,`,`,`,`,~,~,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,,,,,,d,,,,,,d,,d,,,,,,d -,,,,,,,d,,,,,,`,s,`,,,,,,d -,,`,`,`,`,`,`,`,,,,,d,,d,,,,,`,`,`,`,`,`,` +,,,,,,,~,,,,,,~,,~,,,,,,~ +,m(9x9),,,,,,~,,,,,,`,~,`,,,,m(9x9),,~ +,,`,`,`,`,`,`,`,,,,,~,,~,,,,,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,d,`,d,`,,,,`,d,`,d,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,s,,`,,`,,`,,s,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,d,`,d,`,,,,`,d,`,d,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,`,~,`,,,,`,~,`,~,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,~,,`,,`,,`,,~,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,`,~,`,,,,`,~,`,~,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,,,d,,d,,,,,`,`,`,`,`,`,` -,,,,,,,d,,,,,,`,s,`,,,,,,d -,,,,,,,d,,,,,,d,,d,,,,,,d +,,`,`,`,`,`,`,`,,,,,~,,~,,,,,`,`,`,`,`,`,` +,,,,,,,~,,,,,,`,~,`,,,,,,~ +,m(9x9),,,,,,~,,,m{location=library name=Library allow=residents}(9x9),,,~,,~,,,,m(9x9),,~ ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,~,~,`,`,`,`,`,`,`,~,~,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` @@ -2900,7 +2405,7 @@ Smooth/engrave tiles, furnish rooms, and declare locations as required.) build d ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -#zone label(guildhall_zones) start(15; 15; central stairs) hidden() designate zones +"#zone label(guildhall_zones) start(15; 15; central stairs) hidden() designate zones, ready for custom locations to be assigned" ,m(9x9),,,,,,,,,m(9x9),,,,,,,,,m(9x9) ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` @@ -2930,7 +2435,37 @@ Smooth/engrave tiles, furnish rooms, and declare locations as required.) build d ,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -"#build label(guildhall3) start(15; 15; central stairs) message(Remember to enqueue manager orders for this blueprint.) furnish 4 guildhalls, 3 temples, and a library" +#build label(guildhall_doors) start(15; 15; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build doors + + +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,,,,,,d,,,,,,d,,d,,,,,,d +,,,,,,,d,,,,,,`,s,`,,,,,,d +,,`,`,`,`,`,`,`,,,,,d,,d,,,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,d,`,d,`,,,,`,d,`,d,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,s,,`,,`,,`,,s,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,d,`,d,`,,,,`,d,`,d,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,,,d,,d,,,,,`,`,`,`,`,`,` +,,,,,,,d,,,,,,`,s,`,,,,,,d +,,,,,,,d,,,,,,d,,d,,,,,,d +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,`,d,d,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` + + +"#build label(guildhall_furnish) start(15; 15; central stairs) hidden() furnish 4 guildhalls, 3 temples, and a library" ,,`,`,`,`,s,`,`,,,`,s,`,c,`,`,f,,,`,`,s,`,`,`,` @@ -2960,36 +2495,6 @@ Smooth/engrave tiles, furnish rooms, and declare locations as required.) build d ,,`,`,`,`,s,`,`,,,h,~c,~c,s,~c,~c,h,,,`,`,s,`,`,`,` -"#query label(guildhall4) start(15; 15; central stairs) message(The library and temple are restricted to residents only by default. If you'd like them to attract vistors, please go to the (l)ocation menu and change the restriction.) declare a library and temple" - - -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,^ilat&^l{Up}r^q,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,,,,,,`,,,,,,`,,`,,,,,,` -,,,,,,,`,,,,,,`,`,`,,,,,,` -,,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,`,,`,,`,,`,,`,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,,,`,,`,,,,,`,`,`,`,`,`,` -,,,,,,,`,,,,,,`,`,`,,,,,,` -,,,,,,,`,,,,,,`,,`,,,,,,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,^ilal&^l{Up}r^q,,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` -,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,`,`,` - - #notes label(beds_help) Suites for nobles and apartments for the teeming masses Suites screenshot: https://drive.google.com/file/d/1IBqCf6fF3lw7sHiBE_15Euubysl5AAiS @@ -2998,23 +2503,17 @@ Apt. screenshot: https://drive.google.com/file/d/1mDQQXG8BnXqasRGFC9R5N6xNALiswE Features: - Well-appointed suites to satisfy nobles - Apartments with beds and storage to keep dwarves happy and the fortress clean -- Apartments also serve as burial chambers since dwarves like looking at coffins -- Meta blueprint included for designating 5 levels of apartments for a full 200+ dwarves "" Suites Walkthrough: 1) Dig out the suites layer with /suites1. "" -"2) Once the area is dug out, furnish the suites with /suites2. The rooms are left unconfigured so you can assign them to specific nobles. Each room can serve as a bedroom, a dining hall, an office, and/or a tomb. Run ""quickfort orders"" for /suites2." +"2) Once the area is dug out, furnish the suites with /suites2. The rooms are left unzoned so you can configure them for specific nobles. Each room can serve as a bedroom, a dining hall, an office, and/or a tomb. Run ""quickfort orders"" for /suites2." "" Apartments Walkthrough: -"1) Dig out one layer of apartments with /apartments1, or 5 layers at once (enough for 200 dwarves) with by adding ""--repeat down,5"" to the quickfort command." +"1) Dig out one layer of apartments with /apartments1, or 5 layers at once (enough for 200 dwarves) with by adding ""--repeat down,5"" to the quickfort command or adjusting the settings in the gui/quickfort UI." "" -"2) Once a layer is dug out, build beds with /apartments2. Run ""quickfort orders"" for /apartments2." -"" -"3) Once the beds are built, configure the rooms and build the remaining furniture with /apartments3. Run ""quickfort orders"" for /apartments3." -"" -"4) Once the coffins are all in place, run ""burial -pets"" to set them all to accept burials." -"#dig label(suites1) start(18; 18; central ramp) message(Once the area is dug out, run /suites2) noble suites" +"2) Once a layer is dug out, build furniture with /apartments2. Run ""quickfort orders"" for /apartments2." +"#dig label(suites1) start(18; 18; central stairs) message(Once the area is dug out, run /suites2) noble suites" ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d @@ -3050,47 +2549,47 @@ Apartments Walkthrough: ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -"#meta label(suites2) start(central ramp) message(Remember to enqueue manager orders for this blueprint. -bedrooms are left unconfigured so you can assign them to specific nobles.) build furniture and set traffic patterns" +"#meta label(suites2) start(central stairs) message(Remember to enqueue manager orders for this blueprint. +rooms are left unzoned so you can configure them for specific nobles.) build furniture and set traffic patterns" traffic_suites/suites_traffic build_suites/suites_build -#dig label(suites_traffic) start(18; 18; central ramp) hidden() +#dig label(suites_traffic) start(18; 18; central stairs) hidden() don't path through other dwarves' rooms ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,,,,or,,,,,,or,,,,`,,`,,,,or,,,,,,or,,,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,,,or,,,,,,or,,,,`,`,`,,,,or,,,,,,or,,,,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,,,,or,,,,,,or,,,,oh,,oh,,,,or,,,,,,or,,,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,`,`,`,`,`,or,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,`,`,`,`,`,or,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,,,or,,,,,,or,,,,oh,`,oh,,,,or,,,,,,or,,,,`,` +,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,` ,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,,,,or,,,,,,or,,,,`,`,`,,,,or,,,,,,or,,,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,`,`,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,,,or,,,,,,or,,,,`,,`,,,,or,,,,,,or,,,,`,` +,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,` +,`,`,,,,or,,,,,,or,,,,oh,`,oh,,,,or,,,,,,or,,,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,`,`,`,`,`,or,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,`,`,`,`,`,or,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` +,`,`,,,,or,,,,,,or,,,,oh,,oh,,,,or,,,,,,or,,,,`,` ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -#build label(suites_build) start(18; 18; central ramp) hidden() +#build label(suites_build) start(18; 18; central stairs) hidden() ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` @@ -3126,150 +2625,316 @@ build_suites/suites_build ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -"#dig label(apartments1) start(18; 18; central ramp) message(Once the area is dug out, continue with /apartments2.) apartment complex" - -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d -,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,,d,,,,d,,,,d,,,d,d,d,,,d,,,,d,,,,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d +"#dig label(apartments1) start(18; 18; central stairs) message(Once the area is dug out, continue with /apartments2.) apartment complex" + +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,,d,,,d,,,d,,,d,,,d,,d,,,d,,,d,,,d,,,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,,d,,,d,,,d,,,d,,d,d,d,,d,,,d,,,d,,,d,,,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d ,,,,,,,,,,,,,,,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,,d,,d,d,d,,d,d,d,,d,d,d -,,,,,d,,,,d,,,,d,,,d,d,d,,,d,,,,d,,,,d -,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,,d,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,,,d,,,d,,,d,,,d,,,d,d,d,,,d,,,d,,,d,,,d,,,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d ,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,`,~,`,d,,d,d,d,d,d,d,d,d,d,d,d,d,d -,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,,d,d,d -,,,,,d,,,,d,,,,d,,,d,d,d,,,d,,,,d,,,,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d +,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,,,d,,,d,,,d,,,d,,,d,d,d,,,d,,,d,,,d,,,d,,,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d ,,,,,,,,,,,,,,,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,,d,,,,d,,,,d,,,d,d,d,,,d,,,,d,,,,d -,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d -,,,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d,,d,d,d - -"#build label(apartments2) start(18; 18; central ramp) message(Remember to enqueue manager orders for this blueprint. -Once beds have been placed, continue with /apartments3.) build beds" - -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,`,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,,,,,,,,,,,,`,`,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,`,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` -,`,b,`,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,`,b,` -,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,`,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,,,,,,,,,,,,`,`,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,`,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,`,,`,b,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` - -#meta label(apartments3) start(central ramp) message(Remember to enqueue manager orders for this blueprint.) configure rooms and build remaining furniture -query_apartments/apartments_rooms -build2_apartments/apartments_build2 -#query label(apartments_rooms) start(18; 18) hidden() configure rooms - -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,`,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,,,,,,,,,,,,`,`,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,`,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` -,`,r-&,`,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,`,r-&,` -,`,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,`,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,,,,,,,,,,,,`,`,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,`,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,,`,,,,`,,,,`,,,`,`,`,,,`,,,,`,,,,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,,,,`,,,,`,,,,`,,,,`,,,,`,,,,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` -,,,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,`,,`,r-&,` -,,,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,`,,`,`,` - -"#build label(apartments_build2) start(18; 18) hidden() message(Coffins should be configured with DFHack ""burial"" script) build remaining furniture" - -,,,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f -,,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,s,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,d,,,,d,,,,d,,,`,`,`,,,d,,,,d,,,,d -,,,,n,`,h,,n,`,h,,n,`,h,,`,`,`,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,s,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,`,`,`,,n,`,f,,n,`,f,,n,`,f +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,d,,,d,,,d,,,d,,,d,,d,d,d,,d,,,d,,,d,,,d,,,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,,,,d,,,d,,,d,,,d,,,d,,d,,,d,,,d,,,d,,,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d +,,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d,,d,d + +#meta label(apartments2) start(central stairs) zone rooms and build furniture +zone_apartments/apartments_rooms +build_apartments/apartments_build +#zone label(apartments_rooms) start(18; 18; central stairs) hidden() zone rooms +,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5) +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,,`,,,`,,,`,,,`,,,`,,`,,,`,,,`,,,`,,,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,,`,`,`,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,,`,`,`,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5) +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,,,`,,,`,,,`,,,`,,,`,`,`,,,`,,,`,,,`,,,`,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,,`,`,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,,`,`,`,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5) +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,`,,,`,,,`,,,`,,,`,,`,`,`,,`,,,`,,,`,,,`,,,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),,`,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),`,,b(4x5),` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` + +#build label(apartments_build) start(18; 18; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build furniture + +,,,f,h,,f,h,,f,h,,f,h,,f,h,,h,f,,h,f,,h,f,,h,f,,h,f +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,b,`,,b,`,,b,`,,b,`,,b,`,,`,b,,`,b,,`,b,,`,b,,`,b +,,,,`,,,`,,,`,,,`,,,`,,`,,,`,,,`,,,`,,,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,,,`,,,`,,,`,,,`,,`,`,`,,`,,,`,,,`,,,`,,,` +,b,`,,b,`,,b,`,,b,`,,b,`,,`,`,`,,`,b,,`,b,,`,b,,`,b,,`,b +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,f,h,,f,h,,f,h,,f,h,,f,h,,`,`,`,,h,f,,h,f,,h,f,,h,f,,h,f ,,,,,,,,,,,,,,,,`,`,` -,,,,n,`,h,,n,`,h,,n,`,h,,`,s,`,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,`,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,d,,d,,n,`,f,,n,`,f,,n,`,f -,,,,,d,,,,d,,,,d,,,`,`,`,,,d,,,,d,,,,d -,n,`,h,,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,,n,`,h -,`,~,`,d,`,s,`,`,s,`,`,s,`,,`,`,~,`,`,,`,s,`,`,s,`,`,s,`,d,`,~,` -,n,`,f,,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,,n,`,f -,,,,,d,,,,d,,,,d,,,`,`,`,,,d,,,,d,,,,d -,,,,n,`,h,,n,`,h,,n,`,h,,d,,d,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,`,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,`,s,`,,n,`,f,,n,`,f,,n,`,f +,h,f,,h,f,,h,f,,h,f,,h,f,,`,`,`,,f,h,,f,h,,f,h,,f,h,,f,h +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,`,b,,`,b,,`,b,,`,b,,`,b,,`,,`,,b,`,,b,`,,b,`,,b,`,,b,` +,`,,,`,,,`,,,`,,,`,,,`,`,`,,,`,,,`,,,`,,,`,,,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,,,`,,,`,,,`,,,`,,,`,`,`,,,`,,,`,,,`,,,`,,,` +,`,b,,`,b,,`,b,,`,b,,`,b,,`,,`,,b,`,,b,`,,b,`,,b,`,,b,` +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,h,f,,h,f,,h,f,,h,f,,h,f,,`,`,`,,f,h,,f,h,,f,h,,f,h,,f,h ,,,,,,,,,,,,,,,,`,`,` -,,,,n,`,h,,n,`,h,,n,`,h,,`,`,`,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,s,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,`,`,`,,n,`,f,,n,`,f,,n,`,f -,,,,,d,,,,d,,,,d,,,`,`,`,,,d,,,,d,,,,d -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,s,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d,,,,d -,,,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h,,n,`,h -,,,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,`,,`,~,` -,,,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f,,n,`,f +,f,h,,f,h,,f,h,,f,h,,f,h,,`,`,`,,h,f,,h,f,,h,f,,h,f,,h,f +,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,b,`,,b,`,,b,`,,b,`,,b,`,,`,`,`,,`,b,,`,b,,`,b,,`,b,,`,b +,,`,,,`,,,`,,,`,,,`,,`,`,`,,`,,,`,,,`,,,`,,,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,,,`,,,`,,,`,,,`,,`,,,`,,,`,,,`,,,` +,,,b,`,,b,`,,b,`,,b,`,,b,`,,`,b,,`,b,,`,b,,`,b,,`,b +,,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,`,,`,` +,,,f,h,,f,h,,f,h,,f,h,,f,h,,h,f,,h,f,,h,f,,h,f,,h,f + +#notes label(crypt_help) +Places to rest your dead +Screenshot: https://drive.google.com/file/d/1IBqCf6fF3lw7sHiBE_15Euubysl5AAiS +"" +Features: +"- Staged crypt expansion that grows with your, um, need" +- 52 tombs in stage 1 +- 160 additional tombs in stage 2 (212 tombs total) +- Extendable in any direction by applying the blueprints multiple times +"" +Crypt Walkthrough: +1) Dig out the layer with /crypt1. +"" +"2) Once the area is dug out, add initial tombs with /crypt2." +"" +"3) If/when you need additional tombs, apply /crypt3." +"#dig label(crypt1) start(18; 18; central stairs) message(Once the area is dug out, continue with /crypt2.) crypt complex" + +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,d,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,d,d,d,,,,d,d,d,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,,~,,d,d,d,d +,,d,,d,,d,,d,,d,,d,d,d,d,,,,d,d,d,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,d,d,d,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,d,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,d,d,d,d,d,d,d,d,d,d,d,d,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d,d +,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d,,d +,,,,,,,,,,,,d,d,d,d,d,d,d,d,d,d,d + +#meta label(crypt2) start(central stairs) small crypt that can be extended later +zone/crypt_zone +build/crypt_build +"" +#meta label(crypt3) start(central stairs) crypt extension +zone_extended/crypt_extended_zone +build_extended/crypt_extended_build +#zone label(crypt_zone) start(18; 18; central stairs) hidden() zone tombs + + + + + + + + + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,` +,,,,,,,,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,` +,,,,,,,,T{pets=true}(1x1),,T{pets=true}(1x1),,`,`,`,`,,,,`,`,`,`,,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,,~,,`,`,`,` +,,,,,,,,T{pets=true}(1x1),,T{pets=true}(1x1),,`,`,`,`,,,,`,`,`,`,,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,` +,,,,,,,,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,`,`,`,,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,` +,,,,,,,,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` + + + + + + + + + +#build label(crypt_build) start(18; 18; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build urns + + + + + + + + + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n +,,,,,,,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,` +,,,,,,,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,n,,n,,`,,n,,`,s,`,,n,,`,,n,,n +,,,,,,,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,` +,,,,,,,,n,,n,,`,`,`,`,,,,`,`,`,`,,n,,n +,,,,,,,,,,,,`,`,s,`,,~,,`,s,`,` +,,,,,,,,n,,n,,`,`,`,`,,,,`,`,`,`,,n,,n +,,,,,,,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,` +,,,,,,,,n,,n,,`,,n,,`,s,`,,n,,`,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,,,,,,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n +,,,,,,,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,` +,,,,,,,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` + + + + + + + + + +#zone label(crypt_extended_zone) start(18; 18; central stairs) hidden() zone more tombs + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,~,,~,,`,,~,,~,,~,,~,,`,,~,,~,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,~,,~,,`,,~,,~,,~,,~,,`,,~,,~,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,~,,~,,`,,~,,`,`,`,,~,,`,,~,,~,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,~,,~,,`,`,`,`,,,,`,`,`,`,,~,,~,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,,~,,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,~,,~,,`,`,`,`,,,,`,`,`,`,,~,,~,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,~,,~,,`,,~,,`,`,`,,~,,`,,~,,~,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,~,,~,,`,,~,,~,,~,,~,,`,,~,,~,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,~,,~,,`,,~,,~,,~,,~,,`,,~,,~,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,`,,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1),,T{pets=true}(1x1) +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` + +#build label(crypt_extended_build) start(18; 18; central stairs) hidden() message(Remember to enqueue manager orders for this blueprint.) build more urns + +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,~,,~,,`,,~,,~,,~,,~,,`,,~,,~,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,~,,~,,`,,~,,~,,~,,~,,`,,~,,~,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,~,,~,,`,,~,,`,~,`,,~,,`,,~,,~,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,~,,~,,`,`,`,`,,,,`,`,`,`,,~,,~,,n,,n,,n +,,,,,,,,,,,,`,`,~,`,,~,,`,~,`,` +,,n,,n,,n,,~,,~,,`,`,`,`,,,,`,`,`,`,,~,,~,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,`,`,`,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,~,,~,,`,,~,,`,~,`,,~,,`,,~,,~,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,~,,~,,`,,~,,~,,~,,~,,`,,~,,~,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,~,,~,,`,,~,,~,,~,,~,,`,,~,,~,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,n,,n,,n,,n,,n,,`,,n,,n,,n,,n,,`,,n,,n,,n,,n,,n +,,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,` From 25530d6e7be72a8839ea9975e2dc74789a23d934 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 7 Jun 2023 12:26:49 -0700 Subject: [PATCH 0259/1234] guide update - first draft --- docs/guides/quickfort-user-guide.rst | 1362 ++++++++++++++++---------- library/xml | 2 +- scripts | 2 +- 3 files changed, 822 insertions(+), 544 deletions(-) diff --git a/docs/guides/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst index ec416f18f..a06413d40 100644 --- a/docs/guides/quickfort-user-guide.rst +++ b/docs/guides/quickfort-user-guide.rst @@ -4,12 +4,12 @@ Quickfort blueprint creation guide ================================== -`Quickfort ` is a DFHack script that helps you build fortresses from +`Quickfort ` is a DFHack tool that helps you build fortresses from "blueprint" .csv and .xlsx files. Many applications exist to edit these files, such as MS Excel and `Google Sheets `__. Most layout and building-oriented DF commands are supported through the use of multiple files or -spreadsheets, each describing a different phase of DF construction: designation, -building, placing stockpiles/zones, and setting configuration. +spreadsheets, each describing a different phase of DF construction: designating +digging, defining zones, placing stockpiles, and building. The original idea came from :wiki:`Valdemar's ` auto-designation macro. Joel Thornton reimplemented the core logic in Python and extended its @@ -21,51 +21,44 @@ interacts with Dwarf Fortress memory structures directly, allowing for instantaneous blueprint application, error checking and recovery, and many other advanced features. -This guide focuses on DFHack Quickfort's capabilities and teaches players how -to understand and create blueprint files. Some of the text was originally -written by Joel Thornton, reused here with his permission. +This guide focuses on DFHack Quickfort's capabilities and blueprint syntax, and +teaches players how to understand and create blueprint files. Some of the text +was originally written by Joel Thornton, reused here with his permission. -For those just looking to apply existing blueprints, check out the `quickfort -command's documentation ` for syntax. There are also many -ready-to-use blueprints available in the ``hack/data/blueprints`` subfolder in -your DFHack installation. Browse them on your computer or -:source:`online `, or run `gui/quickfort` to browse -and apply them to your fort! +If you are just looking to apply existing blueprints to your fort, check out +`gui/quickfort` (or `quickfort` for the commandline version). There are many +ready-to-use blueprints available in the `quickfort-library-guide` distributed +with DFHack. Before you become an expert at writing blueprints, though, you should know that the easiest way to make a quickfort blueprint is to build your plan "for real" -in Dwarf Fortress and then export your map using the DFHack `blueprint` plugin. -You can apply those blueprints as-is in your next fort, or you can fine-tune -them with additional features from this guide. +in Dwarf Fortress and then export your map using `gui/blueprint`. You can apply +those blueprints as-is in your next fort, or you can fine-tune them with +additional features from this guide. See the `Links`_ section for more information and online resources. - .. contents:: Table of Contents :local: :depth: 2 - Features -------- - General - - Manages blueprints to handle all phases of DF construction - - Supports .csv and multi-worksheet .xlsx blueprint files + - Blueprint modes for all phases of fort design + - Read blueprints from .csv or multi-worksheet .xlsx files - Near-instant application, even for very large and complex blueprints - Blueprints can span multiple z-levels - - You can package all blueprints and keystroke aliases needed for an entire - fortress in a single file for easy sharing - - "meta" blueprints that simplify the application of sequences of blueprints - - Undo functionality for dig, build, place, and zone blueprints - - Rotate blueprints or flip them around to your preference when you apply - them to the map - - Automatic cropping of blueprints so you don't get errors if the blueprint - extends off the map - - Can generate manager orders for everything required by a build blueprint + - Easy sharing of blueprints with multi-blueprint files + - Scripted application of sequences of blueprints + - Easy undo + - Rotate blueprints or flip them around + - Automatic cropping of blueprints that extend off the map + - Generate manager orders for items required by a blueprint - Includes a library of ready-to-use blueprints - - Blueprint debugging features + - Blueprint debugging - Dig mode @@ -76,58 +69,44 @@ Features - Handles carving arbitrarily complex minecart tracks, including tracks that cross other tracks +- Zone and place modes + + - Define zones and stockpiles of any shape, not just rectangles + - Configurable numbers of bins, barrels and wheelbarrows assigned to created + stockpiles + - Automatic splitting of stockpiles that exceed maximum dimension limits + - Create and attach locations to zones + - Full control over stockpile configuration based on the `stockpiles` + settings library + - Configurable zone/location settings, such as the pit/pond toggle or + hospital supply quantities + - Build mode - - Fully integrated with DFHack buildingplan: you can place buildings before - manufacturing building materials and you can use the buildingplan UI for - setting materials preferences + - Integrated with DFHack `buildingplan`: you can place buildings before + manufacturing building materials and you can use the `buildingplan` UI + for setting materials and quality preferences - Designate entire constructions in mid-air without having to wait for each tile to become supported - Automatic expansion of building footprints to their minimum dimensions, so only the center tile of a multi-tile building needs to be recorded in the blueprint - Tile occupancy and validity checking so, for example, buildings that - cannot be placed on a target tile will be skipped instead of messing up - the blueprint. Blueprints that are only partially applied for any reason - (e.g. you need to dig out some more tiles) can be safely reapplied to - build the remaining buildings. + cannot be placed on a target tile will be skipped instead of causing + errors and interrupting the blueprint. Blueprints that are only partially + applied for any reason (e.g. you need to dig out some more tiles) can be + safely reapplied to build the remaining buildings. - Relaxed rules for farm plot and road placement: you can still place the building even if an invalid tile (e.g. stone tiles for farm plots) splits the designated area into two disconnected parts - Intelligent boundary detection for adjacent buildings of the same type (e.g. a 6x6 block of ``wj`` cells will be correctly split into 4 jeweler's workshops) + - Set building properties (such as a name) + - Attach track stops to hauling routes -- Place and zone modes - - - Define stockpiles and zones of any shape, not just rectangles - - Configurable numbers of bins, barrels and wheelbarrows assigned to created - stockpiles - - Automatic splitting of stockpiles and zones that exceed maximum dimension - limits - - Fully configurable zone settings, such as pit/pond and hospital supply - counts - -- Query mode - - - Send arbitrary keystroke sequences to the UI -- *anything* you can do - through the UI is supported - - Supports aliases to simplify frequent keystroke combos - - Includes a library of pre-made and tested aliases to simplify most common - tasks, such as configuring stockpiles for important item types or creating - hauling routes for quantum stockpiles. - - Supports expanding aliases in other aliases for easy management of common - subsequences - - Supports repeating key sequences a specified number of times - - Skips sending keys when the cursor is over a tile that does not have a - stockpile or building, so missing buildings won't desynchronize your - blueprint - - Instant halting of query blueprint application when keystroke errors are - detected, such as when a mistake in a key sequence leaves us stuck in a - submenu, to make query blueprints easier to debug - -Creating blueprints -------------------- +Introduction to blueprints +-------------------------- We recommend using a spreadsheet editor such as Excel, `Google Sheets `__, or `LibreOffice `__ @@ -138,29 +117,27 @@ line (or upper-left cell) of the spreadsheet should look like this:: #dig -The keyword ``dig`` tells Quickfort we are going to be using the Designations -menu in DF. The following "mode" keywords are understood: +The keyword ``dig`` tells Quickfort we are going to be specifying designations. +The following "mode" keywords are understood: ============== =========== Blueprint mode Description ============== =========== -dig Designations menu (:kbd:`d`) -build Build menu (:kbd:`b`) -place Place stockpiles menu (:kbd:`p`) -zone Activity zones menu (:kbd:`i`) -query Set building tasks/prefs menu (:kbd:`q`) +dig Designations (digging, traffic, dumping, etc.) +build Constructions, buildings, and furniture +place Stockpiles +zone Activity zones ============== =========== If no modeline appears in the first cell, Quickfort assumes that it's looking at a ``#dig`` blueprint. There are also other modes that don't directly correspond to Dwarf Fortress -menus, but we'll talk about those `later `. +design operations, but we'll talk about those `later `. If you like, you may enter a comment after the mode keyword. This comment will -appear in the output of ``quickfort list`` when run from the ``DFHack#`` prompt -or in the dialog window when running `gui/quickfort`. You can use this space for -explanations, attribution, etc.:: +appear in the output of ``quickfort list`` or in the dialog window when running +`gui/quickfort`. You can use this space for explanations, attribution, etc.:: #dig grand dining room @@ -176,12 +153,31 @@ readability, but a real .csv file would have commas):: d d d d # # # # # # +The letter ``d`` here stands for "dig". The character sequences in these +blueprints are based on the old (pre-v50) keyboard shortcuts for the various DF +menus. Please see the `quickfort_guide_appendix` below for a full listing. + Note the :kbd:`#` symbols at the right end of each row and below the last row. These are completely optional, but can be helpful to make the row and column positions clear. -Once the dwarves have that dug out, let's build a walled-in bedroom within our -dug-out area:: +Once the dwarves have that dug out, let's zone it as a bedroom:: + + #zone + b b b b # + b b b b # + b b b b # + b b b b # + # # # # # + +This looks very similar to the ``#dig`` blueprint above, but with ``b``s +instead of ``d``s. The ``b``s mark the area for a ``b``edroom zone just like +the ``#dig`` blueprint marked the area for digging. It's important to wait +until after the area is completely dug out before applying further blueprints +since zones can't be applied to hidden tiles and furniture can't be built in +undug walls. + +Now, let's add some walls and furniture:: #build Cw Cw Cw Cw # @@ -190,17 +186,17 @@ dug-out area:: Cw Cw Cw # # # # # # -Note my generosity -- in addition to the bed (:kbd:`b`) I've built a container -(:kbd:`h`) here for the dwarf as well. You must use the full series of keys -needed to build something in each cell, e.g. :kbd:`C`:kbd:`w` indicates we -should enter DF's constructions submenu (:kbd:`C`) and select walls (:kbd:`w`). +The :kbd:`C`:kbd:`w` cells represent the constructed walls, leaving space for a +door that we might want to add later. And note my generosity -- in addition to +the bed (:kbd:`b`) I've built a container (:kbd:`h`) here for the dwarf as +well. -I'd also like to place a booze stockpile in the 2 unoccupied tiles in the room:: +Finally, let's place a booze stockpile in the 2 unoccupied tiles in the room:: - #place Place a food stockpile + #place personal booze stockpile ` ` ` ` # ` ~ ~ ` # - ` f f ` # + ` f f{name="bedroom booze"}:=booze ` ` ` # # # # # # @@ -213,45 +209,19 @@ multilayer or fortress-wide blueprint layouts as "chalk lines". QF is smart enough to recognize this as a 2x1 food stockpile, and creates it as such rather than as two 1x1 food stockpiles. Quickfort treats any connected region of identical designations as a single entity. The tiles can be connected -orthogonally or diagonally, just as long as they are touching. +orthogonally or diagonally, just as long as they are touching. You can also +treat disconnected segments as belonging to the same stockpile, but we'll get +into that later. -Lastly, let's turn the bed into a bedroom and set the food stockpile to hold -only booze. +Now what's all that business attached to the second ``f``? The part between the +curly brackets specifies properties, in this case the name that we want to give +the stockpile. The remaining part, from the colon (``:``) onward, applies the +``booze`` preset from the `stockpiles` library. That will configure the +stockpile to accept only booze. You can use presets (along with other options +that we'll go over later) to configure stockpiles however you want, directly +from the ``#place`` blueprint. -:: - - #query - ` ` ` ` # - ` r& ` # - ` booze # - ` ` ` ` # - # # # # # - -In row 2, column 2 we have ``r&``. This sends the :kbd:`r` key to DF when the -cursor is over the bed, causing us to "make room" and :kbd:`Enter`, represented -by special ``&`` alias, to indicate that we're done setting the size (the -default room size is fine here). - -In column 2, row 3 we have ``booze``. This is one of many alias keywords defined -in the included :source:`aliases library `. -This particular alias sets a food stockpile to accept only booze. It sends the -keys needed to navigate DF's stockpile settings menu, and then it sends an -Escape character to exit back to the map. It is important to exit out of any -menus that you enter while in query mode so that the cursor can move to the next -tile when it is done with the current tile. - -If there weren't an alias named ``booze`` then the literal characters -:kbd:`b`:kbd:`o`:kbd:`o`:kbd:`z`:kbd:`e` would have been sent, so be sure to -spell those aliases correctly! - -You can save a lot of time and effort by using aliases instead of adding all -key sequences directly to your blueprints. For more details, check out the -`quickfort-alias-guide`. You can also see examples of aliases being used in the -query blueprints in the -:source:`DFHack blueprint library `. You can create -your own aliases by adding them to :source:`dfhack-config/quickfort/aliases.txt` -in your DFHack folder or you can package them -`together with your blueprint files `. +And that's it! You now have a series of blueprints that you can "stamp" across your fort to quickly build new bedrooms. Area expansion syntax ~~~~~~~~~~~~~~~~~~~~~ @@ -273,7 +243,7 @@ In Quickfort, the following blueprints are equivalent:: The second example uses Quickfort's "area expansion syntax", which takes the form:: - keys(WxH) + text(WxH) Note that area expansion syntax can only specify rectangular areas. If you want to create extent-based structures (e.g. farm plots or stockpiles) in different @@ -333,6 +303,36 @@ blueprint could also be written as:: ga(4x-2) ` # # # # # # +Property syntax +~~~~~~~~~~~~~~~ + +Many things you can designate with `quickfort` are configurable. All buildings, +stockpiles, and zones, for example, can be named. These configuration elements +are expressed as properties. + +Properties are written between curly brackets (``{}``). There can be multiple +properties defined between those brackets, separated by spaces. Each property +has a name and a value, with an equal sign to connect them. If a property value +has a space within it, it should be surrounded by double quotes (``"``). + +If you have defined the area of something over multiple spreadsheet cells, you +can specify properties in just one of those cells and they will apply to the +whole object. You can even split properties up among multiple cells if that is +more convenient. If you are using expansion syntax, the expansion part always +goes last. + +Here's an example of a seed stockpile that is configured to take from a seed feeder stockpile:: + + #place + f{name=Seeds links_only=true}:=seeds(3x2) + + f + f{name="Seeds feeder" give_to=Seeds}:=seeds + f{containers=0} + +Different modes and different types may have different properties that you can +configure. See the `quickfort_guide_appendix` for a full list. + Automatic area expansion ~~~~~~~~~~~~~~~~~~~~~~~~ @@ -406,15 +406,21 @@ You can go up or down multiple levels by adding a number after the ``<`` or #>2 r(10x10) +#dig mode +--------- + +``#dig`` blueprints are normally the first step in any design. They define the +boundaries and layouts for the blueprints for later stages of construction. Despite their name, ``#dig``` blueprints are for more than just digging. They also handle smoothing, carving, traffic designations, and marking items on the ground for dumping, forbidding, or other similar tags. See the full list of supported designations in the `#dig mode reference`_. + .. _quickfort-dig-priorities: Dig priorities ~~~~~~~~~~~~~~ -DF designation priorities are supported for ``#dig`` blueprints. The full syntax -is ``[letter][number][expansion]``, where if the ``letter`` is not specified, +DF designation priorities are supported in ``#dig`` blueprints. The full syntax +is ``[symbol][number][expansion]``, where if the ``symbol`` is not specified, ``d`` is assumed, and if ``number`` is not specified, ``4`` is assumed (the -default priority). So each of these blueprints is equivalent:: +default priority). So all of these blueprints are equivalent:: #dig dig the interior of the room at high priority d d d d d # @@ -457,222 +463,24 @@ center of the room marked for digging later:: d d d d d # # # # # # # -Then you can use "Toggle Standard/Marking" (:kbd:`d`:kbd:`M`) to convert the -center tiles to regular designations at your leisure. +Then you can use DF's "Toggle Standard/Marking" icons (DF calls them +"blueprints", but hopefully that won't get too confusing in this context) to +convert the center tiles to regular designations at your leisure. To apply an entire dig blueprint in marker mode, regardless of what the blueprint itself says, you can set the global quickfort setting -``force_marker_mode`` to ``true`` before you apply the blueprint. +``force_marker_mode`` to ``true`` before you apply the blueprint by running +``quickfort set force_marker_mode true``. -Note that the in-game UI setting "Standard/Marker Only" (:kbd:`d`:kbd:`m`) does -not have any effect on quickfort. +Note that the state of the in-game vanilla button that you use to draw +designations in either Standard or "Blueprint" mode does not have any effect on +`quickfort`. -Stockpiles and zones -~~~~~~~~~~~~~~~~~~~~ - -It is very common to have stockpiles that accept multiple categories of items or -zones that permit more than one activity. Although it is perfectly valid to -declare a single-purpose stockpile or zone and then modify it with a ``#query`` -blueprint, quickfort also supports directly declaring all the types in the -``#place`` and ``#zone`` blueprints. For example, to declare a 20x10 stockpile -that accepts both corpses and refuse, you could write:: - - #place refuse heap - yr(20x10) - -And similarly, to declare a zone that is a pasture, a fruit picking area, and a -meeting area all at once:: - - #zone main pasture and picnic area - nmg(10x10) - -The order of the individual letters doesn't matter. If you want to configure the -stockpile from scratch in a ``#query`` blueprint, you can place unconfigured -"custom" stockpiles with (:kbd:`c`). It is more efficient, though, to place -stockpiles using the keys that represent the categories of items that you want -to store, and then only use a ``#query`` blueprint if you need fine-grained -customization. - -.. _quickfort-place-containers: - -Stockpile bins, barrels, and wheelbarrows -````````````````````````````````````````` - -Quickfort has global settings for default values for the number of bins, -barrels, and wheelbarrows assigned to stockpiles, but these numbers can be set -for individual stockpiles as well. - -To set the number of bins, barrels, or wheelbarrows, just add a number after the -letter that indicates what type of stockpile it is. For example:: - - #place a stone stockpile with 5 wheelbarrows - s5(3x3) - - #place a bar, ammo, weapon, and armor stockpile with 20 bins - bzpd20(5x5) - -If the specified number exceeds the number of available stockpile tiles, the -number of available tiles is used. For wheelbarrows, that limit is reduced by 1 -to ensure there is at least one non-wheelbarrow tile available in the stockpile. -Otherwise no stone would ever be brought to the stockpile since all tiles would -be occupied by wheelbarrows! - -Quickfort figures out which container type is being set by looking at the letter -that comes just before the number. For example ``zf10`` means 10 barrels in a -stockpile that accepts both ammo and food, whereas ``z10f`` means 10 bins. If -the stockpile category doesn't usually use any container type, like refuse or -corpses, wheelbarrows are assumed:: - - #place a corpse stockpile with 3 wheelbarrows - y3(3x3) - -Note that if you are not using expansion syntax, each tile of the stockpile must -have the same text. Otherwise the stockpile boundaries will not be detected -properly:: - - #place a non-rectangular animal stockpile with 5 wheelbarrows - a5,a5,a5,a5 - a5, , ,a5 - a5, , ,a5 - a5,a5,a5,a5 - -Running ``quickfort orders`` on a ``#place`` blueprint with explicitly set -container/wheelbarrow counts will enqueue manager orders for the specified -number of containers or wheelbarrows, even if that number exceeds the in-game -size of the stockpile. For example, ``quickfort orders`` on the following -blueprint will enqueue 10 rock pots, even though the stockpile only has 9 -tiles:: - - #place - f10(3x3) - -Zone detailed configuration -``````````````````````````` - -Detailed configuration for zones, such as the pit/pond toggle, can also be set -by mimicking the hotkeys used to set them. Note that gather flags default to -true, so specifying them in a blueprint will turn the toggles off. If you need -to set configuration from multiple zone subscreens, separate the key sections -with :kbd:`^`. Note the special syntax for setting hospital supply levels, which -have no in-game hotkeys:: - - #zone a combination hospital and shrub (but not fruit) gathering zone - gGtf^hH{hospital buckets=5 splints=20}(10x10) - -The valid hospital settings (and their maximum values) are:: - - thread (1500000) - cloth (1000000) - splints (100) - crutches (100) - plaster (15000) - buckets (100) - soap (15000) - -To toggle the ``active`` flag for zones, add an :kbd:`a` character to the -string. For example, to create a *disabled* pond zone (that you later intend to -carefully fill with 3-depth water for a dwarven bathtub):: - - #zone disabled pond zone - apPf(1x3) - -Minecart tracks -~~~~~~~~~~~~~~~ - -There are two ways to produce minecart tracks, and they are handled very -differently by the game. You can carve them into hard natural floors or you can -construct them out of building materials. Constructed tracks are conceptually -simpler, so we'll start with them. - -Constructed tracks -`````````````````` - -Quickfort supports the designation of track stops and rollers in ``#build`` -blueprints. You can build a track stop with :kbd:`C`:kbd:`S` and some number of -:kbd:`d` and :kbd:`a` characters for selecting dump direction and friction. You -can build a roller with :kbd:`M`:kbd:`r` and some number of :kbd:`s` and -:kbd:`q` characters for direction and speed. However, this can get confusing -very quickly and is very difficult to read in a blueprint. Moreover, constructed -track segments don't even have keys associated with them at all! - -To solve this problem, Quickfort provides the following keywords for use in -build blueprints:: - - -- Track segments -- - trackN - trackS - trackE - trackW - trackNS - trackNE - trackNW - trackSE - trackSW - trackEW - trackNSE - trackNSW - trackNEW - trackSEW - trackNSEW - - -- Track/ramp segments -- - trackrampN - trackrampS - trackrampE - trackrampW - trackrampNS - trackrampNE - trackrampNW - trackrampSE - trackrampSW - trackrampEW - trackrampNSE - trackrampNSW - trackrampNEW - trackrampSEW - trackrampNSEW - - -- Horizontal and vertical roller segments -- - rollerH - rollerV - rollerNS - rollerSN - rollerEW - rollerWE - - Note: append up to four 'q' characters to roller keywords to set roller - speed. E.g. a roller that propels from East to West at the slowest speed can - be specified with 'rollerEWqqqq'. - - -- Track stops that (optionally) dump to the N/S/E/W -- - trackstop - trackstopN - trackstopS - trackstopE - trackstopW - - Note: append up to four 'a' characters to trackstop keywords to set friction - amount. E.g. a stop that applies the smallest amount of friction can be - specified with 'trackstopaaaa'. - -As an example, you can create an E-W track with stops at each end that dump to -their outside directions with the following blueprint:: - - #build Example track - trackstopW trackEW trackEW trackEW trackstopE - -Note that the **only** way to build track and track/ramp segments is with the -keywords. The UI method of using :kbd:`+` and :kbd:`-` keys to select the track -type from a list does not work since DFHack Quickfort doesn't actually send keys -to the UI to build buildings. The text in your spreadsheet cells is mapped -directly onto DFHack API calls. Only ``#query`` blueprints send actual keycodes -to the UI. - -Carved tracks -````````````` +Carved minecart tracks +~~~~~~~~~~~~~~~~~~~~~~ In the game, you carve a minecart track by specifying a beginning and ending -tile and the game "adds" the designation to the tiles in between. You cannot +tile, and the game "adds" the designation to the tiles in between. You cannot designate single tiles because DF needs a multi-tile track to figure out which direction the track should go on each tile. For example to carve two track segments that cross each other, you might use the cursor to designate a line of @@ -701,8 +509,8 @@ track of the form:: Quickfort supports both styles of specification for carving tracks with ``#dig`` blueprints. You can use the "additive" style to carve tracks in segments or you -can use the aliases to specify the track tile by tile. To designate track -segments, use area expansion syntax with a height or width of 1:: +can use the ``track`` aliases to specify the track tile by tile. To designate +track segments, use area expansion syntax with a height or width of 1:: #dig ` T(1x3) ` # @@ -757,10 +565,239 @@ masterwork engravings for destruction (unless forced to by a commandline parameter). You would run (and let your dwarves complete the jobs for) the sequence of blueprints until no tiles are designated by the "erase" blueprint. +#zone mode +---------- + +Zones define how regions of your fort should be treated. They are also the anchor point for "locations" like taverns and hospitals. Unlike stockpiles or buildings, zones can overlap, which can lead to some interesting layouts. + +Zone designation syntax +~~~~~~~~~~~~~~~~~~~~~~~ + +A zone is declared with a symbol followed by optional properties:: + + #zone a single tile garbage dump zone + d + + #zone a single tile garbage dump zone named "The Dump" + d{name="The Dump"} + + #zone interrogation room + o{name=Interrogation assigned_unit=sheriff} + + #zone a small inactive pond zone + p{name="Fill me" pond=true active=false}(3x3) + +If you want multiple zones that have the same footprint, they can be declared +from the same cell:: + + #zone pasture and training area + n{name="Main pasture"}t{name="Pet training area"}(14x10) + +or from different corners of the same rectangle:: + + #zone pasture and training area + n{name="Main pasture"}(10x2) + t{name="Pet training area"}(10x-2) + +and you can use this technique to achieve partial overlap, of course. The only configuration that can't be specified in a single blueprint is multiple non-rectangular zones that are partially overlapping. You will have to use multiple ``#zone`` blueprints to achieve that. + +Locations, locations, locations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Hospitals, guildhalls, taverns, libraries, and temples are locations. You can +declare a location in the properties for a zone:: + + #zone metalcrafter hall + m{location=guildhall profession=metalcrafter}(7x7) + +You can attach multiple zones to a single location by giving the location a +label (not a name -- you can name zones, but you can't directly name locations) +and then using that label for each of the zones you want to attach:: + + #zone tavern and rented room + b{location=tavern/bigpub name="Rent me"}(3x1) + h{location=tavern/bigpub name="Central pub" allow=residents}(25x40) + +Note that the label ("bigpub" in this case) will never appear in-game. It is only used in the context of the blueprint to identify a common location. + +#place mode +----------- + +``#place`` mode is dedicated to stockpiles, which are a major design element in any fortress. + +Stockpile designation syntax +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Just like zones, stockpiles can have properties like names or lists of other stockpiles to take from. Unlike zones, stockpiles can have configuration specifiers for exactly what types of items to accept. The full syntax looks like this:: + + types{properties}:configuration(expansion) + +You're already familiar with `Property syntax`_ and `Area expansion syntax`_, so let's focus in on the remaining elements. + +Stockpile types +~~~~~~~~~~~~~~~ + +The type of stockpile corresponds to the category of items it accepts. Some types will cause the stockpile to accept bins or barrels. See the full list in the `#place mode reference`_. + +It is very common to have stockpiles that accept multiple categories of items. +Although it is perfectly valid to declare a single-purpose stockpile, +`quickfort` also supports directly declaring all the categories at once. For +example, to declare a 20x10 stockpile that accepts both corpses and refuse, you +could write:: + + #place refuse heap + yr(20x10) + +The order of the individual letters doesn't matter. If you want to configure the +stockpile from scratch, you can place unconfigured "custom" stockpiles with (:kbd:`c`). It is more efficient, though, to place +stockpiles using the keys that represent the categories of items that you want +to store, and then only use a ``#query`` blueprint if you need fine-grained +customization. + +.. _quickfort-place-containers: + +Bins, barrels, and wheelbarrows +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Quickfort has global settings for default values for the number of bins, +barrels, and wheelbarrows assigned to stockpiles, but these numbers can be set +for individual stockpiles as well. + +To set the number of bins, barrels, or wheelbarrows, just add a number after the +letter that indicates what type of stockpile it is. For example:: + + #place a stone stockpile with 5 wheelbarrows + s5(3x3) + + #place a bar, ammo, weapon, and armor stockpile with 20 bins + bzpd20(5x5) + +If the specified number exceeds the number of available stockpile tiles, the +number of available tiles is used. For wheelbarrows, that limit is reduced by 1 +to ensure there is at least one non-wheelbarrow tile available in the stockpile. +Otherwise no stone would ever be brought to the stockpile since all tiles would +be occupied by wheelbarrows! + +Quickfort figures out which container type is being set by looking at the letter +that comes just before the number. For example ``zf10`` means 10 barrels in a +stockpile that accepts both ammo and food, whereas ``z10f`` means 10 bins. If +the stockpile category doesn't usually use any container type, like refuse or +corpses, wheelbarrows are assumed:: + + #place a corpse stockpile with 3 wheelbarrows + y3(3x3) + +Note that if you are not using expansion syntax, each tile of the stockpile must +have the same text. Otherwise the stockpile boundaries will not be detected +properly:: + + #place a non-rectangular animal stockpile with 5 wheelbarrows + a5,a5,a5,a5 + a5, , ,a5 + a5, , ,a5 + a5,a5,a5,a5 + +Running ``quickfort orders`` on a ``#place`` blueprint with explicitly set +container/wheelbarrow counts will enqueue manager orders for the specified +number of containers or wheelbarrows, even if that number exceeds the in-game +size of the stockpile. For example, ``quickfort orders`` on the following +blueprint will enqueue 10 rock pots, even though the stockpile only has 9 +tiles:: + + #place + f10(3x3) + +#build mode +----------- + +``#build`` mode handles buildings, furniture (which are also "buildings" +according to DF), constructions (including constructed tracks), and hauling +routes. + +Building designation syntax +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Other than names, most buildings do not have any extra properties. See the +`#build mode reference`_ for those that do. + +The syntax otherwise looks just like stockpiles, except that it only makes +sense to have a single symbol to indicate what to build on that tile:: + + symbol{properties}:configuration(expansion) + +Here's an example of a simple 5x5 square of flooring:: + + #build + Cf(5x5) + +or a named Jeweler's workshop that takes from specific stockpiles:: + + #build + wj{name="Encrusting center" take_from="Furniture,Gem storage"} + +The ``:configuration`` part is only relevant for hauling routes, which we'll go +over in the next section. + +Hauling route definitions +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Hauling routes are defined by properties and configuration attached to track +stops. You can define a single-stop hauling route for a quantum stockpile as +easily as a multi-stop stone quarry transportation line. The stockpile-like +``:configuration`` part of the syntax controls which item types are considered +"desired" for the hauling route stop. If it's not specified, then all item +types are accepted. This is the most common case since most hauling route +contents are filtered by the stockpiles that the stops take from, but the +flexibility is there for when multiple stops take different items from the same +stockpile, or when a stop only wants a subset of items from a stockpile. + +Here is a common setup for a quantum stone stockpile:: + + #place + s{name="Stone quantum" quantum=true} ~ s5{name="Stone feeder"}(3x3) + #build + ~ trackstopW{take_from="Stone feeder" route="Stone dumper"} + +This sets up the quantum stockpile and the feeder stockpile in the ``#place`` +blueprint, followed by the trackstop and the hauling route configuration in the +``#build`` blueprint. The ``route`` property is the name of the hauling route +to create (or attach to if it already exists). If you are applying a quantum +stockpile blueprint more than once in a fort, be sure to *avoid* defining the +``route`` property so that each application of the blueprint creates a unique +hauling route. Two quantum stockpiles on the same route will not function +propertly. + +Let's look at a slightly more complicated setup where we sort the stone into +different output quantum stockpiles:: + + #place + s{name="Other stone quantum" quantum=true} ~ s5e{name="Rock feeder"}(3x3) + s{name="Ore/clay stone quantum" quantum=true} ~ + s{name="Gem quantum" quantum=true} ~ + #build + ~ trackstopW{take_from="Rock feeder" route="Other stone"}:=otherstone + ~ trackstopW{take_from="Rock feeder" route="Ore/clay"}:=cat_stone-otherstone + ~ trackstopW{take_from="Rock feeder" route="Gems"}:=cat_gems + +You can see how we make use of the stockpile-style configuration syntax to +fine-tune the items desired by the hauling route stop. + +Finally, let's make a series of stops on a common hauling route. There is +nothing particularly special about this example. If the ``route`` property +names an existing route, the stop will be added to that route:: + + #dig + trackE trackEW trackEW trackW + #build + trackstop{route="Tick tock"} ~ ~ trackstop{route="Tick tock"} + +These two track stops (which do not dump their contents) simply exist on a +common route at the ends of a connected carved track. + .. _quickfort-modeline: Modeline markers -~~~~~~~~~~~~~~~~ +---------------- The modeline has some additional optional components that we haven't talked about yet. You can: @@ -774,7 +811,7 @@ about yet. You can: The full modeline syntax, when all optional elements are specified, is:: - #mode label(mylabel) start(X;Y;STARTCOMMENT) hidden() message(mymessage) comment + #mode label(mylabel) start(X;Y;startcomment) hidden() message(mymessage) comment Note that all elements are optional except for the initial ``#mode`` (though, as mentioned in the first section, if a modeline doesn't appear at all in the first @@ -783,16 +820,15 @@ no optional markers). Here are a few examples of modelines with optional elements before we discuss them in more detail:: #dig start(3; 3; Center tile of a 5-tile square) Regular blueprint comment - #build label(noblebedroom) start(10;15) - #query label(configstockpiles) No explicit 'start()' means cursor is at upper left corner + #build label(noblebedroom) No explicit 'start()' so cursor is in upper left #meta label(digwholefort) start(center of stairs on surface) - #dig label(digdining) hidden() called by the digwholefort meta blueprint + #dig label(dig_dining) hidden() called by the digwholefort meta blueprint #zone label(pastures) message(remember to assign animals to the new pastures) .. _quickfort-label: Blueprint labels -```````````````` +~~~~~~~~~~~~~~~~ Labels are displayed in the ``quickfort list`` output and are used for addressing specific blueprints when there are multiple blueprints in a single @@ -807,7 +843,7 @@ user-defined labels. .. _quickfort-start: Start positions -``````````````` +~~~~~~~~~~~~~~~ Start positions specify a cursor offset for a particular blueprint, simplifying the task of blueprint alignment. This is very helpful for blueprints that are @@ -842,7 +878,7 @@ You can use semicolons, commas, or spaces to separate the elements of the .. _quickfort-hidden: Hiding blueprints -````````````````` +~~~~~~~~~~~~~~~~~ A blueprint with a ``hidden()`` marker won't appear in ``quickfort list`` output unless the ``--hidden`` flag is specified. The primary reason for hiding a @@ -853,7 +889,7 @@ managed by a `meta blueprint `. .. _quickfort-message: Messages -```````` +~~~~~~~~ A blueprint with a ``message()`` marker will display a message after the blueprint is applied with ``quickfort run``. This is useful for reminding @@ -870,27 +906,26 @@ quotes automatically when they save/export the file. .. _quickfort-meta: -Meta blueprints -~~~~~~~~~~~~~~~ +#meta mode +---------- -Meta blueprints are blueprints that control how other blueprints are applied. -For example, meta blueprints can bundle a group of other blueprints so that they -can be run with a single command. They can also encode logic, like rotating the -blueprint or duplicating it across a specified number of z-levels. +``#meta`` blueprints are blueprints that control how other blueprints are +applied. For example, meta blueprints can bundle a group of other blueprints so +that they can be run with a single command. They can also encode logic, like +rotating the blueprint or duplicating it across a specified number of z-levels. A common scenario where meta blueprints are useful is when you have several phases to link together. For example you might: 1. Apply a dig blueprint to designate dig areas #. Wait for miners to dig +#. **Apply another dig blueprint** to designate traffic costs +#. **Apply a zone blueprint** to designate zones +#. **Apply a place buildprint** to designate and configure stockpiles #. **Apply a build buildprint** to designate buildings -#. **Apply a place buildprint** to designate stockpiles -#. **Apply a query blueprint** to configure stockpiles -#. Wait for buildings to get built -#. Apply a different query blueprint to configure rooms -Those three "apply"s in the middle might as well get done in one command instead -of three. A ``#meta`` blueprint can help with that. A meta blueprint refers to +Those last four "apply"s might as well get done in one command instead of four. +A ``#meta`` blueprint can help with that. A meta blueprint refers to other blueprints in the same file by their label (see the `Modeline markers`_ section above) in the same format used by the `quickfort` command: ``/