From ca9a0fb7d1f4713cfa3ab6e552ddcbc84439a5fa Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 23 Mar 2023 17:29:39 -0700 Subject: [PATCH 001/851] progress towards cpp20 --- CMakeLists.txt | 13 ++++++------- depends/CMakeLists.txt | 16 ++++++++++++++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ed92b1eca..d031c8784 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,9 +35,10 @@ option(REMOVE_SYMBOLS_FROM_DF_STUBS "Remove debug symbols from DF stubs. (Reduce macro(CHECK_GCC compiler_path) execute_process(COMMAND ${compiler_path} -dumpversion OUTPUT_VARIABLE GCC_VERSION_OUT) string(STRIP "${GCC_VERSION_OUT}" GCC_VERSION_OUT) - if(${GCC_VERSION_OUT} VERSION_LESS "4.8") - message(SEND_ERROR "${compiler_path} version ${GCC_VERSION_OUT} cannot be used - use GCC 4.8 or later") - elseif(${GCC_VERSION_OUT} VERSION_GREATER "4.9.9") + if(${GCC_VERSION_OUT} VERSION_LESS "10") + message(SEND_ERROR "${compiler_path} version ${GCC_VERSION_OUT} cannot be used - use GCC 10 or later") + # TODO: this may need to be removed when DF linux actually comes out + # TODO: and we can test # GCC 5 changes ABI name mangling to enable C++11 changes. # This must be disabled to enable linking against DF. # http://developerblog.redhat.com/2015/02/05/gcc5-and-the-c11-abi/ @@ -66,8 +67,8 @@ if(WIN32) endif() endif() -# Ask for C++11 standard from compilers -set(CMAKE_CXX_STANDARD 11) +# Ask for C++-20 standard from compilers +set(CMAKE_CXX_STANDARD 20) # Require the standard support from compilers. set(CMAKE_CXX_STANDARD_REQUIRED ON) # Use only standard c++ to keep code portable @@ -226,9 +227,7 @@ if(UNIX) ## flags for GCC # default to hidden symbols # ensure compatibility with older CPUs - # enable C++11 features add_definitions(-DLINUX_BUILD) - add_definitions(-D_GLIBCXX_USE_C99) set(GCC_COMMON_FLAGS "-fvisibility=hidden -mtune=generic -Wall -Werror") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COMMON_FLAGS}") diff --git a/depends/CMakeLists.txt b/depends/CMakeLists.txt index 15ff52488..566965f8a 100644 --- a/depends/CMakeLists.txt +++ b/depends/CMakeLists.txt @@ -1,14 +1,26 @@ # list depends here. add_subdirectory(lodepng) -add_subdirectory(lua) add_subdirectory(md5) + +add_subdirectory(lua) add_subdirectory(protobuf) +if(UNIX) + set_target_properties(lua PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-deprecated-enum-enum-conversion") + target_compile_options(protoc + PUBLIC -Wno-deprecated-declarations -Wno-restrict) + target_compile_options(protoc-bin + PUBLIC -Wno-deprecated-declarations -Wno-restrict) + target_compile_options(protobuf-lite + PUBLIC -Wno-deprecated-declarations -Wno-restrict) + target_compile_options(protobuf + PUBLIC -Wno-deprecated-declarations -Wno-restrict) +endif() if(UNIX AND NOT APPLE) # remove this once our MSVC build env has been updated option(INSTALL_GTEST "Enable installation of googletest. (Projects embedding googletest may want to turn this OFF.)" OFF) add_subdirectory(googletest) if(UNIX) - set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-Wno-maybe-uninitialized -Wno-sign-compare") + set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-Wno-maybe-uninitialized -Wno-sign-compare -Wno-restrict") endif() endif() From 9dba18124eb1dd6f25b592fec46e85a8595f6896 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 17 Jun 2023 10:00:54 -0700 Subject: [PATCH 002/851] attach compile options to dfhack that allow protobuf headers to be included --- library/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 8681c9c90..1db78c24e 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -377,6 +377,9 @@ if(WIN32) set_target_properties(dfhack-client PROPERTIES COMPILE_FLAGS "/FI\"Export.h\"" ) else() set_target_properties(dfhack PROPERTIES COMPILE_FLAGS "-include Export.h" ) + # required because of protobuf headers + target_compile_options(dfhack + PUBLIC -Wno-deprecated-declarations -Wno-restrict) set_target_properties(dfhack-client PROPERTIES COMPILE_FLAGS "-include Export.h" ) add_library(dfhooks SHARED Hooks.cpp) target_link_libraries(dfhooks dfhack) From 2efef75b4e4ca368f866bd104f123aaf79c8e568 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 17 Jun 2023 10:46:56 -0700 Subject: [PATCH 003/851] re-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 1fd064d56..103e2dfee 100644 --- a/library/modules/DFSteam.cpp +++ b/library/modules/DFSteam.cpp @@ -108,7 +108,7 @@ static bool is_running_on_wine() { return !!pwine_get_version; } -static DWORD findProcess(LPWSTR name) { +static DWORD findProcess(const LPWSTR name) { PROCESSENTRY32W entry; entry.dwSize = sizeof(PROCESSENTRY32W); From 8a079e1ae755b46822a0e88df09ce9c354f6557d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 17 Jun 2023 22:14:11 -0700 Subject: [PATCH 004/851] get compiling on windows --- library/CMakeLists.txt | 4 ++-- library/modules/DFSteam.cpp | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 1db78c24e..48ebdb986 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -377,9 +377,9 @@ if(WIN32) set_target_properties(dfhack-client PROPERTIES COMPILE_FLAGS "/FI\"Export.h\"" ) else() set_target_properties(dfhack PROPERTIES COMPILE_FLAGS "-include Export.h" ) - # required because of protobuf headers + # required because of transitively-included protobuf headers target_compile_options(dfhack - PUBLIC -Wno-deprecated-declarations -Wno-restrict) + INTERFACE -Wno-deprecated-declarations -Wno-restrict) set_target_properties(dfhack-client PROPERTIES COMPILE_FLAGS "-include Export.h" ) add_library(dfhooks SHARED Hooks.cpp) target_link_libraries(dfhooks dfhack) diff --git a/library/modules/DFSteam.cpp b/library/modules/DFSteam.cpp index 103e2dfee..9aab53466 100644 --- a/library/modules/DFSteam.cpp +++ b/library/modules/DFSteam.cpp @@ -108,7 +108,7 @@ static bool is_running_on_wine() { return !!pwine_get_version; } -static DWORD findProcess(const LPWSTR name) { +static DWORD findProcess(LPCWSTR name) { PROCESSENTRY32W entry; entry.dwSize = sizeof(PROCESSENTRY32W); @@ -150,11 +150,14 @@ static bool launchDFHack(color_ostream& out) { si.cb = sizeof(si); ZeroMemory(&pi, sizeof(pi)); - // note that the enviornment must be explicitly zeroed out and not NULL, + static LPCWSTR procname = L"hack/launchdf.exe"; + static const char * env = "\0"; + + // note that the environment 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); + BOOL res = CreateProcessW(procname, + NULL, NULL, NULL, FALSE, 0, (LPVOID)env, NULL, &si, &pi); return !!res; } From 8f413628c2342c3639d6c44959bd663bcabfb4a0 Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 19 Jun 2023 17:40:40 -0700 Subject: [PATCH 005/851] reinstate alphabetical ordering --- depends/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/depends/CMakeLists.txt b/depends/CMakeLists.txt index 566965f8a..9ec71646a 100644 --- a/depends/CMakeLists.txt +++ b/depends/CMakeLists.txt @@ -1,9 +1,9 @@ # list depends here. add_subdirectory(lodepng) -add_subdirectory(md5) - add_subdirectory(lua) +add_subdirectory(md5) add_subdirectory(protobuf) + if(UNIX) set_target_properties(lua PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-deprecated-enum-enum-conversion") target_compile_options(protoc From 4e48ce64f111778929900caeb777be7ed5cac633 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 22 May 2023 15:07:19 -0700 Subject: [PATCH 006/851] get things mostly ported to SDL2 --- CMakeLists.txt | 41 +-- library/CMakeLists.txt | 4 - library/Core.cpp | 122 ++----- library/Hooks.cpp | 2 +- library/LuaApi.cpp | 4 +- library/include/Core.h | 4 +- library/include/Hooks.h | 54 +-- library/include/SDL_events.h | 210 ----------- library/include/SDL_keyboard.h | 61 ---- library/include/SDL_keysym.h | 329 ------------------ library/include/df/custom/enabler.methods.inc | 2 + library/include/modules/DFSDL.h | 79 +---- library/include/modules/Screen.h | 2 +- library/modules/DFSDL.cpp | 64 ++-- library/modules/Screen.cpp | 2 + library/modules/Textures.cpp | 36 +- library/xml | 2 +- .../remotefortressreader.cpp | 14 +- 18 files changed, 149 insertions(+), 883 deletions(-) delete mode 100644 library/include/SDL_events.h delete mode 100644 library/include/SDL_keyboard.h delete mode 100644 library/include/SDL_keysym.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1309daa4e..545a0e6f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -285,30 +285,27 @@ else() unset(CMAKE_HAVE_PTHREAD_H CACHE) endif() - if(NOT APPLE AND DFHACK_BUILD_32) - set(ZLIB_ROOT /usr/lib/i386-linux-gnu) - 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/) 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 - # 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() +# Download SDL release and extract into depends (in the build dir so as not to clutter up the source dir) +# all we need are the header files, so the same release package will work for all platforms +# (the above statement is untested for OSX) +set(SDL_VERSION 2.26.2) +set(SDL_ZIP_FILE SDL2-devel-${SDL_VERSION}-VC.zip) +set(SDL_ZIP_PATH ${CMAKE_BINARY_DIR}/depends/SDL2/) +file(DOWNLOAD "https://github.com/libsdl-org/SDL/releases/download/release-${SDL_VERSION}/${SDL_ZIP_FILE}" + ${SDL_ZIP_PATH}${SDL_ZIP_FILE} + EXPECTED_MD5 574daf26d48de753d0b1e19823c9d8bb + SHOW_PROGRESS) +file(ARCHIVE_EXTRACT INPUT ${SDL_ZIP_PATH}${SDL_ZIP_FILE} + DESTINATION ${SDL_ZIP_PATH}) +include_directories(${SDL_ZIP_PATH}/SDL2-${SDL_VERSION}/include) if(APPLE) # libstdc++ (GCC 4.8.5 for OS X 10.6) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 8681c9c90..5d2698bb0 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -431,10 +431,6 @@ 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/library/Core.cpp b/library/Core.cpp index 431cd2c9f..6fc453060 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -84,7 +84,7 @@ using namespace DFHack; #include #include "md5wrapper.h" -#include "SDL_events.h" +#include #ifdef LINUX_BUILD #include @@ -2347,99 +2347,47 @@ bool Core::DFH_ncurses_key(int key) return ncurses_wgetch(key, dummy); } -int UnicodeAwareSym(const SDL::KeyboardEvent& ke) -{ - // Assume keyboard layouts don't change the order of numbers: - if( '0' <= ke.ksym.sym && ke.ksym.sym <= '9') return ke.ksym.sym; - if(SDL::K_F1 <= ke.ksym.sym && ke.ksym.sym <= SDL::K_F12) return ke.ksym.sym; - - // These keys are mapped to the same control codes as Ctrl-? - switch (ke.ksym.sym) - { - case SDL::K_RETURN: - case SDL::K_KP_ENTER: - case SDL::K_TAB: - case SDL::K_ESCAPE: - case SDL::K_DELETE: - return ke.ksym.sym; - default: - break; - } - - int unicode = ke.ksym.unicode; - - // convert Ctrl characters to their 0x40-0x5F counterparts: - if (unicode < ' ') - { - unicode += 'A' - 1; - } - - // convert A-Z to their a-z counterparts: - if('A' <= unicode && unicode <= 'Z') - { - unicode += 'a' - 'A'; - } - - // convert various other punctuation marks: - if('\"' == unicode) unicode = '\''; - if('+' == unicode) unicode = '='; - if(':' == unicode) unicode = ';'; - if('<' == unicode) unicode = ','; - if('>' == unicode) unicode = '.'; - if('?' == unicode) unicode = '/'; - if('{' == unicode) unicode = '['; - if('|' == unicode) unicode = '\\'; - if('}' == unicode) unicode = ']'; - if('~' == unicode) unicode = '`'; - - return unicode; -} - // returns true if the event is handled -bool Core::DFH_SDL_Event(SDL::Event* ev) +bool Core::DFH_SDL_Event(SDL_Event* ev) { // do NOT process events before we are ready. if(!started || !ev) return false; - if(ev->type == SDL::ET_ACTIVEEVENT && ev->active.gain) - { + if (ev->type == SDL_WINDOWEVENT && ev->window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { // clear modstate when gaining focus in case alt-tab was used when // losing focus and modstate is now incorrectly set modstate = 0; return false; } - if(ev->type == SDL::ET_KEYDOWN || ev->type == SDL::ET_KEYUP) - { - auto ke = (SDL::KeyboardEvent *)ev; + if (ev->type == SDL_KEYDOWN || ev->type == SDL_KEYUP) { + auto &ke = ev->key; - if (ke->ksym.sym == SDL::K_LSHIFT || ke->ksym.sym == SDL::K_RSHIFT) - modstate = (ev->type == SDL::ET_KEYDOWN) ? modstate | DFH_MOD_SHIFT : modstate & ~DFH_MOD_SHIFT; - else if (ke->ksym.sym == SDL::K_LCTRL || ke->ksym.sym == SDL::K_RCTRL) - modstate = (ev->type == SDL::ET_KEYDOWN) ? modstate | DFH_MOD_CTRL : modstate & ~DFH_MOD_CTRL; - else if (ke->ksym.sym == SDL::K_LALT || ke->ksym.sym == SDL::K_RALT) - modstate = (ev->type == SDL::ET_KEYDOWN) ? modstate | DFH_MOD_ALT : modstate & ~DFH_MOD_ALT; - else if(ke->state == SDL::BTN_PRESSED && !hotkey_states[ke->ksym.sym]) + if (ke.keysym.sym == SDLK_LSHIFT || ke.keysym.sym == SDLK_RSHIFT) + modstate = (ev->type == SDL_KEYDOWN) ? modstate | DFH_MOD_SHIFT : modstate & ~DFH_MOD_SHIFT; + else if (ke.keysym.sym == SDLK_LCTRL || ke.keysym.sym == SDLK_RCTRL) + modstate = (ev->type == SDL_KEYDOWN) ? modstate | DFH_MOD_CTRL : modstate & ~DFH_MOD_CTRL; + else if (ke.keysym.sym == SDLK_LALT || ke.keysym.sym == SDLK_RALT) + modstate = (ev->type == SDL_KEYDOWN) ? modstate | DFH_MOD_ALT : modstate & ~DFH_MOD_ALT; + else if (ke.state == SDL_PRESSED && !hotkey_states[ke.keysym.sym]) { - hotkey_states[ke->ksym.sym] = true; - - // Use unicode so Windows gives the correct value for the - // user's Input Language - if(ke->ksym.unicode && ((ke->ksym.unicode & 0xff80) == 0)) - { - int key = UnicodeAwareSym(*ke); - SelectHotkey(key, modstate); - } - else - { - // Pretend non-ascii characters don't happen: - SelectHotkey(ke->ksym.sym, modstate); - } + hotkey_states[ke.keysym.sym] = true; } - else if(ke->state == SDL::BTN_RELEASED) + else if(ke.state == SDL_RELEASED) { - hotkey_states[ke->ksym.sym] = false; + hotkey_states[ke.keysym.sym] = false; + } + } + else if (ev->type == SDL_TEXTINPUT) { + auto &te = ev->text; + + uint8_t sym = (uint8_t)te.text[0]; + if (sym <= 0x7f && hotkey_states[sym]) { + // register that we have responded to this hotkey, and don't respond + // again even if the key is held down + hotkey_states[sym] = false; + SelectHotkey(sym, modstate); } } return false; @@ -2455,8 +2403,8 @@ bool Core::SelectHotkey(int sym, int modifiers) while (screen->child) screen = screen->child; - if (sym == SDL::K_KP_ENTER) - sym = SDL::K_RETURN; + if (sym == SDLK_KP_ENTER) + sym = SDLK_RETURN; std::string cmd; @@ -2497,7 +2445,7 @@ bool Core::SelectHotkey(int sym, int modifiers) if (cmd.empty()) { // Check the hotkey keybindings - int idx = sym - SDL::K_F1; + int idx = sym - SDLK_F1; if(idx >= 0 && idx < 8) { /* TODO: understand how this changes for v50 @@ -2555,22 +2503,22 @@ static bool parseKeySpec(std::string keyspec, int *psym, int *pmod, std::string } if (keyspec.size() == 1 && keyspec[0] >= 'A' && keyspec[0] <= 'Z') { - *psym = SDL::K_a + (keyspec[0]-'A'); + *psym = SDLK_a + (keyspec[0]-'A'); return true; } else if (keyspec.size() == 1 && keyspec[0] == '`') { - *psym = SDL::K_BACKQUOTE; + *psym = SDLK_BACKQUOTE; return true; } else if (keyspec.size() == 1 && keyspec[0] >= '0' && keyspec[0] <= '9') { - *psym = SDL::K_0 + (keyspec[0]-'0'); + *psym = SDLK_0 + (keyspec[0]-'0'); return true; } else if (keyspec.size() == 2 && keyspec[0] == 'F' && keyspec[1] >= '1' && keyspec[1] <= '9') { - *psym = SDL::K_F1 + (keyspec[1]-'1'); + *psym = SDLK_F1 + (keyspec[1]-'1'); return true; } else if (keyspec.size() == 3 && keyspec.substr(0, 2) == "F1" && keyspec[2] >= '0' && keyspec[2] <= '2') { - *psym = SDL::K_F10 + (keyspec[2]-'0'); + *psym = SDLK_F10 + (keyspec[2]-'0'); return true; } else if (keyspec == "Enter") { - *psym = SDL::K_RETURN; + *psym = SDLK_RETURN; return true; } else return false; diff --git a/library/Hooks.cpp b/library/Hooks.cpp index 4e339e768..31a8ec749 100644 --- a/library/Hooks.cpp +++ b/library/Hooks.cpp @@ -48,7 +48,7 @@ DFhackCExport void dfhooks_prerender() { // 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) { +DFhackCExport bool dfhooks_sdl_event(SDL_Event* event) { if (disabled) return false; return DFHack::Core::getInstance().DFH_SDL_Event(event); diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 0a737875a..7de74470f 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2635,6 +2635,7 @@ static int screen_charToKey(lua_State *L) return 1; } +/* static int screen_zoom(lua_State *L) { using df::global::enabler; @@ -2651,6 +2652,7 @@ static int screen_zoom(lua_State *L) enabler->zoom_display(cmd); return 0; } +*/ } @@ -2671,7 +2673,7 @@ static const luaL_Reg dfhack_screen_funcs[] = { { "_doSimulateInput", screen_doSimulateInput }, { "keyToChar", screen_keyToChar }, { "charToKey", screen_charToKey }, - { "zoom", screen_zoom }, + //{ "zoom", screen_zoom }, { NULL, NULL } }; diff --git a/library/include/Core.h b/library/include/Core.h index 696be4ead..916a63cf3 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -112,7 +112,7 @@ namespace DFHack friend void ::dfhooks_shutdown(); friend void ::dfhooks_update(); friend void ::dfhooks_prerender(); - friend bool ::dfhooks_sdl_event(SDL::Event* event); + friend bool ::dfhooks_sdl_event(SDL_Event* event); friend bool ::dfhooks_ncurses_key(int key); public: /// Get the single Core instance or make one. @@ -195,7 +195,7 @@ namespace DFHack bool InitSimulationThread(); int Update (void); int Shutdown (void); - bool 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/library/include/Hooks.h b/library/include/Hooks.h index 5856fb44f..fb72fdbe3 100644 --- a/library/include/Hooks.h +++ b/library/include/Hooks.h @@ -24,61 +24,11 @@ distribution. #pragma once -/* - * Some much needed SDL fakery. - */ - -#include "Pragma.h" -#include "Export.h" -#include -#include - -#include "modules/Graphic.h" - -// function and variable pointer... we don't try to understand what SDL does here -typedef void * fPtr; -typedef void * vPtr; -struct WINDOW; -namespace SDL -{ - union Event; -} - -// these functions are here because they call into DFHack::Core and therefore need to -// be declared as friend functions/known -#ifdef _DARWIN -DFhackCExport int DFH_SDL_NumJoysticks(void); -DFhackCExport void DFH_SDL_Quit(void); -DFhackCExport int DFH_SDL_PollEvent(SDL::Event* event); -DFhackCExport int DFH_SDL_Init(uint32_t flags); -DFhackCExport int DFH_wgetch(WINDOW * win); -#endif -DFhackCExport int SDL_NumJoysticks(void); -DFhackCExport void SDL_Quit(void); -DFhackCExport int SDL_PollEvent(SDL::Event* event); -DFhackCExport int SDL_PushEvent(SDL::Event* event); -DFhackCExport int SDL_Init(uint32_t flags); -DFhackCExport int wgetch(WINDOW * win); - -DFhackCExport int SDL_UpperBlit(DFHack::DFSDL_Surface* src, DFHack::DFSDL_Rect* srcrect, DFHack::DFSDL_Surface* dst, DFHack::DFSDL_Rect* dstrect); -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); -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); -DFhackCExport void SDL_FreeSurface(vPtr surface); -DFhackCExport vPtr SDL_ConvertSurface(vPtr surface, vPtr format, uint32_t flags); -DFhackCExport int SDL_LockSurface(vPtr surface); -DFhackCExport void SDL_UnlockSurface(vPtr surface); -DFhackCExport uint8_t SDL_GetMouseState(int *x, int *y); -DFhackCExport void * SDL_GetVideoSurface(void); - -DFhackCExport int SDL_SemWait(vPtr sem); -DFhackCExport int SDL_SemPost(vPtr sem); +union SDL_Event; -// new Hooks API DFhackCExport void dfhooks_init(); DFhackCExport void dfhooks_shutdown(); DFhackCExport void dfhooks_update(); DFhackCExport void dfhooks_prerender(); -DFhackCExport bool dfhooks_sdl_event(SDL::Event* event); +DFhackCExport bool dfhooks_sdl_event(SDL_Event* event); DFhackCExport bool dfhooks_ncurses_key(int key); diff --git a/library/include/SDL_events.h b/library/include/SDL_events.h deleted file mode 100644 index 80067f07d..000000000 --- a/library/include/SDL_events.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - SDL - Simple DirectMedia Layer - Copyright (C) 1997-2009 Sam Lantinga - - 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 St, Fifth Floor, Boston, MA 02110-1301 USA - - Sam Lantinga - slouken@libsdl.org -*/ - -// Fake - only structs. Shamelessly pilfered from the SDL library. -// Needed for processing its event types without polluting our namespaces with C garbage - -#pragma once -#include "SDL_keyboard.h" - -namespace SDL -{ - enum ButtonState - { - BTN_RELEASED = 0, - BTN_PRESSED = 1 - }; - - /** Event enumerations */ - enum EventType - { - ET_NOEVENT = 0, /**< Unused (do not remove) */ - ET_ACTIVEEVENT, /**< Application loses/gains visibility */ - ET_KEYDOWN, /**< Keys pressed */ - ET_KEYUP, /**< Keys released */ - ET_MOUSEMOTION, /**< Mouse moved */ - ET_MOUSEBUTTONDOWN, /**< Mouse button pressed */ - ET_MOUSEBUTTONUP, /**< Mouse button released */ - ET_JOYAXISMOTION, /**< Joystick axis motion */ - ET_JOYBALLMOTION, /**< Joystick trackball motion */ - ET_JOYHATMOTION, /**< Joystick hat position change */ - ET_JOYBUTTONDOWN, /**< Joystick button pressed */ - ET_JOYBUTTONUP, /**< Joystick button released */ - ET_QUIT, /**< User-requested quit */ - ET_SYSWMEVENT, /**< System specific event */ - ET_EVENT_RESERVEDA, /**< Reserved for future use.. */ - ET_EVENT_RESERVEDB, /**< Reserved for future use.. */ - ET_VIDEORESIZE, /**< User resized video mode */ - ET_VIDEOEXPOSE, /**< Screen needs to be redrawn */ - ET_EVENT_RESERVED2, /**< Reserved for future use.. */ - ET_EVENT_RESERVED3, /**< Reserved for future use.. */ - ET_EVENT_RESERVED4, /**< Reserved for future use.. */ - ET_EVENT_RESERVED5, /**< Reserved for future use.. */ - ET_EVENT_RESERVED6, /**< Reserved for future use.. */ - ET_EVENT_RESERVED7, /**< Reserved for future use.. */ - /** Events ET_USEREVENT through ET_MAXEVENTS-1 are for your use */ - ET_USEREVENT = 24, - /** This last event is only for bounding internal arrays - * It is the number of bits in the event mask datatype -- Uint32 - */ - ET_NUMEVENTS = 32 - }; - - /** Application visibility event structure */ - struct ActiveEvent - { - uint8_t type; /**< ET_ACTIVEEVENT */ - uint8_t gain; /**< Whether given states were gained or lost (1/0) */ - uint8_t state; /**< A mask of the focus states */ - }; - - /** Keyboard event structure */ - struct KeyboardEvent - { - uint8_t type; /**< ET_KEYDOWN or ET_KEYUP */ - uint8_t which; /**< The keyboard device index */ - uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */ - keysym ksym; - }; - - /** Mouse motion event structure */ - struct MouseMotionEvent - { - uint8_t type; /**< ET_MOUSEMOTION */ - uint8_t which; /**< The mouse device index */ - uint8_t state; /**< The current button state */ - uint16_t x, y; /**< The X/Y coordinates of the mouse */ - int16_t xrel; /**< The relative motion in the X direction */ - int16_t yrel; /**< The relative motion in the Y direction */ - }; - - /** Mouse button event structure */ - struct MouseButtonEvent - { - uint8_t type; /**< ET_MOUSEBUTTONDOWN or ET_MOUSEBUTTONUP */ - uint8_t which; /**< The mouse device index */ - uint8_t button; /**< The mouse button index */ - uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */ - uint16_t x, y; /**< The X/Y coordinates of the mouse at press time */ - }; - - /** Joystick axis motion event structure */ - struct JoyAxisEvent - { - uint8_t type; /**< ET_JOYAXISMOTION */ - uint8_t which; /**< The joystick device index */ - uint8_t axis; /**< The joystick axis index */ - int16_t value; /**< The axis value (range: -32768 to 32767) */ - }; - - /** Joystick trackball motion event structure */ - struct JoyBallEvent - { - uint8_t type; /**< ET_JOYBALLMOTION */ - uint8_t which; /**< The joystick device index */ - uint8_t ball; /**< The joystick trackball index */ - int16_t xrel; /**< The relative motion in the X direction */ - int16_t yrel; /**< The relative motion in the Y direction */ - }; - - /** Joystick hat position change event structure */ - struct JoyHatEvent - { - uint8_t type; /**< ET_JOYHATMOTION */ - uint8_t which; /**< The joystick device index */ - uint8_t hat; /**< The joystick hat index */ - uint8_t value; /**< The hat position value: - * SDL_HAT_LEFTUP SDL_HAT_UP SDL_HAT_RIGHTUP - * SDL_HAT_LEFT SDL_HAT_CENTERED SDL_HAT_RIGHT - * SDL_HAT_LEFTDOWN SDL_HAT_DOWN SDL_HAT_RIGHTDOWN - * Note that zero means the POV is centered. - */ - }; - - /** Joystick button event structure */ - struct JoyButtonEvent - { - uint8_t type; /**< ET_JOYBUTTONDOWN or ET_JOYBUTTONUP */ - uint8_t which; /**< The joystick device index */ - uint8_t button; /**< The joystick button index */ - uint8_t state; /**< BTN_PRESSED or BTN_RELEASED */ - }; - - /** The "window resized" event - * When you get this event, you are responsible for setting a new video - * mode with the new width and height. - */ - struct ResizeEvent - { - uint8_t type; /**< ET_VIDEORESIZE */ - int w; /**< New width */ - int h; /**< New height */ - }; - - /** The "screen redraw" event */ - struct ExposeEvent - { - uint8_t type; /**< ET_VIDEOEXPOSE */ - }; - - /** The "quit requested" event */ - struct QuitEvent - { - uint8_t type; /**< ET_QUIT */ - }; - - /** A user-defined event type */ - struct UserEvent - { - uint8_t type; /**< ETL_USEREVENT through ET_NUMEVENTS-1 */ - int code; /**< User defined event code */ - void *data1; /**< User defined data pointer */ - void *data2; /**< User defined data pointer */ - }; - - /** If you want to use this event, you should include SDL_syswm.h */ - struct SysWMmsg; - struct SysWMEvent - { - uint8_t type; - SysWMmsg *msg; - }; - - /** General event structure */ - union Event - { - uint8_t type; - ActiveEvent active; - KeyboardEvent key; - MouseMotionEvent motion; - MouseButtonEvent button; - JoyAxisEvent jaxis; - JoyBallEvent jball; - JoyHatEvent jhat; - JoyButtonEvent jbutton; - ResizeEvent resize; - ExposeEvent expose; - QuitEvent quit; - UserEvent user; - SysWMEvent syswm; - }; -} diff --git a/library/include/SDL_keyboard.h b/library/include/SDL_keyboard.h deleted file mode 100644 index 1d58bd63f..000000000 --- a/library/include/SDL_keyboard.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - SDL - Simple DirectMedia Layer - Copyright (C) 1997-2009 Sam Lantinga - - 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 St, Fifth Floor, Boston, MA 02110-1301 USA - - Sam Lantinga - slouken@libsdl.org -*/ - -// Fake - only structs. Shamelessly pilfered from the SDL library. -// Needed for processing its event types without polluting our namespaces with C garbage - -#pragma once -#include "SDL_keysym.h" -#include - -namespace SDL -{ - /** Keysym structure - * - * - The scancode is hardware dependent, and should not be used by general - * applications. If no hardware scancode is available, it will be 0. - * - * - The 'unicode' translated character is only available when character - * translation is enabled by the SDL_EnableUNICODE() API. If non-zero, - * this is a UNICODE character corresponding to the keypress. If the - * high 9 bits of the character are 0, then this maps to the equivalent - * ASCII character: - * @code - * char ch; - * if ( (keysym.unicode & 0xFF80) == 0 ) { - * ch = keysym.unicode & 0x7F; - * } else { - * An international character.. - * } - * @endcode - */ - typedef struct keysym - { - uint8_t scancode; /**< hardware specific scancode */ - Key sym; /**< SDL virtual keysym */ - Mod mod; /**< current key modifiers */ - uint16_t unicode; /**< translated character */ - } keysym; - - /** This is the mask which refers to all hotkey bindings */ - #define ALL_HOTKEYS 0xFFFFFFFF -} diff --git a/library/include/SDL_keysym.h b/library/include/SDL_keysym.h deleted file mode 100644 index e19f786af..000000000 --- a/library/include/SDL_keysym.h +++ /dev/null @@ -1,329 +0,0 @@ -/* - SDL - Simple DirectMedia Layer - Copyright (C) 1997-2009 Sam Lantinga - - 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 St, Fifth Floor, Boston, MA 02110-1301 USA - - Sam Lantinga - slouken@libsdl.org -*/ - -// Fake - only structs. Shamelessly pilfered from the SDL library. -// Needed for processing its event types without polluting our namespaces with C garbage - -#pragma once - -namespace SDL -{ - /** What we really want is a mapping of every raw key on the keyboard. - * To support international keyboards, we use the range 0xA1 - 0xFF - * as international virtual keycodes. We'll follow in the footsteps of X11... - * @brief The names of the keys - */ - enum Key - { - /** @name ASCII mapped keysyms - * The keyboard syms have been cleverly chosen to map to ASCII - */ - /*@{*/ - K_UNKNOWN = 0, - K_FIRST = 0, - K_BACKSPACE = 8, - K_TAB = 9, - K_CLEAR = 12, - K_RETURN = 13, - K_PAUSE = 19, - K_ESCAPE = 27, - K_SPACE = 32, - K_EXCLAIM = 33, - K_QUOTEDBL = 34, - K_HASH = 35, - K_DOLLAR = 36, - K_AMPERSAND = 38, - K_QUOTE = 39, - K_LEFTPAREN = 40, - K_RIGHTPAREN = 41, - K_ASTERISK = 42, - K_PLUS = 43, - K_COMMA = 44, - K_MINUS = 45, - K_PERIOD = 46, - K_SLASH = 47, - K_0 = 48, - K_1 = 49, - K_2 = 50, - K_3 = 51, - K_4 = 52, - K_5 = 53, - K_6 = 54, - K_7 = 55, - K_8 = 56, - K_9 = 57, - K_COLON = 58, - K_SEMICOLON = 59, - K_LESS = 60, - K_EQUALS = 61, - K_GREATER = 62, - K_QUESTION = 63, - K_AT = 64, - /* - Skip uppercase letters - */ - K_LEFTBRACKET = 91, - K_BACKSLASH = 92, - K_RIGHTBRACKET = 93, - K_CARET = 94, - K_UNDERSCORE = 95, - K_BACKQUOTE = 96, - K_a = 97, - K_b = 98, - K_c = 99, - K_d = 100, - K_e = 101, - K_f = 102, - K_g = 103, - K_h = 104, - K_i = 105, - K_j = 106, - K_k = 107, - K_l = 108, - K_m = 109, - K_n = 110, - K_o = 111, - K_p = 112, - K_q = 113, - K_r = 114, - K_s = 115, - K_t = 116, - K_u = 117, - K_v = 118, - K_w = 119, - K_x = 120, - K_y = 121, - K_z = 122, - K_DELETE = 127, - /* End of ASCII mapped keysyms */ - /*@}*/ - - /** @name International keyboard syms */ - /*@{*/ - K_WORLD_0 = 160, /* 0xA0 */ - K_WORLD_1 = 161, - K_WORLD_2 = 162, - K_WORLD_3 = 163, - K_WORLD_4 = 164, - K_WORLD_5 = 165, - K_WORLD_6 = 166, - K_WORLD_7 = 167, - K_WORLD_8 = 168, - K_WORLD_9 = 169, - K_WORLD_10 = 170, - K_WORLD_11 = 171, - K_WORLD_12 = 172, - K_WORLD_13 = 173, - K_WORLD_14 = 174, - K_WORLD_15 = 175, - K_WORLD_16 = 176, - K_WORLD_17 = 177, - K_WORLD_18 = 178, - K_WORLD_19 = 179, - K_WORLD_20 = 180, - K_WORLD_21 = 181, - K_WORLD_22 = 182, - K_WORLD_23 = 183, - K_WORLD_24 = 184, - K_WORLD_25 = 185, - K_WORLD_26 = 186, - K_WORLD_27 = 187, - K_WORLD_28 = 188, - K_WORLD_29 = 189, - K_WORLD_30 = 190, - K_WORLD_31 = 191, - K_WORLD_32 = 192, - K_WORLD_33 = 193, - K_WORLD_34 = 194, - K_WORLD_35 = 195, - K_WORLD_36 = 196, - K_WORLD_37 = 197, - K_WORLD_38 = 198, - K_WORLD_39 = 199, - K_WORLD_40 = 200, - K_WORLD_41 = 201, - K_WORLD_42 = 202, - K_WORLD_43 = 203, - K_WORLD_44 = 204, - K_WORLD_45 = 205, - K_WORLD_46 = 206, - K_WORLD_47 = 207, - K_WORLD_48 = 208, - K_WORLD_49 = 209, - K_WORLD_50 = 210, - K_WORLD_51 = 211, - K_WORLD_52 = 212, - K_WORLD_53 = 213, - K_WORLD_54 = 214, - K_WORLD_55 = 215, - K_WORLD_56 = 216, - K_WORLD_57 = 217, - K_WORLD_58 = 218, - K_WORLD_59 = 219, - K_WORLD_60 = 220, - K_WORLD_61 = 221, - K_WORLD_62 = 222, - K_WORLD_63 = 223, - K_WORLD_64 = 224, - K_WORLD_65 = 225, - K_WORLD_66 = 226, - K_WORLD_67 = 227, - K_WORLD_68 = 228, - K_WORLD_69 = 229, - K_WORLD_70 = 230, - K_WORLD_71 = 231, - K_WORLD_72 = 232, - K_WORLD_73 = 233, - K_WORLD_74 = 234, - K_WORLD_75 = 235, - K_WORLD_76 = 236, - K_WORLD_77 = 237, - K_WORLD_78 = 238, - K_WORLD_79 = 239, - K_WORLD_80 = 240, - K_WORLD_81 = 241, - K_WORLD_82 = 242, - K_WORLD_83 = 243, - K_WORLD_84 = 244, - K_WORLD_85 = 245, - K_WORLD_86 = 246, - K_WORLD_87 = 247, - K_WORLD_88 = 248, - K_WORLD_89 = 249, - K_WORLD_90 = 250, - K_WORLD_91 = 251, - K_WORLD_92 = 252, - K_WORLD_93 = 253, - K_WORLD_94 = 254, - K_WORLD_95 = 255, /* 0xFF */ - /*@}*/ - - /** @name Numeric keypad */ - /*@{*/ - K_KP0 = 256, - K_KP1 = 257, - K_KP2 = 258, - K_KP3 = 259, - K_KP4 = 260, - K_KP5 = 261, - K_KP6 = 262, - K_KP7 = 263, - K_KP8 = 264, - K_KP9 = 265, - K_KP_PERIOD = 266, - K_KP_DIVIDE = 267, - K_KP_MULTIPLY = 268, - K_KP_MINUS = 269, - K_KP_PLUS = 270, - K_KP_ENTER = 271, - K_KP_EQUALS = 272, - /*@}*/ - - /** @name Arrows + Home/End pad */ - /*@{*/ - K_UP = 273, - K_DOWN = 274, - K_RIGHT = 275, - K_LEFT = 276, - K_INSERT = 277, - K_HOME = 278, - K_END = 279, - K_PAGEUP = 280, - K_PAGEDOWN = 281, - /*@}*/ - - /** @name Function keys */ - /*@{*/ - K_F1 = 282, - K_F2 = 283, - K_F3 = 284, - K_F4 = 285, - K_F5 = 286, - K_F6 = 287, - K_F7 = 288, - K_F8 = 289, - K_F9 = 290, - K_F10 = 291, - K_F11 = 292, - K_F12 = 293, - K_F13 = 294, - K_F14 = 295, - K_F15 = 296, - /*@}*/ - - /** @name Key state modifier keys */ - /*@{*/ - K_NUMLOCK = 300, - K_CAPSLOCK = 301, - K_SCROLLOCK = 302, - K_RSHIFT = 303, - K_LSHIFT = 304, - K_RCTRL = 305, - K_LCTRL = 306, - K_RALT = 307, - K_LALT = 308, - K_RMETA = 309, - K_LMETA = 310, - K_LSUPER = 311, /**< Left "Windows" key */ - K_RSUPER = 312, /**< Right "Windows" key */ - K_MODE = 313, /**< "Alt Gr" key */ - K_COMPOSE = 314, /**< Multi-key compose key */ - /*@}*/ - - /** @name Miscellaneous function keys */ - /*@{*/ - K_HELP = 315, - K_PRINT = 316, - K_SYSREQ = 317, - K_BREAK = 318, - K_MENU = 319, - K_POWER = 320, /**< Power Macintosh power key */ - K_EURO = 321, /**< Some european keyboards */ - K_UNDO = 322, /**< Atari keyboard has Undo */ - /*@}*/ - - /* Add any other keys here */ - - K_LAST - }; - - /** Enumeration of valid key mods (possibly OR'd together) */ - enum Mod { - KMOD_NONE = 0x0000, - KMOD_LSHIFT= 0x0001, - KMOD_RSHIFT= 0x0002, - KMOD_LCTRL = 0x0040, - KMOD_RCTRL = 0x0080, - KMOD_LALT = 0x0100, - KMOD_RALT = 0x0200, - KMOD_LMETA = 0x0400, - KMOD_RMETA = 0x0800, - KMOD_NUM = 0x1000, - KMOD_CAPS = 0x2000, - KMOD_MODE = 0x4000, - KMOD_RESERVED = 0x8000, - KMOD_CTRL = (KMOD_LCTRL|KMOD_RCTRL), - KMOD_SHIFT = (KMOD_LSHIFT|KMOD_RSHIFT), - KMOD_ALT = (KMOD_LALT|KMOD_RALT), - KMOD_META = (KMOD_LMETA|KMOD_RMETA) - }; -} diff --git a/library/include/df/custom/enabler.methods.inc b/library/include/df/custom/enabler.methods.inc index b06af2345..5cc584bc2 100644 --- a/library/include/df/custom/enabler.methods.inc +++ b/library/include/df/custom/enabler.methods.inc @@ -1,6 +1,8 @@ void zoom_display(df::zoom_commands command) { + /* DFHack::DFSDL::DFSDL_SemWait(async_zoom.sem); async_zoom.queue.push_back(command); DFHack::DFSDL::DFSDL_SemPost(async_zoom.sem); DFHack::DFSDL::DFSDL_SemPost(async_zoom.sem_fill); + */ } diff --git a/library/include/modules/DFSDL.h b/library/include/modules/DFSDL.h index 9f07ea3db..fc65fab34 100644 --- a/library/include/modules/DFSDL.h +++ b/library/include/modules/DFSDL.h @@ -3,60 +3,19 @@ #include "Export.h" #include "ColorText.h" +struct SDL_Surface; +struct SDL_Rect; +struct SDL_PixelFormat; +union SDL_Event; + namespace DFHack { - // SDL stand-in type definitions - typedef signed short SINT16; - typedef void DFSDL_sem; - typedef void DFSDL_Event; - - typedef struct - { - int16_t x, y; - uint16_t w, h; - } DFSDL_Rect; - typedef struct - { - void *palette; // SDL_Palette* - uint8_t BitsPerPixel; - uint8_t BytesPerPixel; - uint8_t Rloss; - uint8_t Gloss; - uint8_t Bloss; - uint8_t Aloss; - uint8_t Rshift; - uint8_t Gshift; - uint8_t Bshift; - uint8_t Ashift; - uint32_t Rmask; - uint32_t Gmask; - uint32_t Bmask; - uint32_t Amask; - uint32_t colorkey; - uint8_t alpha; - } DFSDL_PixelFormat; - typedef struct - { - uint32_t flags; - DFSDL_PixelFormat* format; - int w, h; - int pitch; - void* pixels; - void* userdata; // as far as i could see DF doesnt use this - int locked; - void* lock_data; - DFSDL_Rect clip_rect; - void* map; - int refcount; - } DFSDL_Surface; - - // ========= struct DFTileSurface { bool paintOver; // draw over original tile? - DFSDL_Surface* surface; // from where it should be drawn - DFSDL_Rect* rect; // from which coords (NULL to draw whole surface) - DFSDL_Rect* dstResize; // if not NULL dst rect will be resized (x/y/w/h will be added to original dst) + SDL_Surface* surface; // from where it should be drawn + SDL_Rect* rect; // from which coords (NULL to draw whole surface) + SDL_Rect* dstResize; // if not NULL dst rect will be resized (x/y/w/h will be added to original dst) }; /** @@ -79,17 +38,17 @@ bool init(DFHack::color_ostream &out); */ void cleanup(); -DFHACK_EXPORT DFSDL_Surface * DFIMG_Load(const char *file); -DFHACK_EXPORT int DFSDL_SetAlpha(DFSDL_Surface *surface, uint32_t flag, uint8_t alpha); -DFHACK_EXPORT DFSDL_Surface * DFSDL_GetVideoSurface(void); -DFHACK_EXPORT DFSDL_Surface * DFSDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask); -DFHACK_EXPORT DFSDL_Surface * DFSDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask); -DFHACK_EXPORT int DFSDL_UpperBlit(DFSDL_Surface *src, const DFSDL_Rect *srcrect, DFSDL_Surface *dst, DFSDL_Rect *dstrect); -DFHACK_EXPORT DFSDL_Surface * DFSDL_ConvertSurface(DFSDL_Surface *src, const DFSDL_PixelFormat *fmt, uint32_t flags); -DFHACK_EXPORT void DFSDL_FreeSurface(DFSDL_Surface *surface); -DFHACK_EXPORT int DFSDL_SemWait(DFSDL_sem *sem); -DFHACK_EXPORT int DFSDL_SemPost(DFSDL_sem *sem); -DFHACK_EXPORT int DFSDL_PushEvent(DFSDL_Event *event); +DFHACK_EXPORT SDL_Surface * DFIMG_Load(const char *file); +DFHACK_EXPORT int DFSDL_SetAlpha(SDL_Surface *surface, uint32_t flag, uint8_t alpha); +DFHACK_EXPORT SDL_Surface * DFSDL_GetVideoSurface(void); +DFHACK_EXPORT SDL_Surface * DFSDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask); +DFHACK_EXPORT SDL_Surface * DFSDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask); +DFHACK_EXPORT int DFSDL_UpperBlit(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect); +DFHACK_EXPORT SDL_Surface * DFSDL_ConvertSurface(SDL_Surface *src, const SDL_PixelFormat *fmt, uint32_t flags); +DFHACK_EXPORT void DFSDL_FreeSurface(SDL_Surface *surface); +// DFHACK_EXPORT int DFSDL_SemWait(SDL_sem *sem); +// DFHACK_EXPORT int DFSDL_SemPost(SDL_sem *sem); +DFHACK_EXPORT int DFSDL_PushEvent(SDL_Event *event); } diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index c21e3ad32..887fb5f75 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -191,7 +191,7 @@ namespace DFHack } /// Wrapper to call enabler->zoom_display from plugins - DFHACK_EXPORT void zoom(df::zoom_commands cmd); + //DFHACK_EXPORT void zoom(df::zoom_commands cmd); /// Returns the state of [GRAPHICS:YES/NO] DFHACK_EXPORT bool inGraphicsMode(); diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp index b95b6302a..36e8e1a41 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -14,29 +14,29 @@ using namespace DFHack; static DFLibrary *g_sdl_handle = nullptr; static DFLibrary *g_sdl_image_handle = nullptr; static const std::vector SDL_LIBS { - "SDL.dll", + "SDL2.dll", "SDL.framework/Versions/A/SDL", "SDL.framework/SDL", - "libSDL-1.2.so.0" + "libSDL2-2.0.so.0" }; static const std::vector SDL_IMAGE_LIBS { - "SDL_image.dll", + "SDL2_image.dll", "SDL_image.framework/Versions/A/SDL_image", "SDL_image.framework/SDL_image", - "libSDL_image-1.2.so.0" + "libSDL2_image-2.0.so.0" }; -DFSDL_Surface * (*g_IMG_Load)(const char *) = nullptr; -int (*g_SDL_SetAlpha)(DFSDL_Surface *, uint32_t, uint8_t) = nullptr; -DFSDL_Surface * (*g_SDL_GetVideoSurface)(void) = nullptr; -DFSDL_Surface * (*g_SDL_CreateRGBSurface)(uint32_t, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t) = nullptr; -DFSDL_Surface * (*g_SDL_CreateRGBSurfaceFrom)(void *pixels, int width, int height, int depth, int pitch, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) = nullptr; -int (*g_SDL_UpperBlit)(DFSDL_Surface *, const DFSDL_Rect *, DFSDL_Surface *, DFSDL_Rect *) = nullptr; -DFSDL_Surface * (*g_SDL_ConvertSurface)(DFSDL_Surface *, const DFSDL_PixelFormat *, uint32_t) = nullptr; -void (*g_SDL_FreeSurface)(DFSDL_Surface *) = nullptr; -int (*g_SDL_SemWait)(DFSDL_sem *) = nullptr; -int (*g_SDL_SemPost)(DFSDL_sem *) = nullptr; -int (*g_SDL_PushEvent)(DFSDL_Event *) = nullptr; +SDL_Surface * (*g_IMG_Load)(const char *) = nullptr; +int (*g_SDL_SetAlpha)(SDL_Surface *, uint32_t, uint8_t) = nullptr; +SDL_Surface * (*g_SDL_GetVideoSurface)(void) = nullptr; +SDL_Surface * (*g_SDL_CreateRGBSurface)(uint32_t, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t) = nullptr; +SDL_Surface * (*g_SDL_CreateRGBSurfaceFrom)(void *pixels, int width, int height, int depth, int pitch, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) = nullptr; +int (*g_SDL_UpperBlit)(SDL_Surface *, const SDL_Rect *, SDL_Surface *, SDL_Rect *) = nullptr; +SDL_Surface * (*g_SDL_ConvertSurface)(SDL_Surface *, const SDL_PixelFormat *, uint32_t) = nullptr; +void (*g_SDL_FreeSurface)(SDL_Surface *) = nullptr; +// int (*g_SDL_SemWait)(DFSDL_sem *) = nullptr; +// int (*g_SDL_SemPost)(DFSDL_sem *) = nullptr; +int (*g_SDL_PushEvent)(SDL_Event *) = nullptr; bool DFSDL::init(color_ostream &out) { for (auto &lib_str : SDL_LIBS) { @@ -72,8 +72,8 @@ bool DFSDL::init(color_ostream &out) { bind(g_sdl_handle, SDL_UpperBlit); bind(g_sdl_handle, SDL_ConvertSurface); bind(g_sdl_handle, SDL_FreeSurface); - bind(g_sdl_handle, SDL_SemWait); - bind(g_sdl_handle, SDL_SemPost); + // bind(g_sdl_handle, SDL_SemWait); + // bind(g_sdl_handle, SDL_SemPost); bind(g_sdl_handle, SDL_PushEvent); #undef bind @@ -93,46 +93,46 @@ void DFSDL::cleanup() { } } -DFSDL_Surface * DFSDL::DFIMG_Load(const char *file) { +SDL_Surface * DFSDL::DFIMG_Load(const char *file) { return g_IMG_Load(file); } -int DFSDL::DFSDL_SetAlpha(DFSDL_Surface *surface, uint32_t flag, uint8_t alpha) { +int DFSDL::DFSDL_SetAlpha(SDL_Surface *surface, uint32_t flag, uint8_t alpha) { return g_SDL_SetAlpha(surface, flag, alpha); } -DFSDL_Surface * DFSDL::DFSDL_GetVideoSurface(void) { +SDL_Surface * DFSDL::DFSDL_GetVideoSurface(void) { return g_SDL_GetVideoSurface(); } -DFSDL_Surface * DFSDL::DFSDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) { +SDL_Surface * DFSDL::DFSDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) { return g_SDL_CreateRGBSurface(flags, width, height, depth, Rmask, Gmask, Bmask, Amask); } -DFSDL_Surface * DFSDL::DFSDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) { +SDL_Surface * DFSDL::DFSDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) { return g_SDL_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask); } -int DFSDL::DFSDL_UpperBlit(DFSDL_Surface *src, const DFSDL_Rect *srcrect, DFSDL_Surface *dst, DFSDL_Rect *dstrect) { +int DFSDL::DFSDL_UpperBlit(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect) { return g_SDL_UpperBlit(src, srcrect, dst, dstrect); } -DFSDL_Surface * DFSDL::DFSDL_ConvertSurface(DFSDL_Surface *src, const DFSDL_PixelFormat *fmt, uint32_t flags) { +SDL_Surface * DFSDL::DFSDL_ConvertSurface(SDL_Surface *src, const SDL_PixelFormat *fmt, uint32_t flags) { return g_SDL_ConvertSurface(src, fmt, flags); } -void DFSDL::DFSDL_FreeSurface(DFSDL_Surface *surface) { +void DFSDL::DFSDL_FreeSurface(SDL_Surface *surface) { g_SDL_FreeSurface(surface); } -int DFSDL::DFSDL_SemWait(DFSDL_sem *sem) { - return g_SDL_SemWait(sem); -} +// int DFSDL::DFSDL_SemWait(DFSDL_sem *sem) { +// return g_SDL_SemWait(sem); +// } -int DFSDL::DFSDL_SemPost(DFSDL_sem *sem) { - return g_SDL_SemPost(sem); -} +// int DFSDL::DFSDL_SemPost(DFSDL_sem *sem) { +// return g_SDL_SemPost(sem); +// } -int DFSDL::DFSDL_PushEvent(DFSDL_Event *event) { +int DFSDL::DFSDL_PushEvent(SDL_Event *event) { return g_SDL_PushEvent(event); } diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 6ccf246aa..a36f387b6 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -106,9 +106,11 @@ df::coord2d Screen::getWindowSize() return df::coord2d(gps->dimx, gps->dimy); } +/* void Screen::zoom(df::zoom_commands cmd) { enabler->zoom_display(cmd); } +*/ bool Screen::inGraphicsMode() { diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index a30f879a0..21aadf2da 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -8,6 +8,8 @@ #include "df/enabler.h" +#include + using df::global::enabler; using namespace DFHack; using namespace DFHack::DFSDL; @@ -37,26 +39,34 @@ static long g_window_borders_texpos_start = -1; // // It uses the same pixel format (RGBA, R at lowest address) regardless of // hardware. -DFSDL_Surface * canonicalize_format(DFSDL_Surface *src) { - DFSDL_PixelFormat fmt; +SDL_Surface * canonicalize_format(SDL_Surface *src) { + SDL_PixelFormat fmt; fmt.palette = NULL; fmt.BitsPerPixel = 32; fmt.BytesPerPixel = 4; fmt.Rloss = fmt.Gloss = fmt.Bloss = fmt.Aloss = 0; -//#if SDL_BYTEORDER == SDL_BIG_ENDIAN -// fmt.Rshift = 24; fmt.Gshift = 16; fmt.Bshift = 8; fmt.Ashift = 0; -//#else +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + fmt.Rshift = 24; fmt.Gshift = 16; fmt.Bshift = 8; fmt.Ashift = 0; +#else fmt.Rshift = 0; fmt.Gshift = 8; fmt.Bshift = 16; fmt.Ashift = 24; -//#endif +#endif fmt.Rmask = 255 << fmt.Rshift; fmt.Gmask = 255 << fmt.Gshift; fmt.Bmask = 255 << fmt.Bshift; fmt.Amask = 255 << fmt.Ashift; - fmt.colorkey = 0; - fmt.alpha = 255; - DFSDL_Surface *tgt = DFSDL_ConvertSurface(src, &fmt, 0); // SDL_SWSURFACE + SDL_Surface *tgt = DFSDL_ConvertSurface(src, &fmt, SDL_SWSURFACE); DFSDL_FreeSurface(src); + for (int x = 0; x < tgt->w; ++x) { + for (int y = 0; y < tgt->h; ++y) { + Uint8* p = (Uint8*)tgt->pixels + y * tgt->pitch + x * 4; + if (p[3] == 0) { + for (int c = 0; c < 3; c++) { + p[c] = 0; + } + } + } + } return tgt; } @@ -65,7 +75,7 @@ const uint32_t TILE_HEIGHT_PX = 12; static size_t load_textures(color_ostream & out, const char * fname, long *texpos_start) { - DFSDL_Surface *s = DFIMG_Load(fname); + SDL_Surface *s = DFIMG_Load(fname); if (!s) { out.printerr("unable to load textures from '%s'\n", fname); return 0; @@ -78,12 +88,12 @@ static size_t load_textures(color_ostream & out, const char * fname, long count = 0; for (int y = 0; y < dimy; y++) { for (int x = 0; x < dimx; x++) { - DFSDL_Surface *tile = DFSDL_CreateRGBSurface(0, // SDL_SWSURFACE + SDL_Surface *tile = DFSDL_CreateRGBSurface(0, // SDL_SWSURFACE TILE_WIDTH_PX, TILE_HEIGHT_PX, 32, s->format->Rmask, s->format->Gmask, s->format->Bmask, s->format->Amask); DFSDL_SetAlpha(tile, 0,255); - DFSDL_Rect vp; + SDL_Rect vp; vp.x = TILE_WIDTH_PX * x; vp.y = TILE_HEIGHT_PX * y; vp.w = TILE_WIDTH_PX; @@ -161,7 +171,7 @@ void Textures::cleanup() { auto &raws = textures.raws; size_t texpos_end = g_dfhack_logo_texpos_start + g_num_dfhack_textures; for (size_t idx = g_dfhack_logo_texpos_start; idx <= texpos_end; ++idx) { - DFSDL_FreeSurface((DFSDL_Surface *)raws[idx]); + DFSDL_FreeSurface((SDL_Surface *)raws[idx]); raws[idx] = NULL; } diff --git a/library/xml b/library/xml index 916a49700..bff3a12b3 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 916a497000651b64272dacda3a5005650d3c0c68 +Subproject commit bff3a12b3863f54c5c2f3031c1726f7e28a9e70e diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 56d29371b..6ca69d1a7 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -14,8 +14,6 @@ #include "PluginManager.h" #include "RemoteFortressReader.pb.h" #include "RemoteServer.h" -#include "SDL_events.h" -#include "SDL_keyboard.h" #include "TileTypes.h" #include "VersionInfo.h" #if DF_VERSION_INT > 34011 @@ -126,6 +124,9 @@ #include "dwarf_control.h" #include "item_reader.h" +#include +#include + using namespace DFHack; using namespace df::enums; using namespace RemoteFortressReader; @@ -2894,13 +2895,12 @@ static command_result CopyScreen(color_ostream &stream, const EmptyMessage *in, static command_result PassKeyboardEvent(color_ostream &stream, const KeyboardEvent *in) { #if DF_VERSION_INT > 34011 - SDL::Event e; + SDL_Event e; e.key.type = in->type(); e.key.state = in->state(); - e.key.ksym.mod = (SDL::Mod)in->mod(); - e.key.ksym.scancode = in->scancode(); - e.key.ksym.sym = (SDL::Key)in->sym(); - e.key.ksym.unicode = in->unicode(); + e.key.keysym.mod = in->mod(); + e.key.keysym.scancode = (SDL_Scancode)in->scancode(); + e.key.keysym.sym = in->sym(); DFHack::DFSDL::DFSDL_PushEvent(&e); #endif return CR_OK; From 52151b0e9840b69410ebb67ddeeb26a5897cd43c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 22 May 2023 17:34:00 -0700 Subject: [PATCH 007/851] remove SDL functions that don't exist anymore --- library/include/modules/DFSDL.h | 2 -- library/modules/DFSDL.cpp | 12 ------------ library/modules/Textures.cpp | 2 -- 3 files changed, 16 deletions(-) diff --git a/library/include/modules/DFSDL.h b/library/include/modules/DFSDL.h index fc65fab34..626224d60 100644 --- a/library/include/modules/DFSDL.h +++ b/library/include/modules/DFSDL.h @@ -39,8 +39,6 @@ bool init(DFHack::color_ostream &out); void cleanup(); DFHACK_EXPORT SDL_Surface * DFIMG_Load(const char *file); -DFHACK_EXPORT int DFSDL_SetAlpha(SDL_Surface *surface, uint32_t flag, uint8_t alpha); -DFHACK_EXPORT SDL_Surface * DFSDL_GetVideoSurface(void); DFHACK_EXPORT SDL_Surface * DFSDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask); DFHACK_EXPORT SDL_Surface * DFSDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask); DFHACK_EXPORT int DFSDL_UpperBlit(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect); diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp index 36e8e1a41..7aa7f36d5 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -27,8 +27,6 @@ static const std::vector SDL_IMAGE_LIBS { }; SDL_Surface * (*g_IMG_Load)(const char *) = nullptr; -int (*g_SDL_SetAlpha)(SDL_Surface *, uint32_t, uint8_t) = nullptr; -SDL_Surface * (*g_SDL_GetVideoSurface)(void) = nullptr; SDL_Surface * (*g_SDL_CreateRGBSurface)(uint32_t, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t) = nullptr; SDL_Surface * (*g_SDL_CreateRGBSurfaceFrom)(void *pixels, int width, int height, int depth, int pitch, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) = nullptr; int (*g_SDL_UpperBlit)(SDL_Surface *, const SDL_Rect *, SDL_Surface *, SDL_Rect *) = nullptr; @@ -65,8 +63,6 @@ bool DFSDL::init(color_ostream &out) { } bind(g_sdl_image_handle, IMG_Load); - bind(g_sdl_handle, SDL_SetAlpha); - bind(g_sdl_handle, SDL_GetVideoSurface); bind(g_sdl_handle, SDL_CreateRGBSurface); bind(g_sdl_handle, SDL_CreateRGBSurfaceFrom); bind(g_sdl_handle, SDL_UpperBlit); @@ -97,14 +93,6 @@ SDL_Surface * DFSDL::DFIMG_Load(const char *file) { return g_IMG_Load(file); } -int DFSDL::DFSDL_SetAlpha(SDL_Surface *surface, uint32_t flag, uint8_t alpha) { - return g_SDL_SetAlpha(surface, flag, alpha); -} - -SDL_Surface * DFSDL::DFSDL_GetVideoSurface(void) { - return g_SDL_GetVideoSurface(); -} - SDL_Surface * DFSDL::DFSDL_CreateRGBSurface(uint32_t flags, int width, int height, int depth, uint32_t Rmask, uint32_t Gmask, uint32_t Bmask, uint32_t Amask) { return g_SDL_CreateRGBSurface(flags, width, height, depth, Rmask, Gmask, Bmask, Amask); } diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 21aadf2da..e31e37426 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -82,7 +82,6 @@ static size_t load_textures(color_ostream & out, const char * fname, } s = canonicalize_format(s); - DFSDL_SetAlpha(s, 0, 255); int dimx = s->w / TILE_WIDTH_PX; int dimy = s->h / TILE_HEIGHT_PX; long count = 0; @@ -92,7 +91,6 @@ static size_t load_textures(color_ostream & out, const char * fname, TILE_WIDTH_PX, TILE_HEIGHT_PX, 32, s->format->Rmask, s->format->Gmask, s->format->Bmask, s->format->Amask); - DFSDL_SetAlpha(tile, 0,255); SDL_Rect vp; vp.x = TILE_WIDTH_PX * x; vp.y = TILE_HEIGHT_PX * y; From a48344fd241ddc98049d38310ca501114d188a26 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 22 May 2023 17:49:17 -0700 Subject: [PATCH 008/851] get keybindings working again --- library/Core.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 6fc453060..4b036a83e 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2373,23 +2373,13 @@ bool Core::DFH_SDL_Event(SDL_Event* ev) else if (ke.state == SDL_PRESSED && !hotkey_states[ke.keysym.sym]) { hotkey_states[ke.keysym.sym] = true; + SelectHotkey(ke.keysym.sym, modstate); } else if(ke.state == SDL_RELEASED) { hotkey_states[ke.keysym.sym] = false; } } - else if (ev->type == SDL_TEXTINPUT) { - auto &te = ev->text; - - uint8_t sym = (uint8_t)te.text[0]; - if (sym <= 0x7f && hotkey_states[sym]) { - // register that we have responded to this hotkey, and don't respond - // again even if the key is held down - hotkey_states[sym] = false; - SelectHotkey(sym, modstate); - } - } return false; } @@ -2408,7 +2398,7 @@ bool Core::SelectHotkey(int sym, int modifiers) std::string cmd; - DEBUG(keybinding).print("checking hotkeys for sym=%d, modifiers=%x\n", sym, modifiers); + DEBUG(keybinding).print("checking hotkeys for sym=%d (%c), modifiers=%x\n", sym, sym, modifiers); { std::lock_guard lock(HotkeyMutex); From 61eeea20e8eaef105f400eef13e1d05575b0f832 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 23 May 2023 16:56:42 -0700 Subject: [PATCH 009/851] ensure offline builds still work; clean up --- CMakeLists.txt | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 545a0e6f5..ef3a7bd84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.08") -set(DFHACK_RELEASE "r4") -set(DFHACK_PRERELEASE FALSE) +set(DFHACK_RELEASE "r2rc1") +set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_ABI_VERSION 1) @@ -285,24 +285,23 @@ else() 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}) -# Download SDL release and extract into depends (in the build dir so as not to clutter up the source dir) +# Download SDL release and extract into depends in the build dir # all we need are the header files, so the same release package will work for all platforms # (the above statement is untested for OSX) set(SDL_VERSION 2.26.2) +set(SDL_ZIP_MD5 574daf26d48de753d0b1e19823c9d8bb) set(SDL_ZIP_FILE SDL2-devel-${SDL_VERSION}-VC.zip) set(SDL_ZIP_PATH ${CMAKE_BINARY_DIR}/depends/SDL2/) -file(DOWNLOAD "https://github.com/libsdl-org/SDL/releases/download/release-${SDL_VERSION}/${SDL_ZIP_FILE}" +download_file("https://github.com/libsdl-org/SDL/releases/download/release-${SDL_VERSION}/${SDL_ZIP_FILE}" ${SDL_ZIP_PATH}${SDL_ZIP_FILE} - EXPECTED_MD5 574daf26d48de753d0b1e19823c9d8bb - SHOW_PROGRESS) + ${SDL_ZIP_MD5}) file(ARCHIVE_EXTRACT INPUT ${SDL_ZIP_PATH}${SDL_ZIP_FILE} DESTINATION ${SDL_ZIP_PATH}) include_directories(${SDL_ZIP_PATH}/SDL2-${SDL_VERSION}/include) From 90a280625192c9dd0d286c6a56e0ab8eda9a4110 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 23 May 2023 17:15:47 -0700 Subject: [PATCH 010/851] fix paths --- depends/zlib/lib/.gitignore | 1 - 1 file changed, 1 deletion(-) delete mode 100644 depends/zlib/lib/.gitignore diff --git a/depends/zlib/lib/.gitignore b/depends/zlib/lib/.gitignore deleted file mode 100644 index 683bf139f..000000000 --- a/depends/zlib/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.lib From f6228240d2b4479da1153ba75506119cd071387c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 24 May 2023 03:04:33 -0700 Subject: [PATCH 011/851] move zlib download back to src dir --- CMakeLists.txt | 2 +- depends/zlib/lib/win64/.gitignore | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 depends/zlib/lib/win64/.gitignore diff --git a/CMakeLists.txt b/CMakeLists.txt index ef3a7bd84..667e1d67e 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/${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 05ae92f08522e90415a10929c0170fdfee9a5860 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 24 May 2023 03:17:22 -0700 Subject: [PATCH 012/851] move SDL2 to depends in the src dir --- .gitignore | 7 ++++--- CMakeLists.txt | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index a386b260a..5b4c7f6fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ # linux backup files *~ -#Kdevelop project files +# Kdevelop project files *.kdev4 .kdev4 @@ -70,7 +70,7 @@ tags # Mac OS X .DS_Store files .DS_Store -#VS is annoying about this one. +# VS is annoying about this one. /build/win64/DF_PATH.txt /build/win32/DF_PATH.txt /.vs @@ -81,5 +81,6 @@ tags # external plugins /plugins/CMakeLists.custom.txt -# steam api +# 3rd party downloads depends/steam +depends/SDL2 diff --git a/CMakeLists.txt b/CMakeLists.txt index 667e1d67e..ea2d8f968 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -293,12 +293,13 @@ find_package(ZLIB REQUIRED) include_directories(${ZLIB_INCLUDE_DIRS}) # Download SDL release and extract into depends in the build dir -# all we need are the header files, so the same release package will work for all platforms +# all we need are the header files (including generated headers), so the same release package +# will work for all platforms # (the above statement is untested for OSX) set(SDL_VERSION 2.26.2) set(SDL_ZIP_MD5 574daf26d48de753d0b1e19823c9d8bb) set(SDL_ZIP_FILE SDL2-devel-${SDL_VERSION}-VC.zip) -set(SDL_ZIP_PATH ${CMAKE_BINARY_DIR}/depends/SDL2/) +set(SDL_ZIP_PATH ${dfhack_SOURCE_DIR}/depends/SDL2/) download_file("https://github.com/libsdl-org/SDL/releases/download/release-${SDL_VERSION}/${SDL_ZIP_FILE}" ${SDL_ZIP_PATH}${SDL_ZIP_FILE} ${SDL_ZIP_MD5}) From a51032b8eed05cf3f79ae701423d398fd28b94a2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 24 May 2023 12:15:52 -0700 Subject: [PATCH 013/851] 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 ea2d8f968..ec0fbb3dc 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 3e2940ef8f2ff8da12d556a5714f0d80b08c2ca7 Mon Sep 17 00:00:00 2001 From: Taxi Service Date: Thu, 1 Jun 2023 20:16:31 +0200 Subject: [PATCH 014/851] attempt to set optional tilesize arguments for load_texture() --- data/art/pathable.png | Bin 0 -> 615 bytes library/include/modules/Textures.h | 5 +++++ library/modules/Textures.cpp | 25 +++++++++++++++++-------- plugins/pathable.cpp | 2 +- 4 files changed, 23 insertions(+), 9 deletions(-) create mode 100644 data/art/pathable.png diff --git a/data/art/pathable.png b/data/art/pathable.png new file mode 100644 index 0000000000000000000000000000000000000000..00f7f831d1dd51bc166ef390470a5382781eb631 GIT binary patch literal 615 zcmV-t0+{`YP)TK+Ot%kjw70!PgW+qU zu(P|l?&9G7ZagXS;ROL0*x~6rogBLS677#Q@_acybpoRiRb);T-{JjG$?uO4rUVzyQriJmpEc8an_0002ovPDHLkV1hMj B3>5$X literal 0 HcmV?d00001 diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 95e628d5a..8aa43e5c1 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -46,6 +46,11 @@ DFHACK_EXPORT long getIconsTexposStart(); */ DFHACK_EXPORT long getOnOffTexposStart(); +/** + * Get the first texpos for the pathable 32x32 sprites. It's a 2x1 grid. + */ +DFHACK_EXPORT long getPathableTexposStart(); + /** * Get the first texpos for the control panel icons. 10x2 grid. */ diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index e31e37426..6cc262764 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -25,6 +25,7 @@ static long g_green_pin_texpos_start = -1; 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_pathable_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; @@ -74,7 +75,9 @@ const uint32_t TILE_WIDTH_PX = 8; const uint32_t TILE_HEIGHT_PX = 12; static size_t load_textures(color_ostream & out, const char * fname, - long *texpos_start) { + long *texpos_start, + int tile_w = TILE_WIDTH_PX, + int tile_h = TILE_HEIGHT_PX) { SDL_Surface *s = DFIMG_Load(fname); if (!s) { out.printerr("unable to load textures from '%s'\n", fname); @@ -82,20 +85,20 @@ static size_t load_textures(color_ostream & out, const char * fname, } s = canonicalize_format(s); - int dimx = s->w / TILE_WIDTH_PX; - int dimy = s->h / TILE_HEIGHT_PX; + int dimx = s->w / tile_w; + int dimy = s->h / tile_h; long count = 0; for (int y = 0; y < dimy; y++) { for (int x = 0; x < dimx; x++) { SDL_Surface *tile = DFSDL_CreateRGBSurface(0, // SDL_SWSURFACE - TILE_WIDTH_PX, TILE_HEIGHT_PX, 32, + tile_w, tile_h, 32, s->format->Rmask, s->format->Gmask, s->format->Bmask, s->format->Amask); SDL_Rect vp; - vp.x = TILE_WIDTH_PX * x; - vp.y = TILE_HEIGHT_PX * y; - vp.w = TILE_WIDTH_PX; - vp.h = TILE_HEIGHT_PX; + vp.x = tile_w * x; + vp.y = tile_h * y; + vp.w = tile_w; + vp.h = tile_h; DFSDL_UpperBlit(s, &vp, tile, NULL); if (!count++) *texpos_start = enabler->textures.raws.size(); @@ -137,6 +140,8 @@ void Textures::init(color_ostream &out) { &g_icons_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/on-off.png", &g_on_off_texpos_start); + g_num_dfhack_textures += load_textures(out, "hack/data/art/pathable.png", + &g_pathable_texpos_start, 32, 32); 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", @@ -201,6 +206,10 @@ long Textures::getOnOffTexposStart() { return g_on_off_texpos_start; } +long Textures::getPathableTexposStart() { + return g_pathable_texpos_start; +} + long Textures::getControlPanelTexposStart() { return g_control_panel_texpos_start; } diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 06394f838..916db4a72 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -41,7 +41,7 @@ static void paintScreen(df::coord target, bool skip_unrevealed = false) { 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(); + long on_off_texpos = Textures::getPathableTexposStart(); if (on_off_texpos > 0) { pathable_tile_texpos = on_off_texpos + 0; unpathable_tile_texpos = on_off_texpos + 1; From 95b9cb0ab322e4e538cece4908fcdcae30baee63 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 5 Jun 2023 19:48:14 -0700 Subject: [PATCH 015/851] match DF's version string in ours --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec0fbb3dc..1a8d557b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,8 @@ cmake_policy(SET CMP0074 NEW) project(dfhack) # set up versioning. -set(DF_VERSION "50.08") -set(DFHACK_RELEASE "r2rc1") +set(DF_VERSION "50.08sdl2-5") +set(DFHACK_RELEASE "beta1") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 258b647ef63f89305efa0b82fd0518f0a0f39320 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 5 Jun 2023 19:49:17 -0700 Subject: [PATCH 016/851] extend the title version widget to show longer version strings --- plugins/lua/overlay.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index fda1edc95..68582e8eb 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -597,6 +597,10 @@ function TitleVersionOverlay:init() table.insert(text, {text='Pre-release build', pen=COLOR_LIGHTRED}) end + for _,t in ipairs(text) do + self.frame.w = math.max(self.frame.w, #t) + end + self:addviews{ widgets.Label{ frame={t=0, l=0}, From 0790ace9fde1bf6811244b08a0f29e4ec33bfdce Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 6 Jun 2023 11:26:10 -0700 Subject: [PATCH 017/851] temporarily disable faststart until DF no longer has a race condition --- plugins/faststart.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/faststart.cpp b/plugins/faststart.cpp index de014801c..65895e8bf 100644 --- a/plugins/faststart.cpp +++ b/plugins/faststart.cpp @@ -48,8 +48,10 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { if (enable != is_enabled) { +#if 0 if (!INTERPOSE_HOOK(prep_hook, logic).apply(enable)) return CR_FAILURE; +#endif is_enabled = enable; } From 840a2b3525aeb8cf62223ca8507ba21af5f1824a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 15 Jun 2023 01:14:12 -0700 Subject: [PATCH 018/851] ensure DFHack screens get all string input --- library/include/modules/Screen.h | 3 +++ library/modules/Screen.cpp | 15 +++++++++++++-- plugins/overlay.cpp | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index 887fb5f75..daa08ca59 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -229,6 +229,9 @@ namespace DFHack DFHACK_EXPORT bool hasActiveScreens(Plugin *p); DFHACK_EXPORT void raise(df::viewscreen *screen); + // returns a new set with text interface keys from the text buffer added in (if any) + DFHACK_EXPORT std::set add_text_keys(const std::set& keys); + /// Retrieve the string representation of the bound key. DFHACK_EXPORT std::string getKeyDisplay(df::interface_key key); diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index a36f387b6..d3419398c 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -78,7 +78,6 @@ namespace DFHack { DBG_DECLARE(core, screen, DebugCategory::LINFO); } - /* * Screen painting API. */ @@ -586,6 +585,17 @@ void Hide::merge() { } } } +std::set Screen::add_text_keys(const std::set& keys) { + std::set combined_keys(keys); + if (df::global::enabler->last_text_input[0]) { + char c = df::global::enabler->last_text_input[0]; + df::interface_key key = charToKey(c); + DEBUG(screen).print("adding character %c as interface key %ld\n", c, key); + combined_keys.emplace(key); + } + return combined_keys; +} + string Screen::getKeyDisplay(df::interface_key key) { if (enabler) @@ -940,7 +950,7 @@ int dfhack_lua_viewscreen::do_input(lua_State *L) } lua_pushvalue(L, -2); - Lua::PushInterfaceKeys(L, *keys); + Lua::PushInterfaceKeys(L, Screen::add_text_keys(*keys)); lua_call(L, 2, 0); self->update_focus(L, -1); @@ -1023,6 +1033,7 @@ void dfhack_lua_viewscreen::feed(std::set *keys) lua_pushlightuserdata(Lua::Core::State, keys); safe_call_lua(do_input, 1, 0); + df::global::enabler->last_text_input[0] = '\0'; } void dfhack_lua_viewscreen::onShow() diff --git a/plugins/overlay.cpp b/plugins/overlay.cpp index 784e17129..7185f73a1 100644 --- a/plugins/overlay.cpp +++ b/plugins/overlay.cpp @@ -76,7 +76,7 @@ struct viewscreen_overlay : T { [&](lua_State *L) { Lua::Push(L, T::_identity.getName()); Lua::Push(L, this); - Lua::PushInterfaceKeys(L, *input); + Lua::PushInterfaceKeys(L, Screen::add_text_keys(*input)); }, [&](lua_State *L) { input_is_handled = lua_toboolean(L, -1); }); From f7bef53b422d793c03fc442399df7b22e743a3ed Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 15 Jun 2023 01:35:48 -0700 Subject: [PATCH 019/851] prefer symbols to descriptions for hotkey names --- library/modules/Screen.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index d3419398c..76f782edb 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -598,10 +598,12 @@ std::set Screen::add_text_keys(const std::setGetKeyDisplay(key); - - return "?"; + int c = keyToChar(key); + if (c != -1) + return string(1, c); + if (key >= df::interface_key::CUSTOM_SHIFT_A && key <= df::interface_key::CUSTOM_SHIFT_Z) + return string(1, 'A' + (key - df::interface_key::CUSTOM_SHIFT_A)); + return enabler->GetKeyDisplay(key); } int Screen::keyToChar(df::interface_key key) From e101a6d9dcfd7aeab7b6fd95b2bd8e8e6cdec932 Mon Sep 17 00:00:00 2001 From: Myk Date: Sun, 18 Jun 2023 00:22:30 -0700 Subject: [PATCH 020/851] Update Textures.h --- library/include/modules/Textures.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 8aa43e5c1..bebd78dc9 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -49,7 +49,7 @@ DFHACK_EXPORT long getOnOffTexposStart(); /** * Get the first texpos for the pathable 32x32 sprites. It's a 2x1 grid. */ -DFHACK_EXPORT long getPathableTexposStart(); +DFHACK_EXPORT long getMapPathableTexposStart(); /** * Get the first texpos for the control panel icons. 10x2 grid. From b958727655ce089492db4d540cc59f1291c0e83c Mon Sep 17 00:00:00 2001 From: Myk Date: Sun, 18 Jun 2023 00:23:43 -0700 Subject: [PATCH 021/851] Update Textures.cpp --- library/modules/Textures.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 6cc262764..ba77f41f7 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -206,7 +206,7 @@ long Textures::getOnOffTexposStart() { return g_on_off_texpos_start; } -long Textures::getPathableTexposStart() { +long Textures::getMapPathableTexposStart() { return g_pathable_texpos_start; } From 2101918158302cbe96b99adb9e109232387bfd63 Mon Sep 17 00:00:00 2001 From: Myk Date: Sun, 18 Jun 2023 00:26:52 -0700 Subject: [PATCH 022/851] Update pathable.cpp --- plugins/pathable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 916db4a72..6ed890325 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -41,7 +41,7 @@ static void paintScreen(df::coord target, bool skip_unrevealed = false) { 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::getPathableTexposStart(); + long on_off_texpos = Textures::getMapPathableTexposStart(); if (on_off_texpos > 0) { pathable_tile_texpos = on_off_texpos + 0; unpathable_tile_texpos = on_off_texpos + 1; From 2a361ae7960da49f005e698240165e8662aeda2f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 18 Jun 2023 00:14:38 -0700 Subject: [PATCH 023/851] re-enable faststart now that the DF race condition has been fixed --- plugins/faststart.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/faststart.cpp b/plugins/faststart.cpp index 65895e8bf..de014801c 100644 --- a/plugins/faststart.cpp +++ b/plugins/faststart.cpp @@ -48,10 +48,8 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { if (enable != is_enabled) { -#if 0 if (!INTERPOSE_HOOK(prep_hook, logic).apply(enable)) return CR_FAILURE; -#endif is_enabled = enable; } From 20e425dc4f80417f3865ba7d3a3ea6a0e47b9397 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 23 Jun 2023 14:50:06 -0700 Subject: [PATCH 024/851] update to newest df sdl beta --- CMakeLists.txt | 4 ++-- library/xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a8d557b5..5e6b706f1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,8 +7,8 @@ cmake_policy(SET CMP0074 NEW) project(dfhack) # set up versioning. -set(DF_VERSION "50.08sdl2-5") -set(DFHACK_RELEASE "beta1") +set(DF_VERSION "50.09sdl2-2") +set(DFHACK_RELEASE "rc1") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/library/xml b/library/xml index bff3a12b3..89c307f21 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit bff3a12b3863f54c5c2f3031c1726f7e28a9e70e +Subproject commit 89c307f211d24960d93ba7c46cae40600caed38a From f2dc910b289c9982d57f78a939a4a7a52b47cc16 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 24 Jun 2023 20:10:27 -0500 Subject: [PATCH 025/851] update for 50.09sdl2-3 --- CMakeLists.txt | 2 +- library/xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e6b706f1..fe556d5d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_policy(SET CMP0074 NEW) project(dfhack) # set up versioning. -set(DF_VERSION "50.09sdl2-2") +set(DF_VERSION "50.09sdl2-3") set(DFHACK_RELEASE "rc1") set(DFHACK_PRERELEASE TRUE) diff --git a/library/xml b/library/xml index 89c307f21..52214bbdd 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 89c307f211d24960d93ba7c46cae40600caed38a +Subproject commit 52214bbddf9c8da0f12407ea01b49e25fcfba8a1 From 8f1efcd8a38fe1f484d416f1eaf18182307c006e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 25 Jun 2023 17:44:06 -0700 Subject: [PATCH 026/851] remove need to ignore warnings for dfhack-dependent targets --- library/CMakeLists.txt | 3 --- library/Debug.cpp | 1 + library/include/Core.h | 2 -- library/include/Export.h | 14 ++++++++++++++ library/include/PluginManager.h | 2 -- library/include/RemoteClient.h | 11 ----------- library/include/modules/Buildings.h | 8 +++++++- plugins/channel-safely/channel-manager.cpp | 4 ++-- plugins/channel-safely/include/inlines.h | 2 +- plugins/confirm.cpp | 2 +- plugins/hotkeys.cpp | 2 +- 11 files changed, 27 insertions(+), 24 deletions(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 48ebdb986..8681c9c90 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -377,9 +377,6 @@ if(WIN32) set_target_properties(dfhack-client PROPERTIES COMPILE_FLAGS "/FI\"Export.h\"" ) else() set_target_properties(dfhack PROPERTIES COMPILE_FLAGS "-include Export.h" ) - # required because of transitively-included protobuf headers - target_compile_options(dfhack - INTERFACE -Wno-deprecated-declarations -Wno-restrict) set_target_properties(dfhack-client PROPERTIES COMPILE_FLAGS "-include Export.h" ) add_library(dfhooks SHARED Hooks.cpp) target_link_libraries(dfhooks dfhack) diff --git a/library/Debug.cpp b/library/Debug.cpp index 9b13af168..dafbeb5ce 100644 --- a/library/Debug.cpp +++ b/library/Debug.cpp @@ -26,6 +26,7 @@ redistribute it freely, subject to the following restrictions: #include "Debug.h" #include "DebugManager.h" +#include #include #include #include diff --git a/library/include/Core.h b/library/include/Core.h index 696be4ead..c9f49cbb3 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -40,8 +40,6 @@ distribution. #include #include -#include "RemoteClient.h" - #define DFH_MOD_SHIFT 1 #define DFH_MOD_CTRL 2 #define DFH_MOD_ALT 4 diff --git a/library/include/Export.h b/library/include/Export.h index 9e2a78d4b..ad2b4ceec 100644 --- a/library/include/Export.h +++ b/library/include/Export.h @@ -69,3 +69,17 @@ distribution. #else #define Wformat(type, fmtstr, vararg) #endif + +namespace DFHack +{ + enum command_result + { + CR_LINK_FAILURE = -3, // RPC call failed due to I/O or protocol error + CR_NEEDS_CONSOLE = -2, // Attempt to call interactive command without console + CR_NOT_IMPLEMENTED = -1, // Command not implemented, or plugin not loaded + CR_OK = 0, // Success + CR_FAILURE = 1, // Failure + CR_WRONG_USAGE = 2, // Wrong arguments or ui state + CR_NOT_FOUND = 3 // Target object not found (for RPC mainly) + }; +} diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h index 78c5e5dc8..f67023f93 100644 --- a/library/include/PluginManager.h +++ b/library/include/PluginManager.h @@ -35,8 +35,6 @@ distribution. #include "Core.h" #include "DataFuncs.h" -#include "RemoteClient.h" - typedef struct lua_State lua_State; namespace tthread diff --git a/library/include/RemoteClient.h b/library/include/RemoteClient.h index e71b985cd..17e296a2e 100644 --- a/library/include/RemoteClient.h +++ b/library/include/RemoteClient.h @@ -39,17 +39,6 @@ namespace DFHack using dfproto::IntMessage; using dfproto::StringMessage; - enum command_result - { - CR_LINK_FAILURE = -3, // RPC call failed due to I/O or protocol error - CR_NEEDS_CONSOLE = -2, // Attempt to call interactive command without console - CR_NOT_IMPLEMENTED = -1, // Command not implemented, or plugin not loaded - CR_OK = 0, // Success - CR_FAILURE = 1, // Failure - CR_WRONG_USAGE = 2, // Wrong arguments or ui state - CR_NOT_FOUND = 3 // Target object not found (for RPC mainly) - }; - enum DFHackReplyCode : int16_t { RPC_REPLY_RESULT = -1, RPC_REPLY_FAIL = -2, diff --git a/library/include/modules/Buildings.h b/library/include/modules/Buildings.h index 78163108e..22dbb0370 100644 --- a/library/include/modules/Buildings.h +++ b/library/include/modules/Buildings.h @@ -237,7 +237,7 @@ DFHACK_EXPORT std::string getRoomDescription(df::building *building, df::unit *u * starting at the top left and moving right, row by row, * the block's items are checked for anything on the ground within that stockpile. */ -class DFHACK_EXPORT StockpileIterator : public std::iterator +class DFHACK_EXPORT StockpileIterator { df::building_stockpilest* stockpile; df::map_block* block; @@ -245,6 +245,12 @@ class DFHACK_EXPORT StockpileIterator : public std::iteratorblock_events) { if (auto evT = virtual_cast(event)) { // we want to let the user keep some designations free of being managed - auto b = max(0, cavein_candidates[pos] - least_access); + auto b = std::max(0, cavein_candidates[pos] - least_access); auto v = 1000 + (b * 1700); DEBUG(manager).print("(" COORD ") 1000+1000(%d) -> %d {least-access: %d}\n",COORDARGS(pos), b, v, least_access); evT->priority[Coord(local)] = v; diff --git a/plugins/channel-safely/include/inlines.h b/plugins/channel-safely/include/inlines.h index a29f5a04d..362fd927a 100644 --- a/plugins/channel-safely/include/inlines.h +++ b/plugins/channel-safely/include/inlines.h @@ -23,7 +23,7 @@ namespace CSP { inline uint32_t calc_distance(df::coord p1, df::coord p2) { // calculate chebyshev (chessboard) distance uint32_t distance = abs(p2.z - p1.z); - distance += max(abs(p2.x - p1.x), abs(p2.y - p1.y)); + distance += std::max(abs(p2.x - p1.x), abs(p2.y - p1.y)); return distance; } diff --git a/plugins/confirm.cpp b/plugins/confirm.cpp index 1dfb6809d..bd6e41b64 100644 --- a/plugins/confirm.cpp +++ b/plugins/confirm.cpp @@ -411,7 +411,7 @@ public: Screen::paintTile(corner_ur, x2, y1); Screen::paintTile(corner_dl, x1, y2); Screen::paintTile(corner_dr, x2, y2); - string title = " " + get_title() + " "; + string title = ' ' + get_title() + ' '; Screen::paintString(Screen::Pen(' ', COLOR_DARKGREY, COLOR_BLACK), x2 - 6, y1, "DFHack"); Screen::paintString(Screen::Pen(' ', COLOR_BLACK, COLOR_GREY), diff --git a/plugins/hotkeys.cpp b/plugins/hotkeys.cpp index 136ad7a9d..ef2ca9422 100644 --- a/plugins/hotkeys.cpp +++ b/plugins/hotkeys.cpp @@ -103,7 +103,7 @@ static void find_active_keybindings(color_ostream &out, df::viewscreen *screen, } for (int i = 1; i <= 12; i++) { - valid_keys.push_back("F" + int_to_string(i)); + valid_keys.push_back('F' + int_to_string(i)); } valid_keys.push_back("`"); From 78448f438d5386b773afe28e859468dff87a57a6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 25 Jun 2023 17:53:16 -0700 Subject: [PATCH 027/851] don't leak warning suppression out of protobuf --- depends/CMakeLists.txt | 12 ++++------- .../protobuf/google/protobuf/repeated_field.h | 4 ++++ library/DataDefs.cpp | 4 ++-- library/modules/Gui.cpp | 20 +++++++++---------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/depends/CMakeLists.txt b/depends/CMakeLists.txt index 9ec71646a..0756519ef 100644 --- a/depends/CMakeLists.txt +++ b/depends/CMakeLists.txt @@ -6,14 +6,10 @@ add_subdirectory(protobuf) if(UNIX) set_target_properties(lua PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-deprecated-enum-enum-conversion") - target_compile_options(protoc - PUBLIC -Wno-deprecated-declarations -Wno-restrict) - target_compile_options(protoc-bin - PUBLIC -Wno-deprecated-declarations -Wno-restrict) - target_compile_options(protobuf-lite - PUBLIC -Wno-deprecated-declarations -Wno-restrict) - target_compile_options(protobuf - PUBLIC -Wno-deprecated-declarations -Wno-restrict) + set_target_properties(protoc PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") + set_target_properties(protoc-bin PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") + set_target_properties(protobuf-lite PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") + set_target_properties(protobuf PROPERTIES COMPILE_FLAGS "-Wno-deprecated-declarations -Wno-restrict") endif() if(UNIX AND NOT APPLE) # remove this once our MSVC build env has been updated diff --git a/depends/protobuf/google/protobuf/repeated_field.h b/depends/protobuf/google/protobuf/repeated_field.h index aed4ce9f2..637708254 100644 --- a/depends/protobuf/google/protobuf/repeated_field.h +++ b/depends/protobuf/google/protobuf/repeated_field.h @@ -46,6 +46,10 @@ #ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_H__ #define GOOGLE_PROTOBUF_REPEATED_FIELD_H__ +#ifdef __GNUC__ +#pragma GCC system_header +#endif + #include #include #include diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index f376edc6a..cd261d50f 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -213,12 +213,12 @@ std::string pointer_identity::getFullName() std::string container_identity::getFullName(type_identity *item) { - return "<" + (item ? item->getFullName() : std::string("void")) + ">"; + return '<' + (item ? item->getFullName() : std::string("void")) + '>'; } std::string ptr_container_identity::getFullName(type_identity *item) { - return "<" + (item ? item->getFullName() : std::string("void")) + "*>"; + return '<' + (item ? item->getFullName() : std::string("void")) + std::string("*>"); } std::string bit_container_identity::getFullName(type_identity *) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index d03bcce09..01fbdddf3 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -182,23 +182,23 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) if (game->main_interface.info.open) { newFocusString = baseFocus; newFocusString += "/Info"; - newFocusString += "/" + enum_item_key(game->main_interface.info.current_mode); + newFocusString += '/' + enum_item_key(game->main_interface.info.current_mode); switch(game->main_interface.info.current_mode) { case df::enums::info_interface_mode_type::CREATURES: - newFocusString += "/" + enum_item_key(game->main_interface.info.creatures.current_mode); + newFocusString += '/' + enum_item_key(game->main_interface.info.creatures.current_mode); break; case df::enums::info_interface_mode_type::BUILDINGS: - newFocusString += "/" + enum_item_key(game->main_interface.info.buildings.mode); + newFocusString += '/' + enum_item_key(game->main_interface.info.buildings.mode); break; case df::enums::info_interface_mode_type::LABOR: - newFocusString += "/" + enum_item_key(game->main_interface.info.labor.mode); + newFocusString += '/' + enum_item_key(game->main_interface.info.labor.mode); break; case df::enums::info_interface_mode_type::ARTIFACTS: - newFocusString += "/" + enum_item_key(game->main_interface.info.artifacts.mode); + newFocusString += '/' + enum_item_key(game->main_interface.info.artifacts.mode); break; case df::enums::info_interface_mode_type::JUSTICE: - newFocusString += "/" + enum_item_key(game->main_interface.info.justice.current_mode); + newFocusString += '/' + enum_item_key(game->main_interface.info.justice.current_mode); break; default: break; @@ -209,7 +209,7 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) if (game->main_interface.view_sheets.open) { newFocusString = baseFocus; newFocusString += "/ViewSheets"; - newFocusString += "/" + enum_item_key(game->main_interface.view_sheets.active_sheet); + newFocusString += '/' + enum_item_key(game->main_interface.view_sheets.active_sheet); focusStrings.push_back(newFocusString); } @@ -233,7 +233,7 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) newFocusString += "/Zone"; if (game->main_interface.civzone.cur_bld) { newFocusString += "/Some"; - newFocusString += "/" + enum_item_key(game->main_interface.civzone.cur_bld->type); + newFocusString += '/' + enum_item_key(game->main_interface.civzone.cur_bld->type); } break; case df::enums::main_bottom_mode_type::ZONE_PAINT: @@ -499,7 +499,7 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dungeonmode) if (!adventure) return; - focus += "/" + enum_item_key(adventure->menu); + focus += '/' + enum_item_key(adventure->menu); } */ @@ -1427,7 +1427,7 @@ DFHACK_EXPORT int Gui::makeAnnouncement(df::announcement_type type, df::announce if (flags.bits.D_DISPLAY) { world->status.display_timer = ANNOUNCE_DISPLAY_TIME; - Gui::writeToGamelog("x" + to_string(repeat_count + 1)); + Gui::writeToGamelog('x' + to_string(repeat_count + 1)); } return -1; } From 8235680ff0263c3a42ba6bd3e3a15a07c7577da2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 18 Jun 2023 00:55:55 -0700 Subject: [PATCH 028/851] add unsuspend map textures --- data/art/unsuspend.png | Bin 0 -> 4697 bytes library/LuaApi.cpp | 1 + library/include/modules/Textures.h | 5 +++++ library/modules/Textures.cpp | 7 +++++++ 4 files changed, 13 insertions(+) create mode 100644 data/art/unsuspend.png diff --git a/data/art/unsuspend.png b/data/art/unsuspend.png new file mode 100644 index 0000000000000000000000000000000000000000..11cb910451f6f09086b07c0eac13c590bae8c2d5 GIT binary patch literal 4697 zcmeHKc~BEs8gB^5>B-EfqevS^1es1cCrJ+>V!{z5h#?@(>S8C|fktweG$f!1;<$r| zif4^Cj*g5M9(b+?2(i>rkzIFm$^#r26&!C@L1mnM2?$s_Ra;i={70%f{f^)Fd*Ao_ zzW1u%qJ;S9{@$N@LlD$o5hGWD_e}7>p8df8!|FUWc-eE+DYOc=!X~p(M`e;QonsEsvo^6DV3?BP4k1khJowWu)q;PjFQqiQf8Wo_fB zk|tfN{|lSX)=#2pWM!ynSvh~#wQ;-WY{IqQ#b;P=bP=X2I)!$1Fat4r&o z6{14dK+ebqo0}8dcdbHeC%nDXD$iv!R!#fl7fr)W2y*#~lF1SjGTFO$KolGDmP=x4 zCyYFk`j-f8+-=5$4r^QkQY; zhjneguzl|wTuoM785!ZaIHl0jg}XCoi?7d=F9oW&ZRyfSKL?mQn8yh7>gsd*3%u1a zO9MIv&a=+CTON38Tf)eex%(e3n*ty8;b$EFEid!N5 z>_OHttMy3R%g1YV`O@uE%*SJQCGtVt*(gw7DatrZYt*xF!l)rxHoXZH9t4F+Z6;hh zi=<%l+ge? zIB|_Ji<(wpWdWYcGDXyT`B-Q*f!k6=CDwd8T!I~z-P202od}%9#DI6b<`_1!r22c;n5aCrhD0cwa(>JUDO>JTw01o`9gKw`xrkiSlm zy4fv89c{(UWJDU!5oiU<)2S64ldDgz4^rTRziWOQ<=u0gA`Rdx$OqsGauJ#SKTkZVLM7#{P{0#V&s@ugH+eVa8zr6w|&ocUtLMBn=Mxh{*ns(Aa(->h%1con^cO;2Aw zb-Rfu+;lN;Jp=Mq)y@pW9Y^KkW;@7T?W34SFQd$x{a5PoMwpJEAK1)a4Gw z;gg>~JypeSoHA3jr{cB!e#qWxw>Qr=ZcN1=T-uAi9Az!ov=v_1KR($nv&m?h7*V{s zktkHoO`RuXTsMSP>>eM3ub;dm@Ed#M-76W-^xVq2s@l`(g^CXU0Sz6elS&_t-rX!Z zy#4j~IV>pzRd($Ea&55v$W!UhE)aV5ntOgpyW&E9b8*UL_w`;_h-wjFuPYw*bmj1B z90j5c|grt#*V3}^Ur4;(gY8FQztF@`1dut?8zC1=Q|Ez zP5jfz8IMf+lA|*_Zr;-S=AW!p-zim#Pqf5d`zGn~dhF`qjZpmLBt(G2-@+#?MxrcN;KoWqaVfm0tO;$Jdnqi=TBdcxH$|>0jBF^XV0@#`}YW zGamoFxS+m0{7Kt&C{ggVG5nl7&u>lCBxlOzPpBWz_=A6J6jC{Pl%swWk@511i8BlT E1DgodA^-pY literal 0 HcmV?d00001 diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 7de74470f..d2c32cf63 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1715,6 +1715,7 @@ static const LuaWrapper::FunctionReg dfhack_textures_module[] = { WRAPM(Textures, getRedPinTexposStart), WRAPM(Textures, getIconsTexposStart), WRAPM(Textures, getOnOffTexposStart), + WRAPM(Textures, getMapUnsuspendTexposStart), WRAPM(Textures, getControlPanelTexposStart), WRAPM(Textures, getThinBordersTexposStart), WRAPM(Textures, getMediumBordersTexposStart), diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index bebd78dc9..8032b04a5 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -51,6 +51,11 @@ DFHACK_EXPORT long getOnOffTexposStart(); */ DFHACK_EXPORT long getMapPathableTexposStart(); +/** + * Get the first texpos for the unsuspend 32x32 sprites. It's a 3x1 grid. + */ +DFHACK_EXPORT long getMapUnsuspendTexposStart(); + /** * Get the first texpos for the control panel icons. 10x2 grid. */ diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index ba77f41f7..46dd0a4c5 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -26,6 +26,7 @@ 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_pathable_texpos_start = -1; +static long g_unsuspend_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; @@ -142,6 +143,8 @@ void Textures::init(color_ostream &out) { &g_on_off_texpos_start); g_num_dfhack_textures += load_textures(out, "hack/data/art/pathable.png", &g_pathable_texpos_start, 32, 32); + g_num_dfhack_textures += load_textures(out, "hack/data/art/unsuspend.png", + &g_unsuspend_texpos_start, 32, 32); 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", @@ -210,6 +213,10 @@ long Textures::getMapPathableTexposStart() { return g_pathable_texpos_start; } +long Textures::getMapUnsuspendTexposStart() { + return g_unsuspend_texpos_start; +} + long Textures::getControlPanelTexposStart() { return g_control_panel_texpos_start; } From d54c13121b74e6492d15d4cb1b614f4742a89dbd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 25 Jun 2023 18:56:37 -0700 Subject: [PATCH 029/851] use new icons from RafaelKB --- data/art/unsuspend.png | Bin 4697 -> 971 bytes library/include/modules/Textures.h | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/data/art/unsuspend.png b/data/art/unsuspend.png index 11cb910451f6f09086b07c0eac13c590bae8c2d5..c00d3a1ac1c865ce70acaa4c8983cdb33f874876 100644 GIT binary patch literal 971 zcmV;+12p`JP)Px&Ye_^wRCt{2nLlXMP#njcW7!Vz#gVNSmRBQ*M6{U+vV|t)cZczL=$P1U`PAud_sJ{<9 zc=;u{@5}xEyu25H`L9Xo_)#e(0f6UuslTzWHT~6$Ne4m*3fpS6T2tM&xW%QEbgz9g z0AK(h^}wy{I`k*cWdHzu6&cWPW={esCB1oT0RXmc>DQ*M9AB+gBj-w`5&^9PAr_>R zG}XO}KHs=TpNyzd$(`bp+7g4qwn8lh(4U8(+4|!{kgFm(d>Gn z+4a6XZv9qc@|LIR>g+o@cIi1CyYyU(wh)3W%OcCNNU^lEt0)$Wa9tO!>jD65+eV>K000yU1;1~aCaFr0j$;4{&+}3PD+_pQRIz_} z4*(!vO9!04D1PE{y{=_0^gJ)sSE=Lm^+SLh0sxE}KLXA_Gt!2MXQ@QqLsZ#sbpFfR z_qA!dt_$0?{o_)pcV(HR7O>F@7Hn{xmFFhAXa`RNY-nk0hY!0=hWpJe72i^agP z<2Y~}2g}RLem{)XDWFGoVPIte11k%GAV`Y&=??T&>gcP~13{1kDhS3$HYDPFMY!~@ zW;%!kwdSAd-W6EywzBKcpBu~3+*mH6-^{KB-EfqevS^1es1cCrJ+>V!{z5h#?@(>S8C|fktweG$f!1;<$r| zif4^Cj*g5M9(b+?2(i>rkzIFm$^#r26&!C@L1mnM2?$s_Ra;i={70%f{f^)Fd*Ao_ zzW1u%qJ;S9{@$N@LlD$o5hGWD_e}7>p8df8!|FUWc-eE+DYOc=!X~p(M`e;QonsEsvo^6DV3?BP4k1khJowWu)q;PjFQqiQf8Wo_fB zk|tfN{|lSX)=#2pWM!ynSvh~#wQ;-WY{IqQ#b;P=bP=X2I)!$1Fat4r&o z6{14dK+ebqo0}8dcdbHeC%nDXD$iv!R!#fl7fr)W2y*#~lF1SjGTFO$KolGDmP=x4 zCyYFk`j-f8+-=5$4r^QkQY; zhjneguzl|wTuoM785!ZaIHl0jg}XCoi?7d=F9oW&ZRyfSKL?mQn8yh7>gsd*3%u1a zO9MIv&a=+CTON38Tf)eex%(e3n*ty8;b$EFEid!N5 z>_OHttMy3R%g1YV`O@uE%*SJQCGtVt*(gw7DatrZYt*xF!l)rxHoXZH9t4F+Z6;hh zi=<%l+ge? zIB|_Ji<(wpWdWYcGDXyT`B-Q*f!k6=CDwd8T!I~z-P202od}%9#DI6b<`_1!r22c;n5aCrhD0cwa(>JUDO>JTw01o`9gKw`xrkiSlm zy4fv89c{(UWJDU!5oiU<)2S64ldDgz4^rTRziWOQ<=u0gA`Rdx$OqsGauJ#SKTkZVLM7#{P{0#V&s@ugH+eVa8zr6w|&ocUtLMBn=Mxh{*ns(Aa(->h%1con^cO;2Aw zb-Rfu+;lN;Jp=Mq)y@pW9Y^KkW;@7T?W34SFQd$x{a5PoMwpJEAK1)a4Gw z;gg>~JypeSoHA3jr{cB!e#qWxw>Qr=ZcN1=T-uAi9Az!ov=v_1KR($nv&m?h7*V{s zktkHoO`RuXTsMSP>>eM3ub;dm@Ed#M-76W-^xVq2s@l`(g^CXU0Sz6elS&_t-rX!Z zy#4j~IV>pzRd($Ea&55v$W!UhE)aV5ntOgpyW&E9b8*UL_w`;_h-wjFuPYw*bmj1B z90j5c|grt#*V3}^Ur4;(gY8FQztF@`1dut?8zC1=Q|Ez zP5jfz8IMf+lA|*_Zr;-S=AW!p-zim#Pqf5d`zGn~dhF`qjZpmLBt(G2-@+#?MxrcN;KoWqaVfm0tO;$Jdnqi=TBdcxH$|>0jBF^XV0@#`}YW zGamoFxS+m0{7Kt&C{ggVG5nl7&u>lCBxlOzPpBWz_=A6J6jC{Pl%swWk@511i8BlT E1DgodA^-pY diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 8032b04a5..f16acec4b 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -52,7 +52,7 @@ DFHACK_EXPORT long getOnOffTexposStart(); DFHACK_EXPORT long getMapPathableTexposStart(); /** - * Get the first texpos for the unsuspend 32x32 sprites. It's a 3x1 grid. + * Get the first texpos for the unsuspend 32x32 sprites. It's a 4x1 grid. */ DFHACK_EXPORT long getMapUnsuspendTexposStart(); From 164a8894799d51cbc4b70f86e262eaafbaa87a5b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 26 Jun 2023 16:02:05 -0700 Subject: [PATCH 030/851] update xml ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 52214bbdd..1bfb73d15 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 52214bbddf9c8da0f12407ea01b49e25fcfba8a1 +Subproject commit 1bfb73d154226f94ec01a89a2be34bc8e660974c From 09027543df9274890a1882db5ef8f8f85eec7d94 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 26 Jun 2023 16:31:18 -0700 Subject: [PATCH 031/851] update to 50.09-r1 --- CMakeLists.txt | 6 +++--- docs/changelog.txt | 2 ++ library/xml | 2 +- scripts | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe556d5d3..641c70bec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,9 +7,9 @@ cmake_policy(SET CMP0074 NEW) project(dfhack) # set up versioning. -set(DF_VERSION "50.09sdl2-3") -set(DFHACK_RELEASE "rc1") -set(DFHACK_PRERELEASE TRUE) +set(DF_VERSION "50.09") +set(DFHACK_RELEASE "r1") +set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_ABI_VERSION 1) diff --git a/docs/changelog.txt b/docs/changelog.txt index 7761ad8f7..d10407621 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -49,6 +49,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Removed +# 50.09-r1 + # 50.08-r4 ## New Plugins diff --git a/library/xml b/library/xml index 1bfb73d15..95f67053a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 1bfb73d154226f94ec01a89a2be34bc8e660974c +Subproject commit 95f67053a22ca29c6f03ef005b0acaaa6d58209e diff --git a/scripts b/scripts index 4c74bb905..46bca726e 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 4c74bb9055c1c7a1bd49cbe535e2fc453cd79664 +Subproject commit 46bca726e8044dfc2c72eddfdfcc2021a0486a13 From 354f56cc33942014fdfe8b79e663b1e7a3b1f771 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 29 Jun 2023 20:14:44 -0500 Subject: [PATCH 032/851] include vs17.6 in acceptable version range --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 641c70bec..bedebfbaa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,9 +60,9 @@ endif() if(WIN32) if(NOT MSVC) - message(SEND_ERROR "No MSVC found! MSVC 2022 version 1930 to 1935 is required.") - elseif((MSVC_VERSION LESS 1930) OR (MSVC_VERSION GREATER 1935)) - message(SEND_ERROR "MSVC 2022 version 1930 to 1935 is required, Version Found: ${MSVC_VERSION}") + message(SEND_ERROR "No MSVC found! MSVC 2022 version 1930 to 1936 is required.") + elseif((MSVC_VERSION LESS 1930) OR (MSVC_VERSION GREATER 1936)) + message(SEND_ERROR "MSVC 2022 version 1930 to 1936 is required, Version Found: ${MSVC_VERSION}") endif() endif() From b5fd877b840fd221dfa04219e4dbc64c6204f03b Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 1 Jul 2023 07:13:51 +0000 Subject: [PATCH 033/851] 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 95f67053a..5da8a785c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 95f67053a22ca29c6f03ef005b0acaaa6d58209e +Subproject commit 5da8a785cf176f831a56f934ec8ec6069a965ecf diff --git a/scripts b/scripts index 46bca726e..ee8217978 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 46bca726e8044dfc2c72eddfdfcc2021a0486a13 +Subproject commit ee8217978d25bc8f9c3efa21156dd8ff99896f68 From 175c249d29cc62675a0b5da85e14da295c77cea7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 2 Jul 2023 18:04:06 -0700 Subject: [PATCH 034/851] support copy/paste from system clipboard --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 14 +++++++++++ library/LuaApi.cpp | 6 +++++ library/include/modules/DFSDL.h | 8 +++++++ library/lua/gui/widgets.lua | 10 ++++++++ library/modules/DFSDL.cpp | 41 +++++++++++++++++++++++++++++++++ 6 files changed, 80 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index d10407621..c30d313d5 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 +- ``widgets.EditField``: DFHack edit fields now support cut/copy/paste with the system clipboard with Ctrl-X/Ctrl-C/Ctrl-V ## Documentation diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index d07cb045e..ffd43aea1 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2815,6 +2815,14 @@ and are only documented here for completeness: Returns 0 if the address is not found. Requires a heap snapshot. +* ``dfhack.internal.getClipboardText()`` + + Gets the system clipboard text (converted to CP437 encoding). + +* ``dfhack.internal.setClipboardText(text)`` + + Converts the given text from CP437 to UTF-8 and sets the system clipboard + text. .. _lua-core-context: @@ -4688,6 +4696,12 @@ following keyboard hotkeys: - Ctrl-B/Ctrl-F: move the cursor one word back or forward. - Ctrl-A/Ctrl-E: move the cursor to the beginning/end of the text. +The widget also supports integration with the system clipboard: + +- Ctrl-C: copy current text to the system clipboard +- Ctrl-X: copy current text to the system clipboard and clear text in widget +- Ctrl-V: paste text from the system clipboard (text is converted to cp437) + The ``EditField`` class also provides the following functions: * ``editfield:setCursor([cursor_pos])`` diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index d2c32cf63..13eb01c65 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -47,6 +47,7 @@ distribution. #include "modules/Burrows.h" #include "modules/Constructions.h" #include "modules/Designations.h" +#include "modules/DFSDL.h" #include "modules/Filesystem.h" #include "modules/Gui.h" #include "modules/Items.h" @@ -2999,6 +3000,9 @@ static int msize_address(uintptr_t ptr) return -1; } +static std::string getClipboardText() { return DFSDL::DFSDL_GetClipboardTextCp437(); } +static void setClipboardText(std::string s) { DFSDL::DFSDL_SetClipboardTextCp437(s); } + static const LuaWrapper::FunctionReg dfhack_internal_module[] = { WRAP(getImageBase), WRAP(getRebaseDelta), @@ -3013,6 +3017,8 @@ static const LuaWrapper::FunctionReg dfhack_internal_module[] = { WRAPN(getAddressSizeInHeap, get_address_size_in_heap), WRAPN(getRootAddressOfHeapObject, get_root_address_of_heap_object), WRAPN(msizeAddress, msize_address), + WRAP(getClipboardText), + WRAP(setClipboardText), { NULL, NULL } }; diff --git a/library/include/modules/DFSDL.h b/library/include/modules/DFSDL.h index 626224d60..88dd08f05 100644 --- a/library/include/modules/DFSDL.h +++ b/library/include/modules/DFSDL.h @@ -48,6 +48,14 @@ DFHACK_EXPORT void DFSDL_FreeSurface(SDL_Surface *surface); // DFHACK_EXPORT int DFSDL_SemPost(SDL_sem *sem); DFHACK_EXPORT int DFSDL_PushEvent(SDL_Event *event); +// System clipboard +DFHACK_EXPORT std::string DFSDL_GetClipboardTextUtf8(); +DFHACK_EXPORT std::string DFSDL_GetClipboardTextCp437(); +DFHACK_EXPORT bool DFSDL_SetClipboardTextUtf8(const char *text); +DFHACK_EXPORT bool DFSDL_SetClipboardTextUtf8(const std::string &text); +DFHACK_EXPORT bool DFSDL_SetClipboardTextCp437(const char *text); +DFHACK_EXPORT bool DFSDL_SetClipboardTextCp437(const std::string &text); + } } diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index a58ac228c..8759f97bf 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -772,6 +772,16 @@ function EditField:onInput(keys) elseif keys.CUSTOM_CTRL_E then -- end self:setCursor() return true + elseif keys.CUSTOM_CTRL_C then + dfhack.internal.setClipboardText(self.text) + return true + elseif keys.CUSTOM_CTRL_X then + dfhack.internal.setClipboardText(self.text) + self:setText('') + return true + elseif keys.CUSTOM_CTRL_V then + self:insert(dfhack.internal.getClipboardText()) + return true end -- if we're modal, then unconditionally eat all the input diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp index 7aa7f36d5..4ed4bc5e8 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -3,8 +3,11 @@ #include "modules/DFSDL.h" #include "Debug.h" +#include "MiscUtils.h" #include "PluginManager.h" +#include + namespace DFHack { DBG_DECLARE(core, dfsdl, DebugCategory::LINFO); } @@ -35,6 +38,10 @@ void (*g_SDL_FreeSurface)(SDL_Surface *) = nullptr; // int (*g_SDL_SemWait)(DFSDL_sem *) = nullptr; // int (*g_SDL_SemPost)(DFSDL_sem *) = nullptr; int (*g_SDL_PushEvent)(SDL_Event *) = nullptr; +SDL_bool (*g_SDL_HasClipboardText)(); +int (*g_SDL_SetClipboardText)(const char *text); +char * (*g_SDL_GetClipboardText)(); +void (*g_SDL_free)(void *); bool DFSDL::init(color_ostream &out) { for (auto &lib_str : SDL_LIBS) { @@ -71,6 +78,10 @@ bool DFSDL::init(color_ostream &out) { // bind(g_sdl_handle, SDL_SemWait); // bind(g_sdl_handle, SDL_SemPost); bind(g_sdl_handle, SDL_PushEvent); + bind(g_sdl_handle, SDL_HasClipboardText); + bind(g_sdl_handle, SDL_SetClipboardText); + bind(g_sdl_handle, SDL_GetClipboardText); + bind(g_sdl_handle, SDL_free); #undef bind DEBUG(dfsdl,out).print("sdl successfully loaded\n"); @@ -124,3 +135,33 @@ void DFSDL::DFSDL_FreeSurface(SDL_Surface *surface) { int DFSDL::DFSDL_PushEvent(SDL_Event *event) { return g_SDL_PushEvent(event); } + +std::string DFSDL::DFSDL_GetClipboardTextUtf8() { + if (g_SDL_HasClipboardText() != SDL_TRUE) + return ""; + char *text = g_SDL_GetClipboardText(); + std::string ret = text; + g_SDL_free(text); + return ret; +} + +std::string DFSDL::DFSDL_GetClipboardTextCp437() { + std::string utf8text = DFSDL_GetClipboardTextUtf8(); + return UTF2DF(utf8text); +} + +bool DFSDL::DFSDL_SetClipboardTextUtf8(const char *text) { + return g_SDL_SetClipboardText(text) == 0; +} + +bool DFSDL::DFSDL_SetClipboardTextUtf8(const std::string &text) { + return DFSDL_SetClipboardTextUtf8(text.c_str()); +} + +bool DFSDL::DFSDL_SetClipboardTextCp437(const char *text) { + return DFSDL_SetClipboardTextUtf8(DF2UTF(text)); +} + +bool DFSDL::DFSDL_SetClipboardTextCp437(const std::string &text) { + return DFSDL_SetClipboardTextUtf8(DF2UTF(text)); +} From 18a9a7d1fae4a2410e28383d37a3a409ae7ee0b4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 29 Jun 2023 18:13:16 -0700 Subject: [PATCH 035/851] allow invalid options to default to the first option and make the range slider move the other slider if it would become invalid --- library/lua/gui/widgets.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index a58ac228c..7a3201f28 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1552,8 +1552,7 @@ function CycleHotkeyLabel:setOption(value_or_index, call_on_change) end end if not option_idx then - error(('cannot find option with value or index: "%s"') - :format(value_or_index)) + option_idx = 1 end local old_option_idx = self.option_idx self.option_idx = option_idx @@ -2392,9 +2391,15 @@ local function rangeslider_do_drag(self, width_per_idx) end end if new_left_idx and new_left_idx ~= self.get_left_idx_fn() then + if not new_right_idx and new_left_idx > self.get_right_idx_fn() then + self.on_right_change(new_left_idx) + end self.on_left_change(new_left_idx) end if new_right_idx and new_right_idx ~= self.get_right_idx_fn() then + if new_right_idx < self.get_left_idx_fn() then + self.on_left_change(new_right_idx) + end self.on_right_change(new_right_idx) end end From acd03486a9f7dbd8b935068d180ff2ba296e00ff Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 29 Jun 2023 18:14:15 -0700 Subject: [PATCH 036/851] add some more detail to the focus strings for buildings --- library/modules/Gui.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index ee5eaa31c..e9ca4c411 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -216,6 +216,11 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) newFocusString = baseFocus; newFocusString += "/ViewSheets"; newFocusString += "/" + enum_item_key(game->main_interface.view_sheets.active_sheet); + if (game->main_interface.view_sheets.active_sheet == df::view_sheet_type::BUILDING) { + auto bld = df::building::find(game->main_interface.view_sheets.viewing_bldid); + if (bld) + newFocusString += '/' + enum_item_key(bld->getType()); + } focusStrings.push_back(newFocusString); } @@ -377,6 +382,7 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) if (game->main_interface.unit_selector.open) { newFocusString = baseFocus; newFocusString += "/UnitSelector"; + newFocusString += '/' + enum_item_key(game->main_interface.unit_selector.context); focusStrings.push_back(newFocusString); } if (game->main_interface.announcement_alert.open) { From d39440d33bede73579f88c0a576df133f74b4c74 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 29 Jun 2023 19:36:05 -0700 Subject: [PATCH 037/851] migrate markForTrade logic from logistics to core --- docs/dev/Lua API.rst | 4 ++++ library/LuaApi.cpp | 1 + library/include/modules/Items.h | 3 +++ library/modules/Items.cpp | 38 +++++++++++++++++++++++++++++++++ plugins/logistics.cpp | 26 +--------------------- 5 files changed, 47 insertions(+), 25 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index d07cb045e..33e27be2d 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1775,6 +1775,10 @@ Items module Checks whether the item and all items it contains, if any, can be traded. +* ``dfhack.items.markForTrade(item, depot)`` + + Marks the given item for trade at the given depot. + * ``dfhack.items.isRouteVehicle(item)`` Checks whether the item is an assigned hauling vehicle. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index d2c32cf63..5d9411434 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2014,6 +2014,7 @@ static const LuaWrapper::FunctionReg dfhack_items_module[] = { WRAPM(Items, checkMandates), WRAPM(Items, canTrade), WRAPM(Items, canTradeWithContents), + WRAPM(Items, markForTrade), WRAPM(Items, isRouteVehicle), WRAPM(Items, isSquadEquipment), WRAPN(moveToGround, items_moveToGround), diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h index 7f2c9ce69..08737fb2b 100644 --- a/library/include/modules/Items.h +++ b/library/include/modules/Items.h @@ -33,6 +33,7 @@ distribution. #include "MemAccess.h" #include "DataDefs.h" +#include "df/building_tradedepotst.h" #include "df/item.h" #include "df/item_type.h" #include "df/general_ref.h" @@ -199,6 +200,8 @@ DFHACK_EXPORT bool checkMandates(df::item *item); DFHACK_EXPORT bool canTrade(df::item *item); /// Checks whether the item and all items it contains, if any, can be traded DFHACK_EXPORT bool canTradeWithContents(df::item *item); +/// marks the given item for trade at the given depot +DFHACK_EXPORT bool markForTrade(df::item *item, df::building_tradedepotst *depot); /// Checks whether the item is an assigned hauling vehicle DFHACK_EXPORT bool isRouteVehicle(df::item *item); diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 03d6cda4a..f98c7c46b 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -39,6 +39,7 @@ distribution. using namespace std; #include "ModuleFactory.h" +#include "modules/Job.h" #include "modules/MapCache.h" #include "modules/Materials.h" #include "modules/Items.h" @@ -48,6 +49,7 @@ using namespace std; #include "df/body_part_template_flags.h" #include "df/building.h" #include "df/building_actual.h" +#include "df/building_tradedepotst.h" #include "df/caste_raw.h" #include "df/creature_raw.h" #include "df/general_ref.h" @@ -1637,6 +1639,42 @@ bool Items::canTradeWithContents(df::item *item) return true; } +bool Items::markForTrade(df::item *item, df::building_tradedepotst *depot) { + CHECK_NULL_POINTER(item); + CHECK_NULL_POINTER(depot); + + // validate that the depot is in a good state + if (depot->getBuildStage() < depot->getMaxBuildStage()) + return false; + if (depot->jobs.size() && depot->jobs[0]->job_type == df::job_type::DestroyBuilding) + return false; + + auto href = df::allocate(); + if (!href) + return false; + + auto job = new df::job(); + job->job_type = df::job_type::BringItemToDepot; + job->pos = df::coord(depot->centerx, depot->centery, depot->z); + + // job <-> item link + if (!Job::attachJobItem(job, item, df::job_item_ref::Hauled)) { + delete job; + delete href; + return false; + } + + // job <-> building link + href->building_id = depot->id; + depot->jobs.push_back(job); + job->general_refs.push_back(href); + + // add to job list + Job::linkIntoWorld(job); + + return true; +} + bool Items::isRouteVehicle(df::item *item) { CHECK_NULL_POINTER(item); diff --git a/plugins/logistics.cpp b/plugins/logistics.cpp index d62ee8c36..20b2c343f 100644 --- a/plugins/logistics.cpp +++ b/plugins/logistics.cpp @@ -323,31 +323,7 @@ public: bool designate(color_ostream& out, df::item* item) override { if (!depot) return false; - - auto href = df::allocate(); - if (!href) - return false; - - auto job = new df::job(); - job->job_type = df::job_type::BringItemToDepot; - job->pos = df::coord(depot->centerx, depot->centery, depot->z); - - // job <-> item link - if (!Job::attachJobItem(job, item, df::job_item_ref::Hauled)) { - delete job; - delete href; - return false; - } - - // job <-> building link - href->building_id = depot->id; - depot->jobs.push_back(job); - job->general_refs.push_back(href); - - // add to job list - Job::linkIntoWorld(job); - - return true; + return Items::markForTrade(item, depot); } private: From c660a12502b3707da17d5767aa3a8bdf671c3bfa Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 2 Jul 2023 19:09:15 -0700 Subject: [PATCH 038/851] differentiate between choosing merchant screen and default trade screen --- library/modules/Gui.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index e9ca4c411..dc6f47f59 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -333,6 +333,10 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) if (game->main_interface.trade.open) { newFocusString = baseFocus; newFocusString += "/Trade"; + if (game->main_interface.trade.choosing_merchant) + newFocusString += "/ChoosingMerchant"; + else + newFocusString += "/Default"; focusStrings.push_back(newFocusString); } if (game->main_interface.job_details.open) { From 07e8edcdcaf4c58ac13cb359d433536a217b5232 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 2 Jul 2023 19:27:07 -0700 Subject: [PATCH 039/851] ensure changing text fires the on_change event --- library/lua/gui/widgets.lua | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 8759f97bf..76b5c3b68 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -640,8 +640,12 @@ function EditField:setCursor(cursor) end function EditField:setText(text, cursor) + local old = self.text self.text = text self:setCursor(cursor) + if self.on_change and text ~= old then + self.on_change(self.text, old) + end end function EditField:postUpdateLayout() @@ -699,11 +703,7 @@ function EditField:onInput(keys) end if self.key and (keys.LEAVESCREEN or keys._MOUSE_R_DOWN) then - local old = self.text self:setText(self.saved_text) - if self.on_change and old ~= self.saved_text then - self.on_change(self.text, old) - end self:setFocus(false) return true end @@ -747,9 +747,6 @@ function EditField:onInput(keys) return self.modal end end - if self.on_change and self.text ~= old then - self.on_change(self.text, old) - end return true elseif keys.KEYBOARD_CURSOR_LEFT then self:setCursor(self.cursor - 1) From fdf2430fc45e8a2b620fa55e23afb454886aea63 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 3 Jul 2023 09:09:52 -0700 Subject: [PATCH 040/851] filter out spurious STRING keybindings that don't match actual SDL string input --- docs/changelog.txt | 1 + library/include/modules/Screen.h | 4 ++-- library/modules/Screen.cpp | 8 +++++--- plugins/overlay.cpp | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index d10407621..f30db1b41 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 extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing ## Misc Improvements diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index daa08ca59..b918ab6c2 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -229,8 +229,8 @@ namespace DFHack DFHACK_EXPORT bool hasActiveScreens(Plugin *p); DFHACK_EXPORT void raise(df::viewscreen *screen); - // returns a new set with text interface keys from the text buffer added in (if any) - DFHACK_EXPORT std::set add_text_keys(const std::set& keys); + // returns a new set of interface keys that ensures that string input matches the DF text buffer + DFHACK_EXPORT std::set normalize_text_keys(const std::set& keys); /// Retrieve the string representation of the bound key. DFHACK_EXPORT std::string getKeyDisplay(df::interface_key key); diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 76f782edb..c7ef88c60 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -585,8 +585,10 @@ void Hide::merge() { } } } -std::set Screen::add_text_keys(const std::set& keys) { - std::set combined_keys(keys); +std::set Screen::normalize_text_keys(const std::set& keys) { + std::set combined_keys; + std::copy_if(keys.begin(), keys.end(), std::inserter(combined_keys, combined_keys.begin()), + [](df::interface_key k){ return k <= df::interface_key::STRING_A000 || k > df::interface_key::STRING_A255; } ); if (df::global::enabler->last_text_input[0]) { char c = df::global::enabler->last_text_input[0]; df::interface_key key = charToKey(c); @@ -952,7 +954,7 @@ int dfhack_lua_viewscreen::do_input(lua_State *L) } lua_pushvalue(L, -2); - Lua::PushInterfaceKeys(L, Screen::add_text_keys(*keys)); + Lua::PushInterfaceKeys(L, Screen::normalize_text_keys(*keys)); lua_call(L, 2, 0); self->update_focus(L, -1); diff --git a/plugins/overlay.cpp b/plugins/overlay.cpp index 7185f73a1..5dc9ed327 100644 --- a/plugins/overlay.cpp +++ b/plugins/overlay.cpp @@ -76,7 +76,7 @@ struct viewscreen_overlay : T { [&](lua_State *L) { Lua::Push(L, T::_identity.getName()); Lua::Push(L, this); - Lua::PushInterfaceKeys(L, Screen::add_text_keys(*input)); + Lua::PushInterfaceKeys(L, Screen::normalize_text_keys(*input)); }, [&](lua_State *L) { input_is_handled = lua_toboolean(L, -1); }); From 9ca96567a5b292914023ec9bc6d429076869eed0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 3 Jul 2023 11:05:58 -0700 Subject: [PATCH 041/851] move conversion logic to MiscUtils but keep minimal wrappers in SDL module so we don't leak memory --- docs/dev/Lua API.rst | 9 ++++----- library/LuaApi.cpp | 8 ++------ library/MiscUtils.cpp | 10 ++++++++++ library/include/MiscUtils.h | 4 ++++ library/include/modules/DFSDL.h | 11 ++++------- library/lua/gui/widgets.lua | 6 +++--- library/modules/DFSDL.cpp | 22 ++-------------------- 7 files changed, 29 insertions(+), 41 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index ffd43aea1..830ba6b09 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2815,14 +2815,13 @@ and are only documented here for completeness: Returns 0 if the address is not found. Requires a heap snapshot. -* ``dfhack.internal.getClipboardText()`` +* ``dfhack.internal.getClipboardTextCp437()`` - Gets the system clipboard text (converted to CP437 encoding). + Gets the system clipboard text (and converts text to CP437 encoding). -* ``dfhack.internal.setClipboardText(text)`` +* ``dfhack.internal.setClipboardTextCp437(text)`` - Converts the given text from CP437 to UTF-8 and sets the system clipboard - text. + Sets the system clipboard text from a CP437 string. .. _lua-core-context: diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 13eb01c65..c04a8ef0f 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -47,7 +47,6 @@ distribution. #include "modules/Burrows.h" #include "modules/Constructions.h" #include "modules/Designations.h" -#include "modules/DFSDL.h" #include "modules/Filesystem.h" #include "modules/Gui.h" #include "modules/Items.h" @@ -3000,9 +2999,6 @@ static int msize_address(uintptr_t ptr) return -1; } -static std::string getClipboardText() { return DFSDL::DFSDL_GetClipboardTextCp437(); } -static void setClipboardText(std::string s) { DFSDL::DFSDL_SetClipboardTextCp437(s); } - static const LuaWrapper::FunctionReg dfhack_internal_module[] = { WRAP(getImageBase), WRAP(getRebaseDelta), @@ -3017,8 +3013,8 @@ static const LuaWrapper::FunctionReg dfhack_internal_module[] = { WRAPN(getAddressSizeInHeap, get_address_size_in_heap), WRAPN(getRootAddressOfHeapObject, get_root_address_of_heap_object), WRAPN(msizeAddress, msize_address), - WRAP(getClipboardText), - WRAP(setClipboardText), + WRAP(getClipboardTextCp437), + WRAP(setClipboardTextCp437), { NULL, NULL } }; diff --git a/library/MiscUtils.cpp b/library/MiscUtils.cpp index b959e756e..6b50da347 100644 --- a/library/MiscUtils.cpp +++ b/library/MiscUtils.cpp @@ -27,6 +27,8 @@ distribution. #include "MiscUtils.h" #include "ColorText.h" +#include "modules/DFSDL.h" + #ifndef LINUX_BUILD // We don't want min and max macros #define NOMINMAX @@ -470,3 +472,11 @@ DFHACK_EXPORT std::string DF2CONSOLE(DFHack::color_ostream &out, const std::stri { return out.is_console() ? DF2CONSOLE(in) : in; } + +DFHACK_EXPORT std::string getClipboardTextCp437() { + return UTF2DF(DFHack::DFSDL::DFSDL_GetClipboardText()); +} + +DFHACK_EXPORT bool setClipboardTextCp437(std::string text) { + return DFHack::DFSDL::DFSDL_SetClipboardText(DF2UTF(text).c_str()); +} diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index d14bdb6e9..099e86581 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -496,3 +496,7 @@ DFHACK_EXPORT std::string UTF2DF(const std::string &in); DFHACK_EXPORT std::string DF2UTF(const std::string &in); DFHACK_EXPORT std::string DF2CONSOLE(const std::string &in); DFHACK_EXPORT std::string DF2CONSOLE(DFHack::color_ostream &out, const std::string &in); + +// System clipboard -- submitted and returned text must be in CP437 +DFHACK_EXPORT std::string getClipboardTextCp437(); +DFHACK_EXPORT bool setClipboardTextCp437(std::string text); diff --git a/library/include/modules/DFSDL.h b/library/include/modules/DFSDL.h index 88dd08f05..6cee58342 100644 --- a/library/include/modules/DFSDL.h +++ b/library/include/modules/DFSDL.h @@ -48,13 +48,10 @@ DFHACK_EXPORT void DFSDL_FreeSurface(SDL_Surface *surface); // DFHACK_EXPORT int DFSDL_SemPost(SDL_sem *sem); DFHACK_EXPORT int DFSDL_PushEvent(SDL_Event *event); -// System clipboard -DFHACK_EXPORT std::string DFSDL_GetClipboardTextUtf8(); -DFHACK_EXPORT std::string DFSDL_GetClipboardTextCp437(); -DFHACK_EXPORT bool DFSDL_SetClipboardTextUtf8(const char *text); -DFHACK_EXPORT bool DFSDL_SetClipboardTextUtf8(const std::string &text); -DFHACK_EXPORT bool DFSDL_SetClipboardTextCp437(const char *text); -DFHACK_EXPORT bool DFSDL_SetClipboardTextCp437(const std::string &text); +// submitted and returned text is UTF-8 +// see wrapper functions in MiscUtils.h for cp-437 variants +DFHACK_EXPORT std::string DFSDL_GetClipboardText(); +DFHACK_EXPORT bool DFSDL_SetClipboardText(const char *text); } diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 76b5c3b68..980d0104f 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -770,14 +770,14 @@ function EditField:onInput(keys) self:setCursor() return true elseif keys.CUSTOM_CTRL_C then - dfhack.internal.setClipboardText(self.text) + dfhack.internal.setClipboardTextCp437(self.text) return true elseif keys.CUSTOM_CTRL_X then - dfhack.internal.setClipboardText(self.text) + dfhack.internal.setClipboardTextCp437(self.text) self:setText('') return true elseif keys.CUSTOM_CTRL_V then - self:insert(dfhack.internal.getClipboardText()) + self:insert(dfhack.internal.getClipboardTextCp437()) return true end diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp index 4ed4bc5e8..280fb04d6 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -3,7 +3,6 @@ #include "modules/DFSDL.h" #include "Debug.h" -#include "MiscUtils.h" #include "PluginManager.h" #include @@ -136,7 +135,7 @@ int DFSDL::DFSDL_PushEvent(SDL_Event *event) { return g_SDL_PushEvent(event); } -std::string DFSDL::DFSDL_GetClipboardTextUtf8() { +std::string DFSDL::DFSDL_GetClipboardText() { if (g_SDL_HasClipboardText() != SDL_TRUE) return ""; char *text = g_SDL_GetClipboardText(); @@ -145,23 +144,6 @@ std::string DFSDL::DFSDL_GetClipboardTextUtf8() { return ret; } -std::string DFSDL::DFSDL_GetClipboardTextCp437() { - std::string utf8text = DFSDL_GetClipboardTextUtf8(); - return UTF2DF(utf8text); -} - -bool DFSDL::DFSDL_SetClipboardTextUtf8(const char *text) { +bool DFSDL::DFSDL_SetClipboardText(const char *text) { return g_SDL_SetClipboardText(text) == 0; } - -bool DFSDL::DFSDL_SetClipboardTextUtf8(const std::string &text) { - return DFSDL_SetClipboardTextUtf8(text.c_str()); -} - -bool DFSDL::DFSDL_SetClipboardTextCp437(const char *text) { - return DFSDL_SetClipboardTextUtf8(DF2UTF(text)); -} - -bool DFSDL::DFSDL_SetClipboardTextCp437(const std::string &text) { - return DFSDL_SetClipboardTextUtf8(DF2UTF(text)); -} From ae545aa1d6a3577f6b4a2fbf485335544f4b23f4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 3 Jul 2023 11:18:14 -0700 Subject: [PATCH 042/851] add new linkage dependency on dfhack --- library/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 5d2698bb0..40006a432 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -408,8 +408,8 @@ endif() target_link_libraries(dfhack protobuf-lite clsocket lua jsoncpp_static dfhack-version ${PROJECT_LIBS}) set_target_properties(dfhack PROPERTIES INTERFACE_LINK_LIBRARIES "") -target_link_libraries(dfhack-client protobuf-lite clsocket jsoncpp_static) -target_link_libraries(dfhack-run dfhack-client) +target_link_libraries(dfhack-client protobuf-lite clsocket jsoncpp_static dfhack) +target_link_libraries(dfhack-run dfhack-client dfhack) if(APPLE) add_custom_command(TARGET dfhack-run COMMAND ${dfhack_SOURCE_DIR}/package/darwin/fix-libs.sh WORKING_DIRECTORY ../ COMMENT "Fixing library dependencies...") From 7e92123952e8e146a43f1e8001dedb987c9bacbc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 3 Jul 2023 11:27:13 -0700 Subject: [PATCH 043/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index d10407621..bf8182c73 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: ## Internals ## Lua +- ``dfhack.items.markForTrade``: new API for marking items for trade ## Removed From 5a36a0fcbdaa3cddd0b59408a1d72f6770ab8305 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 3 Jul 2023 11:44:33 -0700 Subject: [PATCH 044/851] ensure we can still inject strings with simulateInput --- library/LuaApi.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index d2c32cf63..8823eb270 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2603,14 +2603,29 @@ static int screen_doSimulateInput(lua_State *L) int sz = lua_rawlen(L, 2); std::set keys; + char str = '\0'; for (int j = 1; j <= sz; j++) { lua_rawgeti(L, 2, j); - keys.insert((df::interface_key)lua_tointeger(L, -1)); + df::interface_key k = (df::interface_key)lua_tointeger(L, -1); + if (!str && k > df::interface_key::STRING_A000 && k <= df::interface_key::STRING_A255) + str = Screen::keyToChar(k); + keys.insert(k); lua_pop(L, 1); } + // if we're injecting a text keybinding, ensure it is reflected in the enabler text buffer + std::string prev_input; + if (str) { + prev_input = (const char *)&df::global::enabler->last_text_input[0]; + df::global::enabler->last_text_input[0] = str; + df::global::enabler->last_text_input[1] = '\0'; + } + screen->feed(&keys); + + if (str) + strcpy((char *)&df::global::enabler->last_text_input[0], prev_input.c_str()); return 0; } From e7f5b1f949fe6903d3e0fd34a603302687a1dae7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 3 Jul 2023 11:53:46 -0700 Subject: [PATCH 045/851] move command_result enum from Export to Core --- library/include/Core.h | 11 +++++++++++ library/include/Export.h | 14 -------------- library/include/RemoteClient.h | 1 + 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/library/include/Core.h b/library/include/Core.h index 92bf63d93..a574b029a 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -72,6 +72,17 @@ namespace DFHack struct Hide; } + enum command_result + { + CR_LINK_FAILURE = -3, // RPC call failed due to I/O or protocol error + CR_NEEDS_CONSOLE = -2, // Attempt to call interactive command without console + CR_NOT_IMPLEMENTED = -1, // Command not implemented, or plugin not loaded + CR_OK = 0, // Success + CR_FAILURE = 1, // Failure + CR_WRONG_USAGE = 2, // Wrong arguments or ui state + CR_NOT_FOUND = 3 // Target object not found (for RPC mainly) + }; + enum state_change_event { SC_UNKNOWN = -1, diff --git a/library/include/Export.h b/library/include/Export.h index ad2b4ceec..9e2a78d4b 100644 --- a/library/include/Export.h +++ b/library/include/Export.h @@ -69,17 +69,3 @@ distribution. #else #define Wformat(type, fmtstr, vararg) #endif - -namespace DFHack -{ - enum command_result - { - CR_LINK_FAILURE = -3, // RPC call failed due to I/O or protocol error - CR_NEEDS_CONSOLE = -2, // Attempt to call interactive command without console - CR_NOT_IMPLEMENTED = -1, // Command not implemented, or plugin not loaded - CR_OK = 0, // Success - CR_FAILURE = 1, // Failure - CR_WRONG_USAGE = 2, // Wrong arguments or ui state - CR_NOT_FOUND = 3 // Target object not found (for RPC mainly) - }; -} diff --git a/library/include/RemoteClient.h b/library/include/RemoteClient.h index 17e296a2e..921d351c3 100644 --- a/library/include/RemoteClient.h +++ b/library/include/RemoteClient.h @@ -26,6 +26,7 @@ distribution. #include "Pragma.h" #include "Export.h" #include "ColorText.h" +#include "Core.h" class CPassiveSocket; class CActiveSocket; From 9ddb3813c1ea14e5be99d59c11d871ba7a53359a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 3 Jul 2023 11:18:14 -0700 Subject: [PATCH 046/851] add new linkage dependency on dfhack --- library/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 5d2698bb0..40006a432 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -408,8 +408,8 @@ endif() target_link_libraries(dfhack protobuf-lite clsocket lua jsoncpp_static dfhack-version ${PROJECT_LIBS}) set_target_properties(dfhack PROPERTIES INTERFACE_LINK_LIBRARIES "") -target_link_libraries(dfhack-client protobuf-lite clsocket jsoncpp_static) -target_link_libraries(dfhack-run dfhack-client) +target_link_libraries(dfhack-client protobuf-lite clsocket jsoncpp_static dfhack) +target_link_libraries(dfhack-run dfhack-client dfhack) if(APPLE) add_custom_command(TARGET dfhack-run COMMAND ${dfhack_SOURCE_DIR}/package/darwin/fix-libs.sh WORKING_DIRECTORY ../ COMMENT "Fixing library dependencies...") From cbdb56a1ac35f9ed7eefd0a518c57f5ee0866a40 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 3 Jul 2023 13:47:43 -0700 Subject: [PATCH 047/851] port API for unit lookup by noble role from quickfort --- docs/changelog.txt | 2 ++ docs/dev/Lua API.rst | 19 ++++++++++-- library/LuaApi.cpp | 10 ++++++ library/include/modules/Units.h | 2 ++ library/modules/Units.cpp | 55 +++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index bf8182c73..814bb3909 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -42,11 +42,13 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Documentation ## API +- ``Units::getUnitByNobleRole``, ``Units::getUnitsByNobleRole``: unit lookup API by role ## Internals ## Lua - ``dfhack.items.markForTrade``: new API for marking items for trade +- ``dfhack.units.getUnitByNobleRole``, ``dfhack.units.getUnitsByNobleRole``: unit lookup API by role ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 33e27be2d..57e63dabb 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1438,10 +1438,25 @@ Units module Note that ``pos2xyz()`` cannot currently be used to convert coordinate objects to the arguments required by this function. +* ``dfhack.units.getUnitByNobleRole(role_name)`` + + Returns the unit assigned to the given noble role, if any. ``role_name`` must + be one of the position codes associated with the active fort government. + Normally, this includes: ``MILITIA_COMMANDER``, ``MILITIA_CAPTAIN``, + ``SHERIFF``, ``CAPTAIN_OF_THE_GUARD``, ``EXPEDITION_LEADER``, ``MAYOR``, + ``MANAGER``, ``CHIEF_MEDICAL_DWARF``, ``BROKER``, ``BOOKKEEPER``, + ``CHAMPION``, ``HAMMERER``, ``DUNGEON_MASTER``, and ``MESSENGER``. Note that + if more than one unit has the role, only the first will be returned. See + ``getUnitsByNobleRole`` below for retrieving all units with a particular role. + +* ``dfhack.units.getUnitsByNobleRole(role_name)`` + + Returns a list of units (possibly empty) assigned to the given noble role. + * ``dfhack.units.getCitizens([ignore_sanity])`` - Returns a table (list) of all citizens, which you would otherwise have to loop over all - units in world and test against ``isCitizen()`` to discover. + Returns a table (list) of all citizens, which you would otherwise have to + loop over all units in world and test against ``isCitizen()`` to discover. * ``dfhack.units.teleport(unit, pos)`` diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 5d9411434..65a899814 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1833,6 +1833,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, multiplyGroupActionTimers), WRAPM(Units, setActionTimers), WRAPM(Units, setGroupActionTimers), + WRAPM(Units, getUnitByNobleRole), { NULL, NULL } }; @@ -1921,6 +1922,14 @@ static int units_getCitizens(lua_State *L) { return 0; } +static int units_getUnitsByNobleRole(lua_State *L) { + std::string role_name = lua_tostring(L, -1); + std::vector units; + Units::getUnitsByNobleRole(units, role_name); + Lua::PushVector(L, units); + return 1; +} + static int units_getStressCutoffs(lua_State *L) { lua_newtable(L); @@ -1935,6 +1944,7 @@ static const luaL_Reg dfhack_units_funcs[] = { { "getNoblePositions", units_getNoblePositions }, { "getUnitsInBox", units_getUnitsInBox }, { "getCitizens", units_getCitizens }, + { "getUnitsByNobleRole", units_getUnitsByNobleRole}, { "getStressCutoffs", units_getStressCutoffs }, { NULL, NULL } }; diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 4fd9246aa..3c56d0890 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -148,6 +148,8 @@ DFHACK_EXPORT df::unit *getUnit(const int32_t index); DFHACK_EXPORT bool getUnitsInBox(std::vector &units, int16_t x1, int16_t y1, int16_t z1, int16_t x2, int16_t y2, int16_t z2); +DFHACK_EXPORT bool getUnitsByNobleRole(std::vector &units, std::string noble); +DFHACK_EXPORT df::unit *getUnitByNobleRole(std::string noble); DFHACK_EXPORT bool getCitizens(std::vector &citizens, bool ignore_sanity = false); DFHACK_EXPORT int32_t findIndexById(int32_t id); diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 533b40ca8..9fb19cfb3 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -59,6 +59,7 @@ using namespace std; #include "df/entity_position_assignment.h" #include "df/entity_raw.h" #include "df/entity_raw_flags.h" +#include "df/entity_site_link.h" #include "df/identity_type.h" #include "df/game_mode.h" #include "df/histfig_entity_link_positionst.h" @@ -80,6 +81,8 @@ using namespace std; #include "df/unit_soul.h" #include "df/unit_wound.h" #include "df/world.h" +#include "df/world_data.h" +#include "df/world_site.h" #include "df/unit_action.h" #include "df/unit_action_type_group.h" @@ -770,6 +773,58 @@ bool Units::getUnitsInBox (std::vector &units, return true; } +static int32_t get_noble_position_id(const df::historical_entity::T_positions &positions, const string &noble) { + string target_id = toUpper(noble); + for (auto &position : positions.own) { + if (position->code == target_id) + return position->id; + } + return -1; +} + +static void get_assigned_noble_units(vector &units, const df::historical_entity::T_positions &positions, int32_t noble_position_id, size_t limit) { + units.clear(); + for (auto &assignment : positions.assignments) { + if (assignment->position_id != noble_position_id) + continue; + auto histfig = df::historical_figure::find(assignment->histfig); + if (!histfig) + continue; + auto unit = df::unit::find(histfig->unit_id); + if (!unit) + continue; + units.emplace_back(unit); + if (limit > 0 && units.size() >= limit) + break; + } +} + +static void get_units_by_noble_role(vector &units, string noble, size_t limit = 0) { + auto &site = df::global::world->world_data->active_site[0]; + for (auto &link : site->entity_links) { + auto gov = df::historical_entity::find(link->entity_id); + if (!gov || gov->type != df::historical_entity_type::SiteGovernment) + continue; + int32_t noble_position_id = get_noble_position_id(gov->positions, noble); + if (noble_position_id < 0) + return; + get_assigned_noble_units(units, gov->positions, noble_position_id, limit); + } +} + +bool Units::getUnitsByNobleRole(vector &units, std::string noble) { + get_units_by_noble_role(units, noble); + return !units.empty(); +} + +df::unit *Units::getUnitByNobleRole(string noble) { + vector units; + get_units_by_noble_role(units, noble, 1); + if (units.empty()) + return NULL; + return units[0]; +} + bool Units::getCitizens(std::vector &citizens, bool ignore_sanity) { for (auto &unit : world->units.active) { if (isCitizen(unit, ignore_sanity)) From 7c63dcd6bd2700ba375bd9c1ff0773d89e9f100f Mon Sep 17 00:00:00 2001 From: IvoryTower33 <133928688+IvoryTower33@users.noreply.github.com> Date: Mon, 3 Jul 2023 23:02:39 +0200 Subject: [PATCH 048/851] Update autonick.txt with fantasy Dwarf names, 210 single&180 composite --- data/dfhack-config/autonick.txt | 375 ++++++++++++++++++++++++++++++++ 1 file changed, 375 insertions(+) diff --git a/data/dfhack-config/autonick.txt b/data/dfhack-config/autonick.txt index 12fbe65e6..17e6e3b2b 100644 --- a/data/dfhack-config/autonick.txt +++ b/data/dfhack-config/autonick.txt @@ -7,6 +7,381 @@ Toady One Threetoe +#Dwarven single names taken from Classic Fantasy works +Balin +Dwalin +Fili +Kili +Gloin +Oin +Bifur +Bofur +Bombur +Dori +Nori +Ori +Gimli +Durin +Thrain +Thror +Fundin +Frerin +Groin +Nain +Gror +Mim +Mim +Ibun +Khim +Fimbrethil +Floi +Nali +Thor +Thrain +Vili +Regin +Fafnir +Brokkr +Sindri +Eitri +Nordri +Sudri +Austri +Doriath +Thingol +Eol +Mim +Telchar +Narvi +Gundabad +Muhrak +Skorri +Draupnir +Alaric +Grimr +Eitri +Havardr +Hreinn +Svidurr +Thorgar +Hrungnir +Galar +Kili +Nori +Skirni +Hreinn +Hroaldr +Fili +Dori +Hreimr +Hreinir +Hroaldr +Groin +Austri +Vestri +Nori +Sudri +Durin +Dvalin +Eikinskjaldi +Bifur +Bafur +Bofur +Bombur +Snorri +Fimafeng +Vitr +Dvali +Dain +Nain +Nipingr +Hrodvitnir +Sveinn +Ivaldi +Svein +Sveinbjorn +Havardr +Haki +Hakon +Mouri +Motsognir +Eberk +Thromar +Kragar +Borgar +Throk +Orvald +Berric +Rogar +Urgen +Morgrim +Keldar +Ingvar +Frandar +Grimsi +Hrokur +Orik +Rundar +Bjornar +Throki +Ulfgar +Dworin +Thranduil +Faldar +Galdor +Volmar +Thorkel +Dorrin +Borkan +Gundrik +Throkir +Raldor +Helgrim +Throgar +Borin +Ragnir +Orvar +Skalf +Baldir +Fror +Thorgil +Egil +Ulfar +Grimbold +Faldur +Keldin +Borgar +Orik +Varrin +Dornir +Halgrim +Gundin +Ulfgar +Fornir +Egil +Skalfar +Grimnor +Roldor +Ulfgard +Borgrim +Faldrik +Keldin +Borgar +Rognir +Balfor +Volmar +Yngvarr +Faldrik +Kaldur +Thrandar +Rundin +Skaldur +Borgin +Haldur +Bjornulf +Orkarn +Ragnor +Baldrick +Thorlin +Graldor +Ulfrik +Fornir +Egil +Grimnor +Roldor +Ulfgard +Borgrim +Yngvarr +Faldrik +Keldin +Borgar +Rognir +Balfor +Volmar +Yngvarr +Faldrik +Keldin +Borgar +Rognir +Balfor +Volmar +Thormund +Brynhild + +#Dwarven composite names taken from Classic Fantasy works +Gorin Stonehammer +Brundar Ironfoot +Haldrek Battlebeard +Orin Stonefist +Frida Stormaxe +Torvald Rockjaw +Einar Blackforge +Thorgar Granitebeard +Ragnir Hammerhelm +Hilda Ironbrow +Grimnar Deepdelver +Ulfrik Ironmane +Freya Thunderstone +Ragnar Firebeard +Gunnar Ironpeak +Astrid Ironheart +Bjorn Steelbreaker +Hrolf Thunderhammer +Sigrun Stonebreaker +Eirik Rockbeard +Helga Frostbeard +Skaldur Stormguard +Agnar Stonehand +Ingrid Mountainmace +Hjalmar Blackstone +Solveig Steelhelm +Rurik Stonegrip +Freyja Silveraxe +Thordur Goldbeard +Gudrun Ironfoot +Vali Fireforge +Thora Frostbeard +Vargr Stoneborn +Astrid Ironbrow +Einar Blackstone +Hilda Hammerheart +Leif Ironshaper +Thrain Stormbrow +Sigrid Steelheart +Haldor Boulderbreaker +Ragnhild Strongarm +Brynjar Ironmantle +Sigrun Thunderbeard +Valgard Steelbeard +Gunnhild Stonefist +Bjorn Ironhelm +Ingrid Ironrock +Eirik Frostbane +Helga Deepforge +Skaldur Ironshield +Agnar Stonemace +Solveig Stormgrip +Hjalmar Mountainheart +Gudrun Firebeard +Thora Thunderstrike +Vargr Ironhand +Freyja Stoneguard +Thordur Blackstone +Rurik Hammerbeard +Solveig Ironbreaker +Astrid Goldhand +Einar Stormbrew +Hilda Steelbeard +Thrain Ironmane +Sigrid Fireheart +Haldor Thunderstone +Ragnhild Ironfoot +Brynjar Blackhelm +Sigrun Frostbeard +Valgard Stoneshield +Gunnhild Ironheart +Bjorn Deepdelver +Ingrid Ironpeak +Eirik Thunderhammer +Gormund Stoneforge +Eovar Broadshield +Thrunir Hammerstone +Brunhild Steelbraid +Garrik Frostbeard +Haldrek Ironhand +Astrid Rockrider +Dagmar Stonefury +Borgar Thunderhelm +Ingrid Ironstrike +Rurik Blackmane +Fjorn Stoneborn +Siv Ironbreaker +Gudrik Stormbeard +Ulfgar Emberforge +Eilif Silverstone +Hilda Stormwarden +Ormar Ironjaw +Vali Steelshaper +Eira Frostbeard +Torgar Graniteheart +Brunhild Firebrand +Haldrek Ironmantle +Solveig Rockbreaker +Thrain Thunderaxe +Brynjar Stoneclaw +Asa Ironhide +Grimnar Blackmane +Ragnvald Hammerfall +Gudbrand Ironhand +Astrid Flamebeard +Ormur Steelbender +Hjalmar Rockjaw +Inga Thunderheart +Valgard Ironbeard +Eirik Swiftstrike +Sylvi Stoneguard +Helge Hammerfist +Jorunn Fireforge +Solveig Ironroot +Thora Stormbeard +Baldur Stonemane +Freydis Ironshaper +Gunnvald Deepstone +Bjorn Blackstone +Ingrid Frostmane +Agnar Steelhammer +Thordur Ironbeard +Ylva Goldhand +Greta Firestone +Rurik Rockhelm +Gunnhild Ironsong +Vali Steelgrip +Brynhild Stormblade +Astrid Ironmantle +Einar Stoneshield +Hilda Frostbeard +Ormr Ironheart +Inga Steelbreaker +Ulfrik Thunderaxe +Freyja Stonebeard +Sigrun Frostfury +Sylvi Blackmane +Thorvald Ironhelm +Eirik Stormstone +Haldora Deepdelver +Sigrid Steelshaper +Gunnar Thunderheart +Bjorn Ironbrow +Ingrid Goldmantle +Agnar Stormforge +Solveig Ironclaw +Thora Rockguard +Grimur Emberstone +Ragnhild Hammerstrike +Vali Ironfist +Brynjar Blackbraid +Astrid Flameforge +Einar Stonestorm +Hilda Frostbane +Ormur Ironhelm +Inga Steelshaper +Gudbrand Thunderbeard +Freya Stonefist +Gunnvald Stormmane +Bjorn Ironhelm +Ingrid Frostforge +Agnar Steelgrip +Thordur Ironhand +Ylva Flameheart +Greta Stonemane +Rurik Ironroot +Gunnhild Steelbeard +Vali Thunderstrike +Thorin Oakenshield +Dain Ironfoot +Gamil Zirak + + # animals Mouse Otter From 4e7f4b638caeb9e610a4e30437898a5f1bd5087f Mon Sep 17 00:00:00 2001 From: IvoryTower33 <133928688+IvoryTower33@users.noreply.github.com> Date: Mon, 3 Jul 2023 23:12:42 +0200 Subject: [PATCH 049/851] Update autonick.txt 350+ dwarf names single and composite --- data/dfhack-config/autonick.txt | 50 +-------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/data/dfhack-config/autonick.txt b/data/dfhack-config/autonick.txt index 17e6e3b2b..7cf9f3861 100644 --- a/data/dfhack-config/autonick.txt +++ b/data/dfhack-config/autonick.txt @@ -17,33 +17,25 @@ Oin Bifur Bofur Bombur -Dori -Nori Ori Gimli -Durin Thrain Thror Fundin Frerin -Groin Nain Gror -Mim -Mim Ibun Khim Fimbrethil Floi Nali Thor -Thrain Vili Regin Fafnir Brokkr Sindri -Eitri Nordri Sudri Austri @@ -60,34 +52,23 @@ Draupnir Alaric Grimr Eitri -Havardr -Hreinn Svidurr Thorgar Hrungnir Galar -Kili -Nori Skirni Hreinn -Hroaldr -Fili Dori Hreimr Hreinir Hroaldr Groin -Austri Vestri Nori -Sudri Durin Dvalin Eikinskjaldi -Bifur Bafur -Bofur -Bombur Snorri Fimafeng Vitr @@ -124,12 +105,10 @@ Orik Rundar Bjornar Throki -Ulfgar Dworin Thranduil Faldar Galdor -Volmar Thorkel Dorrin Borkan @@ -145,35 +124,19 @@ Skalf Baldir Fror Thorgil -Egil Ulfar Grimbold Faldur -Keldin -Borgar -Orik Varrin Dornir Halgrim Gundin Ulfgar -Fornir -Egil Skalfar -Grimnor -Roldor -Ulfgard -Borgrim -Faldrik -Keldin -Borgar -Rognir -Balfor -Volmar Yngvarr -Faldrik Kaldur Thrandar +Keldin Rundin Skaldur Borgin @@ -191,17 +154,7 @@ Grimnor Roldor Ulfgard Borgrim -Yngvarr -Faldrik -Keldin -Borgar -Rognir -Balfor -Volmar -Yngvarr Faldrik -Keldin -Borgar Rognir Balfor Volmar @@ -254,7 +207,6 @@ Brynjar Ironmantle Sigrun Thunderbeard Valgard Steelbeard Gunnhild Stonefist -Bjorn Ironhelm Ingrid Ironrock Eirik Frostbane Helga Deepforge From 9e3094c0fcb7bb20997be7444c1858c25185bb32 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 4 Jul 2023 02:43:29 +0000 Subject: [PATCH 050/851] [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.23.1 → 0.23.2](https://github.com/python-jsonschema/check-jsonschema/compare/0.23.1...0.23.2) --- .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 efa59812d..1d481edce 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.23.1 + rev: 0.23.2 hooks: - id: check-github-workflows - repo: https://github.com/Lucas-C/pre-commit-hooks From ba974aff9822030ebf7c8642bf53d93be5fe7089 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 4 Jul 2023 07:15:34 +0000 Subject: [PATCH 051/851] 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 5da8a785c..0d4230a9d 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 5da8a785cf176f831a56f934ec8ec6069a965ecf +Subproject commit 0d4230a9db2ebc381e73296bc4e19bee09551771 diff --git a/scripts b/scripts index ee8217978..086efd3d0 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ee8217978d25bc8f9c3efa21156dd8ff99896f68 +Subproject commit 086efd3d0562837937065148d26090e04b819060 From e3d3affdbc9d4c91940a72fa448a7bd0f267733c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 5 Jul 2023 10:25:07 -0700 Subject: [PATCH 052/851] Revert "add new linkage dependency on dfhack" This reverts commit 9ddb3813c1ea14e5be99d59c11d871ba7a53359a. --- library/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 40006a432..5d2698bb0 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -408,8 +408,8 @@ endif() target_link_libraries(dfhack protobuf-lite clsocket lua jsoncpp_static dfhack-version ${PROJECT_LIBS}) set_target_properties(dfhack PROPERTIES INTERFACE_LINK_LIBRARIES "") -target_link_libraries(dfhack-client protobuf-lite clsocket jsoncpp_static dfhack) -target_link_libraries(dfhack-run dfhack-client dfhack) +target_link_libraries(dfhack-client protobuf-lite clsocket jsoncpp_static) +target_link_libraries(dfhack-run dfhack-client) if(APPLE) add_custom_command(TARGET dfhack-run COMMAND ${dfhack_SOURCE_DIR}/package/darwin/fix-libs.sh WORKING_DIRECTORY ../ COMMENT "Fixing library dependencies...") From 125e4c623b9a13048e698af2f4b4b16587091837 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 5 Jul 2023 11:07:51 -0700 Subject: [PATCH 053/851] avoid inducing link dependency on dfhack --- library/Core.cpp | 9 +++++++++ library/include/Core.h | 8 ++------ library/modules/Gui.cpp | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 4b036a83e..8d632e107 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1471,6 +1471,10 @@ std::string Core::getHackPath() #endif } +df::viewscreen * Core::getTopViewscreen() { + return getInstance().top_viewscreen; +} + bool Core::InitMainThread() { Filesystem::init(); @@ -1855,6 +1859,11 @@ void *Core::GetData( std::string key ) } } +Core& Core::getInstance() { + static Core instance; + return instance; +} + bool Core::isSuspended(void) { return ownerThread.load() == std::this_thread::get_id(); diff --git a/library/include/Core.h b/library/include/Core.h index a574b029a..a41aff927 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -125,11 +125,7 @@ namespace DFHack friend bool ::dfhooks_ncurses_key(int key); public: /// Get the single Core instance or make one. - static Core& getInstance() - { - static Core instance; - return instance; - } + static Core& getInstance(); /// check if the activity lock is owned by this thread bool isSuspended(void); /// Is everything OK? @@ -177,7 +173,7 @@ namespace DFHack bool isWorldLoaded() { return (last_world_data_ptr != NULL); } bool isMapLoaded() { return (last_local_map_ptr != NULL && last_world_data_ptr != NULL); } - static df::viewscreen *getTopViewscreen() { return getInstance().top_viewscreen; } + static df::viewscreen *getTopViewscreen(); DFHack::Console &getConsole() { return con; } diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 39f600bbf..102fef9d6 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -1709,7 +1709,7 @@ bool Gui::autoDFAnnouncement(df::report_init r, string message) if (a_flags.bits.D_DISPLAY) { world->status.display_timer = r.display_timer; - Gui::writeToGamelog("x" + to_string(repeat_count + 1)); + Gui::writeToGamelog('x' + to_string(repeat_count + 1)); } DEBUG(gui).print("Announcement succeeded as repeat:\n%s\n", message.c_str()); return true; From 0bbb72b44f59cadb4246081ef6ff9d4121fcbf22 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 5 Jul 2023 11:46:33 -0700 Subject: [PATCH 054/851] Revert "add new linkage dependency on dfhack" This reverts commit ae545aa1d6a3577f6b4a2fbf485335544f4b23f4. --- library/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 40006a432..5d2698bb0 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -408,8 +408,8 @@ endif() target_link_libraries(dfhack protobuf-lite clsocket lua jsoncpp_static dfhack-version ${PROJECT_LIBS}) set_target_properties(dfhack PROPERTIES INTERFACE_LINK_LIBRARIES "") -target_link_libraries(dfhack-client protobuf-lite clsocket jsoncpp_static dfhack) -target_link_libraries(dfhack-run dfhack-client dfhack) +target_link_libraries(dfhack-client protobuf-lite clsocket jsoncpp_static) +target_link_libraries(dfhack-run dfhack-client) if(APPLE) add_custom_command(TARGET dfhack-run COMMAND ${dfhack_SOURCE_DIR}/package/darwin/fix-libs.sh WORKING_DIRECTORY ../ COMMENT "Fixing library dependencies...") From 43ea9b94c3026ce05acddd297c31e4e9e720a826 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 5 Jul 2023 12:08:18 -0700 Subject: [PATCH 055/851] move clipboard wrappers into DFSDL module (but not in the namespace) --- library/MiscUtils.cpp | 8 -------- library/include/MiscUtils.h | 4 ---- library/include/modules/DFSDL.h | 11 ++++++++--- library/modules/DFSDL.cpp | 28 +++++++++++++++++++++------- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/library/MiscUtils.cpp b/library/MiscUtils.cpp index 6b50da347..7ffd4e1c6 100644 --- a/library/MiscUtils.cpp +++ b/library/MiscUtils.cpp @@ -472,11 +472,3 @@ DFHACK_EXPORT std::string DF2CONSOLE(DFHack::color_ostream &out, const std::stri { return out.is_console() ? DF2CONSOLE(in) : in; } - -DFHACK_EXPORT std::string getClipboardTextCp437() { - return UTF2DF(DFHack::DFSDL::DFSDL_GetClipboardText()); -} - -DFHACK_EXPORT bool setClipboardTextCp437(std::string text) { - return DFHack::DFSDL::DFSDL_SetClipboardText(DF2UTF(text).c_str()); -} diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index 099e86581..d14bdb6e9 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -496,7 +496,3 @@ DFHACK_EXPORT std::string UTF2DF(const std::string &in); DFHACK_EXPORT std::string DF2UTF(const std::string &in); DFHACK_EXPORT std::string DF2CONSOLE(const std::string &in); DFHACK_EXPORT std::string DF2CONSOLE(DFHack::color_ostream &out, const std::string &in); - -// System clipboard -- submitted and returned text must be in CP437 -DFHACK_EXPORT std::string getClipboardTextCp437(); -DFHACK_EXPORT bool setClipboardTextCp437(std::string text); diff --git a/library/include/modules/DFSDL.h b/library/include/modules/DFSDL.h index 6cee58342..36dd641d5 100644 --- a/library/include/modules/DFSDL.h +++ b/library/include/modules/DFSDL.h @@ -47,12 +47,17 @@ DFHACK_EXPORT void DFSDL_FreeSurface(SDL_Surface *surface); // DFHACK_EXPORT int DFSDL_SemWait(SDL_sem *sem); // DFHACK_EXPORT int DFSDL_SemPost(SDL_sem *sem); DFHACK_EXPORT int DFSDL_PushEvent(SDL_Event *event); +DFHACK_EXPORT void DFSDL_free(void *ptr); // submitted and returned text is UTF-8 -// see wrapper functions in MiscUtils.h for cp-437 variants -DFHACK_EXPORT std::string DFSDL_GetClipboardText(); -DFHACK_EXPORT bool DFSDL_SetClipboardText(const char *text); +// see wrapper functions below for cp-437 variants +DFHACK_EXPORT char * DFSDL_GetClipboardText(); +DFHACK_EXPORT int DFSDL_SetClipboardText(const char *text); } +// System clipboard -- submitted and returned text must be in CP437 +DFHACK_EXPORT std::string getClipboardTextCp437(); +DFHACK_EXPORT bool setClipboardTextCp437(std::string text); + } diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp index 280fb04d6..bc50769d0 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -135,15 +135,29 @@ int DFSDL::DFSDL_PushEvent(SDL_Event *event) { return g_SDL_PushEvent(event); } -std::string DFSDL::DFSDL_GetClipboardText() { - if (g_SDL_HasClipboardText() != SDL_TRUE) +void DFSDL::DFSDL_free(void *ptr) { + g_SDL_free(ptr); +} + +char * DFSDL::DFSDL_GetClipboardText() { + return g_SDL_GetClipboardText(); +} + +int DFSDL::DFSDL_SetClipboardText(const char *text) { + return g_SDL_SetClipboardText(text); +} + +DFHACK_EXPORT std::string DFHack::getClipboardTextCp437() { + if (!g_sdl_handle || g_SDL_HasClipboardText() != SDL_TRUE) return ""; char *text = g_SDL_GetClipboardText(); - std::string ret = text; - g_SDL_free(text); - return ret; + std::string textcp437 = UTF2DF(text); + DFHack::DFSDL::DFSDL_free(text); + return textcp437; } -bool DFSDL::DFSDL_SetClipboardText(const char *text) { - return g_SDL_SetClipboardText(text) == 0; +DFHACK_EXPORT bool DFHack::setClipboardTextCp437(std::string text) { + if (!g_sdl_handle) + return false; + return 0 == DFHack::DFSDL::DFSDL_SetClipboardText(DF2UTF(text).c_str()); } From c587cad47150722c78b064e59215f00728c8a4fd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 5 Jul 2023 17:37:49 -0700 Subject: [PATCH 056/851] generalize to civ roles as well --- docs/dev/Lua API.rst | 12 +++++------- library/modules/Units.cpp | 16 +++++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 57e63dabb..0554629a9 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1441,13 +1441,11 @@ Units module * ``dfhack.units.getUnitByNobleRole(role_name)`` Returns the unit assigned to the given noble role, if any. ``role_name`` must - be one of the position codes associated with the active fort government. - Normally, this includes: ``MILITIA_COMMANDER``, ``MILITIA_CAPTAIN``, - ``SHERIFF``, ``CAPTAIN_OF_THE_GUARD``, ``EXPEDITION_LEADER``, ``MAYOR``, - ``MANAGER``, ``CHIEF_MEDICAL_DWARF``, ``BROKER``, ``BOOKKEEPER``, - ``CHAMPION``, ``HAMMERER``, ``DUNGEON_MASTER``, and ``MESSENGER``. Note that - if more than one unit has the role, only the first will be returned. See - ``getUnitsByNobleRole`` below for retrieving all units with a particular role. + be one of the position codes associated with the active fort or civilization + government. For example: ``CAPTAIN_OF_THE_GUARD``, ``MAYOR``, or ``BARON``. + Note that if more than one unit has the role, only the first will be + returned. See ``getUnitsByNobleRole`` below for retrieving all units with a + particular role. * ``dfhack.units.getUnitsByNobleRole(role_name)`` diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 9fb19cfb3..737ff0982 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -782,8 +782,7 @@ static int32_t get_noble_position_id(const df::historical_entity::T_positions &p return -1; } -static void get_assigned_noble_units(vector &units, const df::historical_entity::T_positions &positions, int32_t noble_position_id, size_t limit) { - units.clear(); +static void add_assigned_noble_units(vector &units, const df::historical_entity::T_positions &positions, int32_t noble_position_id, size_t limit) { for (auto &assignment : positions.assignments) { if (assignment->position_id != noble_position_id) continue; @@ -802,17 +801,20 @@ static void get_assigned_noble_units(vector &units, const df::histor static void get_units_by_noble_role(vector &units, string noble, size_t limit = 0) { auto &site = df::global::world->world_data->active_site[0]; for (auto &link : site->entity_links) { - auto gov = df::historical_entity::find(link->entity_id); - if (!gov || gov->type != df::historical_entity_type::SiteGovernment) + auto he = df::historical_entity::find(link->entity_id); + if (!he || + (he->type != df::historical_entity_type::SiteGovernment && + he->type != df::historical_entity_type::Civilization)) continue; - int32_t noble_position_id = get_noble_position_id(gov->positions, noble); + int32_t noble_position_id = get_noble_position_id(he->positions, noble); if (noble_position_id < 0) - return; - get_assigned_noble_units(units, gov->positions, noble_position_id, limit); + continue; + add_assigned_noble_units(units, he->positions, noble_position_id, limit); } } bool Units::getUnitsByNobleRole(vector &units, std::string noble) { + units.clear(); get_units_by_noble_role(units, noble); return !units.empty(); } From 0b9f84a5da94ebcba9106e6f0df5de2a36842635 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 5 Jul 2023 19:06:57 -0700 Subject: [PATCH 057/851] don't print error if a building is not selected --- plugins/lua/buildingplan/inspectoroverlay.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/lua/buildingplan/inspectoroverlay.lua b/plugins/lua/buildingplan/inspectoroverlay.lua index 5262eccc8..1fcf19028 100644 --- a/plugins/lua/buildingplan/inspectoroverlay.lua +++ b/plugins/lua/buildingplan/inspectoroverlay.lua @@ -124,7 +124,7 @@ local function mouse_is_over_resume_button(rect) end function InspectorOverlay:onInput(keys) - if not require('plugins.buildingplan').isPlannedBuilding(dfhack.gui.getSelectedBuilding()) then + if not require('plugins.buildingplan').isPlannedBuilding(dfhack.gui.getSelectedBuilding(true)) then return false end if keys._MOUSE_L_DOWN and mouse_is_over_resume_button(self.frame_parent_rect) then @@ -136,7 +136,7 @@ function InspectorOverlay:onInput(keys) end function InspectorOverlay:render(dc) - if not require('plugins.buildingplan').isPlannedBuilding(dfhack.gui.getSelectedBuilding()) then + if not require('plugins.buildingplan').isPlannedBuilding(dfhack.gui.getSelectedBuilding(true)) then return end if reset_inspector_flag then From 785405b281d5c4cc09e87146fe26eed450216667 Mon Sep 17 00:00:00 2001 From: Myk Date: Wed, 5 Jul 2023 22:34:25 -0700 Subject: [PATCH 058/851] Update DFSDL.cpp --- 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 bc50769d0..aa54cf66c 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -5,7 +5,7 @@ #include "Debug.h" #include "PluginManager.h" -#include +#include namespace DFHack { DBG_DECLARE(core, dfsdl, DebugCategory::LINFO); From c0190397a9a355d068686a106d9791db06a3fb79 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 6 Jul 2023 07:16:05 +0000 Subject: [PATCH 059/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 086efd3d0..64aff9c2d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 086efd3d0562837937065148d26090e04b819060 +Subproject commit 64aff9c2deb0dd49ee755257c43d2a9fc62f92bb From aa6d28bab60868e42b366af930e17219be54a828 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 6 Jul 2023 03:21:19 -0700 Subject: [PATCH 060/851] generalize dfhack.items.isRequestedTradeGood --- docs/dev/Lua API.rst | 15 + library/include/modules/Items.h | 5 + library/modules/Items.cpp | 495 ++++++++++++++++++++++++++++++++ 3 files changed, 515 insertions(+) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 785e477dd..7f99af2d3 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1770,7 +1770,22 @@ Items module * ``dfhack.items.getValue(item)`` +<<<<<<< Updated upstream Calculates the Basic Value of an item, as seen in the View Item screen. +======= + Calculates the value of an item. If a ``df.caravan_state`` object is given + (from ``df.global.plotinfo.caravans`` or + ``df.global.main_interface.trade.mer``), then the value is modified by civ + properties and any trade agreements that might be in effect. In this case, + specify ``caravan_buying`` as ``true`` to get the price the caravan will pay + for the item and ``false`` to get the price that the caravan will sell the + item for. + +* ``dfhack.items.isRequestedTradeGood(item[, caravan_state])`` + + Returns whether a caravan will pay extra for the given item. If caravan_state + is not given, checks all active caravans. +>>>>>>> Stashed changes * ``dfhack.items.createItem(item_type, item_subtype, mat_type, mat_index, unit)`` diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h index 08737fb2b..f3dfe6dae 100644 --- a/library/include/modules/Items.h +++ b/library/include/modules/Items.h @@ -202,6 +202,11 @@ DFHACK_EXPORT bool canTrade(df::item *item); DFHACK_EXPORT bool canTradeWithContents(df::item *item); /// marks the given item for trade at the given depot DFHACK_EXPORT bool markForTrade(df::item *item, df::building_tradedepotst *depot); +<<<<<<< Updated upstream +======= +/// Returns true if an active caravan will pay extra for the given item +DFHACK_EXPORT bool isRequestedTradeGood(df::item *item, df::caravan_state *caravan = NULL); +>>>>>>> Stashed changes /// Checks whether the item is an assigned hauling vehicle DFHACK_EXPORT bool isRouteVehicle(df::item *item); diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index f98c7c46b..e67fc64a6 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -1435,7 +1435,502 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat return value; } +<<<<<<< Updated upstream int Items::getValue(df::item *item) +======= +static int32_t get_war_multiplier(df::item *item, df::caravan_state *caravan) { + static const int32_t DEFAULT_WAR_MULTIPLIER = 256; + + if (!caravan) + return DEFAULT_WAR_MULTIPLIER; + auto caravan_he = df::historical_entity::find(caravan->entity); + if (!caravan_he) + return DEFAULT_WAR_MULTIPLIER; + int32_t war_alignment = caravan_he->entity_raw->sphere_alignment[df::sphere_type::WAR]; + if (war_alignment == DEFAULT_WAR_MULTIPLIER) + return DEFAULT_WAR_MULTIPLIER; + switch (item->getType()) { + case df::item_type::WEAPON: + { + auto weap_def = df::itemdef_weaponst::find(item->getSubtype()); + auto caravan_cre_raw = df::creature_raw::find(caravan_he->race); + if (!weap_def || !caravan_cre_raw || caravan_cre_raw->adultsize < weap_def->minimum_size) + return DEFAULT_WAR_MULTIPLIER; + break; + } + case df::item_type::ARMOR: + case df::item_type::SHOES: + case df::item_type::HELM: + case df::item_type::GLOVES: + case df::item_type::PANTS: + { + if (item->getEffectiveArmorLevel() <= 0) + return DEFAULT_WAR_MULTIPLIER; + auto caravan_cre_raw = df::creature_raw::find(caravan_he->race); + auto maker_cre_raw = df::creature_raw::find(item->getMakerRace()); + if (!caravan_cre_raw || !maker_cre_raw) + return DEFAULT_WAR_MULTIPLIER; + if (caravan_cre_raw->adultsize < ((maker_cre_raw->adultsize * 6) / 7)) + return DEFAULT_WAR_MULTIPLIER; + if (caravan_cre_raw->adultsize > ((maker_cre_raw->adultsize * 8) / 7)) + return DEFAULT_WAR_MULTIPLIER; + break; + } + case df::item_type::SHIELD: + case df::item_type::AMMO: + case df::item_type::BACKPACK: + case df::item_type::QUIVER: + break; + default: + return DEFAULT_WAR_MULTIPLIER; + } + return war_alignment; +} + +static const int32_t DEFAULT_AGREEMENT_MULTIPLIER = 128; + +static int32_t get_buy_request_multiplier(df::item *item, const df::entity_buy_prices *buy_prices) { + if (!buy_prices) + return DEFAULT_AGREEMENT_MULTIPLIER; + + int16_t item_type = item->getType(); + int16_t item_subtype = item->getSubtype(); + int16_t mat_type = item->getMaterial(); + int32_t mat_subtype = item->getMaterialIndex(); + + for (size_t idx = 0; idx < buy_prices->price.size(); ++idx) { + if (buy_prices->items->item_type[idx] != item_type) + continue; + if (buy_prices->items->item_subtype[idx] != -1 && buy_prices->items->item_subtype[idx] != item_subtype) + continue; + if (buy_prices->items->mat_types[idx] != -1 && buy_prices->items->mat_types[idx] != mat_type) + continue; + if (buy_prices->items->mat_indices[idx] != -1 && buy_prices->items->mat_indices[idx] != mat_subtype) + continue; + return buy_prices->price[idx]; + } + return DEFAULT_AGREEMENT_MULTIPLIER; +} + +template +static int get_price(const std::vector &res, int32_t val, const std::vector &pri) { + for (size_t idx = 0; idx < res.size(); ++idx) { + if (res[idx] == val && pri.size() > idx) + return pri[idx]; + } + return -1; +} + +template +static int get_price(const std::vector &mat_res, int32_t mat, const std::vector &gloss_res, int32_t gloss, const std::vector &pri) { + for (size_t idx = 0; idx < mat_res.size(); ++idx) { + if (mat_res[idx] == mat && (gloss_res[idx] == -1 || gloss_res[idx] == gloss) && pri.size() > idx) + return pri[idx]; + } + return -1; +} + +static const uint16_t PLANT_BASE = 419; +static const uint16_t NUM_PLANT_TYPES = 200; + +static int32_t get_sell_request_multiplier(df::item *item, const df::historical_entity::T_resources &resources, const std::vector *prices) { + 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 const df::dfhack_material_category leather_cat(df::dfhack_material_category::mask_leather); + + int16_t item_type = item->getType(); + int16_t item_subtype = item->getSubtype(); + int16_t mat_type = item->getMaterial(); + int32_t mat_subtype = item->getMaterialIndex(); + + bool inorganic = mat_type == df::builtin_mats::INORGANIC; + bool is_plant = (uint16_t)(mat_type - PLANT_BASE) < NUM_PLANT_TYPES; + + switch (item_type) { + case df::item_type::BAR: + if (inorganic) { + if (int32_t price = get_price(resources.metals, mat_subtype, prices[df::entity_sell_category::MetalBars]); price != -1) + return price; + } + break; + case df::item_type::SMALLGEM: + if (inorganic) { + if (int32_t price = get_price(resources.gems, mat_subtype, prices[df::entity_sell_category::SmallCutGems]); price != -1) + return price; + } + break; + case df::item_type::BLOCKS: + if (inorganic) { + if (int32_t price = get_price(resources.stones, mat_subtype, prices[df::entity_sell_category::StoneBlocks]); price != -1) + return price; + } + break; + case df::item_type::ROUGH: + if (int32_t price = get_price(resources.misc_mat.glass.mat_type, mat_type, resources.misc_mat.glass.mat_index, mat_subtype, + prices[df::entity_sell_category::Glass]); price != -1) + return price; + break; + case df::item_type::BOULDER: + if (int32_t price = get_price(resources.stones, mat_subtype, prices[df::entity_sell_category::Stone]); price != -1) + return price; + if (int32_t price = get_price(resources.misc_mat.clay.mat_type, mat_type, resources.misc_mat.clay.mat_index, mat_subtype, + prices[df::entity_sell_category::Clay]); price != -1) + return price; + break; + case df::item_type::WOOD: + if (int32_t price = get_price(resources.organic.wood.mat_type, mat_type, resources.organic.wood.mat_index, mat_subtype, + prices[df::entity_sell_category::Wood]); price != -1) + return price; + break; + case df::item_type::CHAIN: + if (is_plant) { + if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, + prices[df::entity_sell_category::RopesPlant]); price != -1) + return price; + } + { + MaterialInfo mi; + mi.decode(mat_type, mat_subtype); + if (mi.isValid()) { + if (mi.matches(silk_cat)) { + if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, + prices[df::entity_sell_category::RopesSilk]); price != -1) + return price; + } + if (mi.matches(yarn_cat)) { + if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, + prices[df::entity_sell_category::RopesYarn]); price != -1) + return price; + } + } + } + break; + case df::item_type::FLASK: + if (int32_t price = get_price(resources.misc_mat.flasks.mat_type, mat_type, resources.misc_mat.flasks.mat_index, mat_subtype, + prices[df::entity_sell_category::FlasksWaterskins]); price != -1) + return price; + break; + case df::item_type::GOBLET: + if (int32_t price = get_price(resources.misc_mat.crafts.mat_type, mat_type, resources.misc_mat.crafts.mat_index, mat_subtype, + prices[df::entity_sell_category::CupsMugsGoblets]); price != -1) + return price; + break; + case df::item_type::INSTRUMENT: + if (int32_t price = get_price(resources.instrument_type, mat_subtype, prices[df::entity_sell_category::Instruments]); price != -1) + return price; + break; + case df::item_type::TOY: + if (int32_t price = get_price(resources.toy_type, mat_subtype, prices[df::entity_sell_category::Toys]); price != -1) + return price; + break; + case df::item_type::CAGE: + if (int32_t price = get_price(resources.misc_mat.cages.mat_type, mat_type, resources.misc_mat.cages.mat_index, mat_subtype, + prices[df::entity_sell_category::Cages]); price != -1) + return price; + break; + case df::item_type::BARREL: + if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, + prices[df::entity_sell_category::Barrels]); price != -1) + return price; + break; + case df::item_type::BUCKET: + if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, + prices[df::entity_sell_category::Buckets]); price != -1) + return price; + break; + case df::item_type::WEAPON: + if (int32_t price = get_price(resources.weapon_type, mat_subtype, prices[df::entity_sell_category::Weapons]); price != -1) + return price; + if (int32_t price = get_price(resources.digger_type, mat_subtype, prices[df::entity_sell_category::DiggingImplements]); price != -1) + return price; + if (int32_t price = get_price(resources.training_weapon_type, mat_subtype, prices[df::entity_sell_category::TrainingWeapons]); price != -1) + return price; + break; + case df::item_type::ARMOR: + if (int32_t price = get_price(resources.armor_type, mat_subtype, prices[df::entity_sell_category::Bodywear]); price != -1) + return price; + break; + case df::item_type::SHOES: + if (int32_t price = get_price(resources.shoes_type, mat_subtype, prices[df::entity_sell_category::Footwear]); price != -1) + return price; + break; + case df::item_type::SHIELD: + if (int32_t price = get_price(resources.shield_type, mat_subtype, prices[df::entity_sell_category::Shields]); price != -1) + return price; + break; + case df::item_type::HELM: + if (int32_t price = get_price(resources.helm_type, mat_subtype, prices[df::entity_sell_category::Headwear]); price != -1) + return price; + break; + case df::item_type::GLOVES: + if (int32_t price = get_price(resources.gloves_type, mat_subtype, prices[df::entity_sell_category::Handwear]); price != -1) + return price; + break; + case df::item_type::BAG: + { + MaterialInfo mi; + mi.decode(mat_type, mat_subtype); + if (mi.isValid() && mi.matches(leather_cat)) { + if (int32_t price = get_price(resources.organic.leather.mat_type, mat_type, resources.organic.leather.mat_index, mat_subtype, + prices[df::entity_sell_category::BagsLeather]); price != -1) + return price; + } + if (is_plant) { + if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, + prices[df::entity_sell_category::BagsPlant]); price != -1) + return price; + } + if (mi.isValid() && mi.matches(silk_cat)) { + if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, + prices[df::entity_sell_category::BagsSilk]); price != -1) + return price; + } + if (mi.isValid() && mi.matches(yarn_cat)) { + if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, + prices[df::entity_sell_category::BagsYarn]); price != -1) + return price; + } + } + break; + case df::item_type::FIGURINE: + case df::item_type::AMULET: + case df::item_type::SCEPTER: + case df::item_type::CROWN: + case df::item_type::RING: + case df::item_type::EARRING: + case df::item_type::BRACELET: + case df::item_type::TOTEM: + case df::item_type::BOOK: + if (int32_t price = get_price(resources.misc_mat.crafts.mat_type, mat_type, resources.misc_mat.crafts.mat_index, mat_subtype, + prices[df::entity_sell_category::Crafts]); price != -1) + return price; + break; + case df::item_type::AMMO: + if (int32_t price = get_price(resources.ammo_type, mat_subtype, prices[df::entity_sell_category::Ammo]); price != -1) + return price; + break; + case df::item_type::GEM: + if (inorganic) { + if (int32_t price = get_price(resources.gems, mat_subtype, prices[df::entity_sell_category::LargeCutGems]); price != -1) + return price; + } + break; + case df::item_type::ANVIL: + if (int32_t price = get_price(resources.metal.anvil.mat_type, mat_type, resources.metal.anvil.mat_index, mat_subtype, + prices[df::entity_sell_category::Anvils]); price != -1) + return price; + break; + case df::item_type::MEAT: + if (int32_t price = get_price(resources.misc_mat.meat.mat_type, mat_type, resources.misc_mat.meat.mat_index, mat_subtype, + prices[df::entity_sell_category::Meat]); price != -1) + return price; + break; + case df::item_type::FISH: + case df::item_type::FISH_RAW: + if (int32_t price = get_price(resources.fish_races, mat_type, resources.fish_castes, mat_subtype, + prices[df::entity_sell_category::Fish]); price != -1) + return price; + break; + case df::item_type::VERMIN: + case df::item_type::PET: + if (int32_t price = get_price(resources.animals.pet_races, mat_type, resources.animals.pet_castes, mat_subtype, + prices[df::entity_sell_category::Pets]); price != -1) + return price; + break; + case df::item_type::SEEDS: + if (int32_t price = get_price(resources.seeds.mat_type, mat_type, resources.seeds.mat_index, mat_subtype, + prices[df::entity_sell_category::Seeds]); price != -1) + return price; + break; + case df::item_type::PLANT: + if (int32_t price = get_price(resources.plants.mat_type, mat_type, resources.plants.mat_index, mat_subtype, + prices[df::entity_sell_category::Plants]); price != -1) + return price; + break; + case df::item_type::SKIN_TANNED: + if (int32_t price = get_price(resources.organic.leather.mat_type, mat_type, resources.organic.leather.mat_index, mat_subtype, + prices[df::entity_sell_category::Leather]); price != -1) + return price; + break; + case df::item_type::PLANT_GROWTH: + if (is_plant) { + if (int32_t price = get_price(resources.tree_fruit_plants, mat_type, resources.tree_fruit_growths, mat_subtype, + prices[df::entity_sell_category::FruitsNuts]); price != -1) + return price; + if (int32_t price = get_price(resources.shrub_fruit_plants, mat_type, resources.shrub_fruit_growths, mat_subtype, + prices[df::entity_sell_category::GardenVegetables]); price != -1) + return price; + } + break; + case df::item_type::THREAD: + if (is_plant) { + if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, + prices[df::entity_sell_category::ThreadPlant]); price != -1) + return price; + } + { + MaterialInfo mi; + mi.decode(mat_type, mat_subtype); + if (mi.isValid() && mi.matches(silk_cat)) { + if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, + prices[df::entity_sell_category::ThreadSilk]); price != -1) + return price; + } + if (mi.isValid() && mi.matches(yarn_cat)) { + if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, + prices[df::entity_sell_category::ThreadYarn]); price != -1) + return price; + } + } + break; + case df::item_type::CLOTH: + if (is_plant) { + if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, + prices[df::entity_sell_category::ClothPlant]); price != -1) + return price; + } + { + MaterialInfo mi; + mi.decode(mat_type, mat_subtype); + if (mi.isValid() && mi.matches(silk_cat)) { + if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, + prices[df::entity_sell_category::ClothSilk]); price != -1) + return price; + } + if (mi.isValid() && mi.matches(yarn_cat)) { + if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, + prices[df::entity_sell_category::ClothYarn]); price != -1) + return price; + } + } + break; + case df::item_type::PANTS: + if (int32_t price = get_price(resources.pants_type, mat_subtype, prices[df::entity_sell_category::Legwear]); price != -1) + return price; + break; + case df::item_type::BACKPACK: + if (int32_t price = get_price(resources.misc_mat.backpacks.mat_type, mat_type, resources.misc_mat.backpacks.mat_index, mat_subtype, + prices[df::entity_sell_category::Backpacks]); price != -1) + return price; + break; + case df::item_type::QUIVER: + if (int32_t price = get_price(resources.misc_mat.quivers.mat_type, mat_type, resources.misc_mat.quivers.mat_index, mat_subtype, + prices[df::entity_sell_category::Quivers]); price != -1) + return price; + break; + case df::item_type::TRAPCOMP: + if (int32_t price = get_price(resources.trapcomp_type, mat_subtype, prices[df::entity_sell_category::TrapComponents]); price != -1) + return price; + break; + case df::item_type::DRINK: + if (int32_t price = get_price(resources.misc_mat.booze.mat_type, mat_type, resources.misc_mat.booze.mat_index, mat_subtype, + prices[df::entity_sell_category::Drinks]); price != -1) + return price; + break; + case df::item_type::POWDER_MISC: + if (int32_t price = get_price(resources.misc_mat.powders.mat_type, mat_type, resources.misc_mat.powders.mat_index, mat_subtype, + prices[df::entity_sell_category::Powders]); price != -1) + return price; + if (int32_t price = get_price(resources.misc_mat.sand.mat_type, mat_type, resources.misc_mat.sand.mat_index, mat_subtype, + prices[df::entity_sell_category::Sand]); price != -1) + return price; + break; + case df::item_type::CHEESE: + if (int32_t price = get_price(resources.misc_mat.cheese.mat_type, mat_type, resources.misc_mat.cheese.mat_index, mat_subtype, + prices[df::entity_sell_category::Cheese]); price != -1) + return price; + break; + case df::item_type::LIQUID_MISC: + if (int32_t price = get_price(resources.misc_mat.extracts.mat_type, mat_type, resources.misc_mat.extracts.mat_index, mat_subtype, + prices[df::entity_sell_category::Extracts]); price != -1) + return price; + break; + case df::item_type::SPLINT: + if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, + prices[df::entity_sell_category::Splints]); price != -1) + return price; + break; + case df::item_type::CRUTCH: + if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, + prices[df::entity_sell_category::Crutches]); price != -1) + return price; + break; + case df::item_type::TOOL: + if (int32_t price = get_price(resources.tool_type, mat_subtype, prices[df::entity_sell_category::Tools]); price != -1) + return price; + break; + case df::item_type::EGG: + if (int32_t price = get_price(resources.egg_races, mat_type, resources.egg_castes, mat_subtype, + prices[df::entity_sell_category::Eggs]); price != -1) + return price; + break; + case df::item_type::SHEET: + if (int32_t price = get_price(resources.organic.parchment.mat_type, mat_type, resources.organic.parchment.mat_index, mat_subtype, + prices[df::entity_sell_category::Parchment]); price != -1) + return price; + break; + default: + break; + } + + for (size_t idx = 0; idx < resources.wood_products.item_type.size(); ++idx) { + if (resources.wood_products.item_type[idx] == item_type && + (resources.wood_products.item_subtype[idx] == -1 || resources.wood_products.item_subtype[idx] == item_subtype) && + resources.wood_products.material.mat_type[idx] == mat_type && + (resources.wood_products.material.mat_index[idx] == -1 || resources.wood_products.material.mat_index[idx] == mat_subtype) && + prices[df::entity_sell_category::Miscellaneous].size() > idx) + return prices[df::entity_sell_category::Miscellaneous][idx]; + } + + return DEFAULT_AGREEMENT_MULTIPLIER; +} + +static int32_t get_sell_request_multiplier(df::item *item, const df::caravan_state *caravan) { + const df::entity_sell_prices *sell_prices = caravan->sell_prices; + if (!sell_prices) + return DEFAULT_AGREEMENT_MULTIPLIER; + + auto caravan_he = df::historical_entity::find(caravan->entity); + if (!caravan_he) + return DEFAULT_AGREEMENT_MULTIPLIER; + + return get_sell_request_multiplier(item, caravan_he->resources, &sell_prices->price[0]); +} + +static int32_t get_trade_agreement_multiplier(df::item *item, const df::caravan_state *caravan, bool caravan_buying) { + if (!caravan) + return DEFAULT_AGREEMENT_MULTIPLIER; + return caravan_buying ? get_buy_request_multiplier(item, caravan->buy_prices) + : get_sell_request_multiplier(item, caravan); +} + +static bool is_requested_trade_good(df::item *item, df::caravan_state *caravan) { + auto trade_state = caravan->trade_state; + if (caravan->time_remaining <= 0 || + (trade_state != df::caravan_state::T_trade_state::Approaching && + trade_state != df::caravan_state::T_trade_state::AtDepot)) + return false; + return get_buy_request_multiplier(item, caravan->buy_prices) > DEFAULT_AGREEMENT_MULTIPLIER; +} + +bool Items::isRequestedTradeGood(df::item *item, df::caravan_state *caravan) { + if (caravan) + return is_requested_trade_good(item, caravan); + + for (auto caravan : df::global::plotinfo->caravans) { + auto trade_state = caravan->trade_state; + if (caravan->time_remaining <= 0 || + (trade_state != df::caravan_state::T_trade_state::Approaching && + trade_state != df::caravan_state::T_trade_state::AtDepot)) + continue; + if (get_buy_request_multiplier(item, caravan->buy_prices) > DEFAULT_AGREEMENT_MULTIPLIER) + return true; + } + return false; +} + +int Items::getValue(df::item *item, df::caravan_state *caravan, bool caravan_buying) +>>>>>>> Stashed changes { CHECK_NULL_POINTER(item); From 9849885df6e370a17b658d2558f519592b05624f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 6 Jul 2023 03:23:17 -0700 Subject: [PATCH 061/851] Revert "generalize dfhack.items.isRequestedTradeGood" This reverts commit aa6d28bab60868e42b366af930e17219be54a828. --- docs/dev/Lua API.rst | 15 - library/include/modules/Items.h | 5 - library/modules/Items.cpp | 495 -------------------------------- 3 files changed, 515 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 7f99af2d3..785e477dd 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1770,22 +1770,7 @@ Items module * ``dfhack.items.getValue(item)`` -<<<<<<< Updated upstream Calculates the Basic Value of an item, as seen in the View Item screen. -======= - Calculates the value of an item. If a ``df.caravan_state`` object is given - (from ``df.global.plotinfo.caravans`` or - ``df.global.main_interface.trade.mer``), then the value is modified by civ - properties and any trade agreements that might be in effect. In this case, - specify ``caravan_buying`` as ``true`` to get the price the caravan will pay - for the item and ``false`` to get the price that the caravan will sell the - item for. - -* ``dfhack.items.isRequestedTradeGood(item[, caravan_state])`` - - Returns whether a caravan will pay extra for the given item. If caravan_state - is not given, checks all active caravans. ->>>>>>> Stashed changes * ``dfhack.items.createItem(item_type, item_subtype, mat_type, mat_index, unit)`` diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h index f3dfe6dae..08737fb2b 100644 --- a/library/include/modules/Items.h +++ b/library/include/modules/Items.h @@ -202,11 +202,6 @@ DFHACK_EXPORT bool canTrade(df::item *item); DFHACK_EXPORT bool canTradeWithContents(df::item *item); /// marks the given item for trade at the given depot DFHACK_EXPORT bool markForTrade(df::item *item, df::building_tradedepotst *depot); -<<<<<<< Updated upstream -======= -/// Returns true if an active caravan will pay extra for the given item -DFHACK_EXPORT bool isRequestedTradeGood(df::item *item, df::caravan_state *caravan = NULL); ->>>>>>> Stashed changes /// Checks whether the item is an assigned hauling vehicle DFHACK_EXPORT bool isRouteVehicle(df::item *item); diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index e67fc64a6..f98c7c46b 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -1435,502 +1435,7 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat return value; } -<<<<<<< Updated upstream int Items::getValue(df::item *item) -======= -static int32_t get_war_multiplier(df::item *item, df::caravan_state *caravan) { - static const int32_t DEFAULT_WAR_MULTIPLIER = 256; - - if (!caravan) - return DEFAULT_WAR_MULTIPLIER; - auto caravan_he = df::historical_entity::find(caravan->entity); - if (!caravan_he) - return DEFAULT_WAR_MULTIPLIER; - int32_t war_alignment = caravan_he->entity_raw->sphere_alignment[df::sphere_type::WAR]; - if (war_alignment == DEFAULT_WAR_MULTIPLIER) - return DEFAULT_WAR_MULTIPLIER; - switch (item->getType()) { - case df::item_type::WEAPON: - { - auto weap_def = df::itemdef_weaponst::find(item->getSubtype()); - auto caravan_cre_raw = df::creature_raw::find(caravan_he->race); - if (!weap_def || !caravan_cre_raw || caravan_cre_raw->adultsize < weap_def->minimum_size) - return DEFAULT_WAR_MULTIPLIER; - break; - } - case df::item_type::ARMOR: - case df::item_type::SHOES: - case df::item_type::HELM: - case df::item_type::GLOVES: - case df::item_type::PANTS: - { - if (item->getEffectiveArmorLevel() <= 0) - return DEFAULT_WAR_MULTIPLIER; - auto caravan_cre_raw = df::creature_raw::find(caravan_he->race); - auto maker_cre_raw = df::creature_raw::find(item->getMakerRace()); - if (!caravan_cre_raw || !maker_cre_raw) - return DEFAULT_WAR_MULTIPLIER; - if (caravan_cre_raw->adultsize < ((maker_cre_raw->adultsize * 6) / 7)) - return DEFAULT_WAR_MULTIPLIER; - if (caravan_cre_raw->adultsize > ((maker_cre_raw->adultsize * 8) / 7)) - return DEFAULT_WAR_MULTIPLIER; - break; - } - case df::item_type::SHIELD: - case df::item_type::AMMO: - case df::item_type::BACKPACK: - case df::item_type::QUIVER: - break; - default: - return DEFAULT_WAR_MULTIPLIER; - } - return war_alignment; -} - -static const int32_t DEFAULT_AGREEMENT_MULTIPLIER = 128; - -static int32_t get_buy_request_multiplier(df::item *item, const df::entity_buy_prices *buy_prices) { - if (!buy_prices) - return DEFAULT_AGREEMENT_MULTIPLIER; - - int16_t item_type = item->getType(); - int16_t item_subtype = item->getSubtype(); - int16_t mat_type = item->getMaterial(); - int32_t mat_subtype = item->getMaterialIndex(); - - for (size_t idx = 0; idx < buy_prices->price.size(); ++idx) { - if (buy_prices->items->item_type[idx] != item_type) - continue; - if (buy_prices->items->item_subtype[idx] != -1 && buy_prices->items->item_subtype[idx] != item_subtype) - continue; - if (buy_prices->items->mat_types[idx] != -1 && buy_prices->items->mat_types[idx] != mat_type) - continue; - if (buy_prices->items->mat_indices[idx] != -1 && buy_prices->items->mat_indices[idx] != mat_subtype) - continue; - return buy_prices->price[idx]; - } - return DEFAULT_AGREEMENT_MULTIPLIER; -} - -template -static int get_price(const std::vector &res, int32_t val, const std::vector &pri) { - for (size_t idx = 0; idx < res.size(); ++idx) { - if (res[idx] == val && pri.size() > idx) - return pri[idx]; - } - return -1; -} - -template -static int get_price(const std::vector &mat_res, int32_t mat, const std::vector &gloss_res, int32_t gloss, const std::vector &pri) { - for (size_t idx = 0; idx < mat_res.size(); ++idx) { - if (mat_res[idx] == mat && (gloss_res[idx] == -1 || gloss_res[idx] == gloss) && pri.size() > idx) - return pri[idx]; - } - return -1; -} - -static const uint16_t PLANT_BASE = 419; -static const uint16_t NUM_PLANT_TYPES = 200; - -static int32_t get_sell_request_multiplier(df::item *item, const df::historical_entity::T_resources &resources, const std::vector *prices) { - 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 const df::dfhack_material_category leather_cat(df::dfhack_material_category::mask_leather); - - int16_t item_type = item->getType(); - int16_t item_subtype = item->getSubtype(); - int16_t mat_type = item->getMaterial(); - int32_t mat_subtype = item->getMaterialIndex(); - - bool inorganic = mat_type == df::builtin_mats::INORGANIC; - bool is_plant = (uint16_t)(mat_type - PLANT_BASE) < NUM_PLANT_TYPES; - - switch (item_type) { - case df::item_type::BAR: - if (inorganic) { - if (int32_t price = get_price(resources.metals, mat_subtype, prices[df::entity_sell_category::MetalBars]); price != -1) - return price; - } - break; - case df::item_type::SMALLGEM: - if (inorganic) { - if (int32_t price = get_price(resources.gems, mat_subtype, prices[df::entity_sell_category::SmallCutGems]); price != -1) - return price; - } - break; - case df::item_type::BLOCKS: - if (inorganic) { - if (int32_t price = get_price(resources.stones, mat_subtype, prices[df::entity_sell_category::StoneBlocks]); price != -1) - return price; - } - break; - case df::item_type::ROUGH: - if (int32_t price = get_price(resources.misc_mat.glass.mat_type, mat_type, resources.misc_mat.glass.mat_index, mat_subtype, - prices[df::entity_sell_category::Glass]); price != -1) - return price; - break; - case df::item_type::BOULDER: - if (int32_t price = get_price(resources.stones, mat_subtype, prices[df::entity_sell_category::Stone]); price != -1) - return price; - if (int32_t price = get_price(resources.misc_mat.clay.mat_type, mat_type, resources.misc_mat.clay.mat_index, mat_subtype, - prices[df::entity_sell_category::Clay]); price != -1) - return price; - break; - case df::item_type::WOOD: - if (int32_t price = get_price(resources.organic.wood.mat_type, mat_type, resources.organic.wood.mat_index, mat_subtype, - prices[df::entity_sell_category::Wood]); price != -1) - return price; - break; - case df::item_type::CHAIN: - if (is_plant) { - if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, - prices[df::entity_sell_category::RopesPlant]); price != -1) - return price; - } - { - MaterialInfo mi; - mi.decode(mat_type, mat_subtype); - if (mi.isValid()) { - if (mi.matches(silk_cat)) { - if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, - prices[df::entity_sell_category::RopesSilk]); price != -1) - return price; - } - if (mi.matches(yarn_cat)) { - if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, - prices[df::entity_sell_category::RopesYarn]); price != -1) - return price; - } - } - } - break; - case df::item_type::FLASK: - if (int32_t price = get_price(resources.misc_mat.flasks.mat_type, mat_type, resources.misc_mat.flasks.mat_index, mat_subtype, - prices[df::entity_sell_category::FlasksWaterskins]); price != -1) - return price; - break; - case df::item_type::GOBLET: - if (int32_t price = get_price(resources.misc_mat.crafts.mat_type, mat_type, resources.misc_mat.crafts.mat_index, mat_subtype, - prices[df::entity_sell_category::CupsMugsGoblets]); price != -1) - return price; - break; - case df::item_type::INSTRUMENT: - if (int32_t price = get_price(resources.instrument_type, mat_subtype, prices[df::entity_sell_category::Instruments]); price != -1) - return price; - break; - case df::item_type::TOY: - if (int32_t price = get_price(resources.toy_type, mat_subtype, prices[df::entity_sell_category::Toys]); price != -1) - return price; - break; - case df::item_type::CAGE: - if (int32_t price = get_price(resources.misc_mat.cages.mat_type, mat_type, resources.misc_mat.cages.mat_index, mat_subtype, - prices[df::entity_sell_category::Cages]); price != -1) - return price; - break; - case df::item_type::BARREL: - if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, - prices[df::entity_sell_category::Barrels]); price != -1) - return price; - break; - case df::item_type::BUCKET: - if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, - prices[df::entity_sell_category::Buckets]); price != -1) - return price; - break; - case df::item_type::WEAPON: - if (int32_t price = get_price(resources.weapon_type, mat_subtype, prices[df::entity_sell_category::Weapons]); price != -1) - return price; - if (int32_t price = get_price(resources.digger_type, mat_subtype, prices[df::entity_sell_category::DiggingImplements]); price != -1) - return price; - if (int32_t price = get_price(resources.training_weapon_type, mat_subtype, prices[df::entity_sell_category::TrainingWeapons]); price != -1) - return price; - break; - case df::item_type::ARMOR: - if (int32_t price = get_price(resources.armor_type, mat_subtype, prices[df::entity_sell_category::Bodywear]); price != -1) - return price; - break; - case df::item_type::SHOES: - if (int32_t price = get_price(resources.shoes_type, mat_subtype, prices[df::entity_sell_category::Footwear]); price != -1) - return price; - break; - case df::item_type::SHIELD: - if (int32_t price = get_price(resources.shield_type, mat_subtype, prices[df::entity_sell_category::Shields]); price != -1) - return price; - break; - case df::item_type::HELM: - if (int32_t price = get_price(resources.helm_type, mat_subtype, prices[df::entity_sell_category::Headwear]); price != -1) - return price; - break; - case df::item_type::GLOVES: - if (int32_t price = get_price(resources.gloves_type, mat_subtype, prices[df::entity_sell_category::Handwear]); price != -1) - return price; - break; - case df::item_type::BAG: - { - MaterialInfo mi; - mi.decode(mat_type, mat_subtype); - if (mi.isValid() && mi.matches(leather_cat)) { - if (int32_t price = get_price(resources.organic.leather.mat_type, mat_type, resources.organic.leather.mat_index, mat_subtype, - prices[df::entity_sell_category::BagsLeather]); price != -1) - return price; - } - if (is_plant) { - if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, - prices[df::entity_sell_category::BagsPlant]); price != -1) - return price; - } - if (mi.isValid() && mi.matches(silk_cat)) { - if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, - prices[df::entity_sell_category::BagsSilk]); price != -1) - return price; - } - if (mi.isValid() && mi.matches(yarn_cat)) { - if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, - prices[df::entity_sell_category::BagsYarn]); price != -1) - return price; - } - } - break; - case df::item_type::FIGURINE: - case df::item_type::AMULET: - case df::item_type::SCEPTER: - case df::item_type::CROWN: - case df::item_type::RING: - case df::item_type::EARRING: - case df::item_type::BRACELET: - case df::item_type::TOTEM: - case df::item_type::BOOK: - if (int32_t price = get_price(resources.misc_mat.crafts.mat_type, mat_type, resources.misc_mat.crafts.mat_index, mat_subtype, - prices[df::entity_sell_category::Crafts]); price != -1) - return price; - break; - case df::item_type::AMMO: - if (int32_t price = get_price(resources.ammo_type, mat_subtype, prices[df::entity_sell_category::Ammo]); price != -1) - return price; - break; - case df::item_type::GEM: - if (inorganic) { - if (int32_t price = get_price(resources.gems, mat_subtype, prices[df::entity_sell_category::LargeCutGems]); price != -1) - return price; - } - break; - case df::item_type::ANVIL: - if (int32_t price = get_price(resources.metal.anvil.mat_type, mat_type, resources.metal.anvil.mat_index, mat_subtype, - prices[df::entity_sell_category::Anvils]); price != -1) - return price; - break; - case df::item_type::MEAT: - if (int32_t price = get_price(resources.misc_mat.meat.mat_type, mat_type, resources.misc_mat.meat.mat_index, mat_subtype, - prices[df::entity_sell_category::Meat]); price != -1) - return price; - break; - case df::item_type::FISH: - case df::item_type::FISH_RAW: - if (int32_t price = get_price(resources.fish_races, mat_type, resources.fish_castes, mat_subtype, - prices[df::entity_sell_category::Fish]); price != -1) - return price; - break; - case df::item_type::VERMIN: - case df::item_type::PET: - if (int32_t price = get_price(resources.animals.pet_races, mat_type, resources.animals.pet_castes, mat_subtype, - prices[df::entity_sell_category::Pets]); price != -1) - return price; - break; - case df::item_type::SEEDS: - if (int32_t price = get_price(resources.seeds.mat_type, mat_type, resources.seeds.mat_index, mat_subtype, - prices[df::entity_sell_category::Seeds]); price != -1) - return price; - break; - case df::item_type::PLANT: - if (int32_t price = get_price(resources.plants.mat_type, mat_type, resources.plants.mat_index, mat_subtype, - prices[df::entity_sell_category::Plants]); price != -1) - return price; - break; - case df::item_type::SKIN_TANNED: - if (int32_t price = get_price(resources.organic.leather.mat_type, mat_type, resources.organic.leather.mat_index, mat_subtype, - prices[df::entity_sell_category::Leather]); price != -1) - return price; - break; - case df::item_type::PLANT_GROWTH: - if (is_plant) { - if (int32_t price = get_price(resources.tree_fruit_plants, mat_type, resources.tree_fruit_growths, mat_subtype, - prices[df::entity_sell_category::FruitsNuts]); price != -1) - return price; - if (int32_t price = get_price(resources.shrub_fruit_plants, mat_type, resources.shrub_fruit_growths, mat_subtype, - prices[df::entity_sell_category::GardenVegetables]); price != -1) - return price; - } - break; - case df::item_type::THREAD: - if (is_plant) { - if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, - prices[df::entity_sell_category::ThreadPlant]); price != -1) - return price; - } - { - MaterialInfo mi; - mi.decode(mat_type, mat_subtype); - if (mi.isValid() && mi.matches(silk_cat)) { - if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, - prices[df::entity_sell_category::ThreadSilk]); price != -1) - return price; - } - if (mi.isValid() && mi.matches(yarn_cat)) { - if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, - prices[df::entity_sell_category::ThreadYarn]); price != -1) - return price; - } - } - break; - case df::item_type::CLOTH: - if (is_plant) { - if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, - prices[df::entity_sell_category::ClothPlant]); price != -1) - return price; - } - { - MaterialInfo mi; - mi.decode(mat_type, mat_subtype); - if (mi.isValid() && mi.matches(silk_cat)) { - if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, - prices[df::entity_sell_category::ClothSilk]); price != -1) - return price; - } - if (mi.isValid() && mi.matches(yarn_cat)) { - if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, - prices[df::entity_sell_category::ClothYarn]); price != -1) - return price; - } - } - break; - case df::item_type::PANTS: - if (int32_t price = get_price(resources.pants_type, mat_subtype, prices[df::entity_sell_category::Legwear]); price != -1) - return price; - break; - case df::item_type::BACKPACK: - if (int32_t price = get_price(resources.misc_mat.backpacks.mat_type, mat_type, resources.misc_mat.backpacks.mat_index, mat_subtype, - prices[df::entity_sell_category::Backpacks]); price != -1) - return price; - break; - case df::item_type::QUIVER: - if (int32_t price = get_price(resources.misc_mat.quivers.mat_type, mat_type, resources.misc_mat.quivers.mat_index, mat_subtype, - prices[df::entity_sell_category::Quivers]); price != -1) - return price; - break; - case df::item_type::TRAPCOMP: - if (int32_t price = get_price(resources.trapcomp_type, mat_subtype, prices[df::entity_sell_category::TrapComponents]); price != -1) - return price; - break; - case df::item_type::DRINK: - if (int32_t price = get_price(resources.misc_mat.booze.mat_type, mat_type, resources.misc_mat.booze.mat_index, mat_subtype, - prices[df::entity_sell_category::Drinks]); price != -1) - return price; - break; - case df::item_type::POWDER_MISC: - if (int32_t price = get_price(resources.misc_mat.powders.mat_type, mat_type, resources.misc_mat.powders.mat_index, mat_subtype, - prices[df::entity_sell_category::Powders]); price != -1) - return price; - if (int32_t price = get_price(resources.misc_mat.sand.mat_type, mat_type, resources.misc_mat.sand.mat_index, mat_subtype, - prices[df::entity_sell_category::Sand]); price != -1) - return price; - break; - case df::item_type::CHEESE: - if (int32_t price = get_price(resources.misc_mat.cheese.mat_type, mat_type, resources.misc_mat.cheese.mat_index, mat_subtype, - prices[df::entity_sell_category::Cheese]); price != -1) - return price; - break; - case df::item_type::LIQUID_MISC: - if (int32_t price = get_price(resources.misc_mat.extracts.mat_type, mat_type, resources.misc_mat.extracts.mat_index, mat_subtype, - prices[df::entity_sell_category::Extracts]); price != -1) - return price; - break; - case df::item_type::SPLINT: - if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, - prices[df::entity_sell_category::Splints]); price != -1) - return price; - break; - case df::item_type::CRUTCH: - if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, - prices[df::entity_sell_category::Crutches]); price != -1) - return price; - break; - case df::item_type::TOOL: - if (int32_t price = get_price(resources.tool_type, mat_subtype, prices[df::entity_sell_category::Tools]); price != -1) - return price; - break; - case df::item_type::EGG: - if (int32_t price = get_price(resources.egg_races, mat_type, resources.egg_castes, mat_subtype, - prices[df::entity_sell_category::Eggs]); price != -1) - return price; - break; - case df::item_type::SHEET: - if (int32_t price = get_price(resources.organic.parchment.mat_type, mat_type, resources.organic.parchment.mat_index, mat_subtype, - prices[df::entity_sell_category::Parchment]); price != -1) - return price; - break; - default: - break; - } - - for (size_t idx = 0; idx < resources.wood_products.item_type.size(); ++idx) { - if (resources.wood_products.item_type[idx] == item_type && - (resources.wood_products.item_subtype[idx] == -1 || resources.wood_products.item_subtype[idx] == item_subtype) && - resources.wood_products.material.mat_type[idx] == mat_type && - (resources.wood_products.material.mat_index[idx] == -1 || resources.wood_products.material.mat_index[idx] == mat_subtype) && - prices[df::entity_sell_category::Miscellaneous].size() > idx) - return prices[df::entity_sell_category::Miscellaneous][idx]; - } - - return DEFAULT_AGREEMENT_MULTIPLIER; -} - -static int32_t get_sell_request_multiplier(df::item *item, const df::caravan_state *caravan) { - const df::entity_sell_prices *sell_prices = caravan->sell_prices; - if (!sell_prices) - return DEFAULT_AGREEMENT_MULTIPLIER; - - auto caravan_he = df::historical_entity::find(caravan->entity); - if (!caravan_he) - return DEFAULT_AGREEMENT_MULTIPLIER; - - return get_sell_request_multiplier(item, caravan_he->resources, &sell_prices->price[0]); -} - -static int32_t get_trade_agreement_multiplier(df::item *item, const df::caravan_state *caravan, bool caravan_buying) { - if (!caravan) - return DEFAULT_AGREEMENT_MULTIPLIER; - return caravan_buying ? get_buy_request_multiplier(item, caravan->buy_prices) - : get_sell_request_multiplier(item, caravan); -} - -static bool is_requested_trade_good(df::item *item, df::caravan_state *caravan) { - auto trade_state = caravan->trade_state; - if (caravan->time_remaining <= 0 || - (trade_state != df::caravan_state::T_trade_state::Approaching && - trade_state != df::caravan_state::T_trade_state::AtDepot)) - return false; - return get_buy_request_multiplier(item, caravan->buy_prices) > DEFAULT_AGREEMENT_MULTIPLIER; -} - -bool Items::isRequestedTradeGood(df::item *item, df::caravan_state *caravan) { - if (caravan) - return is_requested_trade_good(item, caravan); - - for (auto caravan : df::global::plotinfo->caravans) { - auto trade_state = caravan->trade_state; - if (caravan->time_remaining <= 0 || - (trade_state != df::caravan_state::T_trade_state::Approaching && - trade_state != df::caravan_state::T_trade_state::AtDepot)) - continue; - if (get_buy_request_multiplier(item, caravan->buy_prices) > DEFAULT_AGREEMENT_MULTIPLIER) - return true; - } - return false; -} - -int Items::getValue(df::item *item, df::caravan_state *caravan, bool caravan_buying) ->>>>>>> Stashed changes { CHECK_NULL_POINTER(item); From c2e647b79b7befc81dd56f9e011a647967413a22 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 3 Jul 2023 18:05:30 -0700 Subject: [PATCH 062/851] fix item prices and algorithm adjust prices according to race WAR affinity --- docs/changelog.txt | 2 + docs/dev/Lua API.rst | 12 +++- library/include/modules/Items.h | 5 +- library/modules/Items.cpp | 115 ++++++++++++++++++++++++++++---- 4 files changed, 117 insertions(+), 17 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 8971dd0ac..4a8a100df 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -47,10 +47,12 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - ``Units::getUnitByNobleRole``, ``Units::getUnitsByNobleRole``: unit lookup API by role ## Internals +- Price calculations fixed for many item types ## Lua - ``dfhack.items.markForTrade``: new API for marking items for trade - ``dfhack.units.getUnitByNobleRole``, ``dfhack.units.getUnitsByNobleRole``: unit lookup API by role +- ``dfhack.items.getValue``: gained optional ``caravan`` and ``caravan_buying`` parameters for prices that take trader races and agreements into account ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 785e477dd..e81a34de3 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1768,9 +1768,15 @@ Items module Calculates the base value for an item of the specified type and material. -* ``dfhack.items.getValue(item)`` - - Calculates the Basic Value of an item, as seen in the View Item screen. +* ``dfhack.items.getValue(item[, caravan_state, caravan_buying])`` + + Calculates the value of an item. If a ``df.caravan_state`` object is given + (from ``df.global.plotinfo.caravans`` or + ``df.global.main_interface.trade.mer``), then the value is modified by civ + properties and any trade agreements that might be in effect. In this case, + specify ``caravan_buying`` as ``true`` to get the price the caravan will pay + for the item and ``false`` to get the price that the caravan will sell the + item for. * ``dfhack.items.createItem(item_type, item_subtype, mat_type, mat_index, unit)`` diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h index 08737fb2b..6cce5d2f1 100644 --- a/library/include/modules/Items.h +++ b/library/include/modules/Items.h @@ -34,6 +34,7 @@ distribution. #include "DataDefs.h" #include "df/building_tradedepotst.h" +#include "df/caravan_state.h" #include "df/item.h" #include "df/item_type.h" #include "df/general_ref.h" @@ -189,8 +190,8 @@ DFHACK_EXPORT df::proj_itemst *makeProjectile(MapExtras::MapCache &mc, df::item /// Gets value of base-quality item with specified type and material DFHACK_EXPORT int getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat_type, int32_t mat_subtype); -/// Gets the value of a specific item, ignoring civ values and trade agreements -DFHACK_EXPORT int getValue(df::item *item); +/// Gets the value of a specific item, taking into account civ values and trade agreements if a caravan is given +DFHACK_EXPORT int getValue(df::item *item, df::caravan_state *caravan = NULL, bool caravan_buying = false); DFHACK_EXPORT int32_t createItem(df::item_type type, int16_t item_subtype, int16_t mat_type, int32_t mat_index, df::unit* creator); diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index f98c7c46b..a2107aa1d 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -50,8 +50,10 @@ using namespace std; #include "df/building.h" #include "df/building_actual.h" #include "df/building_tradedepotst.h" +#include "df/caravan_state.h" #include "df/caste_raw.h" #include "df/creature_raw.h" +#include "df/entity_raw.h" #include "df/general_ref.h" #include "df/general_ref_building_holderst.h" #include "df/general_ref_contained_in_itemst.h" @@ -828,15 +830,15 @@ std::string Items::getDescription(df::item *item, int type, bool decorate) item->getItemDescription(&tmp, type); if (decorate) { - if (item->flags.bits.foreign) - tmp = "(" + tmp + ")"; - addQuality(tmp, item->getQuality()); if (item->isImproved()) { tmp = '\xAE' + tmp + '\xAF'; // («) + tmp + (») addQuality(tmp, item->getImprovementQuality()); } + + if (item->flags.bits.foreign) + tmp = "(" + tmp + ")"; } return tmp; @@ -1197,18 +1199,24 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat switch (item_type) { case item_type::BAR: - case item_type::SMALLGEM: case item_type::BLOCKS: case item_type::SKIN_TANNED: value = 5; break; - case item_type::ROUGH: + case item_type::SMALLGEM: + value = 20; + break; + case item_type::BOULDER: case item_type::WOOD: value = 3; break; + case item_type::ROUGH: + value = 6; + break; + case item_type::DOOR: case item_type::FLOODGATE: case item_type::BED: @@ -1224,6 +1232,7 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat case item_type::TABLE: case item_type::COFFIN: case item_type::BOX: + case item_type::BAG: case item_type::BIN: case item_type::ARMORSTAND: case item_type::WEAPONRACK: @@ -1367,6 +1376,7 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat case item_type::COIN: case item_type::GLOB: case item_type::ORTHOPEDIC_CAST: + case item_type::BRANCH: value = 1; break; @@ -1435,7 +1445,61 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat return value; } -int Items::getValue(df::item *item) +static int32_t get_war_multiplier(df::item *item, df::caravan_state *caravan) { + static const int32_t DEFAULT_MULTIPLIER = 256; + + if (!caravan) + return DEFAULT_MULTIPLIER; + auto caravan_he = df::historical_entity::find(caravan->entity); + if (!caravan_he) + return DEFAULT_MULTIPLIER; + int32_t war_alignment = caravan_he->entity_raw->sphere_alignment[df::sphere_type::WAR]; + if (war_alignment == DEFAULT_MULTIPLIER) + return DEFAULT_MULTIPLIER; + switch (item->getType()) { + case df::item_type::WEAPON: + { + auto weap_def = df::itemdef_weaponst::find(item->getSubtype()); + auto caravan_cre_raw = df::creature_raw::find(caravan_he->race); + if (!weap_def || !caravan_cre_raw || caravan_cre_raw->adultsize < weap_def->minimum_size) + return DEFAULT_MULTIPLIER; + break; + } + case df::item_type::ARMOR: + case df::item_type::SHOES: + case df::item_type::HELM: + case df::item_type::GLOVES: + case df::item_type::PANTS: + { + if (item->getEffectiveArmorLevel() <= 0) + return DEFAULT_MULTIPLIER; + auto caravan_cre_raw = df::creature_raw::find(caravan_he->race); + auto maker_cre_raw = df::creature_raw::find(item->getMakerRace()); + if (!caravan_cre_raw || !maker_cre_raw) + return DEFAULT_MULTIPLIER; + if (caravan_cre_raw->adultsize < ((maker_cre_raw->adultsize * 6) / 7)) + return DEFAULT_MULTIPLIER; + if (caravan_cre_raw->adultsize > ((maker_cre_raw->adultsize * 8) / 7)) + return DEFAULT_MULTIPLIER; + break; + } + case df::item_type::SHIELD: + case df::item_type::AMMO: + case df::item_type::BACKPACK: + case df::item_type::QUIVER: + break; + default: + return DEFAULT_MULTIPLIER; + } + return war_alignment; +} + +// returns 0 if the multiplier would be equal to 1.0 +static float get_trade_agreement_multiplier(df::item *item, df::caravan_state *caravan, bool caravan_buying) { + return 0; +} + +int Items::getValue(df::item *item, df::caravan_state *caravan, bool caravan_buying) { CHECK_NULL_POINTER(item); @@ -1447,16 +1511,38 @@ int Items::getValue(df::item *item) // Get base value for item type, subtype, and material int value = getItemBaseValue(item_type, item_subtype, mat_type, mat_subtype); - // Ignore entity value modifications + // entity value modifications + value *= get_war_multiplier(item, caravan); + value >>= 8; // Improve value based on quality - int quality = item->getQuality(); - value *= (quality + 1); - if (quality == 5) + switch (item->getQuality()) { + case 1: + value *= 1.1; + value += 3; + break; + case 2: + value *= 1.2; + value += 6; + break; + case 3: + value *= 1.333; + value += 10; + break; + case 4: + value *= 1.5; + value += 15; + break; + case 5: value *= 2; + value += 30; + break; + default: + break; + } // Add improvement values - int impValue = item->getThreadDyeValue(NULL) + item->getImprovementsValue(NULL); + int impValue = item->getThreadDyeValue(caravan) + item->getImprovementsValue(caravan); if (item_type == item_type::AMMO) // Ammo improvements are worth less impValue /= 30; value += impValue; @@ -1481,12 +1567,17 @@ int Items::getValue(df::item *item) if (item->flags.bits.artifact_mood) value *= 10; + // modify buy/sell prices if a caravan is given + float trade_agreement_multiplier = get_trade_agreement_multiplier(item, caravan, caravan_buying); + if (trade_agreement_multiplier > 0) + value *= trade_agreement_multiplier; + // Boost value from stack size value *= item->getStackSize(); // ...but not for coins if (item_type == item_type::COIN) { - value /= 500; + value /= 50; if (!value) value = 1; } From 2aeb86ba8f553c209a646842e2b9615f00685605 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 3 Jul 2023 18:45:33 -0700 Subject: [PATCH 063/851] implement trade agreement buy prices --- library/modules/Items.cpp | 66 ++++++++++++++++++++++++++++----------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index a2107aa1d..63c2a1992 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -53,6 +53,9 @@ using namespace std; #include "df/caravan_state.h" #include "df/caste_raw.h" #include "df/creature_raw.h" +#include "df/entity_buy_prices.h" +#include "df/entity_buy_requests.h" +#include "df/entity_sell_prices.h" #include "df/entity_raw.h" #include "df/general_ref.h" #include "df/general_ref_building_holderst.h" @@ -1446,23 +1449,23 @@ int Items::getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat } static int32_t get_war_multiplier(df::item *item, df::caravan_state *caravan) { - static const int32_t DEFAULT_MULTIPLIER = 256; + static const int32_t DEFAULT_WAR_MULTIPLIER = 256; if (!caravan) - return DEFAULT_MULTIPLIER; + return DEFAULT_WAR_MULTIPLIER; auto caravan_he = df::historical_entity::find(caravan->entity); if (!caravan_he) - return DEFAULT_MULTIPLIER; + return DEFAULT_WAR_MULTIPLIER; int32_t war_alignment = caravan_he->entity_raw->sphere_alignment[df::sphere_type::WAR]; - if (war_alignment == DEFAULT_MULTIPLIER) - return DEFAULT_MULTIPLIER; + if (war_alignment == DEFAULT_WAR_MULTIPLIER) + return DEFAULT_WAR_MULTIPLIER; switch (item->getType()) { case df::item_type::WEAPON: { auto weap_def = df::itemdef_weaponst::find(item->getSubtype()); auto caravan_cre_raw = df::creature_raw::find(caravan_he->race); if (!weap_def || !caravan_cre_raw || caravan_cre_raw->adultsize < weap_def->minimum_size) - return DEFAULT_MULTIPLIER; + return DEFAULT_WAR_MULTIPLIER; break; } case df::item_type::ARMOR: @@ -1472,15 +1475,15 @@ static int32_t get_war_multiplier(df::item *item, df::caravan_state *caravan) { case df::item_type::PANTS: { if (item->getEffectiveArmorLevel() <= 0) - return DEFAULT_MULTIPLIER; + return DEFAULT_WAR_MULTIPLIER; auto caravan_cre_raw = df::creature_raw::find(caravan_he->race); auto maker_cre_raw = df::creature_raw::find(item->getMakerRace()); if (!caravan_cre_raw || !maker_cre_raw) - return DEFAULT_MULTIPLIER; + return DEFAULT_WAR_MULTIPLIER; if (caravan_cre_raw->adultsize < ((maker_cre_raw->adultsize * 6) / 7)) - return DEFAULT_MULTIPLIER; + return DEFAULT_WAR_MULTIPLIER; if (caravan_cre_raw->adultsize > ((maker_cre_raw->adultsize * 8) / 7)) - return DEFAULT_MULTIPLIER; + return DEFAULT_WAR_MULTIPLIER; break; } case df::item_type::SHIELD: @@ -1489,14 +1492,42 @@ static int32_t get_war_multiplier(df::item *item, df::caravan_state *caravan) { case df::item_type::QUIVER: break; default: - return DEFAULT_MULTIPLIER; + return DEFAULT_WAR_MULTIPLIER; } return war_alignment; } -// returns 0 if the multiplier would be equal to 1.0 -static float get_trade_agreement_multiplier(df::item *item, df::caravan_state *caravan, bool caravan_buying) { - return 0; +static const int32_t DEFAULT_AGREEMENT_MULTIPLIER = 128; + +static int32_t get_buy_request_multiplier(df::item *item, const df::entity_buy_prices *buy_prices) { + int16_t item_type = item->getType(); + int16_t item_subtype = item->getSubtype(); + int16_t mat_type = item->getMaterial(); + int32_t mat_subtype = item->getMaterialIndex(); + + for (size_t idx = 0; idx < buy_prices->price.size(); ++idx) { + if (buy_prices->items->item_type[idx] != item_type) + continue; + if (buy_prices->items->item_subtype[idx] != -1 && buy_prices->items->item_subtype[idx] != item_subtype) + continue; + if (buy_prices->items->mat_types[idx] != -1 && buy_prices->items->mat_types[idx] != mat_type) + continue; + if (buy_prices->items->mat_indices[idx] != -1 && buy_prices->items->mat_indices[idx] != mat_subtype) + continue; + return buy_prices->price[idx]; + } + return DEFAULT_AGREEMENT_MULTIPLIER; +} + +static int32_t get_sell_request_multiplier(df::item *item, const df::entity_sell_prices *sell_prices) { + return DEFAULT_AGREEMENT_MULTIPLIER; +} + +static int32_t get_trade_agreement_multiplier(df::item *item, df::caravan_state *caravan, bool caravan_buying) { + if (!caravan) + return DEFAULT_AGREEMENT_MULTIPLIER; + return caravan_buying ? get_buy_request_multiplier(item, caravan->buy_prices) + : get_sell_request_multiplier(item, caravan->sell_prices); } int Items::getValue(df::item *item, df::caravan_state *caravan, bool caravan_buying) @@ -1567,10 +1598,9 @@ int Items::getValue(df::item *item, df::caravan_state *caravan, bool caravan_buy if (item->flags.bits.artifact_mood) value *= 10; - // modify buy/sell prices if a caravan is given - float trade_agreement_multiplier = get_trade_agreement_multiplier(item, caravan, caravan_buying); - if (trade_agreement_multiplier > 0) - value *= trade_agreement_multiplier; + // modify buy/sell prices + value *= get_trade_agreement_multiplier(item, caravan, caravan_buying); + value >>= 7; // Boost value from stack size value *= item->getStackSize(); From c45dcdd7b0aa1d458d06e5ee2cc0dfd2a0866c0f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 4 Jul 2023 01:53:45 -0700 Subject: [PATCH 064/851] implement sell_prices adjustments --- library/modules/Items.cpp | 393 +++++++++++++++++++++++++++++++++++++- 1 file changed, 390 insertions(+), 3 deletions(-) diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 63c2a1992..537be7c3a 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -50,11 +50,14 @@ using namespace std; #include "df/building.h" #include "df/building_actual.h" #include "df/building_tradedepotst.h" +#include "df/builtin_mats.h" #include "df/caravan_state.h" #include "df/caste_raw.h" #include "df/creature_raw.h" +#include "df/dfhack_material_category.h" #include "df/entity_buy_prices.h" #include "df/entity_buy_requests.h" +#include "df/entity_sell_category.h" #include "df/entity_sell_prices.h" #include "df/entity_raw.h" #include "df/general_ref.h" @@ -1500,6 +1503,9 @@ static int32_t get_war_multiplier(df::item *item, df::caravan_state *caravan) { static const int32_t DEFAULT_AGREEMENT_MULTIPLIER = 128; static int32_t get_buy_request_multiplier(df::item *item, const df::entity_buy_prices *buy_prices) { + if (!buy_prices) + return DEFAULT_AGREEMENT_MULTIPLIER; + int16_t item_type = item->getType(); int16_t item_subtype = item->getSubtype(); int16_t mat_type = item->getMaterial(); @@ -1519,15 +1525,396 @@ static int32_t get_buy_request_multiplier(df::item *item, const df::entity_buy_p return DEFAULT_AGREEMENT_MULTIPLIER; } -static int32_t get_sell_request_multiplier(df::item *item, const df::entity_sell_prices *sell_prices) { +template +static int get_price(const std::vector &res, int32_t val, const std::vector &pri) { + for (size_t idx = 0; idx < res.size(); ++idx) { + if (res[idx] == val && pri.size() > idx) + return pri[idx]; + } + return -1; +} + +template +static int get_price(const std::vector &mat_res, int32_t mat, const std::vector &gloss_res, int32_t gloss, const std::vector &pri) { + for (size_t idx = 0; idx < mat_res.size(); ++idx) { + if (mat_res[idx] == mat && (gloss_res[idx] == -1 || gloss_res[idx] == gloss) && pri.size() > idx) + return pri[idx]; + } + return -1; +} + +static const uint16_t PLANT_BASE = 419; +static const uint16_t NUM_PLANT_TYPES = 200; + +static int32_t get_sell_request_multiplier(df::item *item, const df::historical_entity::T_resources &resources, const std::vector *prices) { + 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 const df::dfhack_material_category leather_cat(df::dfhack_material_category::mask_leather); + + int16_t item_type = item->getType(); + int16_t item_subtype = item->getSubtype(); + int16_t mat_type = item->getMaterial(); + int32_t mat_subtype = item->getMaterialIndex(); + + bool inorganic = mat_type == df::builtin_mats::INORGANIC; + bool is_plant = (uint16_t)(mat_type - PLANT_BASE) < NUM_PLANT_TYPES; + + switch (item_type) { + case df::item_type::BAR: + if (inorganic) { + if (int32_t price = get_price(resources.metals, mat_subtype, prices[df::entity_sell_category::MetalBars]); price != -1) + return price; + } + break; + case df::item_type::SMALLGEM: + if (inorganic) { + if (int32_t price = get_price(resources.gems, mat_subtype, prices[df::entity_sell_category::SmallCutGems]); price != -1) + return price; + } + break; + case df::item_type::BLOCKS: + if (inorganic) { + if (int32_t price = get_price(resources.stones, mat_subtype, prices[df::entity_sell_category::StoneBlocks]); price != -1) + return price; + } + break; + case df::item_type::ROUGH: + if (int32_t price = get_price(resources.misc_mat.glass.mat_type, mat_type, resources.misc_mat.glass.mat_index, mat_subtype, + prices[df::entity_sell_category::Glass]); price != -1) + return price; + break; + case df::item_type::BOULDER: + if (int32_t price = get_price(resources.stones, mat_subtype, prices[df::entity_sell_category::Stone]); price != -1) + return price; + if (int32_t price = get_price(resources.misc_mat.clay.mat_type, mat_type, resources.misc_mat.clay.mat_index, mat_subtype, + prices[df::entity_sell_category::Clay]); price != -1) + return price; + break; + case df::item_type::WOOD: + if (int32_t price = get_price(resources.organic.wood.mat_type, mat_type, resources.organic.wood.mat_index, mat_subtype, + prices[df::entity_sell_category::Wood]); price != -1) + return price; + break; + case df::item_type::CHAIN: + if (is_plant) { + if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, + prices[df::entity_sell_category::RopesPlant]); price != -1) + return price; + } + { + MaterialInfo mi; + mi.decode(mat_type, mat_subtype); + if (mi.isValid()) { + if (mi.matches(silk_cat)) { + if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, + prices[df::entity_sell_category::RopesSilk]); price != -1) + return price; + } + if (mi.matches(yarn_cat)) { + if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, + prices[df::entity_sell_category::RopesYarn]); price != -1) + return price; + } + } + } + break; + case df::item_type::FLASK: + if (int32_t price = get_price(resources.misc_mat.flasks.mat_type, mat_type, resources.misc_mat.flasks.mat_index, mat_subtype, + prices[df::entity_sell_category::FlasksWaterskins]); price != -1) + return price; + break; + case df::item_type::GOBLET: + if (int32_t price = get_price(resources.misc_mat.crafts.mat_type, mat_type, resources.misc_mat.crafts.mat_index, mat_subtype, + prices[df::entity_sell_category::CupsMugsGoblets]); price != -1) + return price; + break; + case df::item_type::INSTRUMENT: + if (int32_t price = get_price(resources.instrument_type, mat_subtype, prices[df::entity_sell_category::Instruments]); price != -1) + return price; + break; + case df::item_type::TOY: + if (int32_t price = get_price(resources.toy_type, mat_subtype, prices[df::entity_sell_category::Toys]); price != -1) + return price; + break; + case df::item_type::CAGE: + if (int32_t price = get_price(resources.misc_mat.cages.mat_type, mat_type, resources.misc_mat.cages.mat_index, mat_subtype, + prices[df::entity_sell_category::Cages]); price != -1) + return price; + break; + case df::item_type::BARREL: + if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, + prices[df::entity_sell_category::Barrels]); price != -1) + return price; + break; + case df::item_type::BUCKET: + if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, + prices[df::entity_sell_category::Buckets]); price != -1) + return price; + break; + case df::item_type::WEAPON: + if (int32_t price = get_price(resources.weapon_type, mat_subtype, prices[df::entity_sell_category::Weapons]); price != -1) + return price; + if (int32_t price = get_price(resources.digger_type, mat_subtype, prices[df::entity_sell_category::DiggingImplements]); price != -1) + return price; + if (int32_t price = get_price(resources.training_weapon_type, mat_subtype, prices[df::entity_sell_category::TrainingWeapons]); price != -1) + return price; + break; + case df::item_type::ARMOR: + if (int32_t price = get_price(resources.armor_type, mat_subtype, prices[df::entity_sell_category::Bodywear]); price != -1) + return price; + break; + case df::item_type::SHOES: + if (int32_t price = get_price(resources.shoes_type, mat_subtype, prices[df::entity_sell_category::Footwear]); price != -1) + return price; + break; + case df::item_type::SHIELD: + if (int32_t price = get_price(resources.shield_type, mat_subtype, prices[df::entity_sell_category::Shields]); price != -1) + return price; + break; + case df::item_type::HELM: + if (int32_t price = get_price(resources.helm_type, mat_subtype, prices[df::entity_sell_category::Headwear]); price != -1) + return price; + break; + case df::item_type::GLOVES: + if (int32_t price = get_price(resources.gloves_type, mat_subtype, prices[df::entity_sell_category::Handwear]); price != -1) + return price; + break; + case df::item_type::BAG: + { + MaterialInfo mi; + mi.decode(mat_type, mat_subtype); + if (mi.isValid() && mi.matches(leather_cat)) { + if (int32_t price = get_price(resources.organic.leather.mat_type, mat_type, resources.organic.leather.mat_index, mat_subtype, + prices[df::entity_sell_category::BagsLeather]); price != -1) + return price; + } + if (is_plant) { + if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, + prices[df::entity_sell_category::BagsPlant]); price != -1) + return price; + } + if (mi.isValid() && mi.matches(silk_cat)) { + if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, + prices[df::entity_sell_category::BagsSilk]); price != -1) + return price; + } + if (mi.isValid() && mi.matches(yarn_cat)) { + if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, + prices[df::entity_sell_category::BagsYarn]); price != -1) + return price; + } + } + break; + case df::item_type::FIGURINE: + case df::item_type::AMULET: + case df::item_type::SCEPTER: + case df::item_type::CROWN: + case df::item_type::RING: + case df::item_type::EARRING: + case df::item_type::BRACELET: + case df::item_type::TOTEM: + case df::item_type::BOOK: + if (int32_t price = get_price(resources.misc_mat.crafts.mat_type, mat_type, resources.misc_mat.crafts.mat_index, mat_subtype, + prices[df::entity_sell_category::Crafts]); price != -1) + return price; + break; + case df::item_type::AMMO: + if (int32_t price = get_price(resources.ammo_type, mat_subtype, prices[df::entity_sell_category::Ammo]); price != -1) + return price; + break; + case df::item_type::GEM: + if (inorganic) { + if (int32_t price = get_price(resources.gems, mat_subtype, prices[df::entity_sell_category::LargeCutGems]); price != -1) + return price; + } + break; + case df::item_type::ANVIL: + if (int32_t price = get_price(resources.metal.anvil.mat_type, mat_type, resources.metal.anvil.mat_index, mat_subtype, + prices[df::entity_sell_category::Anvils]); price != -1) + return price; + break; + case df::item_type::MEAT: + if (int32_t price = get_price(resources.misc_mat.meat.mat_type, mat_type, resources.misc_mat.meat.mat_index, mat_subtype, + prices[df::entity_sell_category::Meat]); price != -1) + return price; + break; + case df::item_type::FISH: + case df::item_type::FISH_RAW: + if (int32_t price = get_price(resources.fish_races, mat_type, resources.fish_castes, mat_subtype, + prices[df::entity_sell_category::Fish]); price != -1) + return price; + break; + case df::item_type::VERMIN: + case df::item_type::PET: + if (int32_t price = get_price(resources.animals.pet_races, mat_type, resources.animals.pet_castes, mat_subtype, + prices[df::entity_sell_category::Pets]); price != -1) + return price; + break; + case df::item_type::SEEDS: + if (int32_t price = get_price(resources.seeds.mat_type, mat_type, resources.seeds.mat_index, mat_subtype, + prices[df::entity_sell_category::Seeds]); price != -1) + return price; + break; + case df::item_type::PLANT: + if (int32_t price = get_price(resources.plants.mat_type, mat_type, resources.plants.mat_index, mat_subtype, + prices[df::entity_sell_category::Plants]); price != -1) + return price; + break; + case df::item_type::SKIN_TANNED: + if (int32_t price = get_price(resources.organic.leather.mat_type, mat_type, resources.organic.leather.mat_index, mat_subtype, + prices[df::entity_sell_category::Leather]); price != -1) + return price; + break; + case df::item_type::PLANT_GROWTH: + if (is_plant) { + if (int32_t price = get_price(resources.tree_fruit_plants, mat_type, resources.tree_fruit_growths, mat_subtype, + prices[df::entity_sell_category::FruitsNuts]); price != -1) + return price; + if (int32_t price = get_price(resources.shrub_fruit_plants, mat_type, resources.shrub_fruit_growths, mat_subtype, + prices[df::entity_sell_category::GardenVegetables]); price != -1) + return price; + } + break; + case df::item_type::THREAD: + if (is_plant) { + if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, + prices[df::entity_sell_category::ThreadPlant]); price != -1) + return price; + } + { + MaterialInfo mi; + mi.decode(mat_type, mat_subtype); + if (mi.isValid() && mi.matches(silk_cat)) { + if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, + prices[df::entity_sell_category::ThreadSilk]); price != -1) + return price; + } + if (mi.isValid() && mi.matches(yarn_cat)) { + if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, + prices[df::entity_sell_category::ThreadYarn]); price != -1) + return price; + } + } + break; + case df::item_type::CLOTH: + if (is_plant) { + if (int32_t price = get_price(resources.organic.fiber.mat_type, mat_type, resources.organic.fiber.mat_index, mat_subtype, + prices[df::entity_sell_category::ClothPlant]); price != -1) + return price; + } + { + MaterialInfo mi; + mi.decode(mat_type, mat_subtype); + if (mi.isValid() && mi.matches(silk_cat)) { + if (int32_t price = get_price(resources.organic.silk.mat_type, mat_type, resources.organic.silk.mat_index, mat_subtype, + prices[df::entity_sell_category::ClothSilk]); price != -1) + return price; + } + if (mi.isValid() && mi.matches(yarn_cat)) { + if (int32_t price = get_price(resources.organic.wool.mat_type, mat_type, resources.organic.wool.mat_index, mat_subtype, + prices[df::entity_sell_category::ClothYarn]); price != -1) + return price; + } + } + break; + case df::item_type::PANTS: + if (int32_t price = get_price(resources.pants_type, mat_subtype, prices[df::entity_sell_category::Legwear]); price != -1) + return price; + break; + case df::item_type::BACKPACK: + if (int32_t price = get_price(resources.misc_mat.backpacks.mat_type, mat_type, resources.misc_mat.backpacks.mat_index, mat_subtype, + prices[df::entity_sell_category::Backpacks]); price != -1) + return price; + break; + case df::item_type::QUIVER: + if (int32_t price = get_price(resources.misc_mat.quivers.mat_type, mat_type, resources.misc_mat.quivers.mat_index, mat_subtype, + prices[df::entity_sell_category::Quivers]); price != -1) + return price; + break; + case df::item_type::TRAPCOMP: + if (int32_t price = get_price(resources.trapcomp_type, mat_subtype, prices[df::entity_sell_category::TrapComponents]); price != -1) + return price; + break; + case df::item_type::DRINK: + if (int32_t price = get_price(resources.misc_mat.booze.mat_type, mat_type, resources.misc_mat.booze.mat_index, mat_subtype, + prices[df::entity_sell_category::Drinks]); price != -1) + return price; + break; + case df::item_type::POWDER_MISC: + if (int32_t price = get_price(resources.misc_mat.powders.mat_type, mat_type, resources.misc_mat.powders.mat_index, mat_subtype, + prices[df::entity_sell_category::Powders]); price != -1) + return price; + if (int32_t price = get_price(resources.misc_mat.sand.mat_type, mat_type, resources.misc_mat.sand.mat_index, mat_subtype, + prices[df::entity_sell_category::Sand]); price != -1) + return price; + break; + case df::item_type::CHEESE: + if (int32_t price = get_price(resources.misc_mat.cheese.mat_type, mat_type, resources.misc_mat.cheese.mat_index, mat_subtype, + prices[df::entity_sell_category::Cheese]); price != -1) + return price; + break; + case df::item_type::LIQUID_MISC: + if (int32_t price = get_price(resources.misc_mat.extracts.mat_type, mat_type, resources.misc_mat.extracts.mat_index, mat_subtype, + prices[df::entity_sell_category::Extracts]); price != -1) + return price; + break; + case df::item_type::SPLINT: + if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, + prices[df::entity_sell_category::Splints]); price != -1) + return price; + break; + case df::item_type::CRUTCH: + if (int32_t price = get_price(resources.misc_mat.barrels.mat_type, mat_type, resources.misc_mat.barrels.mat_index, mat_subtype, + prices[df::entity_sell_category::Crutches]); price != -1) + return price; + break; + case df::item_type::TOOL: + if (int32_t price = get_price(resources.tool_type, mat_subtype, prices[df::entity_sell_category::Tools]); price != -1) + return price; + break; + case df::item_type::EGG: + if (int32_t price = get_price(resources.egg_races, mat_type, resources.egg_castes, mat_subtype, + prices[df::entity_sell_category::Eggs]); price != -1) + return price; + break; + case df::item_type::SHEET: + if (int32_t price = get_price(resources.organic.parchment.mat_type, mat_type, resources.organic.parchment.mat_index, mat_subtype, + prices[df::entity_sell_category::Parchment]); price != -1) + return price; + break; + default: + break; + } + + for (size_t idx = 0; idx < resources.wood_products.item_type.size(); ++idx) { + if (resources.wood_products.item_type[idx] == item_type && + (resources.wood_products.item_subtype[idx] == -1 || resources.wood_products.item_subtype[idx] == item_subtype) && + resources.wood_products.material.mat_type[idx] == mat_type && + (resources.wood_products.material.mat_index[idx] == -1 || resources.wood_products.material.mat_index[idx] == mat_subtype) && + prices[df::entity_sell_category::Miscellaneous].size() > idx) + return prices[df::entity_sell_category::Miscellaneous][idx]; + } + return DEFAULT_AGREEMENT_MULTIPLIER; } -static int32_t get_trade_agreement_multiplier(df::item *item, df::caravan_state *caravan, bool caravan_buying) { +static int32_t get_sell_request_multiplier(df::item *item, const df::caravan_state *caravan) { + const df::entity_sell_prices *sell_prices = caravan->sell_prices; + if (!sell_prices) + return DEFAULT_AGREEMENT_MULTIPLIER; + + auto caravan_he = df::historical_entity::find(caravan->entity); + if (!caravan_he) + return DEFAULT_AGREEMENT_MULTIPLIER; + + return get_sell_request_multiplier(item, caravan_he->resources, &sell_prices->price[0]); +} + +static int32_t get_trade_agreement_multiplier(df::item *item, const df::caravan_state *caravan, bool caravan_buying) { if (!caravan) return DEFAULT_AGREEMENT_MULTIPLIER; return caravan_buying ? get_buy_request_multiplier(item, caravan->buy_prices) - : get_sell_request_multiplier(item, caravan->sell_prices); + : get_sell_request_multiplier(item, caravan); } int Items::getValue(df::item *item, df::caravan_state *caravan, bool caravan_buying) From b938891e113238f2b9f7e365d62b998115271d55 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 4 Jul 2023 03:58:45 -0700 Subject: [PATCH 065/851] add dfhack.items.isRequestedTradeGood --- docs/changelog.txt | 3 ++- docs/dev/Lua API.rst | 4 ++++ library/LuaApi.cpp | 1 + library/include/modules/Items.h | 2 ++ library/modules/Items.cpp | 13 +++++++++++++ 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 4a8a100df..e6a9dd36d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -50,8 +50,9 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Price calculations fixed for many item types ## Lua -- ``dfhack.items.markForTrade``: new API for marking items for trade - ``dfhack.units.getUnitByNobleRole``, ``dfhack.units.getUnitsByNobleRole``: unit lookup API by role +- ``dfhack.items.markForTrade``: mark items for trade +- ``dfhack.items.isRequestedTradeGood``: discover whether an item is named in a trade agreement with an active caravan - ``dfhack.items.getValue``: gained optional ``caravan`` and ``caravan_buying`` parameters for prices that take trader races and agreements into account ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index e81a34de3..8553d4e1a 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1778,6 +1778,10 @@ Items module for the item and ``false`` to get the price that the caravan will sell the item for. +* ``dfhack.items.isRequestedTradeGood(item)`` + + Returns whether any active caravan will pay extra for the given item. + * ``dfhack.items.createItem(item_type, item_subtype, mat_type, mat_index, unit)`` Creates an item, similar to the `createitem` plugin. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 7fb14baeb..7afb3b9ea 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2020,6 +2020,7 @@ static const LuaWrapper::FunctionReg dfhack_items_module[] = { WRAPM(Items, getSubtypeDef), WRAPM(Items, getItemBaseValue), WRAPM(Items, getValue), + WRAPM(Items, isRequestedTradeGood), WRAPM(Items, createItem), WRAPM(Items, checkMandates), WRAPM(Items, canTrade), diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h index 6cce5d2f1..c473654e3 100644 --- a/library/include/modules/Items.h +++ b/library/include/modules/Items.h @@ -203,6 +203,8 @@ DFHACK_EXPORT bool canTrade(df::item *item); DFHACK_EXPORT bool canTradeWithContents(df::item *item); /// marks the given item for trade at the given depot DFHACK_EXPORT bool markForTrade(df::item *item, df::building_tradedepotst *depot); +/// Returns true if an active caravan will pay extra for the given item +DFHACK_EXPORT bool isRequestedTradeGood(df::item *item); /// Checks whether the item is an assigned hauling vehicle DFHACK_EXPORT bool isRouteVehicle(df::item *item); diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 537be7c3a..06741894d 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -1917,6 +1917,19 @@ static int32_t get_trade_agreement_multiplier(df::item *item, const df::caravan_ : get_sell_request_multiplier(item, caravan); } +bool Items::isRequestedTradeGood(df::item *item) { + for (auto caravan : df::global::plotinfo->caravans) { + auto trade_state = caravan->trade_state; + if (caravan->time_remaining <= 0 || + (trade_state != df::caravan_state::T_trade_state::Approaching && + trade_state != df::caravan_state::T_trade_state::AtDepot)) + continue; + if (get_buy_request_multiplier(item, caravan->buy_prices) > DEFAULT_AGREEMENT_MULTIPLIER) + return true; + } + return false; +} + int Items::getValue(df::item *item, df::caravan_state *caravan, bool caravan_buying) { CHECK_NULL_POINTER(item); From 7d3c8bd0406fd6d89fc01300510b5b479528982e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 5 Jul 2023 12:16:36 -0700 Subject: [PATCH 066/851] add notes to the API section of the changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index e6a9dd36d..bbd682c2d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -45,6 +45,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## API - ``Units::getUnitByNobleRole``, ``Units::getUnitsByNobleRole``: unit lookup API by role +- ``Items::markForTrade()``, ``Items::isRequestedTradeGood()``, ``Items::getValue``: see Lua notes below ## Internals - Price calculations fixed for many item types From 6a8522ab5e762ae5df6f5e7e26e3ef2babd32a94 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 6 Jul 2023 03:21:19 -0700 Subject: [PATCH 067/851] generalize dfhack.items.isRequestedTradeGood --- docs/dev/Lua API.rst | 5 +++-- library/include/modules/Items.h | 2 +- library/modules/Items.cpp | 14 +++++++++++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 8553d4e1a..11bac3f61 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1778,9 +1778,10 @@ Items module for the item and ``false`` to get the price that the caravan will sell the item for. -* ``dfhack.items.isRequestedTradeGood(item)`` +* ``dfhack.items.isRequestedTradeGood(item[, caravan_state])`` - Returns whether any active caravan will pay extra for the given item. + Returns whether a caravan will pay extra for the given item. If caravan_state + is not given, checks all active caravans. * ``dfhack.items.createItem(item_type, item_subtype, mat_type, mat_index, unit)`` diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h index c473654e3..7541660f4 100644 --- a/library/include/modules/Items.h +++ b/library/include/modules/Items.h @@ -204,7 +204,7 @@ DFHACK_EXPORT bool canTradeWithContents(df::item *item); /// marks the given item for trade at the given depot DFHACK_EXPORT bool markForTrade(df::item *item, df::building_tradedepotst *depot); /// Returns true if an active caravan will pay extra for the given item -DFHACK_EXPORT bool isRequestedTradeGood(df::item *item); +DFHACK_EXPORT bool isRequestedTradeGood(df::item *item, df::caravan_state *caravan = NULL); /// Checks whether the item is an assigned hauling vehicle DFHACK_EXPORT bool isRouteVehicle(df::item *item); diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 06741894d..3fc08813c 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -1917,7 +1917,19 @@ static int32_t get_trade_agreement_multiplier(df::item *item, const df::caravan_ : get_sell_request_multiplier(item, caravan); } -bool Items::isRequestedTradeGood(df::item *item) { +static bool is_requested_trade_good(df::item *item, df::caravan_state *caravan) { + auto trade_state = caravan->trade_state; + if (caravan->time_remaining <= 0 || + (trade_state != df::caravan_state::T_trade_state::Approaching && + trade_state != df::caravan_state::T_trade_state::AtDepot)) + return false; + return get_buy_request_multiplier(item, caravan->buy_prices) > DEFAULT_AGREEMENT_MULTIPLIER; +} + +bool Items::isRequestedTradeGood(df::item *item, df::caravan_state *caravan) { + if (caravan) + return is_requested_trade_good(item, caravan); + for (auto caravan : df::global::plotinfo->caravans) { auto trade_state = caravan->trade_state; if (caravan->time_remaining <= 0 || From 0b1ca6913c84a4a8a676a2070d623bb799c8b3f2 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 6 Jul 2023 10:37:31 +0000 Subject: [PATCH 068/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 64aff9c2d..36b1dd308 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 64aff9c2deb0dd49ee755257c43d2a9fc62f92bb +Subproject commit 36b1dd308920fc404cf2a67d5ad697b375ec984c From b657e8d8016e91ffeb002b4297af85c1ef84d984 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 7 Jul 2023 07:15:19 +0000 Subject: [PATCH 069/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 36b1dd308..e7a9aab2c 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 36b1dd308920fc404cf2a67d5ad697b375ec984c +Subproject commit e7a9aab2cd0065a7b90b03c27919b692fba44a0b From 0aa2146e11b2b6af03b50d00e380e691bdd4e405 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 7 Jul 2023 13:06:42 -0700 Subject: [PATCH 070/851] bump version number to 50.09-r2rc1 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dde3a05b..f3d1b4e1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.09") -set(DFHACK_RELEASE "r1") -set(DFHACK_PRERELEASE FALSE) +set(DFHACK_RELEASE "r2rc1") +set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_ABI_VERSION 1) From 36c6c5ee939bcf68d092fc77d83a7f59e926b50b Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 8 Apr 2023 12:11:15 -0500 Subject: [PATCH 071/851] 3dveins - tradeoffs for v50 allow dropping orphan veins; this is necessitated by what appears to be a bug in the gem spire generation code, which appears to occasionally spew gems in places that are quite distant from the gem spires themselves --- plugins/3dveins.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/3dveins.cpp b/plugins/3dveins.cpp index eaf741caf..f79949370 100644 --- a/plugins/3dveins.cpp +++ b/plugins/3dveins.cpp @@ -914,6 +914,7 @@ bool VeinGenerator::scan_block_tiles(Block *b, df::coord2d column, int z) for (int y = 0; y < 16; y++) { df::coord2d tile(x,y); + GeoLayer *layer = mapLayer(b, tile); if (!layer) continue; @@ -1363,7 +1364,7 @@ bool VeinGenerator::place_orphan(t_veinkey key, int size, GeoLayer *from) ENUM_KEY_STR(inclusion_type, key.second).c_str() ); - return false; + return true; } for (auto it = best.begin(); size > 0 && it != best.end(); ++it) From 9a5867219004b921ded7129fc8590cabf115b02f Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 4 Jul 2023 10:07:50 -0500 Subject: [PATCH 072/851] reenable 3dveins --- plugins/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 4029b8e2e..63e5274ae 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -73,7 +73,7 @@ set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) # If you are adding a plugin that you do not intend to commit to the DFHack repo, # see instructions for adding "external" plugins at the end of this file. -#dfhack_plugin(3dveins 3dveins.cpp) +dfhack_plugin(3dveins 3dveins.cpp) dfhack_plugin(add-spatter add-spatter.cpp) dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua) dfhack_plugin(autochop autochop.cpp LINK_LIBRARIES lua) From 02a4b7f63f4a6ea9d59b5693855e66e57e2eb2f6 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 4 Jul 2023 11:01:26 -0500 Subject: [PATCH 073/851] 3dveins: use debugfilter --- plugins/3dveins.cpp | 69 ++++++++++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/plugins/3dveins.cpp b/plugins/3dveins.cpp index f79949370..659f16ecc 100644 --- a/plugins/3dveins.cpp +++ b/plugins/3dveins.cpp @@ -7,15 +7,16 @@ #include "Core.h" #include "Console.h" +#include "DataDefs.h" +#include "Debug.h" #include "Export.h" +#include "MiscUtils.h" #include "PluginManager.h" + #include "modules/MapCache.h" #include "modules/Random.h" #include "modules/World.h" -#include "MiscUtils.h" - -#include "DataDefs.h" #include "df/world.h" #include "df/world_data.h" #include "df/world_region_details.h" @@ -47,6 +48,10 @@ DFHACK_PLUGIN("3dveins"); REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(gametype); +namespace DFHack { + DBG_DECLARE(_3dveins, process, DebugCategory::LINFO); +} + command_result cmd_3dveins(color_ostream &out, std::vector & parameters); DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) @@ -431,11 +436,13 @@ struct GeoLayer void print_mineral_stats(color_ostream &out) { for (auto it = mineral_count.begin(); it != mineral_count.end(); ++it) - out << " " << MaterialInfo(0,it->first.first).getToken() - << " " << ENUM_KEY_STR(inclusion_type,it->first.second) - << ": \t\t" << it->second << " (" << (float(it->second)/unmined_tiles) << ")" << std::endl; + INFO(process, out).print("3dveins: %s %s: %d (%f)\n", + MaterialInfo(0, it->first.first).getToken(), + ENUM_KEY_STR(inclusion_type, it->first.second), + it->second, + (float(it->second) / unmined_tiles)); - out.print(" Total tiles: %d (%d unmined)\n", tiles, unmined_tiles); + INFO(process, out).print ("3dveins: Total tiles: %d (%d unmined)\n", tiles, unmined_tiles); } bool form_veins(color_ostream &out); @@ -467,12 +474,12 @@ struct GeoBiome void print_mineral_stats(color_ostream &out) { - out.print("Geological biome %d:\n", info.geo_index); + INFO(process,out).print("3dveins: Geological biome %d:\n", info.geo_index); for (size_t i = 0; i < layers.size(); i++) if (layers[i]) { - out << " Layer " << i << std::endl; + INFO(process, out).print("3dveins: Layer %d\n", i); layers[i]->print_mineral_stats(out); } } @@ -586,7 +593,7 @@ bool VeinGenerator::init_biomes() if (info.geo_index < 0 || !info.geobiome) { - out.printerr("Biome %zd is not defined.\n", i); + ERR(process, out).print("Biome %zd is not defined.\n", i); return false; } @@ -797,8 +804,7 @@ bool VeinGenerator::scan_layer_depth(Block *b, df::coord2d column, int z) { if (z != min_level[idx]-1 && min_level[idx] <= top_solid) { - out.printerr( - "Discontinuous layer %d at (%d,%d,%d).\n", + ERR(process, out).print("Discontinuous layer %d at (%d,%d,%d).\n", layer->index, x+column.x*16, y+column.y*16, z ); return false; @@ -848,7 +854,7 @@ bool VeinGenerator::adjust_layer_depth(df::coord2d column) if (max_level[i+1] != min_level[i]-1) { - out.printerr( + ERR(process, out).print( "Gap or overlap with next layer %d at (%d,%d,%d-%d).\n", i+1, x+column.x*16, y+column.y*16, max_level[i+1], min_level[i] ); @@ -891,7 +897,7 @@ bool VeinGenerator::adjust_layer_depth(df::coord2d column) } } - out.printerr( + ERR(process, out).print( "Layer height change in layer %d at (%d,%d,%d): %d instead of %d.\n", i, x+column.x*16, y+column.y*16, max_level[i], size, biome->layers[i]->thickness @@ -933,7 +939,7 @@ bool VeinGenerator::scan_block_tiles(Block *b, df::coord2d column, int z) if (unsigned(key.first) >= materials.size() || unsigned(key.second) >= NUM_INCLUSIONS) { - out.printerr("Invalid vein code: %d %d - aborting.\n",key.first,key.second); + ERR(process, out).print("Invalid vein code: %d %d - aborting.\n",key.first,key.second); return false; } @@ -942,7 +948,7 @@ bool VeinGenerator::scan_block_tiles(Block *b, df::coord2d column, int z) if (status == -1) { // Report first occurence of unreasonable vein spec - out.printerr( + WARN(process, out).print( "Unexpected vein %s %s - ", MaterialInfo(0,key.first).getToken().c_str(), ENUM_KEY_STR(inclusion_type, key.second).c_str() @@ -950,9 +956,9 @@ bool VeinGenerator::scan_block_tiles(Block *b, df::coord2d column, int z) status = materials[key.first].default_type; if (status < 0) - out.printerr("will be left in place.\n"); + WARN(process, out).print("will be left in place.\n"); else - out.printerr( + WARN(process, out).print( "correcting to %s.\n", ENUM_KEY_STR(inclusion_type, df::inclusion_type(status)).c_str() ); @@ -1091,7 +1097,7 @@ void VeinGenerator::write_block_tiles(Block *b, df::coord2d column, int z) if (!ok) { - out.printerr( + ERR(process, out).print( "Couldn't write %d vein at (%d,%d,%d)\n", mat, x+column.x*16, y+column.y*16, z ); @@ -1282,7 +1288,7 @@ bool GeoLayer::form_veins(color_ostream &out) if (parent_id >= (int)refs.size()) { - out.printerr("Forward vein reference in biome %d.\n", biome->info.geo_index); + ERR(process, out).print("Forward vein reference in biome %d.\n", biome->info.geo_index); return false; } @@ -1302,7 +1308,7 @@ bool GeoLayer::form_veins(color_ostream &out) if (vptr->parent) ctx = "only be in "+MaterialInfo(0,vptr->parent_mat()).getToken(); - out.printerr( + WARN(process, out).print( "Duplicate vein %s %s in biome %d layer %d - will %s.\n", MaterialInfo(0,key.first).getToken().c_str(), ENUM_KEY_STR(inclusion_type, key.second).c_str(), @@ -1358,7 +1364,7 @@ bool VeinGenerator::place_orphan(t_veinkey key, int size, GeoLayer *from) if (best.empty()) { - out.printerr( + ERR(process,out).print( "Could not place orphaned vein %s %s anywhere.\n", MaterialInfo(0,key.first).getToken().c_str(), ENUM_KEY_STR(inclusion_type, key.second).c_str() @@ -1392,7 +1398,7 @@ bool VeinGenerator::place_orphan(t_veinkey key, int size, GeoLayer *from) if (size > 0) { - out.printerr( + WARN(process, out).print( "Could not place all of orphaned vein %s %s: %d left.\n", MaterialInfo(0,key.first).getToken().c_str(), ENUM_KEY_STR(inclusion_type, key.second).c_str(), @@ -1542,7 +1548,7 @@ bool VeinGenerator::place_veins(bool verbose) if (!isStoneInorganic(key.first)) { - out.printerr( + ERR(process, out).print( "Invalid vein material: %s\n", MaterialInfo(0, key.first).getToken().c_str() ); @@ -1552,7 +1558,7 @@ bool VeinGenerator::place_veins(bool verbose) if (!is_valid_enum_item(key.second)) { - out.printerr("Invalid vein type: %d\n", key.second); + ERR(process, out).print("Invalid vein type: %d\n", key.second); return false; } @@ -1565,13 +1571,13 @@ bool VeinGenerator::place_veins(bool verbose) sort(queue.begin(), queue.end(), vein_cmp); // Place tiles - out.print("Processing... (%zu)", queue.size()); + TRACE(process,out).print("Processing... (%zu)", queue.size()); for (size_t j = 0; j < queue.size(); j++) { if (queue[j]->parent && !queue[j]->parent->placed) { - out.printerr( + ERR(process, out).print( "\nParent vein not placed for %s %s.\n", MaterialInfo(0,queue[j]->vein.first).getToken().c_str(), ENUM_KEY_STR(inclusion_type, queue[j]->vein.second).c_str() @@ -1583,9 +1589,9 @@ bool VeinGenerator::place_veins(bool verbose) if (verbose) { if (j > 0) - out.print("done."); + TRACE(process, out).print("done."); - out.print( + TRACE(process, out).print( "\nVein layer %zu of %zu: %s %s (%.2f%%)... ", j+1, queue.size(), MaterialInfo(0,queue[j]->vein.first).getToken().c_str(), @@ -1595,14 +1601,13 @@ bool VeinGenerator::place_veins(bool verbose) } else { - out.print("\rVein layer %zu of %zu... ", j+1, queue.size()); - out.flush(); + TRACE(process, out).print("\rVein layer %zu of %zu... ", j+1, queue.size()); } queue[j]->place_tiles(); } - out.print("done.\n"); + TRACE(process, out).print("done.\n"); return true; } From d346bbfe6f363f63802d89cccc3d90ec09c93446 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 4 Jul 2023 11:18:39 -0500 Subject: [PATCH 074/851] 3dveins: satisfy gcc's overly aggressive linter --- plugins/3dveins.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/3dveins.cpp b/plugins/3dveins.cpp index 659f16ecc..71115d38a 100644 --- a/plugins/3dveins.cpp +++ b/plugins/3dveins.cpp @@ -436,8 +436,8 @@ struct GeoLayer void print_mineral_stats(color_ostream &out) { for (auto it = mineral_count.begin(); it != mineral_count.end(); ++it) - INFO(process, out).print("3dveins: %s %s: %d (%f)\n", - MaterialInfo(0, it->first.first).getToken(), + INFO(process, out).print("3dveins: %s %s: %ld (%f)\n", + MaterialInfo(0, it->first.first).getToken().c_str(), ENUM_KEY_STR(inclusion_type, it->first.second), it->second, (float(it->second) / unmined_tiles)); @@ -1589,7 +1589,9 @@ bool VeinGenerator::place_veins(bool verbose) if (verbose) { if (j > 0) + { TRACE(process, out).print("done."); + } TRACE(process, out).print( "\nVein layer %zu of %zu: %s %s (%.2f%%)... ", From 4b669ec83a85125f60fafbedeee3734bdd79c222 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 4 Jul 2023 11:22:34 -0500 Subject: [PATCH 075/851] uncross eyes and try again --- plugins/3dveins.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/3dveins.cpp b/plugins/3dveins.cpp index 71115d38a..8fd7ac900 100644 --- a/plugins/3dveins.cpp +++ b/plugins/3dveins.cpp @@ -436,9 +436,9 @@ struct GeoLayer void print_mineral_stats(color_ostream &out) { for (auto it = mineral_count.begin(); it != mineral_count.end(); ++it) - INFO(process, out).print("3dveins: %s %s: %ld (%f)\n", + INFO(process, out).print("3dveins: %s %s: %d (%f)\n", MaterialInfo(0, it->first.first).getToken().c_str(), - ENUM_KEY_STR(inclusion_type, it->first.second), + ENUM_KEY_STR(inclusion_type, it->first.second).c_str(), it->second, (float(it->second) / unmined_tiles)); @@ -479,7 +479,7 @@ struct GeoBiome for (size_t i = 0; i < layers.size(); i++) if (layers[i]) { - INFO(process, out).print("3dveins: Layer %d\n", i); + INFO(process, out).print("3dveins: Layer %ld\n", i); layers[i]->print_mineral_stats(out); } } From 6997b6be21b1697e1192e336287ab2dd668a9bbb Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Fri, 7 Jul 2023 16:00:39 -0500 Subject: [PATCH 076/851] add changelog for 3dveins --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index bbd682c2d..891a9a93e 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 +- ``3dveins``: reinstated for v50, this plugin replaces vanilla DF's blobby vein generation with veins that flow smoothly and naturally between z-levels ## Fixes - Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing From 734de0dcd126eed3a48884926d3c199089efab07 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 7 Jul 2023 14:49:10 -0700 Subject: [PATCH 077/851] make EditField ignore Ctrl-A until we get Home key support --- library/lua/gui/widgets.lua | 7 ++++--- scripts | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index d6dcafd63..b034ed1e8 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -756,9 +756,10 @@ function EditField:onInput(keys) find('.*[%w_%-][^%w_%-]') self:setCursor(prev_word_end or 1) return true - elseif keys.CUSTOM_CTRL_A then -- home - self:setCursor(1) - return true + -- commented out until we get HOME key support from DF + -- elseif keys.CUSTOM_CTRL_A then -- home + -- self:setCursor(1) + -- return true elseif keys.KEYBOARD_CURSOR_RIGHT then self:setCursor(self.cursor + 1) return true diff --git a/scripts b/scripts index e7a9aab2c..33ecf539b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit e7a9aab2cd0065a7b90b03c27919b692fba44a0b +Subproject commit 33ecf539b0dc993818d6830ce26a234a321b9ae3 From 0ac05197c616ff011f26cc698e12c004f8db2f03 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Fri, 7 Jul 2023 17:21:25 -0500 Subject: [PATCH 078/851] fix an ambiguity in def'n of operator== this resolve an error that arises when compiling with msvc 1936 which was previously ignored due to a bug in the compiler --- library/include/Core.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library/include/Core.h b/library/include/Core.h index a41aff927..dc2408ae9 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -106,10 +106,14 @@ namespace DFHack StateChangeScript(state_change_event event, std::string path, bool save_specific = false) :event(event), path(path), save_specific(save_specific) { } - bool operator==(const StateChangeScript& other) + bool const operator==(const StateChangeScript& other) { return event == other.event && path == other.path && save_specific == other.save_specific; } + bool const operator!=(const StateChangeScript& other) + { + return !(operator==(other)); + } }; // Core is a singleton. Why? Because it is closely tied to SDL calls. It tracks the global state of DF. From 44c41d2df946580b9aa96445c824591724473cbb Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 7 Jul 2023 22:29:43 +0000 Subject: [PATCH 079/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 33ecf539b..37701795f 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 33ecf539b0dc993818d6830ce26a234a321b9ae3 +Subproject commit 37701795f5705f5498df9543afdfb1255595976e From fb9e72e487f13bcf854cbe1739848a72cc5eaf69 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Fri, 7 Jul 2023 17:39:50 -0500 Subject: [PATCH 080/851] =?UTF-8?q?3dveins:=20ERR=20=E2=86=92=20WARN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/3dveins.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/plugins/3dveins.cpp b/plugins/3dveins.cpp index 8fd7ac900..6b95c2e87 100644 --- a/plugins/3dveins.cpp +++ b/plugins/3dveins.cpp @@ -593,7 +593,7 @@ bool VeinGenerator::init_biomes() if (info.geo_index < 0 || !info.geobiome) { - ERR(process, out).print("Biome %zd is not defined.\n", i); + WARN(process, out).print("Biome %zd is not defined.\n", i); return false; } @@ -804,7 +804,7 @@ bool VeinGenerator::scan_layer_depth(Block *b, df::coord2d column, int z) { if (z != min_level[idx]-1 && min_level[idx] <= top_solid) { - ERR(process, out).print("Discontinuous layer %d at (%d,%d,%d).\n", + WARN(process, out).print("Discontinuous layer %d at (%d,%d,%d).\n", layer->index, x+column.x*16, y+column.y*16, z ); return false; @@ -854,7 +854,7 @@ bool VeinGenerator::adjust_layer_depth(df::coord2d column) if (max_level[i+1] != min_level[i]-1) { - ERR(process, out).print( + WARN(process, out).print( "Gap or overlap with next layer %d at (%d,%d,%d-%d).\n", i+1, x+column.x*16, y+column.y*16, max_level[i+1], min_level[i] ); @@ -897,7 +897,7 @@ bool VeinGenerator::adjust_layer_depth(df::coord2d column) } } - ERR(process, out).print( + WARN(process, out).print( "Layer height change in layer %d at (%d,%d,%d): %d instead of %d.\n", i, x+column.x*16, y+column.y*16, max_level[i], size, biome->layers[i]->thickness @@ -939,7 +939,7 @@ bool VeinGenerator::scan_block_tiles(Block *b, df::coord2d column, int z) if (unsigned(key.first) >= materials.size() || unsigned(key.second) >= NUM_INCLUSIONS) { - ERR(process, out).print("Invalid vein code: %d %d - aborting.\n",key.first,key.second); + WARN(process, out).print("Invalid vein code: %d %d - aborting.\n",key.first,key.second); return false; } @@ -1097,7 +1097,7 @@ void VeinGenerator::write_block_tiles(Block *b, df::coord2d column, int z) if (!ok) { - ERR(process, out).print( + WARN(process, out).print( "Couldn't write %d vein at (%d,%d,%d)\n", mat, x+column.x*16, y+column.y*16, z ); @@ -1288,7 +1288,7 @@ bool GeoLayer::form_veins(color_ostream &out) if (parent_id >= (int)refs.size()) { - ERR(process, out).print("Forward vein reference in biome %d.\n", biome->info.geo_index); + WARN(process, out).print("Forward vein reference in biome %d.\n", biome->info.geo_index); return false; } @@ -1364,7 +1364,7 @@ bool VeinGenerator::place_orphan(t_veinkey key, int size, GeoLayer *from) if (best.empty()) { - ERR(process,out).print( + WARN(process,out).print( "Could not place orphaned vein %s %s anywhere.\n", MaterialInfo(0,key.first).getToken().c_str(), ENUM_KEY_STR(inclusion_type, key.second).c_str() @@ -1548,7 +1548,7 @@ bool VeinGenerator::place_veins(bool verbose) if (!isStoneInorganic(key.first)) { - ERR(process, out).print( + WARN(process, out).print( "Invalid vein material: %s\n", MaterialInfo(0, key.first).getToken().c_str() ); @@ -1558,7 +1558,7 @@ bool VeinGenerator::place_veins(bool verbose) if (!is_valid_enum_item(key.second)) { - ERR(process, out).print("Invalid vein type: %d\n", key.second); + WARN(process, out).print("Invalid vein type: %d\n", key.second); return false; } @@ -1577,7 +1577,7 @@ bool VeinGenerator::place_veins(bool verbose) { if (queue[j]->parent && !queue[j]->parent->placed) { - ERR(process, out).print( + WARN(process, out).print( "\nParent vein not placed for %s %s.\n", MaterialInfo(0,queue[j]->vein.first).getToken().c_str(), ENUM_KEY_STR(inclusion_type, queue[j]->vein.second).c_str() From 6f4816102111a7f8615f170b1cedeaee32dd5adc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 7 Jul 2023 15:57:24 -0700 Subject: [PATCH 081/851] fix quoting in changelog --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 891a9a93e..fef273c64 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -34,7 +34,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # Future ## New Plugins -- ``3dveins``: reinstated for v50, this plugin replaces vanilla DF's blobby vein generation with veins that flow smoothly and naturally between z-levels +- `3dveins`: reinstated for v50, this plugin replaces vanilla DF's blobby vein generation with veins that flow smoothly and naturally between z-levels ## Fixes - Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing From ad49c6735f6bc52c797750dc1c2de7f02e434867 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 8 Jul 2023 00:42:40 +0000 Subject: [PATCH 082/851] Auto-update submodules plugins/stonesense: master --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index d7fa20079..367d602a2 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit d7fa20079e89cc6516a0f5406a5ad112436066bb +Subproject commit 367d602a2949ab7121e2d9233c29a7fb1b9e6bec From 1fba8b16f5f2cdf89b80fe8d89acffc98bd5e48a Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Fri, 7 Jul 2023 19:26:45 -0500 Subject: [PATCH 083/851] replace `dts:make_unique` with `std::make_unique` 2014 here we come! --- library/Core.cpp | 6 +++--- library/include/MiscUtils.h | 22 ---------------------- library/modules/Graphic.cpp | 2 +- library/modules/Materials.cpp | 2 +- plugins/autofarm.cpp | 2 +- plugins/tailor.cpp | 2 +- 6 files changed, 7 insertions(+), 29 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 8d632e107..e4713c07f 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1404,7 +1404,7 @@ Core::~Core() } Core::Core() : - d(dts::make_unique()), + d(std::make_unique()), script_path_mutex{}, HotkeyMutex{}, HotkeyCond{}, @@ -1501,7 +1501,7 @@ bool Core::InitMainThread() { #else const char * path = "hack\\symbols.xml"; #endif - auto local_vif = dts::make_unique(); + auto local_vif = std::make_unique(); std::cerr << "Identifying DF version.\n"; try { @@ -1517,7 +1517,7 @@ bool Core::InitMainThread() { return false; } vif = std::move(local_vif); - auto local_p = dts::make_unique(*vif); + auto local_p = std::make_unique(*vif); local_p->ValidateDescriptionOS(); vinfo = local_p->getDescriptor(); diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index d14bdb6e9..59adcdbe5 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -61,28 +61,6 @@ namespace DFHack { class color_ostream; } -/*! \namespace dts - * std.reverse() == dts, The namespace that include forward compatible helpers - * which can be used from newer standards. The preprocessor check prefers - * standard version if one is available. The standard version gets imported with - * using. - */ -namespace dts { -// Check if lib supports the feature test macro or version is over c++14. -#if __cpp_lib_make_unique < 201304 && __cplusplus < 201402L -//! Insert c++14 make_unique to be forward compatible. Array versions are -//! missing -template -typename std::enable_if::value, std::unique_ptr >::type -make_unique(Args&&... args) -{ - return std::unique_ptr{new T{std::forward(args)...}}; -} -#else /* >= c++14 */ -using std::make_unique; -#endif -} - template void print_bits ( T val, std::ostream& out ) { diff --git a/library/modules/Graphic.cpp b/library/modules/Graphic.cpp index 7f6b8f4d3..b55ee83ed 100644 --- a/library/modules/Graphic.cpp +++ b/library/modules/Graphic.cpp @@ -44,7 +44,7 @@ using namespace DFHack; std::unique_ptr DFHack::createGraphic() { - return dts::make_unique(); + return std::make_unique(); } bool Graphic::Register(DFTileSurface* (*func)(int,int)) diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index 7a1ef249f..7922b5417 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -604,7 +604,7 @@ bool DFHack::isStoneInorganic(int material) std::unique_ptr DFHack::createMaterials() { - return dts::make_unique(); + return std::make_unique(); } Materials::Materials() diff --git a/plugins/autofarm.cpp b/plugins/autofarm.cpp index 44253b2f9..e1511153c 100644 --- a/plugins/autofarm.cpp +++ b/plugins/autofarm.cpp @@ -436,7 +436,7 @@ DFhackCExport command_result plugin_init(color_ostream& out, std::vector ()); + autofarmInstance = std::move(std::make_unique()); autofarmInstance->load_state(out); return CR_OK; } diff --git a/plugins/tailor.cpp b/plugins/tailor.cpp index 2b44d11ae..df8781caa 100644 --- a/plugins/tailor.cpp +++ b/plugins/tailor.cpp @@ -588,7 +588,7 @@ static int do_cycle(color_ostream &out); DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { DEBUG(config,out).print("initializing %s\n", plugin_name); - tailor_instance = dts::make_unique(); + tailor_instance = std::make_unique(); // provide a configuration interface for the plugin commands.push_back(PluginCommand( From 0b78eb7cbcbc4a426b1e2726df5eb57b2f628664 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 8 Jul 2023 20:58:26 +0000 Subject: [PATCH 084/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 37701795f..f28878046 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 37701795f5705f5498df9543afdfb1255595976e +Subproject commit f288780464352648b1829afb3a81128ee3cb0aeb From 8740288a9bd0cae6c049fb6558155e84a44f0959 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 8 Jul 2023 21:15:21 +0000 Subject: [PATCH 085/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index f28878046..14552dde1 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit f288780464352648b1829afb3a81128ee3cb0aeb +Subproject commit 14552dde1fca00bec8fbcab4b361f36727b5f75c From 88732d724c5eb21b463ab3dea98c5586f02a60c6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 8 Jul 2023 14:16:04 -0700 Subject: [PATCH 086/851] update version to 50.09-r2rc2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f3d1b4e1c..f4cb3a9f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.09") -set(DFHACK_RELEASE "r2rc1") +set(DFHACK_RELEASE "r2rc2") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From f987bca8f9d61174aaf8e9233cc493d8b2ebec43 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 24 May 2023 13:13:42 -0700 Subject: [PATCH 087/851] prevent DF interface events for handled hotkeys --- library/Core.cpp | 37 ++++++++++++++++++++++++++++--------- library/include/Core.h | 1 - 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index e4713c07f..78d74a476 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2359,8 +2359,10 @@ bool Core::DFH_ncurses_key(int key) // returns true if the event is handled bool Core::DFH_SDL_Event(SDL_Event* ev) { + static std::map hotkey_states; + // do NOT process events before we are ready. - if(!started || !ev) + if (!started || !ev) return false; if (ev->type == SDL_WINDOWEVENT && ev->window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { @@ -2372,23 +2374,40 @@ bool Core::DFH_SDL_Event(SDL_Event* ev) if (ev->type == SDL_KEYDOWN || ev->type == SDL_KEYUP) { auto &ke = ev->key; + auto &sym = ke.keysym.sym; - if (ke.keysym.sym == SDLK_LSHIFT || ke.keysym.sym == SDLK_RSHIFT) + if (sym == SDLK_LSHIFT || sym == SDLK_RSHIFT) modstate = (ev->type == SDL_KEYDOWN) ? modstate | DFH_MOD_SHIFT : modstate & ~DFH_MOD_SHIFT; - else if (ke.keysym.sym == SDLK_LCTRL || ke.keysym.sym == SDLK_RCTRL) + else if (sym == SDLK_LCTRL || sym == SDLK_RCTRL) modstate = (ev->type == SDL_KEYDOWN) ? modstate | DFH_MOD_CTRL : modstate & ~DFH_MOD_CTRL; - else if (ke.keysym.sym == SDLK_LALT || ke.keysym.sym == SDLK_RALT) + else if (sym == SDLK_LALT || sym == SDLK_RALT) modstate = (ev->type == SDL_KEYDOWN) ? modstate | DFH_MOD_ALT : modstate & ~DFH_MOD_ALT; - else if (ke.state == SDL_PRESSED && !hotkey_states[ke.keysym.sym]) + else if (ke.state == SDL_PRESSED && !hotkey_states[sym]) { - hotkey_states[ke.keysym.sym] = true; - SelectHotkey(ke.keysym.sym, modstate); + // the check against hotkey_states[sym] ensures we only process keybindings once per keypress + DEBUG(keybinding).print("key down: sym=%d (%c)\n", sym, sym); + bool handled = SelectHotkey(sym, modstate); + if (handled) { + DEBUG(keybinding).print("inhibiting SDL key down event\n"); + hotkey_states[sym] = true; + return true; + } } - else if(ke.state == SDL_RELEASED) + else if (ke.state == SDL_RELEASED) { - hotkey_states[ke.keysym.sym] = false; + DEBUG(keybinding).print("key up: sym=%d (%c)\n", sym, sym); + hotkey_states[sym] = false; } } + else if (ev->type == SDL_TEXTINPUT) { + auto &te = ev->text; + DEBUG(keybinding).print("text input: '%s'\n", te.text); + if (strlen(te.text) == 1 && hotkey_states[te.text[0]]) { + DEBUG(keybinding).print("inhibiting SDL text event\n"); + return true; + } + } + return false; } diff --git a/library/include/Core.h b/library/include/Core.h index dc2408ae9..180b5cc7b 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -250,7 +250,6 @@ namespace DFHack int8_t modstate; std::map > key_bindings; - std::map hotkey_states; std::string hotkey_cmd; enum hotkey_set_t { NO, From 5a719f0e6694a0986dc2b84bb524ba39f08eb105 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 7 Jun 2023 01:10:20 -0700 Subject: [PATCH 088/851] update docs --- docs/builtins/keybinding.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/builtins/keybinding.rst b/docs/builtins/keybinding.rst index c9665a048..c6553e48c 100644 --- a/docs/builtins/keybinding.rst +++ b/docs/builtins/keybinding.rst @@ -33,6 +33,11 @@ The ```` parameter above has the following **case-sensitive** syntax:: where the ``KEY`` part can be any recognized key and :kbd:`[`:kbd:`]` denote optional parts. +DFHack commands can advertise the contexts in which they can be usefully run. +For example, a command that acts on a selected unit can tell `keybinding` that +it is not "applicable" in the current context if a unit is not actively +selected. + When multiple commands are bound to the same key combination, DFHack selects the first applicable one. Later ``add`` commands, and earlier entries within one ``add`` command have priority. Commands that are not specifically intended for From 7a618fd113152520ff7c14932ef25dd6ca3c663a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 8 Jul 2023 18:39:38 -0700 Subject: [PATCH 089/851] make event suppression configurable --- library/Core.cpp | 14 +++++++++++++- library/lua/dfhack.lua | 5 +++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/library/Core.cpp b/library/Core.cpp index 78d74a476..13717ad30 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2356,6 +2356,18 @@ bool Core::DFH_ncurses_key(int key) return ncurses_wgetch(key, dummy); } +static bool getSuppressDuplicateKeyboardEvents() { + auto L = Lua::Core::State; + color_ostream_proxy out(Core::getInstance().getConsole()); + Lua::StackUnwinder top(L); + bool suppress = false; + Lua::CallLuaModuleFunction(out, L, "dfhack", "getSuppressDuplicateKeyboardEvents", 0, 1, + Lua::DEFAULT_LUA_LAMBDA, [&](lua_State* L) { + suppress = lua_toboolean(L, -1); + }, false); + return suppress; +} + // returns true if the event is handled bool Core::DFH_SDL_Event(SDL_Event* ev) { @@ -2390,7 +2402,7 @@ bool Core::DFH_SDL_Event(SDL_Event* ev) if (handled) { DEBUG(keybinding).print("inhibiting SDL key down event\n"); hotkey_states[sym] = true; - return true; + return getSuppressDuplicateKeyboardEvents(); } } else if (ke.state == SDL_RELEASED) diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 8ea5e9dac..860b56cc1 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -63,6 +63,11 @@ function dfhack.getHideArmokTools() return dfhack.HIDE_ARMOK_TOOLS end +dfhack.SUPPRESS_DUPLICATE_KEYBOARD_EVENTS = true +function dfhack.getSuppressDuplicateKeyboardEvents() + return dfhack.SUPPRESS_DUPLICATE_KEYBOARD_EVENTS +end + -- Error handling safecall = dfhack.safecall From ed8bf1cff1af4b09807e2c68deb69fdc7ee0570a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 8 Jul 2023 18:40:53 -0700 Subject: [PATCH 090/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index fef273c64..3ff8ad217 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 - ``widgets.EditField``: DFHack edit fields now support cut/copy/paste with the system clipboard with Ctrl-X/Ctrl-C/Ctrl-V +- Suppress DF keyboard events when a DFHack keybinding is matched. This prevents, for example, a backtick from appearing in a textbox as text when you launch `gui/launcher` from the backtick keybinding. ## Documentation From ff6f7c9454b4b4ff7406f1e9e3b0a620720947be Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 9 Jul 2023 10:18:10 -0700 Subject: [PATCH 091/851] realign the misery docs to the actual implementation --- docs/changelog.txt | 1 + docs/plugins/misery.rst | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fef273c64..7313f6f8a 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -43,6 +43,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - ``widgets.EditField``: DFHack edit fields now support cut/copy/paste with the system clipboard with Ctrl-X/Ctrl-C/Ctrl-V ## Documentation +- `misery`: rewrite the documentation to clarify the actual effects of the plugin ## API - ``Units::getUnitByNobleRole``, ``Units::getUnitsByNobleRole``: unit lookup API by role diff --git a/docs/plugins/misery.rst b/docs/plugins/misery.rst index 8a65d8419..458253bb5 100644 --- a/docs/plugins/misery.rst +++ b/docs/plugins/misery.rst @@ -2,11 +2,12 @@ misery ====== .. dfhack-tool:: - :summary: Increase the intensity of your citizens' negative thoughts. + :summary: Lower the baseline for your citizens' happiness. :tags: fort gameplay units -When enabled, negative thoughts that your citizens have will multiply by the -specified factor. This makes it more challenging to keep them happy. +When enabled, all of your citizens receive a negative thought about a +particularly nasty soapy bath. You can vary the strength of this negative +thought to increase or decrease the difficulty of keeping your citizens happy. Usage ----- @@ -18,18 +19,18 @@ Usage misery misery clear -The default misery factor is ``2``, meaning that your dwarves will become -miserable twice as fast. +The default misery factor is ``2``, which will result in a moderate hit to your +dwarves' happiness. Larger numbers increase the challenge. Examples -------- ``enable misery`` - Start multiplying bad thoughts for your citizens! + Start adding bad thoughts about nasty soapy baths to your citizens! ``misery 5`` - Make dwarves become unhappy 5 times faster than normal -- this is quite - challenging to handle! + Change the strength of the soapy bath negative thought to something quite + large -- this is very challenging to handle! ``misery clear`` Clear away negative thoughts added by ``misery``. Note that this will not From 206c05feafdb36884845be99093f1fce45466ee2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 9 Jul 2023 10:39:26 -0700 Subject: [PATCH 092/851] document preference variables --- docs/Core.rst | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/Core.rst b/docs/Core.rst index 763858b61..ac17401dc 100644 --- a/docs/Core.rst +++ b/docs/Core.rst @@ -377,6 +377,26 @@ Other (non-DFHack-specific) variables that affect DFHack: sensitive), ``DF2CONSOLE()`` will produce UTF-8-encoded text. Note that this should be the case in most UTF-8-capable \*nix terminal emulators already. +Core preferences +================ + +There are a few settings that can be changed dynamically via +`gui/control-panel` to affect runtime behavior. You can also toggle these from +the commandline using the `lua` command, e.g. +``lua dfhack.HIDE_ARMOK_TOOLS=true`` or by editing the generated +``dfhack-config/init/dfhack.control-panel-preferences.init`` file and +restarting DF. + +- ``dfhack.HIDE_CONSOLE_ON_STARTUP``: Whether to hide the external DFHack + terminal window on startup. This, of course, is not useful to change + dynamically. You'll have to use `gui/control-panel` or edit the init file + directly and restart DF for it to have an effect. + +- ``dfhack.HIDE_ARMOK_TOOLS``: Whether to hide "armok" tools in command lists. + +- ``dfhack.SUPPRESS_DUPLICATE_KEYBOARD_EVENTS``: Whether to prevent DFHack + keybindings from producing DF key events. + Miscellaneous notes =================== This section is for odd but important notes that don't fit anywhere else. From 6e565f327573ce6f43552f5b9fe5f2656a820b45 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 9 Jul 2023 15:42:43 -0700 Subject: [PATCH 093/851] fix/update summaries --- docs/plugins/misery.rst | 2 +- plugins/misery.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/misery.rst b/docs/plugins/misery.rst index 458253bb5..3bcd5588a 100644 --- a/docs/plugins/misery.rst +++ b/docs/plugins/misery.rst @@ -2,7 +2,7 @@ misery ====== .. dfhack-tool:: - :summary: Lower the baseline for your citizens' happiness. + :summary: Make citizens more miserable. :tags: fort gameplay units When enabled, all of your citizens receive a negative thought about a diff --git a/plugins/misery.cpp b/plugins/misery.cpp index f241394ae..5e3bf6e1f 100644 --- a/plugins/misery.cpp +++ b/plugins/misery.cpp @@ -72,7 +72,7 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector Date: Sun, 9 Jul 2023 15:50:56 -0700 Subject: [PATCH 094/851] simplify retrieval of setting property --- library/Core.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 13717ad30..0a1c19351 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2360,12 +2360,8 @@ static bool getSuppressDuplicateKeyboardEvents() { auto L = Lua::Core::State; color_ostream_proxy out(Core::getInstance().getConsole()); Lua::StackUnwinder top(L); - bool suppress = false; - Lua::CallLuaModuleFunction(out, L, "dfhack", "getSuppressDuplicateKeyboardEvents", 0, 1, - Lua::DEFAULT_LUA_LAMBDA, [&](lua_State* L) { - suppress = lua_toboolean(L, -1); - }, false); - return suppress; + return DFHack::Lua::PushModulePublic(out, L, "dfhack", "SUPPRESS_DUPLICATE_KEYBOARD_EVENTS") && + lua_toboolean(L, -1); } // returns true if the event is handled From 49d21bad90ce6db48db1e32dc880c9a4c3f07b4c Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 10 Jul 2023 18:27:54 +0000 Subject: [PATCH 095/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 14552dde1..fafe4677c 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 14552dde1fca00bec8fbcab4b361f36727b5f75c +Subproject commit fafe4677cd26d1915c417828368b6fe94e2caa95 From d0d12414bf71e67953a095514c870faf95c2ed3f Mon Sep 17 00:00:00 2001 From: egocarib Date: Mon, 10 Jul 2023 18:43:50 -0500 Subject: [PATCH 096/851] Fix small typo --- docs/dev/compile/Compile.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev/compile/Compile.rst b/docs/dev/compile/Compile.rst index 22b9a7b1a..d9a0fa4c8 100644 --- a/docs/dev/compile/Compile.rst +++ b/docs/dev/compile/Compile.rst @@ -89,7 +89,7 @@ assistance. All Platforms ============= Before you can compile the code you'll need to configure your build with cmake. Some IDEs can do this, -but from command line is the usual way to do this; thought the Windows section below points out some +but from command line is the usual way to do this; though the Windows section below points out some Windows batch files that can be used to avoid opening a terminal/command-prompt. You should seek cmake's documentation online or via ``cmake --help`` to see how the command works. See From 755ddd9db31e6744f6e9f161471d18f786306b15 Mon Sep 17 00:00:00 2001 From: egocarib Date: Mon, 10 Jul 2023 19:36:05 -0500 Subject: [PATCH 097/851] Additional sentence improvements --- docs/dev/compile/Compile.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dev/compile/Compile.rst b/docs/dev/compile/Compile.rst index d9a0fa4c8..5e605e391 100644 --- a/docs/dev/compile/Compile.rst +++ b/docs/dev/compile/Compile.rst @@ -88,9 +88,9 @@ assistance. All Platforms ============= -Before you can compile the code you'll need to configure your build with cmake. Some IDEs can do this, -but from command line is the usual way to do this; though the Windows section below points out some -Windows batch files that can be used to avoid opening a terminal/command-prompt. +Before you can compile the code you'll need to configure your build with cmake. Some IDEs can do this +for you, but it's more common to do it from the command line. Windows developers can refer to the +Windows section below for batch files that can be used to avoid opening a terminal/command-prompt. You should seek cmake's documentation online or via ``cmake --help`` to see how the command works. See the `build-options` page for help finding the DFHack build options relevant to you. From e2a91ed3bbac5f26021a46a49d92adf3902ef4e1 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 13 Jul 2023 07:14:52 +0000 Subject: [PATCH 098/851] 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 0d4230a9d..19dd3a941 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 0d4230a9db2ebc381e73296bc4e19bee09551771 +Subproject commit 19dd3a94162a2ff3374cbdb1cadc92b55a626c92 From 324a8c52e70297396cfe1dc7079b645093badecf Mon Sep 17 00:00:00 2001 From: Myk Date: Thu, 13 Jul 2023 16:08:00 -0700 Subject: [PATCH 099/851] Update changelog.txt --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index bf8182c73..21e2da45b 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 +- `autonick`: add more variety to nicknames based on famous literary dwarves ## Documentation From 66d67e3cf791d557f6c0c808b0a4cfc96cc230dc Mon Sep 17 00:00:00 2001 From: IvoryTower33 <133928688+IvoryTower33@users.noreply.github.com> Date: Fri, 14 Jul 2023 02:49:15 +0200 Subject: [PATCH 100/851] Update data/dfhack-config/autonick.txt Co-authored-by: Myk --- data/dfhack-config/autonick.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/data/dfhack-config/autonick.txt b/data/dfhack-config/autonick.txt index 7cf9f3861..bdd40beed 100644 --- a/data/dfhack-config/autonick.txt +++ b/data/dfhack-config/autonick.txt @@ -23,7 +23,6 @@ Thrain Thror Fundin Frerin -Nain Gror Ibun Khim From fa690f4bad7ee7c97abba456e96daa84d6fbcf4a Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 14 Jul 2023 07:14:51 +0000 Subject: [PATCH 101/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index fafe4677c..6c0296642 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit fafe4677cd26d1915c417828368b6fe94e2caa95 +Subproject commit 6c02966423052ec4bd19a32cd553820262a1d170 From 83f8be5312f9a63a21705bb89c3c58a68042382e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 15 Jul 2023 14:26:51 -0700 Subject: [PATCH 102/851] add better noble suites and apartments --- data/blueprints/dreamfort.csv | 182 +++++++++++++++++----------------- docs/changelog.txt | 1 + 2 files changed, 92 insertions(+), 91 deletions(-) diff --git a/data/blueprints/dreamfort.csv b/data/blueprints/dreamfort.csv index 93cb4e3f7..5ac765523 100644 --- a/data/blueprints/dreamfort.csv +++ b/data/blueprints/dreamfort.csv @@ -783,7 +783,7 @@ corridor_traps/surface_corridor_traps ,,,`,,`,Cf,Cf,,,,,Cf,,`,,,~,~,~,,,`,Cf,,Cf,,,Cf,,Cf,`,,` ,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` ,,,`,Cf,Cf,,,,,,,,Cf,Cf,,,,~,,,,Cf,Cf,,,,,,,,Cf,Cf,` -,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,Cf,Cf,Cf,Cf,Cf,Cf,Cf,`,`,`,`,`,`,`,`,`,`,`,` @@ -1687,7 +1687,7 @@ build2/industry_build2 ,,w,`,`,`,`,`,`,"w{name=""Wood feeder""}(2x5)",,"g{name=""Goods feeder"" containers=0}:+cat_food/tallow+wax-crafts-goblets(3x3)",,`,,`,`,`,`,`,,"hlS{name=""Cloth/bones feeder"" containers=0}:+cat_refuse/skulls/,bones/,hair/,shells/,teeth/,horns/-adamantinethread(5x5)",,,~,~,`,`,`,`,`,`,c ,,w,`,`,`,`,`,`,~,~,~,~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c ,,`,`,`,`,`,"c{name=""Goods/wood quantum"" quantum=true give_to=""Pots,Barrels,Jugs,Bags,Seeds feeder""}:+all",`,~,~,~,~,~,,`,,`,,`,,~,~,~,~,~,`,"r{name=""Cloth/bones quantum"" quantum=true}:+all",`,`,`,`,c -,,"c{name=""Lye"" barrels=2}:+miscliquid",`,`,`,`,`,`,~,~,"u{name=""Furniture feeder""}:-sand(3x2)",~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c +,,"c{name=""Lye"" barrels=0}:+miscliquid",`,`,`,`,`,`,~,~,"u{name=""Furniture feeder""}:-sand(3x2)",~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c ,,c,`,`,`,`,`,`,~,~,~,~,~,,`,`,`,`,`,,~,~,~,~,~,`,`,`,`,`,`,c ,,c,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,c ,,c,`,`,`,`,`,`,`,`,`,`,`,`,"bnpdz{name=""Bar/military feeder"" containers=0}:-potash+adamantinethread(5x3)",,,,~,`,`,`,`,`,`,`,`,`,`,`,`,c @@ -1771,7 +1771,7 @@ build2/industry_build2 ,,,,`,`,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,es,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,eg,`,`,`,wf,`,`,`,ek,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,eg,`,`,`,wf{max_general_orders=9},`,`,`,ek,`,`,`,`,`,`,`,`,` ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` @@ -2501,37 +2501,37 @@ Apartments Walkthrough: "#dig label(suites1) start(18; 18; central stairs) message(Once the area is dug out, run /suites2) noble suites" ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,d,d,,,,d,,,,,,d,,,,d,,d,,,,d,,,,,,d,,,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,,,d,,,,,,d,,,,d,d,d,,,,d,,,,,,d,,,,d,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d ,d,d,,d,d,d,d,d,d,d,d,d,d,,d,`,~,`,d,,d,d,d,d,d,d,d,d,d,d,,d,d ,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,`,`,`,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d -,d,d,,,,d,,,,,,d,,,,d,d,d,,,,d,,,,,,d,,,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,d,d,d,d,d,d,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,d,d,d,d,d,,d,d -,d,d,,,,d,,,,,,d,,,,d,,d,,,,d,,,,,,d,,,,d,d -,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,,,,,,,,,,,,,,d,d,d,,,,,,,,,,,,,,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d,d,d,d,d,d,d,d,d,,,d,d,d,d,d,d,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,d,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,d,d,d,d,d,,,d,d,d,d,d,,d,,d,,d,d,d,d,d,,,d,d,d,d,d,,d +,d,,,,d,,,,,,,d,,,,d,d,d,,,,d,,,,,,,d,,,,d ,d,d,d,d,d,d,d,d,d,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 stairs) message(Remember to enqueue manager orders for this blueprint. @@ -2541,73 +2541,73 @@ build_suites/suites_build #dig label(suites_traffic) start(18; 18; central stairs) hidden() don't path through other dwarves' rooms ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,,,,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,,,,`,` +,`,,,,or,,,,,,,or,,,,`,`,`,,,,or,,,,,,,or,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,or,`,`,`,`,`,,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,,`,`,`,`,`,or,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,or,`,`,`,`,`,,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,,`,`,`,`,`,or,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,or,,,,,,,or,,,,oh,`,oh,,,,or,,,,,,,or,,,,` ,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,` ,`,`,,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,,`,` ,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,`,`,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,oh,`,` -,`,`,,,,or,,,,,,or,,,,oh,`,oh,,,,or,,,,,,or,,,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,`,`,`,`,`,or,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,,,,,,,,,,,,,oh,`,oh,,,,,,,,,,,,,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,or,`,`,`,`,`,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,`,`,`,`,`,or,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,`,`,`,`,`,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,`,`,`,`,`,,`,` -,`,`,,,,or,,,,,,or,,,,oh,,oh,,,,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,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,or,`,`,`,`,`,,,`,`,`,`,`,or,oh,`,oh,or,`,`,`,`,`,,,`,`,`,`,`,or,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,`,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,`,`,`,`,`,,,`,`,`,`,`,,oh,,oh,,`,`,`,`,`,,,`,`,`,`,`,,` +,`,,,,or,,,,,,,or,,,,`,`,`,,,,or,,,,,,,or,,,,` ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` #build label(suites_build) start(18; 18; central stairs) hidden() ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,,,,d,,,,,,d,,,,d,,d,,,,d,,,,,,d,,,,`,` -,`,`,,a,r,`,`,h,,h,`,`,r,a,,`,s,`,,a,r,`,`,h,,h,`,`,r,a,,`,` -,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,` -,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,` -,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,s,`,,c,`,`,`,f,,f,`,`,`,c,,`,` -,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,` -,`,`,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,`,` -,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,n,`,s,`,t,,`,` -,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,` -,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,` -,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,s,`,,`,`,`,`,h,,h,`,`,`,`,,`,` -,`,`,,a,r,`,`,h,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,h,`,`,r,a,,`,` -,`,`,,,,d,,,,,,d,,,,`,`,`,,,,d,,,,,,d,,,,`,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,s,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,s,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` ,`,`,d,`,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,`,d,`,` ,`,`,,s,`,`,s,`,`,s,`,`,s,,`,`,~,`,`,,s,`,`,s,`,`,s,`,`,s,,`,` ,`,`,d,`,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,`,d,`,` -,`,`,,,,d,,,,,,d,,,,`,`,`,,,,d,,,,,,d,,,,`,` -,`,`,,a,r,`,`,h,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,h,`,`,r,a,,`,` -,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,s,`,,`,`,`,`,h,,h,`,`,`,`,,`,` -,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,` -,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,` -,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,n,`,s,`,t,,`,` -,`,`,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,`,` -,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,`,`,,t,`,s,`,n,,n,`,s,`,t,,`,` -,`,`,,c,`,`,`,f,,f,`,`,`,c,,`,s,`,,c,`,`,`,f,,f,`,`,`,c,,`,` -,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,`,`,b,`,`,d,`,` -,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,`,`,,`,`,`,`,h,,h,`,`,`,`,,`,` -,`,`,,a,r,`,`,h,,h,`,`,r,a,,`,s,`,,a,r,`,`,h,,h,`,`,r,a,,`,` -,`,`,,,,d,,,,,,d,,,,d,,d,,,,d,,,,,,d,,,,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,s,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,,,,,,,,,,,,,,`,`,`,,,,,,,,,,,,,,,` +,`,,t,`,s,`,n,,,n,`,s,`,t,,`,s,`,,t,`,s,`,n,,,n,`,s,`,t,,` +,`,,c,`,`,`,f,,,f,`,`,`,c,,`,`,`,,c,`,`,`,f,,,f,`,`,`,c,,` +,`,d,`,`,b,`,`,,,`,`,b,`,`,d,`,`,`,d,`,`,b,`,`,,,`,`,b,`,`,d,` +,`,,`,`,`,`,h,,,h,`,`,`,`,,`,s,`,,`,`,`,`,h,,,h,`,`,`,`,,` +,`,,a,r,`,`,h,,,h,`,`,r,a,,d,,d,,a,r,`,`,h,,,h,`,`,r,a,,` +,`,,,,d,,,,,,,d,,,,`,`,`,,,,d,,,,,,,d,,,,` ,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` "#dig label(apartments1) start(18; 18; central stairs) message(Once the area is dug out, continue with /apartments2.) apartment complex" @@ -2700,13 +2700,13 @@ b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,b(4x5),,,,`,`,`,b(4x5),,,b(4x5),,,b(4x5),,,b ,,,,,,,,,,,,,,,,`,`,` ,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,,d,,d,,b,`,,b,`,,b,`,,b,`,,b,` ,d,,,d,,,d,,,d,,,d,,,`,`,`,,,d,,,d,,,d,,,d,,,d -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,`,`,`,` ,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,`,~,`,`,,`,`,`,`,`,`,`,`,`,`,`,`,` -,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` +,`,`,`,`,`,`,`,`,`,`,`,`,`,d,`,`,`,`,`,d,`,`,`,`,`,`,`,`,`,`,`,`,` ,d,,,d,,,d,,,d,,,d,,,`,`,`,,,d,,,d,,,d,,,d,,,d -,`,b,,`,b,,`,b,,`,b,,`,b,,`,,`,,b,`,,b,`,,b,`,,b,`,,b,` +,`,b,,`,b,,`,b,,`,b,,`,b,,d,,d,,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 ,,,,,,,,,,,,,,,,`,`,` diff --git a/docs/changelog.txt b/docs/changelog.txt index bb0512fab..d12ed37aa 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -43,6 +43,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - `autonick`: add more variety to nicknames based on famous literary dwarves - ``widgets.EditField``: DFHack edit fields now support cut/copy/paste with the system clipboard with Ctrl-X/Ctrl-C/Ctrl-V - Suppress DF keyboard events when a DFHack keybinding is matched. This prevents, for example, a backtick from appearing in a textbox as text when you launch `gui/launcher` from the backtick keybinding. +- Dreamfort: give noble suites double-thick walls and add apartment doors ## Documentation - `misery`: rewrite the documentation to clarify the actual effects of the plugin From a820b95d8c7aa7e00c89c38cf65ce4c73c5eb18e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 15 Jul 2023 14:27:58 -0700 Subject: [PATCH 103/851] include exotic pets as tameable --- docs/changelog.txt | 1 + plugins/stockpiles/StockpileSerializer.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index bb0512fab..9c29d5ed0 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: - Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing ## Misc Improvements +- `stockpiles`: include exotic pets in the "tameable" filter - `autonick`: add more variety to nicknames based on famous literary dwarves - ``widgets.EditField``: DFHack edit fields now support cut/copy/paste with the system clipboard with Ctrl-X/Ctrl-C/Ctrl-V - Suppress DF keyboard events when a DFHack keybinding is matched. This prevents, for example, a backtick from appearing in a textbox as text when you launch `gui/launcher` from the backtick keybinding. diff --git a/plugins/stockpiles/StockpileSerializer.cpp b/plugins/stockpiles/StockpileSerializer.cpp index 4e2806e22..536ad3e4e 100644 --- a/plugins/stockpiles/StockpileSerializer.cpp +++ b/plugins/stockpiles/StockpileSerializer.cpp @@ -615,7 +615,9 @@ static bool serialize_list_creature(color_ostream& out, FuncWriteExport add_valu } static string get_filter_string(df::creature_raw *r) { - if (!r->caste.size() || !r->caste[0]->flags.is_set(df::enums::caste_raw_flags::PET)) + if (!r->caste.size() || + (!r->caste[0]->flags.is_set(df::enums::caste_raw_flags::PET) && + !r->caste[0]->flags.is_set(df::enums::caste_raw_flags::PET_EXOTIC))) return r->name[0]; return r->name[0] + "/tameable"; } From 04b0c16f0fc00846e25eeb38fdc68bba94c43073 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 16 Jul 2023 07:13:50 +0000 Subject: [PATCH 104/851] 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 19dd3a941..8358a5173 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 19dd3a94162a2ff3374cbdb1cadc92b55a626c92 +Subproject commit 8358a51735ac1daeaa11d5a008c16301fa6759ce From 5c7aea0775a6de9a436813f1c25af2bfd5540816 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 15 Jul 2023 20:20:51 -0700 Subject: [PATCH 105/851] fix logic for autotrain and autotrade --- docs/changelog.txt | 2 ++ plugins/logistics.cpp | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 6e669c893..dc5c2ce46 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -38,6 +38,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Fixes - Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing +- `logistics`: don't autotrain domestic animals brought by invaders (they'll get attacked by friendly creatures as soon as you let them out of their cage) +- `logistics`: don't bring trade goods to depot if the only caravans present are tribute caravans ## Misc Improvements - `stockpiles`: include exotic pets in the "tameable" filter diff --git a/plugins/logistics.cpp b/plugins/logistics.cpp index 20b2c343f..a7da0e553 100644 --- a/plugins/logistics.cpp +++ b/plugins/logistics.cpp @@ -330,11 +330,13 @@ private: df::building_tradedepotst * const depot; static df::building_tradedepotst * get_active_trade_depot() { - // at least one caravan must be approaching or ready to trade + // at least one non-tribute caravan must be approaching or ready to trade if (!plotinfo->caravans.size()) return NULL; bool found = false; for (auto caravan : plotinfo->caravans) { + if (caravan->flags.bits.tribute) + continue; auto trade_state = caravan->trade_state; auto time_remaining = caravan->time_remaining; if ((trade_state == df::caravan_state::T_trade_state::Approaching || @@ -392,8 +394,9 @@ public: bool can_designate(color_ostream& out, df::item* item) override { auto unit = get_caged_unit(item); - return unit && Units::isTamable(unit) && !Units::isTame(unit) - && !has_training_assignment(unit); + return unit && !Units::isInvader(unit) && + Units::isTamable(unit) && !Units::isTame(unit) && + !has_training_assignment(unit); } bool designate(color_ostream& out, df::item* item) override { From 39612f0d5a4e36137982ffdf192e25e5f5e8a681 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 16 Jul 2023 11:55:45 -0700 Subject: [PATCH 106/851] trade a bin if any contents can be traded the new trade screens will make it easy to filter out unwanted items later --- docs/dev/Lua API.rst | 7 ++++++- library/LuaApi.cpp | 1 + library/include/modules/Items.h | 4 +++- library/modules/Items.cpp | 21 +++++++++++++++++++++ plugins/logistics.cpp | 2 +- 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 11bac3f61..6862f1d1e 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1797,7 +1797,12 @@ Items module * ``dfhack.items.canTradeWithContents(item)`` - Checks whether the item and all items it contains, if any, can be traded. + Returns false if the item or any contained items cannot be traded. + +* ``canTradeAnyWithContents(item)`` + + Returns true if the item is empty and can be traded or if the item contains + any item that can be traded. * ``dfhack.items.markForTrade(item, depot)`` diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 7afb3b9ea..55d265baf 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2025,6 +2025,7 @@ static const LuaWrapper::FunctionReg dfhack_items_module[] = { WRAPM(Items, checkMandates), WRAPM(Items, canTrade), WRAPM(Items, canTradeWithContents), + WRAPM(Items, canTradeAnyWithContents), WRAPM(Items, markForTrade), WRAPM(Items, isRouteVehicle), WRAPM(Items, isSquadEquipment), diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h index 7541660f4..beccd669a 100644 --- a/library/include/modules/Items.h +++ b/library/include/modules/Items.h @@ -199,8 +199,10 @@ DFHACK_EXPORT int32_t createItem(df::item_type type, int16_t item_subtype, int16 DFHACK_EXPORT bool checkMandates(df::item *item); /// Checks whether the item can be traded DFHACK_EXPORT bool canTrade(df::item *item); -/// Checks whether the item and all items it contains, if any, can be traded +/// Returns false if the item or any contained items cannot be traded DFHACK_EXPORT bool canTradeWithContents(df::item *item); +/// Returns true if the item is empty and can be traded or if the item contains any item that can be traded +DFHACK_EXPORT bool canTradeAnyWithContents(df::item *item); /// marks the given item for trade at the given depot DFHACK_EXPORT bool markForTrade(df::item *item, df::building_tradedepotst *depot); /// Returns true if an active caravan will pay extra for the given item diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 3fc08813c..3694e0203 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -2172,6 +2172,27 @@ bool Items::canTradeWithContents(df::item *item) return true; } +bool Items::canTradeAnyWithContents(df::item *item) +{ + CHECK_NULL_POINTER(item); + + if (item->flags.bits.in_inventory) + return false; + + vector contained_items; + getContainedItems(item, &contained_items); + + if (contained_items.empty()) + return canTrade(item); + + for (df::item *cit : contained_items) { + if (canTrade(cit)) + return true; + } + + return false; +} + bool Items::markForTrade(df::item *item, df::building_tradedepotst *depot) { CHECK_NULL_POINTER(item); CHECK_NULL_POINTER(depot); diff --git a/plugins/logistics.cpp b/plugins/logistics.cpp index a7da0e553..643fb4941 100644 --- a/plugins/logistics.cpp +++ b/plugins/logistics.cpp @@ -317,7 +317,7 @@ public: } bool can_designate(color_ostream& out, df::item* item) override { - return Items::canTradeWithContents(item); + return Items::canTradeAnyWithContents(item); } bool designate(color_ostream& out, df::item* item) override { From e565aa35788dafb2ff872fc4d34bb1a7da64e953 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 16 Jul 2023 11:58:00 -0700 Subject: [PATCH 107/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index dc5c2ce46..354eec135 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -43,6 +43,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Misc Improvements - `stockpiles`: include exotic pets in the "tameable" filter +- `logistics`: bring an autotraded bin to the depot if any item inside is tradeable instead of marking all items within the bin as untradeable if any individual item is untradeable - `autonick`: add more variety to nicknames based on famous literary dwarves - ``widgets.EditField``: DFHack edit fields now support cut/copy/paste with the system clipboard with Ctrl-X/Ctrl-C/Ctrl-V - Suppress DF keyboard events when a DFHack keybinding is matched. This prevents, for example, a backtick from appearing in a textbox as text when you launch `gui/launcher` from the backtick keybinding. From 2fa4efbb8afc42a948e0535182e42500091b160f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 15 Jul 2023 14:31:43 -0700 Subject: [PATCH 108/851] initial implementation of pasture assignment screen --- docs/changelog.txt | 1 + plugins/CMakeLists.txt | 2 +- plugins/lua/zone.lua | 820 +++++++++++++++++++++++++++++++++++++++++ plugins/zone.cpp | 21 +- 4 files changed, 834 insertions(+), 10 deletions(-) create mode 100644 plugins/lua/zone.lua diff --git a/docs/changelog.txt b/docs/changelog.txt index 6e669c893..e7c9fe568 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -35,6 +35,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins - `3dveins`: reinstated for v50, this plugin replaces vanilla DF's blobby vein generation with veins that flow smoothly and naturally between z-levels +- `zone`: new searchable, sortable, filterable screen for assigning units to pastures ## Fixes - Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 63e5274ae..c037fc4a0 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -168,7 +168,7 @@ dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua) 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) +dfhack_plugin(zone zone.cpp LINK_LIBRARIES lua) # If you are adding a plugin that you do not intend to commit to the DFHack repo, # see instructions for adding "external" plugins at the end of this file. diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua new file mode 100644 index 000000000..d712747e8 --- /dev/null +++ b/plugins/lua/zone.lua @@ -0,0 +1,820 @@ +local _ENV = mkmodule('plugins.zone') + +local gui = require('gui') +local overlay = require('plugins.overlay') +local widgets = require('gui.widgets') + +local CH_UP = string.char(30) +local CH_DN = string.char(31) +local CH_MALE = string.char(11) +local CH_FEMALE = string.char(12) + +local STATUS = { + NONE={label='Unknown', value=0}, + PASTURED_HERE={label='Pastured here', value=1}, + PASTURED_ELSEWHERE={label='Pastured elsewhere', value=2}, + RESTRAINT={label='On restraint', value=3}, + BUILT_CAGE={label='On display in cage', value=4}, + ITEM_CAGE={label='In movable cage', value=5}, + ROAMING={label='Roaming', value=6}, +} +local STATUS_REVMAP = {} +for k, v in pairs(STATUS) do + STATUS_REVMAP[v.value] = k +end + +local DISPOSITION = { + NONE={label='Unknown', value=0}, + PET={label='Pet', value=1}, + TAME={label='Domesticated', value=2}, + TRAINED={label='Partially trained', value=3}, + WILD_TRAINABLE={label='Wild (trainable)', value=4}, + WILD_UNTRAINABLE={label='Wild (untrainable)', value=5}, + HOSTILE={label='Hostile', value=6}, +} +local DISPOSITION_REVMAP = {} +for k, v in pairs(DISPOSITION) do + DISPOSITION_REVMAP[v.value] = k +end + +local EGG = { + NONE={label='Unknown', value=0}, + NOT_EGG_LAYING={label='Not egg laying', value=1}, + EGG_LAYING={label='Egg laying', value=2}, +} + +local GRAZE = { + NONE={label='Unknown', value=0}, + NOT_GRAZING={label='Not grazing', value=1}, + GRAZING={label='Grazing', value=2}, +} + +-- ------------------- +-- Pasture +-- + +local STATUS_COL_WIDTH = 18 +local DISPOSITION_COL_WIDTH = 18 +local GENDER_COL_WIDTH = 6 +local LARGE_SLIDER_LABEL_WIDTH = STATUS_COL_WIDTH + 4 +local LARGE_SLIDER_WIDTH = 48 +local SMALL_SLIDER_LABEL_WIDTH = 18 +local SMALL_SLIDER_WIDTH = 40 + +Pasture = defclass(Pasture, widgets.Window) +Pasture.ATTRS { + frame_title='Assign units to pasture', + frame={w=LARGE_SLIDER_WIDTH+SMALL_SLIDER_WIDTH+6, h=47}, + resizable=true, + resize_min={h=27}, +} + +local function sort_noop(a, b) + -- this function is used as a marker and never actually gets called + error('sort_noop should not be called') +end + +local function sort_base(a, b) + if a.data.race == b.data.race then + return a.data.gender < b.data.gender + end + return a.data.race < b.data.race +end + +local function sort_by_name_desc(a, b) + if a.search_key == b.search_key then + return sort_base(a, b) + end + return a.search_key < b.search_key +end + +local function sort_by_name_asc(a, b) + if a.search_key == b.search_key then + return sort_base(a, b) + end + return a.search_key > b.search_key +end + +local function sort_by_gender_desc(a, b) + if a.data.gender == b.data.gender then + return sort_base(a, b) + end + return a.data.gender < b.data.gender +end + +local function sort_by_gender_asc(a, b) + if a.data.gender == b.data.gender then + return sort_base(a, b) + end + return a.data.gender > b.data.gender +end + +local function sort_by_disposition_desc(a, b) + if a.data.disposition == b.data.disposition then + return sort_base(a, b) + end + return a.data.disposition < b.data.disposition +end + +local function sort_by_disposition_asc(a, b) + if a.data.disposition == b.data.disposition then + return sort_base(a, b) + end + return a.data.disposition > b.data.disposition +end + +local function sort_by_status_desc(a, b) + if a.data.status == b.data.status then + return sort_base(a, b) + end + return a.data.status < b.data.status +end + +local function sort_by_status_asc(a, b) + if a.data.status == b.data.status then + return sort_base(a, b) + end + return a.data.status > b.data.status +end + +function Pasture:init() + self:addviews{ + widgets.CycleHotkeyLabel{ + view_id='sort', + frame={l=0, t=0, w=26}, + label='Sort by:', + key='CUSTOM_SHIFT_S', + options={ + {label='status'..CH_DN, value=sort_by_status_desc}, + {label='status'..CH_UP, value=sort_by_status_asc}, + {label='disposition'..CH_DN, value=sort_by_disposition_desc}, + {label='disposition'..CH_UP, value=sort_by_disposition_asc}, + {label='gender'..CH_DN, value=sort_by_gender_desc}, + {label='gender'..CH_UP, value=sort_by_gender_asc}, + {label='name'..CH_DN, value=sort_by_name_desc}, + {label='name'..CH_UP, value=sort_by_name_asc}, + }, + initial_option=sort_by_status_desc, + on_change=self:callback('refresh_list', 'sort'), + }, + widgets.EditField{ + view_id='search', + frame={l=35, t=0}, + label_text='Search: ', + on_char=function(ch) return ch:match('[%l -]') end, + }, + widgets.Panel{ + frame={t=2, l=0, w=LARGE_SLIDER_WIDTH, h=4}, + subviews={ + widgets.CycleHotkeyLabel{ + view_id='min_status', + frame={l=0, t=0, w=LARGE_SLIDER_LABEL_WIDTH}, + label='Min status:', + label_below=true, + key_back='CUSTOM_SHIFT_Z', + key='CUSTOM_SHIFT_X', + options={ + {label=STATUS.PASTURED_HERE.label, value=STATUS.PASTURED_HERE.value}, + {label=STATUS.PASTURED_ELSEWHERE.label, value=STATUS.PASTURED_ELSEWHERE.value}, + {label=STATUS.RESTRAINT.label, value=STATUS.RESTRAINT.value}, + {label=STATUS.BUILT_CAGE.label, value=STATUS.BUILT_CAGE.value}, + {label=STATUS.ITEM_CAGE.label, value=STATUS.ITEM_CAGE.value}, + {label=STATUS.ROAMING.label, value=STATUS.ROAMING.value}, + }, + initial_option=STATUS.PASTURED_HERE.value, + on_change=function(val) + if self.subviews.max_status:getOptionValue() < val then + self.subviews.max_status:setOption(val) + end + self:refresh_list() + end, + }, + widgets.CycleHotkeyLabel{ + view_id='max_status', + frame={r=1, t=0, w=LARGE_SLIDER_LABEL_WIDTH}, + label='Max status:', + label_below=true, + key_back='CUSTOM_SHIFT_Q', + key='CUSTOM_SHIFT_W', + options={ + {label=STATUS.PASTURED_HERE.label, value=STATUS.PASTURED_HERE.value}, + {label=STATUS.PASTURED_ELSEWHERE.label, value=STATUS.PASTURED_ELSEWHERE.value}, + {label=STATUS.RESTRAINT.label, value=STATUS.RESTRAINT.value}, + {label=STATUS.BUILT_CAGE.label, value=STATUS.BUILT_CAGE.value}, + {label=STATUS.ITEM_CAGE.label, value=STATUS.ITEM_CAGE.value}, + {label=STATUS.ROAMING.label, value=STATUS.ROAMING.value}, + }, + initial_option=STATUS.ROAMING.value, + on_change=function(val) + if self.subviews.min_status:getOptionValue() > val then + self.subviews.min_status:setOption(val) + end + self:refresh_list() + end, + }, + widgets.RangeSlider{ + frame={l=0, t=3}, + num_stops=6, + get_left_idx_fn=function() + return self.subviews.min_status:getOptionValue() + end, + get_right_idx_fn=function() + return self.subviews.max_status:getOptionValue() + end, + on_left_change=function(idx) self.subviews.min_status:setOption(idx, true) end, + on_right_change=function(idx) self.subviews.max_status:setOption(idx, true) end, + }, + }, + }, + widgets.Panel{ + frame={t=7, l=0, w=LARGE_SLIDER_WIDTH, h=4}, + subviews={ + widgets.CycleHotkeyLabel{ + view_id='min_disposition', + frame={l=0, t=0, w=LARGE_SLIDER_LABEL_WIDTH}, + label='Min disposition:', + label_below=true, + key_back='CUSTOM_SHIFT_C', + key='CUSTOM_SHIFT_V', + options={ + {label=DISPOSITION.PET.label, value=DISPOSITION.PET.value}, + {label=DISPOSITION.TAME.label, value=DISPOSITION.TAME.value}, + {label=DISPOSITION.TRAINED.label, value=DISPOSITION.TRAINED.value}, + {label=DISPOSITION.WILD_TRAINABLE.label, value=DISPOSITION.WILD_TRAINABLE.value}, + {label=DISPOSITION.WILD_UNTRAINABLE.label, value=DISPOSITION.WILD_UNTRAINABLE.value}, + {label=DISPOSITION.HOSTILE.label, value=DISPOSITION.HOSTILE.value}, + }, + initial_option=DISPOSITION.PET.value, + on_change=function(val) + if self.subviews.max_disposition:getOptionValue() < val then + self.subviews.max_disposition:setOption(val) + end + self:refresh_list() + end, + }, + widgets.CycleHotkeyLabel{ + view_id='max_disposition', + frame={r=1, t=0, w=LARGE_SLIDER_LABEL_WIDTH}, + label='Max disposition:', + label_below=true, + key_back='CUSTOM_SHIFT_E', + key='CUSTOM_SHIFT_R', + options={ + {label=DISPOSITION.PET.label, value=DISPOSITION.PET.value}, + {label=DISPOSITION.TAME.label, value=DISPOSITION.TAME.value}, + {label=DISPOSITION.TRAINED.label, value=DISPOSITION.TRAINED.value}, + {label=DISPOSITION.WILD_TRAINABLE.label, value=DISPOSITION.WILD_TRAINABLE.value}, + {label=DISPOSITION.WILD_UNTRAINABLE.label, value=DISPOSITION.WILD_UNTRAINABLE.value}, + {label=DISPOSITION.HOSTILE.label, value=DISPOSITION.HOSTILE.value}, + }, + initial_option=DISPOSITION.HOSTILE.value, + on_change=function(val) + if self.subviews.min_disposition:getOptionValue() > val then + self.subviews.min_disposition:setOption(val) + end + self:refresh_list() + end, + }, + widgets.RangeSlider{ + frame={l=0, t=3}, + num_stops=6, + get_left_idx_fn=function() + return self.subviews.min_disposition:getOptionValue() + end, + get_right_idx_fn=function() + return self.subviews.max_disposition:getOptionValue() + end, + on_left_change=function(idx) self.subviews.min_disposition:setOption(idx, true) end, + on_right_change=function(idx) self.subviews.max_disposition:setOption(idx, true) end, + }, + }, + }, + widgets.Panel{ + frame={t=2, l=LARGE_SLIDER_WIDTH+1, w=SMALL_SLIDER_WIDTH, h=4}, + subviews={ + widgets.CycleHotkeyLabel{ + view_id='min_egg', + frame={l=0, t=0, w=SMALL_SLIDER_LABEL_WIDTH}, + label='Min egg:', + label_below=true, + key_back='CUSTOM_SHIFT_B', + key='CUSTOM_SHIFT_N', + options={ + {label=EGG.NOT_EGG_LAYING.label, value=EGG.NOT_EGG_LAYING.value}, + {label=EGG.EGG_LAYING.label, value=EGG.EGG_LAYING.value}, + }, + initial_option=EGG.NOT_EGG_LAYING.value, + on_change=function(val) + if self.subviews.max_egg:getOptionValue() < val then + self.subviews.max_egg:setOption(val) + end + self:refresh_list() + end, + }, + widgets.CycleHotkeyLabel{ + view_id='max_egg', + frame={r=1, t=0, w=SMALL_SLIDER_LABEL_WIDTH}, + label='Max egg:', + label_below=true, + key_back='CUSTOM_SHIFT_T', + key='CUSTOM_SHIFT_Y', + options={ + {label=EGG.NOT_EGG_LAYING.label, value=EGG.NOT_EGG_LAYING.value}, + {label=EGG.EGG_LAYING.label, value=EGG.EGG_LAYING.value}, + }, + initial_option=EGG.EGG_LAYING.value, + on_change=function(val) + if self.subviews.min_egg:getOptionValue() > val then + self.subviews.min_egg:setOption(val) + end + self:refresh_list() + end, + }, + widgets.RangeSlider{ + frame={l=0, t=3}, + num_stops=2, + get_left_idx_fn=function() + return self.subviews.min_egg:getOptionValue() + end, + get_right_idx_fn=function() + return self.subviews.max_egg:getOptionValue() + end, + on_left_change=function(idx) self.subviews.min_egg:setOption(idx, true) end, + on_right_change=function(idx) self.subviews.max_egg:setOption(idx, true) end, + }, + }, + }, + widgets.Panel{ + frame={t=7, l=LARGE_SLIDER_WIDTH+1, w=SMALL_SLIDER_WIDTH, h=4}, + subviews={ + widgets.CycleHotkeyLabel{ + view_id='min_graze', + frame={l=0, t=0, w=SMALL_SLIDER_LABEL_WIDTH}, + label='Min graze:', + label_below=true, + key_back='CUSTOM_SHIFT_M', + key='CUSTOM_SHIFT_L', + options={ + {label=GRAZE.NOT_GRAZING.label, value=GRAZE.NOT_GRAZING.value}, + {label=GRAZE.GRAZING.label, value=GRAZE.GRAZING.value}, + }, + initial_option=GRAZE.NOT_GRAZING.value, + on_change=function(val) + if self.subviews.max_graze:getOptionValue() < val then + self.subviews.max_graze:setOption(val) + end + self:refresh_list() + end, + }, + widgets.CycleHotkeyLabel{ + view_id='max_graze', + frame={r=1, t=0, w=SMALL_SLIDER_LABEL_WIDTH}, + label='Max graze:', + label_below=true, + key_back='CUSTOM_SHIFT_U', + key='CUSTOM_SHIFT_I', + options={ + {label=GRAZE.NOT_GRAZING.label, value=GRAZE.NOT_GRAZING.value}, + {label=GRAZE.GRAZING.label, value=GRAZE.GRAZING.value}, + }, + initial_option=GRAZE.GRAZING.value, + on_change=function(val) + if self.subviews.min_graze:getOptionValue() > val then + self.subviews.min_graze:setOption(val) + end + self:refresh_list() + end, + }, + widgets.RangeSlider{ + frame={l=0, t=3}, + num_stops=2, + get_left_idx_fn=function() + return self.subviews.min_graze:getOptionValue() + end, + get_right_idx_fn=function() + return self.subviews.max_graze:getOptionValue() + end, + on_left_change=function(idx) self.subviews.min_graze:setOption(idx, true) end, + on_right_change=function(idx) self.subviews.max_graze:setOption(idx, true) end, + }, + }, + }, + widgets.Panel{ + view_id='list_panel', + frame={t=12, l=0, r=0, b=4}, + subviews={ + widgets.CycleHotkeyLabel{ + view_id='sort_status', + frame={t=0, l=0, w=7}, + options={ + {label='status', value=sort_noop}, + {label='status'..CH_DN, value=sort_by_status_desc}, + {label='status'..CH_UP, value=sort_by_status_asc}, + }, + initial_option=sort_by_status_desc, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_status'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_disposition', + frame={t=0, l=STATUS_COL_WIDTH+2, w=12}, + options={ + {label='disposition', value=sort_noop}, + {label='disposition'..CH_DN, value=sort_by_disposition_desc}, + {label='disposition'..CH_UP, value=sort_by_disposition_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_disposition'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_gender', + frame={t=0, l=STATUS_COL_WIDTH+2+DISPOSITION_COL_WIDTH+2, w=7}, + options={ + {label='gender', value=sort_noop}, + {label='gender'..CH_DN, value=sort_by_gender_desc}, + {label='gender'..CH_UP, value=sort_by_gender_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_gender'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_name', + frame={t=0, l=STATUS_COL_WIDTH+2+DISPOSITION_COL_WIDTH+2+GENDER_COL_WIDTH+2, w=5}, + options={ + {label='name', value=sort_noop}, + {label='name'..CH_DN, value=sort_by_name_desc}, + {label='name'..CH_UP, value=sort_by_name_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_name'), + }, + widgets.FilteredList{ + view_id='list', + frame={l=0, t=2, r=0, b=0}, + on_submit=self:callback('toggle_item'), + on_submit2=self:callback('toggle_range'), + on_select=self:callback('select_item'), + }, + } + }, + widgets.HotkeyLabel{ + frame={l=0, b=2}, + label='Assign all/none', + key='CUSTOM_CTRL_A', + on_activate=self:callback('toggle_visible'), + auto_width=true, + }, + widgets.WrappedLabel{ + frame={b=0, l=0, r=0}, + text_to_wrap='Click to assign/unassign to current pasture. Shift click to assign/unassign a range.', + }, + } + + -- replace the FilteredList's built-in EditField with our own + self.subviews.list.list.frame.t = 0 + self.subviews.list.edit.visible = false + self.subviews.list.edit = self.subviews.search + self.subviews.search.on_change = self.subviews.list:callback('onFilterChange') + + self.subviews.list:setChoices(self:get_choices()) +end + +function Pasture:refresh_list(sort_widget, sort_fn) + sort_widget = sort_widget or 'sort' + sort_fn = sort_fn or self.subviews.sort:getOptionValue() + if sort_fn == sort_noop then + self.subviews[sort_widget]:cycle() + return + end + for _,widget_name in ipairs{'sort', 'sort_status', 'sort_disposition', 'sort_gender', 'sort_name'} do + self.subviews[widget_name]:setOption(sort_fn) + end + local list = self.subviews.list + local saved_filter = list:getFilter() + list:setFilter('') + list:setChoices(self:get_choices(), list:getSelected()) + list:setFilter(saved_filter) +end + +local function make_search_key(data) + local out = '' + for c in data.desc:gmatch("[%w%s]") do + out = out .. c:lower() + end + return out +end + +local function make_choice_text(data) + return { + {width=STATUS_COL_WIDTH, text=function() return STATUS[STATUS_REVMAP[data.status]].label end}, + {gap=2, width=DISPOSITION_COL_WIDTH, text=function() return DISPOSITION[DISPOSITION_REVMAP[data.disposition]].label end}, + {gap=2, width=GENDER_COL_WIDTH, text=data.gender == 0 and CH_FEMALE or CH_MALE}, + {gap=2, text=data.desc}, + } +end + +local function get_unit_description(unit, raw) + local race = dfhack.units.isChild(unit) and raw.general_child_name[0] or raw.caste[unit.caste].caste_name[0] + local name = dfhack.TranslateName(dfhack.units.getVisibleName(unit)) + if name and #name > 0 then + name = ('%s, %s'):format(name, race) + else + name = race + end + if #unit.syndromes.active > 0 then + for _, unit_syndrome in ipairs(unit.syndromes.active) do + local syndrome = df.syndrome.find(unit_syndrome.type) + if not syndrome then goto continue end + for _, effect in ipairs(syndrome.ce) do + if df.creature_interaction_effect_display_namest:is_instance(effect) then + return name .. ' ' .. effect.name + end + end + ::continue:: + end + end + return name +end + +local function get_cage_ref(unit) + return dfhack.units.getGeneralRef(unit, df.general_ref_type.CONTAINED_IN_ITEM) +end + +local function get_status(unit) + local assigned_pasture_ref = dfhack.units.getGeneralRef(unit, df.general_ref_type.BUILDING_CIVZONE_ASSIGNED) + if assigned_pasture_ref then + if df.global.game.main_interface.civzone.cur_bld.id == assigned_pasture_ref.building_id then + return STATUS.PASTURED_HERE.value + else + return STATUS.PASTURED_ELSEWHERE.value + end + end + if dfhack.units.getGeneralRef(unit, df.general_ref_type.BUILDING_CHAIN) then + return STATUS.RESTRAINT.value + end + local cage_ref = get_cage_ref(unit) + if cage_ref then + local cage = df.item.find(cage_ref.item_id) + if dfhack.items.getGeneralRef(cage, df.general_ref_type.BUILDING_HOLDER) then + return STATUS.BUILT_CAGE.value + else + return STATUS.ITEM_CAGE.value + end + end + return STATUS.ROAMING.value +end + +local function get_disposition(unit) + local disposition = DISPOSITION.NONE + if dfhack.units.isPet(unit) then + disposition = DISPOSITION.PET + elseif dfhack.units.isDomesticated(unit) then + disposition = DISPOSITION.TAME + elseif dfhack.units.isTame(unit) then + disposition = DISPOSITION.TRAINED + elseif dfhack.units.isTamable(unit) then + disposition = DISPOSITION.WILD_TRAINABLE + elseif dfhack.units.isInvader(unit) then + disposition = DISPOSITION.HOSTILE + else + disposition = DISPOSITION.WILD_UNTRAINABLE + end + return disposition.value +end + +local function is_pasturable_unit(unit) + return dfhack.units.isActive(unit) and + ((dfhack.units.isAnimal(unit) and dfhack.units.isOwnCiv(unit)) or get_cage_ref(unit)) and + not dfhack.units.isDead(unit) and + not dfhack.units.isMerchant(unit) and + not dfhack.units.isForest(unit) + +end + +function Pasture:cache_choices() + if self.choices then return self.choices end + + local choices = {} + for _, unit in ipairs(df.global.world.units.active) do + if not is_pasturable_unit(unit) then goto continue end + local raw = df.creature_raw.find(unit.race) + local data = { + unit=unit, + desc=get_unit_description(unit, raw), + gender=unit.sex, + race=raw.creature_id, + status=get_status(unit), + disposition=get_disposition(unit), + egg=dfhack.units.isEggLayer(unit) and EGG.EGG_LAYING.value or EGG.NOT_EGG_LAYING.value, + graze=dfhack.units.isGrazer(unit) and GRAZE.GRAZING.value or GRAZE.NOT_GRAZING.value, + } + local choice = { + search_key=make_search_key(data), + data=data, + text=make_choice_text(data), + } + table.insert(choices, choice) + ::continue:: + end + + self.choices = choices + return choices +end + +function Pasture:get_choices() + local raw_choices = self:cache_choices() + local min_status = self.subviews.min_status:getOptionValue() + local max_status = self.subviews.max_status:getOptionValue() + local min_disposition = self.subviews.min_disposition:getOptionValue() + local max_disposition = self.subviews.max_disposition:getOptionValue() + local min_egg = self.subviews.min_egg:getOptionValue() + local max_egg = self.subviews.max_egg:getOptionValue() + local min_graze = self.subviews.min_graze:getOptionValue() + local max_graze = self.subviews.max_graze:getOptionValue() + local choices = {} + for _,choice in ipairs(raw_choices) do + local data = choice.data + if min_status > data.status then goto continue end + if max_status < data.status then goto continue end + if min_disposition > data.disposition then goto continue end + if max_disposition < data.disposition then goto continue end + if min_egg > data.egg then goto continue end + if max_egg < data.egg then goto continue end + if min_graze > data.graze then goto continue end + if max_graze < data.graze then goto continue end + table.insert(choices, choice) + ::continue:: + end + table.sort(choices, self.subviews.sort:getOptionValue()) + return choices +end + +local function unassign_unit(bld, unit) + if not bld then return end + for au_idx, au_id in ipairs(bld.assigned_units) do + if au_id == unit.id then + bld.assigned_units:erase(au_idx) + return + end + end +end + +local function detach_unit(unit) + for idx = #unit.general_refs-1, 0, -1 do + local ref = unit.general_refs[idx] + if df.general_ref_building_civzone_assignedst:is_instance(ref) then + unassign_unit(df.building.find(ref.building_id), unit) + unit.general_refs:erase(idx) + ref:delete() + elseif df.general_ref_contained_in_itemst:is_instance(ref) then + local cage = df.item.find(ref.item_id) + if cage then + local built_cage_ref = dfhack.items.getGeneralRef(cage, df.general_ref_type.BUILDING_HOLDER) + if built_cage_ref then + unassign_unit(df.building.find(built_cage_ref.building_id), unit) + -- unit's general ref will be removed when the unit is released from the cage + end + end + elseif df.general_ref_building_chainst:is_instance(ref) then + local chain = df.building.find(ref.building_id) + if chain then + chain.assigned = nil + end + end + end +end + +local function attach_unit(unit) + local pasture = df.global.game.main_interface.civzone.cur_bld + local ref = df.new(df.general_ref_building_civzone_assignedst) + ref.building_id = pasture.id; + unit.general_refs:insert('#', ref) + pasture.assigned_units:insert('#', unit.id) +end + +local function toggle_item_base(choice, target_value) + if target_value == nil then + target_value = choice.data.status ~= STATUS.PASTURED_HERE.value + end + + if target_value and choice.data.status == STATUS.PASTURED_HERE.value then + return + end + if not target_value and choice.data.status ~= STATUS.PASTURED_HERE.value then + return + end + + local unit = choice.data.unit + detach_unit(unit) + + if target_value then + attach_unit(unit) + end + + choice.data.status = get_status(unit) +end + +function Pasture:select_item(idx, choice) + if not dfhack.internal.getModifiers().shift then + self.prev_list_idx = self.subviews.list.list:getSelected() + end +end + +function Pasture:toggle_item(idx, choice) + toggle_item_base(choice) +end + +function Pasture:toggle_range(idx, choice) + if not self.prev_list_idx then + self:toggle_item(idx, choice) + return + end + local choices = self.subviews.list:getVisibleChoices() + local list_idx = self.subviews.list.list:getSelected() + local target_value + for i = list_idx, self.prev_list_idx, list_idx < self.prev_list_idx and 1 or -1 do + target_value = toggle_item_base(choices[i], target_value) + end + self.prev_list_idx = list_idx +end + +function Pasture:toggle_visible() + local target_value + for _, choice in ipairs(self.subviews.list:getVisibleChoices()) do + target_value = toggle_item_base(choice, target_value) + end +end + + +-- ------------------- +-- PastureScreen +-- + +view = view or nil + +PastureScreen = defclass(PastureScreen, gui.ZScreen) +PastureScreen.ATTRS { + focus_path='zone/pasture', +} + +function PastureScreen:init() + self:addviews{Pasture{}} +end + +function PastureScreen:onInput(keys) + local handled = PastureScreen.super.onInput(self, keys) + if keys._MOUSE_L_DOWN then + -- if any click is made outside of our window, we need to recheck unit properites + local window = self.subviews[1] + if not window:getMouseFramePos() then + for _, choice in ipairs(self.subviews.list:getChoices()) do + choice.data.status = get_status(choice.data.unit) + end + window:refresh_list() + end + end + return handled +end + +function PastureScreen:onRenderFrame() + if df.global.game.main_interface.bottom_mode_selected ~= df.main_bottom_mode_type.ZONE or + not df.global.game.main_interface.civzone.cur_bld or + df.global.game.main_interface.civzone.cur_bld.type ~= df.civzone_type.Pen + then + view:dismiss() + end +end + +function PastureScreen:onDismiss() + view = nil +end + +-- ------------------- +-- PastureOverlay +-- + +PastureOverlay = defclass(PastureOverlay, overlay.OverlayWidget) +PastureOverlay.ATTRS{ + default_pos={x=9,y=13}, + default_enabled=true, + viewscreens='dwarfmode/Zone/Some/Pen', + frame={w=30, h=1}, + frame_background=gui.CLEAR_PEN, +} + +function PastureOverlay:init() + self:addviews{ + widgets.HotkeyLabel{ + frame={t=0, l=0}, + label='DFHack search and sort', + key='CUSTOM_CTRL_T', + on_activate=function() view = view and view:raise() or PastureScreen{}:show() end, + }, + } +end + +OVERLAY_WIDGETS = { + pasture=PastureOverlay, +} + +return _ENV diff --git a/plugins/zone.cpp b/plugins/zone.cpp index 878014bb0..5d162302a 100644 --- a/plugins/zone.cpp +++ b/plugins/zone.cpp @@ -15,6 +15,13 @@ // - unassign single creature under cursor from current zone // - pitting own dwarves :) +#include "PluginManager.h" + +using namespace DFHack; + +DFHACK_PLUGIN("zone"); + +/* #include #include #include @@ -29,8 +36,6 @@ #include "df/unit_relationship_type.h" #include "df/viewscreen_dwarfmodest.h" #include "df/world.h" - -#include "PluginManager.h" #include "uicommon.h" #include "VTableInterpose.h" @@ -49,9 +54,6 @@ using std::unordered_map; using std::unordered_set; using std::vector; -using namespace DFHack; - -DFHACK_PLUGIN("zone"); DFHACK_PLUGIN_IS_ENABLED(is_enabled); REQUIRE_GLOBAL(cursor); @@ -2177,11 +2179,12 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { return CR_OK; } +*/ DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { - commands.push_back(PluginCommand( - "zone", - "Manage activity zones.", - df_zone)); + // commands.push_back(PluginCommand( + // "zone", + // "Manage activity zones.", + // df_zone)); return CR_OK; } From b10ef79a293a15757885f5b79175b94b94389936 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 15 Jul 2023 15:17:15 -0700 Subject: [PATCH 109/851] tag units that are opposed to life as hostile --- plugins/lua/zone.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index d712747e8..faafc1a59 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -574,7 +574,7 @@ local function get_disposition(unit) disposition = DISPOSITION.TRAINED elseif dfhack.units.isTamable(unit) then disposition = DISPOSITION.WILD_TRAINABLE - elseif dfhack.units.isInvader(unit) then + elseif dfhack.units.isInvader(unit) or dfhack.units.isOpposedToLife(unit) then disposition = DISPOSITION.HOSTILE else disposition = DISPOSITION.WILD_UNTRAINABLE From 4331d7bcc735cc140eb256c1edc034d6f60e0578 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 15 Jul 2023 19:26:59 -0700 Subject: [PATCH 110/851] document the overlay functionality --- docs/plugins/zone.rst | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/docs/plugins/zone.rst b/docs/plugins/zone.rst index af6ee2b5f..2e1bbc613 100644 --- a/docs/plugins/zone.rst +++ b/docs/plugins/zone.rst @@ -3,7 +3,7 @@ zone .. dfhack-tool:: :summary: Manage activity zones, cages, and the animals therein. - :tags: unavailable fort productivity animals buildings + :tags: unavailable fort productivity animals buildings interface Usage ----- @@ -157,3 +157,31 @@ cages and then place one pen/pasture activity zone above them, covering all cages you want to use. Then use ``zone set`` (like with ``assign``) and run ``zone tocages ``. ``tocages`` can be used together with ``nick`` or ``remnick`` to adjust nicknames while assigning to cages. + +Overlay +------- + +Advanced unit selection is available via an `overlay` widget that appears when +you select a pasture zone. + +In the window that pops up when you click the hotkey hint or hit the hotkey on your keyboard, you can: + +- search for units by name +- sort or filter by status (Pastured here, Pastured elsewhere, On restraint, On + display in cage, In movable cage, or Roaming) +- sort or filter by disposition (Pet, Domesticated, Partially trained, Wild + (trainable), Wild (untrainable), or Hostile) +- sort by gender +- sort by name +- filter by whether the unit lays eggs +- filter by whether the unit needs a grazing area + +The window is fully navigatable via keyboard or mouse. Hit Enter or click on a +unit to assign/unassign it to the currently selected pasture. Shift click to +assign/unassign a range of units. + +You can also keep the window open and click around on different pastures, so +you can manage multiple pastures without having to close and reopen the window. + +As for all other overlays, you can disable this one in `gui/control-panel` on +the Overlays tab if you don't want the option of using it. From 5fb299c6dffc6520b32dd057d970eee9bc36dde0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 16 Jul 2023 12:30:12 -0700 Subject: [PATCH 111/851] expand egg-laying filter to the entire race, not just the unit --- docs/dev/Lua API.rst | 1 + library/LuaApi.cpp | 1 + library/include/modules/Units.h | 1 + library/modules/Units.cpp | 12 ++++++++++++ plugins/lua/zone.lua | 22 +++++++++------------- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 11bac3f61..5552a62b5 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1360,6 +1360,7 @@ Units module * ``dfhack.units.isGeldable(unit)`` * ``dfhack.units.isGelded(unit)`` * ``dfhack.units.isEggLayer(unit)`` +* ``dfhack.units.isEggLayerRace(unit)`` * ``dfhack.units.isGrazer(unit)`` * ``dfhack.units.isMilkable(unit)`` diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 7afb3b9ea..951a77d1d 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1765,6 +1765,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, isGeldable), WRAPM(Units, isGelded), WRAPM(Units, isEggLayer), + WRAPM(Units, isEggLayerRace), WRAPM(Units, isGrazer), WRAPM(Units, isMilkable), WRAPM(Units, isForest), diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 3c56d0890..23b4647b2 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -114,6 +114,7 @@ DFHACK_EXPORT bool isMarkedForGelding(df::unit* unit); DFHACK_EXPORT bool isGeldable(df::unit* unit); DFHACK_EXPORT bool isGelded(df::unit* unit); DFHACK_EXPORT bool isEggLayer(df::unit* unit); +DFHACK_EXPORT bool isEggLayerRace(df::unit* unit); DFHACK_EXPORT bool isGrazer(df::unit* unit); DFHACK_EXPORT bool isMilkable(df::unit* unit); DFHACK_EXPORT bool isForest(df::unit* unit); diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 737ff0982..ed667b2a2 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -555,6 +555,18 @@ bool Units::isEggLayer(df::unit* unit) || caste->flags.is_set(caste_raw_flags::LAYS_UNUSUAL_EGGS); } +bool Units::isEggLayerRace(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + df::creature_raw *raw = world->raws.creatures.all[unit->race]; + for (auto &caste : raw->caste) { + if (caste->flags.is_set(caste_raw_flags::LAYS_EGGS) + || caste->flags.is_set(caste_raw_flags::LAYS_UNUSUAL_EGGS)) + return true; + } + return false; +} + bool Units::isGrazer(df::unit* unit) { CHECK_NULL_POINTER(unit); diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index faafc1a59..70d099721 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -294,15 +294,14 @@ function Pasture:init() subviews={ widgets.CycleHotkeyLabel{ view_id='min_egg', - frame={l=0, t=0, w=SMALL_SLIDER_LABEL_WIDTH}, - label='Min egg:', - label_below=true, + frame={l=0, t=1, w=SMALL_SLIDER_LABEL_WIDTH}, key_back='CUSTOM_SHIFT_B', key='CUSTOM_SHIFT_N', options={ {label=EGG.NOT_EGG_LAYING.label, value=EGG.NOT_EGG_LAYING.value}, {label=EGG.EGG_LAYING.label, value=EGG.EGG_LAYING.value}, }, + option_gap=0, initial_option=EGG.NOT_EGG_LAYING.value, on_change=function(val) if self.subviews.max_egg:getOptionValue() < val then @@ -313,15 +312,14 @@ function Pasture:init() }, widgets.CycleHotkeyLabel{ view_id='max_egg', - frame={r=1, t=0, w=SMALL_SLIDER_LABEL_WIDTH}, - label='Max egg:', - label_below=true, + frame={r=1, t=1, w=SMALL_SLIDER_LABEL_WIDTH}, key_back='CUSTOM_SHIFT_T', key='CUSTOM_SHIFT_Y', options={ {label=EGG.NOT_EGG_LAYING.label, value=EGG.NOT_EGG_LAYING.value}, {label=EGG.EGG_LAYING.label, value=EGG.EGG_LAYING.value}, }, + option_gap=0, initial_option=EGG.EGG_LAYING.value, on_change=function(val) if self.subviews.min_egg:getOptionValue() > val then @@ -349,15 +347,14 @@ function Pasture:init() subviews={ widgets.CycleHotkeyLabel{ view_id='min_graze', - frame={l=0, t=0, w=SMALL_SLIDER_LABEL_WIDTH}, - label='Min graze:', - label_below=true, + frame={l=0, t=1, w=SMALL_SLIDER_LABEL_WIDTH}, key_back='CUSTOM_SHIFT_M', key='CUSTOM_SHIFT_L', options={ {label=GRAZE.NOT_GRAZING.label, value=GRAZE.NOT_GRAZING.value}, {label=GRAZE.GRAZING.label, value=GRAZE.GRAZING.value}, }, + option_gap=0, initial_option=GRAZE.NOT_GRAZING.value, on_change=function(val) if self.subviews.max_graze:getOptionValue() < val then @@ -368,15 +365,14 @@ function Pasture:init() }, widgets.CycleHotkeyLabel{ view_id='max_graze', - frame={r=1, t=0, w=SMALL_SLIDER_LABEL_WIDTH}, - label='Max graze:', - label_below=true, + frame={r=1, t=1, w=SMALL_SLIDER_LABEL_WIDTH}, key_back='CUSTOM_SHIFT_U', key='CUSTOM_SHIFT_I', options={ {label=GRAZE.NOT_GRAZING.label, value=GRAZE.NOT_GRAZING.value}, {label=GRAZE.GRAZING.label, value=GRAZE.GRAZING.value}, }, + option_gap=0, initial_option=GRAZE.GRAZING.value, on_change=function(val) if self.subviews.min_graze:getOptionValue() > val then @@ -605,7 +601,7 @@ function Pasture:cache_choices() race=raw.creature_id, status=get_status(unit), disposition=get_disposition(unit), - egg=dfhack.units.isEggLayer(unit) and EGG.EGG_LAYING.value or EGG.NOT_EGG_LAYING.value, + egg=dfhack.units.isEggLayerRace(unit) and EGG.EGG_LAYING.value or EGG.NOT_EGG_LAYING.value, graze=dfhack.units.isGrazer(unit) and GRAZE.GRAZING.value or GRAZE.NOT_GRAZING.value, } local choice = { From a017700dc65ee314c94157437c0ced2186310176 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 16 Jul 2023 13:43:52 -0700 Subject: [PATCH 112/851] convert egg and graze sliders into tristates --- plugins/lua/zone.lua | 161 ++++++++++--------------------------------- 1 file changed, 35 insertions(+), 126 deletions(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 70d099721..f0dd5e742 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -37,18 +37,6 @@ for k, v in pairs(DISPOSITION) do DISPOSITION_REVMAP[v.value] = k end -local EGG = { - NONE={label='Unknown', value=0}, - NOT_EGG_LAYING={label='Not egg laying', value=1}, - EGG_LAYING={label='Egg laying', value=2}, -} - -local GRAZE = { - NONE={label='Unknown', value=0}, - NOT_GRAZING={label='Not grazing', value=1}, - GRAZING={label='Grazing', value=2}, -} - -- ------------------- -- Pasture -- @@ -56,15 +44,13 @@ local GRAZE = { local STATUS_COL_WIDTH = 18 local DISPOSITION_COL_WIDTH = 18 local GENDER_COL_WIDTH = 6 -local LARGE_SLIDER_LABEL_WIDTH = STATUS_COL_WIDTH + 4 -local LARGE_SLIDER_WIDTH = 48 -local SMALL_SLIDER_LABEL_WIDTH = 18 -local SMALL_SLIDER_WIDTH = 40 +local SLIDER_LABEL_WIDTH = math.max(STATUS_COL_WIDTH, DISPOSITION_COL_WIDTH) + 4 +local SLIDER_WIDTH = 48 Pasture = defclass(Pasture, widgets.Window) Pasture.ATTRS { frame_title='Assign units to pasture', - frame={w=LARGE_SLIDER_WIDTH+SMALL_SLIDER_WIDTH+6, h=47}, + frame={w=6+SLIDER_WIDTH*2, h=47}, resizable=true, resize_min={h=27}, } @@ -164,11 +150,11 @@ function Pasture:init() on_char=function(ch) return ch:match('[%l -]') end, }, widgets.Panel{ - frame={t=2, l=0, w=LARGE_SLIDER_WIDTH, h=4}, + frame={t=2, l=0, w=SLIDER_WIDTH, h=4}, subviews={ widgets.CycleHotkeyLabel{ view_id='min_status', - frame={l=0, t=0, w=LARGE_SLIDER_LABEL_WIDTH}, + frame={l=0, t=0, w=SLIDER_LABEL_WIDTH}, label='Min status:', label_below=true, key_back='CUSTOM_SHIFT_Z', @@ -191,7 +177,7 @@ function Pasture:init() }, widgets.CycleHotkeyLabel{ view_id='max_status', - frame={r=1, t=0, w=LARGE_SLIDER_LABEL_WIDTH}, + frame={r=1, t=0, w=SLIDER_LABEL_WIDTH}, label='Max status:', label_below=true, key_back='CUSTOM_SHIFT_Q', @@ -227,11 +213,11 @@ function Pasture:init() }, }, widgets.Panel{ - frame={t=7, l=0, w=LARGE_SLIDER_WIDTH, h=4}, + frame={t=2, l=SLIDER_WIDTH+2, w=SLIDER_WIDTH, h=4}, subviews={ widgets.CycleHotkeyLabel{ view_id='min_disposition', - frame={l=0, t=0, w=LARGE_SLIDER_LABEL_WIDTH}, + frame={l=0, t=0, w=SLIDER_LABEL_WIDTH}, label='Min disposition:', label_below=true, key_back='CUSTOM_SHIFT_C', @@ -254,7 +240,7 @@ function Pasture:init() }, widgets.CycleHotkeyLabel{ view_id='max_disposition', - frame={r=1, t=0, w=LARGE_SLIDER_LABEL_WIDTH}, + frame={r=1, t=0, w=SLIDER_LABEL_WIDTH}, label='Max disposition:', label_below=true, key_back='CUSTOM_SHIFT_E', @@ -290,114 +276,41 @@ function Pasture:init() }, }, widgets.Panel{ - frame={t=2, l=LARGE_SLIDER_WIDTH+1, w=SMALL_SLIDER_WIDTH, h=4}, + frame={t=7, l=4, r=0, h=1}, subviews={ widgets.CycleHotkeyLabel{ - view_id='min_egg', - frame={l=0, t=1, w=SMALL_SLIDER_LABEL_WIDTH}, + view_id='egg', + frame={l=0, t=0, w=23}, key_back='CUSTOM_SHIFT_B', key='CUSTOM_SHIFT_N', + label='Egg layers:', options={ - {label=EGG.NOT_EGG_LAYING.label, value=EGG.NOT_EGG_LAYING.value}, - {label=EGG.EGG_LAYING.label, value=EGG.EGG_LAYING.value}, + {label='Include', value='include'}, + {label='Only', value='only'}, + {label='Exclude', value='exclude'}, }, - option_gap=0, - initial_option=EGG.NOT_EGG_LAYING.value, - on_change=function(val) - if self.subviews.max_egg:getOptionValue() < val then - self.subviews.max_egg:setOption(val) - end - self:refresh_list() - end, + initial_option='include', + on_change=self:callback('refresh_list'), }, widgets.CycleHotkeyLabel{ - view_id='max_egg', - frame={r=1, t=1, w=SMALL_SLIDER_LABEL_WIDTH}, + view_id='graze', + frame={l=29, t=0, w=20}, key_back='CUSTOM_SHIFT_T', key='CUSTOM_SHIFT_Y', + label='Grazers:', options={ - {label=EGG.NOT_EGG_LAYING.label, value=EGG.NOT_EGG_LAYING.value}, - {label=EGG.EGG_LAYING.label, value=EGG.EGG_LAYING.value}, - }, - option_gap=0, - initial_option=EGG.EGG_LAYING.value, - on_change=function(val) - if self.subviews.min_egg:getOptionValue() > val then - self.subviews.min_egg:setOption(val) - end - self:refresh_list() - end, - }, - widgets.RangeSlider{ - frame={l=0, t=3}, - num_stops=2, - get_left_idx_fn=function() - return self.subviews.min_egg:getOptionValue() - end, - get_right_idx_fn=function() - return self.subviews.max_egg:getOptionValue() - end, - on_left_change=function(idx) self.subviews.min_egg:setOption(idx, true) end, - on_right_change=function(idx) self.subviews.max_egg:setOption(idx, true) end, - }, - }, - }, - widgets.Panel{ - frame={t=7, l=LARGE_SLIDER_WIDTH+1, w=SMALL_SLIDER_WIDTH, h=4}, - subviews={ - widgets.CycleHotkeyLabel{ - view_id='min_graze', - frame={l=0, t=1, w=SMALL_SLIDER_LABEL_WIDTH}, - key_back='CUSTOM_SHIFT_M', - key='CUSTOM_SHIFT_L', - options={ - {label=GRAZE.NOT_GRAZING.label, value=GRAZE.NOT_GRAZING.value}, - {label=GRAZE.GRAZING.label, value=GRAZE.GRAZING.value}, + {label='Include', value='include'}, + {label='Only', value='only'}, + {label='Exclude', value='exclude'}, }, - option_gap=0, - initial_option=GRAZE.NOT_GRAZING.value, - on_change=function(val) - if self.subviews.max_graze:getOptionValue() < val then - self.subviews.max_graze:setOption(val) - end - self:refresh_list() - end, - }, - widgets.CycleHotkeyLabel{ - view_id='max_graze', - frame={r=1, t=1, w=SMALL_SLIDER_LABEL_WIDTH}, - key_back='CUSTOM_SHIFT_U', - key='CUSTOM_SHIFT_I', - options={ - {label=GRAZE.NOT_GRAZING.label, value=GRAZE.NOT_GRAZING.value}, - {label=GRAZE.GRAZING.label, value=GRAZE.GRAZING.value}, - }, - option_gap=0, - initial_option=GRAZE.GRAZING.value, - on_change=function(val) - if self.subviews.min_graze:getOptionValue() > val then - self.subviews.min_graze:setOption(val) - end - self:refresh_list() - end, - }, - widgets.RangeSlider{ - frame={l=0, t=3}, - num_stops=2, - get_left_idx_fn=function() - return self.subviews.min_graze:getOptionValue() - end, - get_right_idx_fn=function() - return self.subviews.max_graze:getOptionValue() - end, - on_left_change=function(idx) self.subviews.min_graze:setOption(idx, true) end, - on_right_change=function(idx) self.subviews.max_graze:setOption(idx, true) end, + initial_option='include', + on_change=self:callback('refresh_list'), }, }, }, widgets.Panel{ view_id='list_panel', - frame={t=12, l=0, r=0, b=4}, + frame={t=9, l=0, r=0, b=4}, subviews={ widgets.CycleHotkeyLabel{ view_id='sort_status', @@ -584,7 +497,6 @@ local function is_pasturable_unit(unit) not dfhack.units.isDead(unit) and not dfhack.units.isMerchant(unit) and not dfhack.units.isForest(unit) - end function Pasture:cache_choices() @@ -601,8 +513,8 @@ function Pasture:cache_choices() race=raw.creature_id, status=get_status(unit), disposition=get_disposition(unit), - egg=dfhack.units.isEggLayerRace(unit) and EGG.EGG_LAYING.value or EGG.NOT_EGG_LAYING.value, - graze=dfhack.units.isGrazer(unit) and GRAZE.GRAZING.value or GRAZE.NOT_GRAZING.value, + egg=dfhack.units.isEggLayerRace(unit), + graze=dfhack.units.isGrazer(unit), } local choice = { search_key=make_search_key(data), @@ -623,10 +535,8 @@ function Pasture:get_choices() local max_status = self.subviews.max_status:getOptionValue() local min_disposition = self.subviews.min_disposition:getOptionValue() local max_disposition = self.subviews.max_disposition:getOptionValue() - local min_egg = self.subviews.min_egg:getOptionValue() - local max_egg = self.subviews.max_egg:getOptionValue() - local min_graze = self.subviews.min_graze:getOptionValue() - local max_graze = self.subviews.max_graze:getOptionValue() + local egg = self.subviews.egg:getOptionValue() + local graze = self.subviews.graze:getOptionValue() local choices = {} for _,choice in ipairs(raw_choices) do local data = choice.data @@ -634,10 +544,10 @@ function Pasture:get_choices() if max_status < data.status then goto continue end if min_disposition > data.disposition then goto continue end if max_disposition < data.disposition then goto continue end - if min_egg > data.egg then goto continue end - if max_egg < data.egg then goto continue end - if min_graze > data.graze then goto continue end - if max_graze < data.graze then goto continue end + if egg == 'only' and not data.egg then goto continue end + if egg == 'exclude' and data.egg then goto continue end + if graze == 'only' and not data.graze then goto continue end + if graze == 'exclude' and data.graze then goto continue end table.insert(choices, choice) ::continue:: end @@ -741,7 +651,6 @@ function Pasture:toggle_visible() end end - -- ------------------- -- PastureScreen -- From ce12cd6e29008b58fd4efd300dc1c8a5f1323025 Mon Sep 17 00:00:00 2001 From: Myk Date: Sun, 16 Jul 2023 14:22:10 -0700 Subject: [PATCH 113/851] colorize! --- plugins/lua/zone.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index f0dd5e742..032582304 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -285,9 +285,9 @@ function Pasture:init() key='CUSTOM_SHIFT_N', label='Egg layers:', options={ - {label='Include', value='include'}, - {label='Only', value='only'}, - {label='Exclude', value='exclude'}, + {label='Include', value='include', pen=COLOR_GREEN}, + {label='Only', value='only', pen=COLOR_YELLOW}, + {label='Exclude', value='exclude', pen=COLOR_RED}, }, initial_option='include', on_change=self:callback('refresh_list'), @@ -299,9 +299,9 @@ function Pasture:init() key='CUSTOM_SHIFT_Y', label='Grazers:', options={ - {label='Include', value='include'}, - {label='Only', value='only'}, - {label='Exclude', value='exclude'}, + {label='Include', value='include', pen=COLOR_GREEN}, + {label='Only', value='only', pen=COLOR_YELLOW}, + {label='Exclude', value='exclude', pen=COLOR_RED}, }, initial_option='include', on_change=self:callback('refresh_list'), From 7c9974cac1bdf728661cb4d8249578afbfa355ba Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 16 Jul 2023 21:24:47 +0000 Subject: [PATCH 114/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 6c0296642..4c4688d51 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 6c02966423052ec4bd19a32cd553820262a1d170 +Subproject commit 4c4688d517e7d1b885f13f662f996c2430ea18e2 From 2d2ecf6f0dc0d737ff22a9c3d4b411324ad85e0d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 16 Jul 2023 20:24:39 -0700 Subject: [PATCH 115/851] add TextButton --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 12 ++++++++-- library/lua/gui/widgets.lua | 46 +++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 163306650..e45273a25 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -65,6 +65,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - ``dfhack.items.markForTrade``: mark items for trade - ``dfhack.items.isRequestedTradeGood``: discover whether an item is named in a trade agreement with an active caravan - ``dfhack.items.getValue``: gained optional ``caravan`` and ``caravan_buying`` parameters for prices that take trader races and agreements into account +- ``widgets.TextButton``: wraps a ``HotkeyLabel`` and decorates it to look more like a button ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 954ea952d..b52bf3c76 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5063,13 +5063,21 @@ The CycleHotkeyLabel widget implements the following methods: selected option if no index is given. If an option was defined as just a string, then this function will return ``nil`` for that option. -ToggleHotkeyLabel ------------------ +ToggleHotkeyLabel class +----------------------- This is a specialized subclass of CycleHotkeyLabel that has two options: ``On`` (with a value of ``true``) and ``Off`` (with a value of ``false``). The ``On`` option is rendered in green. +TextButton class +---------------- + +This is a Panel subclass that wraps a HotkeyLabel with some decorators on the +sides to make it look more like a button, suitable for both graphics and ASCII +mdoes. All HotkeyLabel parameters passed to the constructor are passed through +to the wrapped HotkeyLabel. + List class ---------- diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index b034ed1e8..74d193025 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1489,6 +1489,52 @@ function HotkeyLabel:onInput(keys) end end +---------------- +-- TextButton -- +---------------- + +TextButton = defclass(TextButton, Panel) + +local BUTTON_PEN = dfhack.pen.parse{fg=COLOR_YELLOW, bg=COLOR_RED} + +function TextButton:init(info) + self.label = HotkeyLabel{ + frame={t=0, l=1, r=1}, + key=info.key, + key_sep=info.key_sep, + label=info.label, + on_activate=info.on_activate, + text_pen=info.text_pen, + text_dpen=info.text_dpen, + text_hpen=info.text_hpen, + disabled=info.disabled, + enabled=info.enabled, + auto_height=info.auto_height, + auto_width=info.auto_width, + on_click=info.on_click, + on_rclick=info.on_rclick, + scroll_keys=info.scroll_keys, + } + + self:addviews{ + Label{ + frame={t=0, l=0, w=1}, + text=string.char(221), -- half-width stripe on left + text_pen=BUTTON_PEN, + }, + self.label, + Label{ + frame={t=0, r=0, w=1}, + text=string.char(222), -- half-width stripe on right + text_pen=BUTTON_PEN, + } + } +end + +function TextButton:setLabel(label) + self.label:setLabel(label) +end + ---------------------- -- CycleHotkeyLabel -- ---------------------- From e1946018f88f8f9c69ebe07928a3bd5ef9c17e06 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 16 Jul 2023 20:24:46 -0700 Subject: [PATCH 116/851] use TextButton in zone overlay --- plugins/lua/zone.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 032582304..0040089c8 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -700,16 +700,16 @@ end PastureOverlay = defclass(PastureOverlay, overlay.OverlayWidget) PastureOverlay.ATTRS{ - default_pos={x=9,y=13}, + default_pos={x=7,y=13}, default_enabled=true, viewscreens='dwarfmode/Zone/Some/Pen', - frame={w=30, h=1}, + frame={w=32, h=1}, frame_background=gui.CLEAR_PEN, } function PastureOverlay:init() self:addviews{ - widgets.HotkeyLabel{ + widgets.TextButton{ frame={t=0, l=0}, label='DFHack search and sort', key='CUSTOM_CTRL_T', From b8346cb069a9d40c758277df295a9601b49d961c Mon Sep 17 00:00:00 2001 From: plule <630159+plule@users.noreply.github.com> Date: Mon, 17 Jul 2023 15:42:08 +0200 Subject: [PATCH 117/851] Remove redundant checks on open tiles --- plugins/autodump.cpp | 2 +- plugins/channel-safely/channel-safely-plugin.cpp | 3 +-- plugins/dig-now.cpp | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/autodump.cpp b/plugins/autodump.cpp index a214f5c94..3c8638cea 100644 --- a/plugins/autodump.cpp +++ b/plugins/autodump.cpp @@ -131,7 +131,7 @@ static command_result autodump_main(color_ostream &out, vector & parame return CR_FAILURE; } df::tiletype ttype = MC.tiletypeAt(pos_cursor); - if(!DFHack::isWalkable(ttype) || DFHack::isOpenTerrain(ttype)) + if(!DFHack::isWalkable(ttype)) { out.printerr("Cursor should be placed over a floor.\n"); return CR_FAILURE; diff --git a/plugins/channel-safely/channel-safely-plugin.cpp b/plugins/channel-safely/channel-safely-plugin.cpp index 910e0ee7c..a297bf700 100644 --- a/plugins/channel-safely/channel-safely-plugin.cpp +++ b/plugins/channel-safely/channel-safely-plugin.cpp @@ -120,8 +120,7 @@ df::coord simulate_fall(const df::coord &pos) { while (Maps::ensureTileBlock(resting_pos)) { df::tiletype tt = *Maps::getTileType(resting_pos); - df::tiletype_shape_basic basic_shape = tileShapeBasic(tileShape(tt)); - if (isWalkable(tt) && basic_shape != df::tiletype_shape_basic::Open) + if (isWalkable(tt)) break; --resting_pos.z; } diff --git a/plugins/dig-now.cpp b/plugins/dig-now.cpp index 1cd56255b..028d4af6d 100644 --- a/plugins/dig-now.cpp +++ b/plugins/dig-now.cpp @@ -832,8 +832,7 @@ static DFCoord simulate_fall(const DFCoord &pos) { while (Maps::ensureTileBlock(resting_pos)) { df::tiletype tt = *Maps::getTileType(resting_pos); - df::tiletype_shape_basic basic_shape = tileShapeBasic(tileShape(tt)); - if (isWalkable(tt) && basic_shape != df::tiletype_shape_basic::Open) + if (isWalkable(tt)) break; --resting_pos.z; } From 27f1a4443cfee5bce7e620ffe3228b266b336740 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 17 Jul 2023 13:34:49 -0700 Subject: [PATCH 118/851] rearrange pastures dialog according to feedback --- plugins/lua/zone.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 0040089c8..09ce4daa8 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -213,7 +213,7 @@ function Pasture:init() }, }, widgets.Panel{ - frame={t=2, l=SLIDER_WIDTH+2, w=SLIDER_WIDTH, h=4}, + frame={t=7, l=0, w=SLIDER_WIDTH, h=4}, subviews={ widgets.CycleHotkeyLabel{ view_id='min_disposition', @@ -276,7 +276,7 @@ function Pasture:init() }, }, widgets.Panel{ - frame={t=7, l=4, r=0, h=1}, + frame={t=3, l=SLIDER_WIDTH+2, r=0, h=3}, subviews={ widgets.CycleHotkeyLabel{ view_id='egg', @@ -294,7 +294,7 @@ function Pasture:init() }, widgets.CycleHotkeyLabel{ view_id='graze', - frame={l=29, t=0, w=20}, + frame={l=0, t=2, w=20}, key_back='CUSTOM_SHIFT_T', key='CUSTOM_SHIFT_Y', label='Grazers:', @@ -310,7 +310,7 @@ function Pasture:init() }, widgets.Panel{ view_id='list_panel', - frame={t=9, l=0, r=0, b=4}, + frame={t=12, l=0, r=0, b=4}, subviews={ widgets.CycleHotkeyLabel{ view_id='sort_status', From 7ee3c6d0a529def19b1b75683a746d645d6f7aa8 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 17 Jul 2023 13:46:54 -0700 Subject: [PATCH 119/851] update steam-deploy to v3 --- .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 e4178e1d0..e6c06ffe5 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -64,7 +64,7 @@ jobs: ccache -d win64-cross/ccache --cleanup ccache -d win64-cross/ccache --show-stats - name: Steam deploy - uses: game-ci/steam-deploy@v2 + uses: game-ci/steam-deploy@v3 with: username: ${{ secrets.STEAM_USERNAME }} password: ${{ secrets.STEAM_PASSWORD }} From ab50b140d20536e5c53389e76d8c984c9e0167e1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 17 Jul 2023 17:36:11 -0700 Subject: [PATCH 120/851] remove args no longer used in v3 --- .github/workflows/steam.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index e6c06ffe5..a67a87b81 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -67,10 +67,7 @@ jobs: uses: game-ci/steam-deploy@v3 with: username: ${{ secrets.STEAM_USERNAME }} - password: ${{ secrets.STEAM_PASSWORD }} configVdf: ${{ secrets.STEAM_CONFIG_VDF}} - ssfnFileName: ${{ secrets.STEAM_SSFN_FILE_NAME }} - ssfnFileContents: ${{ secrets.STEAM_SSFN_FILE_CONTENTS }} appId: 2346660 buildDescription: ${{ github.event.inputs.version }} rootPath: build From 9e720b2de75cb54694db500e6239374fa95f9ae2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 18 Jul 2023 03:37:21 -0700 Subject: [PATCH 121/851] properly handle animals in cages in non-cage buildings --- plugins/lua/zone.lua | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 09ce4daa8..e8a943381 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -449,6 +449,17 @@ local function get_cage_ref(unit) return dfhack.units.getGeneralRef(unit, df.general_ref_type.CONTAINED_IN_ITEM) end +local function get_built_cage(item_cage) + if not item_cage then return end + local built_cage_ref = dfhack.items.getGeneralRef(item_cage, df.general_ref_type.BUILDING_HOLDER) + if not built_cage_ref then return end + local built_cage = df.building.find(built_cage_ref.building_id) + if not built_cage then return end + if built_cage:getType() == df.building_type.Cage then + return built_cage + end +end + local function get_status(unit) local assigned_pasture_ref = dfhack.units.getGeneralRef(unit, df.general_ref_type.BUILDING_CIVZONE_ASSIGNED) if assigned_pasture_ref then @@ -463,8 +474,7 @@ local function get_status(unit) end local cage_ref = get_cage_ref(unit) if cage_ref then - local cage = df.item.find(cage_ref.item_id) - if dfhack.items.getGeneralRef(cage, df.general_ref_type.BUILDING_HOLDER) then + if get_built_cage(df.item.find(cage_ref.item_id)) then return STATUS.BUILT_CAGE.value else return STATUS.ITEM_CAGE.value @@ -573,13 +583,10 @@ local function detach_unit(unit) unit.general_refs:erase(idx) ref:delete() elseif df.general_ref_contained_in_itemst:is_instance(ref) then - local cage = df.item.find(ref.item_id) - if cage then - local built_cage_ref = dfhack.items.getGeneralRef(cage, df.general_ref_type.BUILDING_HOLDER) - if built_cage_ref then - unassign_unit(df.building.find(built_cage_ref.building_id), unit) - -- unit's general ref will be removed when the unit is released from the cage - end + local built_cage = get_built_cage(df.item.find(ref.item_id)) + if built_cage and built_cage:getType() == df.building_type.Cage then + unassign_unit(built_cage, unit) + -- unit's general ref will be removed when the unit is released from the cage end elseif df.general_ref_building_chainst:is_instance(ref) then local chain = df.building.find(ref.building_id) From 0d81f5ce6eba0cea97953c81525f22cfa6a4e085 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 18 Jul 2023 23:09:19 -0700 Subject: [PATCH 122/851] don't include dead citizens in the citizens list --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 3 +-- library/modules/Units.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index e45273a25..97bc202fe 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: - Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing - `logistics`: don't autotrain domestic animals brought by invaders (they'll get attacked by friendly creatures as soon as you let them out of their cage) - `logistics`: don't bring trade goods to depot if the only caravans present are tribute caravans +- `gui/create-item`: when choosing a citizen to create the chosen items, avoid choosing a dead citizen ## Misc Improvements - `stockpiles`: include exotic pets in the "tameable" filter diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index b52bf3c76..6776bb617 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1454,8 +1454,7 @@ Units module * ``dfhack.units.getCitizens([ignore_sanity])`` - Returns a table (list) of all citizens, which you would otherwise have to - loop over all units in world and test against ``isCitizen()`` to discover. + Returns a list of all living citizens. * ``dfhack.units.teleport(unit, pos)`` diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index ed667b2a2..f517a07b5 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -841,7 +841,7 @@ df::unit *Units::getUnitByNobleRole(string noble) { bool Units::getCitizens(std::vector &citizens, bool ignore_sanity) { for (auto &unit : world->units.active) { - if (isCitizen(unit, ignore_sanity)) + if (isCitizen(unit, ignore_sanity) && isAlive(unit)) citizens.emplace_back(unit); } return true; From 7ec34ec5f880645c8f3fa2802e8576b6d797da78 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 18 Jul 2023 23:15:22 -0700 Subject: [PATCH 123/851] remove unneeded linkage to SDL --- CMakeLists.txt | 2 +- plugins/remotefortressreader/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f4cb3a9f3..69a3efed9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -394,7 +394,7 @@ macro(dfhack_test name files) if(UNIX AND NOT APPLE) # remove this once our MSVC build env has been updated add_executable(${name} ${files}) target_include_directories(${name} PUBLIC depends/googletest/googletest/include) - target_link_libraries(${name} dfhack gtest SDL) + target_link_libraries(${name} dfhack gtest) add_test(NAME ${name} COMMAND ${name}) endif() endmacro() diff --git a/plugins/remotefortressreader/CMakeLists.txt b/plugins/remotefortressreader/CMakeLists.txt index 262d163f1..37aa64b23 100644 --- a/plugins/remotefortressreader/CMakeLists.txt +++ b/plugins/remotefortressreader/CMakeLists.txt @@ -25,7 +25,7 @@ set(PROJECT_PROTO ) if(UNIX AND NOT APPLE) - set(PROJECT_LIBS ${PROJECT_LIBS} SDL) + set(PROJECT_LIBS ${PROJECT_LIBS}) endif() # this makes sure all the stuff is put in proper places and linked to dfhack From 19643111e0ed27ec316eebc14161aa6b499e737f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 19 Jul 2023 00:35:36 -0700 Subject: [PATCH 124/851] move SUPPRESS_DUPLICATE_KEYBOARD_EVENTS pref into cpp --- docs/Core.rst | 3 --- docs/dev/Lua API.rst | 6 ++++++ library/Core.cpp | 26 +++++++++++++++----------- library/LuaApi.cpp | 14 +++++++++++++- library/include/Core.h | 4 ++++ library/lua/dfhack.lua | 5 ----- 6 files changed, 38 insertions(+), 20 deletions(-) diff --git a/docs/Core.rst b/docs/Core.rst index ac17401dc..a8991147f 100644 --- a/docs/Core.rst +++ b/docs/Core.rst @@ -394,9 +394,6 @@ restarting DF. - ``dfhack.HIDE_ARMOK_TOOLS``: Whether to hide "armok" tools in command lists. -- ``dfhack.SUPPRESS_DUPLICATE_KEYBOARD_EVENTS``: Whether to prevent DFHack - keybindings from producing DF key events. - Miscellaneous notes =================== This section is for odd but important notes that don't fit anywhere else. diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index b52bf3c76..2cf1df52a 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2857,6 +2857,12 @@ and are only documented here for completeness: Sets the system clipboard text from a CP437 string. +* ``dfhack.internal.getSuppressDuplicateKeyboardEvents()`` +* ``dfhack.internal.setSuppressDuplicateKeyboardEvents(suppress)`` + + Gets and sets the flag for whether to suppress DF key events when a DFHack + keybinding is matched and a command is launched. + .. _lua-core-context: Core interpreter context diff --git a/library/Core.cpp b/library/Core.cpp index 0a1c19351..c4b03a7ac 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1423,6 +1423,7 @@ Core::Core() : memset(&(s_mods), 0, sizeof(s_mods)); // set up hotkey capture + suppress_duplicate_keyboard_events = true; hotkey_set = NO; last_world_data_ptr = NULL; last_local_map_ptr = NULL; @@ -1430,7 +1431,6 @@ Core::Core() : top_viewscreen = NULL; color_ostream::log_errors_to_stderr = true; - }; void Core::fatal (std::string output) @@ -2356,12 +2356,14 @@ bool Core::DFH_ncurses_key(int key) return ncurses_wgetch(key, dummy); } -static bool getSuppressDuplicateKeyboardEvents() { - auto L = Lua::Core::State; - color_ostream_proxy out(Core::getInstance().getConsole()); - Lua::StackUnwinder top(L); - return DFHack::Lua::PushModulePublic(out, L, "dfhack", "SUPPRESS_DUPLICATE_KEYBOARD_EVENTS") && - lua_toboolean(L, -1); +bool Core::getSuppressDuplicateKeyboardEvents() { + return suppress_duplicate_keyboard_events; +} + +void Core::setSuppressDuplicateKeyboardEvents(bool suppress) { + DEBUG(keybinding).print("setting suppress_duplicate_keyboard_events to %s\n", + suppress ? "true" : "false"); + suppress_duplicate_keyboard_events = suppress; } // returns true if the event is handled @@ -2396,9 +2398,10 @@ bool Core::DFH_SDL_Event(SDL_Event* ev) DEBUG(keybinding).print("key down: sym=%d (%c)\n", sym, sym); bool handled = SelectHotkey(sym, modstate); if (handled) { - DEBUG(keybinding).print("inhibiting SDL key down event\n"); + DEBUG(keybinding).print("%sinhibiting SDL key down event\n", + suppress_duplicate_keyboard_events ? "" : "not "); hotkey_states[sym] = true; - return getSuppressDuplicateKeyboardEvents(); + return suppress_duplicate_keyboard_events; } } else if (ke.state == SDL_RELEASED) @@ -2411,8 +2414,9 @@ bool Core::DFH_SDL_Event(SDL_Event* ev) auto &te = ev->text; DEBUG(keybinding).print("text input: '%s'\n", te.text); if (strlen(te.text) == 1 && hotkey_states[te.text[0]]) { - DEBUG(keybinding).print("inhibiting SDL text event\n"); - return true; + DEBUG(keybinding).print("%sinhibiting SDL text event\n", + suppress_duplicate_keyboard_events ? "" : "not "); + return suppress_duplicate_keyboard_events; } } diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 2cd900934..050c99b86 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -3611,13 +3611,23 @@ static int internal_md5file(lua_State *L) } } +static int internal_getSuppressDuplicateKeyboardEvents(lua_State *L) { + Lua::Push(L, Core::getInstance().getSuppressDuplicateKeyboardEvents()); + return 1; +} + +static int internal_setSuppressDuplicateKeyboardEvents(lua_State *L) { + bool suppress = lua_toboolean(L, 1); + Core::getInstance().setSuppressDuplicateKeyboardEvents(suppress); + return 0; +} + static const luaL_Reg dfhack_internal_funcs[] = { { "getPE", internal_getPE }, { "getMD5", internal_getmd5 }, { "getAddress", internal_getAddress }, { "setAddress", internal_setAddress }, { "getVTable", internal_getVTable }, - { "adjustOffset", internal_adjustOffset }, { "getMemRanges", internal_getMemRanges }, { "patchMemory", internal_patchMemory }, @@ -3639,6 +3649,8 @@ static const luaL_Reg dfhack_internal_funcs[] = { { "getCommandDescription", internal_getCommandDescription }, { "threadid", internal_threadid }, { "md5File", internal_md5file }, + { "getSuppressDuplicateKeyboardEvents", internal_getSuppressDuplicateKeyboardEvents }, + { "setSuppressDuplicateKeyboardEvents", internal_setSuppressDuplicateKeyboardEvents }, { NULL, NULL } }; diff --git a/library/include/Core.h b/library/include/Core.h index 180b5cc7b..b470ebbde 100644 --- a/library/include/Core.h +++ b/library/include/Core.h @@ -159,6 +159,9 @@ namespace DFHack std::string findScript(std::string name); void getScriptPaths(std::vector *dest); + bool getSuppressDuplicateKeyboardEvents(); + void setSuppressDuplicateKeyboardEvents(bool suppress); + bool ClearKeyBindings(std::string keyspec); bool AddKeyBinding(std::string keyspec, std::string cmdline); std::vector ListKeyBindings(std::string keyspec); @@ -249,6 +252,7 @@ namespace DFHack }; int8_t modstate; + bool suppress_duplicate_keyboard_events; std::map > key_bindings; std::string hotkey_cmd; enum hotkey_set_t { diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 860b56cc1..8ea5e9dac 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -63,11 +63,6 @@ function dfhack.getHideArmokTools() return dfhack.HIDE_ARMOK_TOOLS end -dfhack.SUPPRESS_DUPLICATE_KEYBOARD_EVENTS = true -function dfhack.getSuppressDuplicateKeyboardEvents() - return dfhack.SUPPRESS_DUPLICATE_KEYBOARD_EVENTS -end - -- Error handling safecall = dfhack.safecall From 5ce8dbba68054e99cf5369346841dc7fe4fb0b55 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 19 Jul 2023 15:27:10 +0000 Subject: [PATCH 125/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 4c4688d51..7903cb22e 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 4c4688d517e7d1b885f13f662f996c2430ea18e2 +Subproject commit 7903cb22e3c8ba0d51e71ba5318d63c578b20edb From 2151bb6a78d5f0e422e1d25d9579319f3851d919 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 20 Jul 2023 07:13:22 +0000 Subject: [PATCH 126/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 7903cb22e..1ee2a979c 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 7903cb22e3c8ba0d51e71ba5318d63c578b20edb +Subproject commit 1ee2a979cd341dae0289ad29a97c1bfaed8d5937 From 462ee0cba7f89d1148f885f1725c23c59cd8cab4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 20 Jul 2023 17:43:57 -0700 Subject: [PATCH 127/851] generalize mod directory scanning --- library/lua/script-manager.lua | 50 ++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/library/lua/script-manager.lua b/library/lua/script-manager.lua index 450012357..91b4985ac 100644 --- a/library/lua/script-manager.lua +++ b/library/lua/script-manager.lua @@ -74,7 +74,7 @@ function list() end --------------------- --- mod script paths +-- mod paths -- this perhaps could/should be queried from the Steam API -- are there any installation configurations where this will be wrong, though? @@ -98,8 +98,8 @@ local function get_mod_id_and_version(path) end if not version then -- note this doesn't include the closing brace since some people put - -- non-number characters in here, and DF only reads the digits as the - -- numeric version + -- non-number characters in here, and DF only reads the leading digits + -- as the numeric version _,_,version = line:find('^%[NUMERIC_VERSION:(%d+)') end -- note that we do *not* want to break out of this loop early since @@ -108,37 +108,31 @@ local function get_mod_id_and_version(path) return id, version end -local function add_script_path(mod_script_paths, path) +local function add_mod_paths(mod_paths, id, base_path, subdir) + local sep = base_path:endswith('/') and '' or '/' + local path = ('%s%s%s'):format(base_path, sep, subdir) if dfhack.filesystem.isdir(path) then - print('indexing mod scripts: ' .. path) - table.insert(mod_script_paths, path) + print('indexing mod path: ' .. path) + table.insert(mod_paths, {id=id, path=path}) end end -local function add_script_paths(mod_script_paths, base_path, include_modactive) - if not base_path:endswith('/') then - base_path = base_path .. '/' - end - if include_modactive then - add_script_path(mod_script_paths, base_path..'scripts_modactive') - end - add_script_path(mod_script_paths, base_path..'scripts_modinstalled') -end - -function get_mod_script_paths() +function get_mod_paths(installed_subdir, active_subdir) -- ordered map of mod id -> {handled=bool, versions=map of version -> path} local mods = utils.OrderedTable() - local mod_script_paths = {} + local mod_paths = {} -- if a world is loaded, process active mods first, and lock to active version - if dfhack.isWorldLoaded() then + if active_subdir and dfhack.isWorldLoaded() then for _,path in ipairs(df.global.world.object_loader.object_load_order_src_dir) do path = tostring(path.value) + -- skip vanilla "mods" if not path:startswith(INSTALLED_MODS_PATH) then goto continue end local id = get_mod_id_and_version(path) if not id then goto continue end mods[id] = {handled=true} - add_script_paths(mod_script_paths, path, true) + add_mod_paths(mod_paths, id, path, active_subdir) + add_mod_paths(mod_paths, id, path, installed_subdir) ::continue:: end end @@ -159,8 +153,8 @@ function get_mod_script_paths() ::skip_path_root:: end - -- add script paths from most recent version of all not-yet-handled mods - for _,v in pairs(mods) do + -- add paths from most recent version of all not-yet-handled mods + for id,v in pairs(mods) do if v.handled then goto continue end local max_version, path for version,mod_path in pairs(v.versions) do @@ -169,11 +163,19 @@ function get_mod_script_paths() max_version = version end end - add_script_paths(mod_script_paths, path) + add_mod_paths(mod_paths, id, path, installed_subdir) ::continue:: end - return mod_script_paths + return mod_paths +end + +function get_mod_script_paths() + local paths = {} + for _,v in ipairs(get_mod_paths('scripts_modinstalled', 'scripts_modactive')) do + table.insert(paths, v.path) + end + return paths end return _ENV From e67df53c482555a9318dbd28eec0f34a78c4de4c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 20 Jul 2023 17:44:09 -0700 Subject: [PATCH 128/851] document new blueprints dir in mods --- docs/guides/modding-guide.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/guides/modding-guide.rst b/docs/guides/modding-guide.rst index 38117503c..297e8482a 100644 --- a/docs/guides/modding-guide.rst +++ b/docs/guides/modding-guide.rst @@ -45,6 +45,7 @@ this:: info.txt graphics/... objects/... + blueprints/... scripts_modactive/example-mod.lua scripts_modactive/internal/example-mod/... scripts_modinstalled/... @@ -58,6 +59,9 @@ Let's go through that line by line. - Modifications to the game raws (potentially with custom raw tokens) go in the :file:`graphics/` and :file:`objects/` folders. You can read more about the files that go in these directories on the :wiki:`Modding` wiki page. +- Any `quickfort` blueprints included with your mod go in the + :file:`blueprints` folder. Note that your mod can *just* be blueprints and + nothing else if you like. - A control script in :file:`scripts_modactive/` directory that handles system-level event hooks (e.g. reloading state when a world is loaded), registering `overlays `, and From 237075080924cc01cd45ad5c7d3b4939a96ab5eb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 20 Jul 2023 19:17:09 -0700 Subject: [PATCH 129/851] add warm/damp highlight overlay for ascii mode --- docs/plugins/dig.rst | 8 +++ plugins/lua/dig.lua | 29 +++++++++ plugins/pathable.cpp | 148 +++++++++++++++++++++++++++++++++++++++---- 3 files changed, 174 insertions(+), 11 deletions(-) create mode 100644 plugins/lua/dig.lua diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index a10db97df..46238add6 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -179,3 +179,11 @@ Filters: Take current designation and apply the selected pattern to it. After you have a pattern set, you can use ``expdig`` to apply it again. + +Overlay +------- + +This tool also provides an overlay that is managed by the `overlay` framework. +When the ``dig.asciiwarmdamp`` overlay is enabled and you are in non-graphics +(ASCII) mode, warm tiles will be highlighted in red and damp tiles will be +highlighted in blue. diff --git a/plugins/lua/dig.lua b/plugins/lua/dig.lua new file mode 100644 index 000000000..c9b8cf62b --- /dev/null +++ b/plugins/lua/dig.lua @@ -0,0 +1,29 @@ +local _ENV = mkmodule('plugins.dig') + +local overlay = require('plugins.overlay') +local pathable = require('plugins.pathable') + +WarmDampOverlay = defclass(WarmDampOverlay, overlay.OverlayWidget) +WarmDampOverlay.ATTRS{ + viewscreens={ + 'dwarfmode/Designate/DIG_DIG', + 'dwarfmode/Designate/DIG_REMOVE_STAIRS_RAMPS', + 'dwarfmode/Designate/DIG_STAIR_UP', + 'dwarfmode/Designate/DIG_STAIR_UPDOWN', + 'dwarfmode/Designate/DIG_STAIR_DOWN', + 'dwarfmode/Designate/DIG_RAMP', + 'dwarfmode/Designate/DIG_CHANNEL', + 'dwarfmode/Designate/DIG_FROM_MARKER', + 'dwarfmode/Designate/DIG_TO_MARKER', + }, + default_enabled=true, + overlay_only=true, +} + +function WarmDampOverlay:onRenderFrame(dc) + pathable.paintScreenWarmDamp() +end + +OVERLAY_WIDGETS = {overlay=WarmDampOverlay} + +return _ENV diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 6ed890325..a7f6af0cd 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -1,23 +1,27 @@ +#include "Debug.h" +#include "PluginManager.h" +#include "TileTypes.h" + #include "modules/Gui.h" #include "modules/Maps.h" #include "modules/Screen.h" #include "modules/Textures.h" -#include "Debug.h" -#include "LuaTools.h" -#include "PluginManager.h" - #include "df/init.h" +#include "df/map_block.h" +#include "df/tile_designation.h" + +#include using namespace DFHack; DFHACK_PLUGIN("pathable"); -REQUIRE_GLOBAL(gps); +REQUIRE_GLOBAL(init); +REQUIRE_GLOBAL(selection_rect); REQUIRE_GLOBAL(window_x); REQUIRE_GLOBAL(window_y); REQUIRE_GLOBAL(window_z); -REQUIRE_GLOBAL(world); namespace DFHack { DBG_DECLARE(pathable, log, DebugCategory::LINFO); @@ -31,7 +35,7 @@ DFhackCExport command_result plugin_shutdown(color_ostream &out) { return CR_OK; } -static void paintScreen(df::coord target, bool skip_unrevealed = false) { +static void paintScreenPathable(df::coord target, bool show_hidden = false) { DEBUG(log).print("entering paintScreen\n"); bool use_graphics = Screen::inGraphicsMode(); @@ -39,8 +43,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 = df::global::init->load_bar_texpos[1]; - long unpathable_tile_texpos = df::global::init->load_bar_texpos[4]; + long pathable_tile_texpos = init->load_bar_texpos[1]; + long unpathable_tile_texpos = init->load_bar_texpos[4]; long on_off_texpos = Textures::getMapPathableTexposStart(); if (on_off_texpos > 0) { pathable_tile_texpos = on_off_texpos + 0; @@ -61,7 +65,7 @@ static void paintScreen(df::coord target, bool skip_unrevealed = false) { continue; } - if (skip_unrevealed && !Maps::isTileVisible(map_pos)) { + if (!show_hidden && !Maps::isTileVisible(map_pos)) { TRACE(log).print("skipping hidden tile\n"); continue; } @@ -110,7 +114,129 @@ static void paintScreen(df::coord target, bool skip_unrevealed = false) { } } +static bool init_mouse_selection_rect(rect2d &rect) { + df::coord mouse_pos = Gui::getMousePos(); + if (!mouse_pos.isValid()) + return false; + rect.first.x = std::min(selection_rect->start_x, (int32_t)mouse_pos.x); + rect.second.x = std::max(selection_rect->start_x, (int32_t)mouse_pos.x); + rect.first.y = std::min(selection_rect->start_y, (int32_t)mouse_pos.y); + rect.second.y = std::max(selection_rect->start_y, (int32_t)mouse_pos.y); + return true; +} + +static bool in_mouse_selection_rect(const rect2d &rect, const df::coord &pos) { + return ((pos.y == rect.first.y || pos.y == rect.second.y) && (pos.x >= rect.first.x || pos.x <= rect.second.x)) || + ((pos.x == rect.first.x || pos.x == rect.second.x) && (pos.y >= rect.first.y || pos.y <= rect.second.y)); +} + +static bool is_warm(const df::coord &pos) { + auto block = Maps::getTileBlock(pos); + if (!block) + return false; + return block->temperature_1[pos.x&15][pos.y&15] >= 10075; +} + +static bool is_rough_wall(int16_t x, int16_t y, int16_t z) { + df::tiletype *tt = Maps::getTileType(x, y, z); + if (!tt) + return false; + + return tileShape(*tt) == df::tiletype_shape::WALL && + tileSpecial(*tt) != df::tiletype_special::SMOOTH; +} + +static bool will_leak(int16_t x, int16_t y, int16_t z) { + auto des = Maps::getTileDesignation(x, y, z); + if (!des) + return false; + if (des->bits.liquid_type == df::tile_liquid::Water && des->bits.flow_size >= 1) + return true; + if (des->bits.water_table && is_rough_wall(x, y, z)) + return true; + return false; +} + +static bool is_damp(const df::coord &pos) { + return will_leak(pos.x-1, pos.y-1, pos.z) || + will_leak(pos.x, pos.y-1, pos.z) || + will_leak(pos.x+1, pos.y-1, pos.z) || + will_leak(pos.x-1, pos.y, pos.z) || + will_leak(pos.x+1, pos.y, pos.z) || + will_leak(pos.x-1, pos.y+1, pos.z) || + will_leak(pos.x, pos.y+1, pos.z) || + will_leak(pos.x+1, pos.y+1, pos.z); + will_leak(pos.x, pos.y+1, pos.z+1); +} + +static void paintScreenWarmDamp(bool show_hidden = false) { + DEBUG(log).print("entering paintScreenDampWarm\n"); + + if (Screen::inGraphicsMode()) + return; + + bool has_mouse_selection_rect = selection_rect->start_x >= 0; + rect2d mouse_sel_rect; + if (has_mouse_selection_rect) { + has_mouse_selection_rect = init_mouse_selection_rect(mouse_sel_rect); + } + + bool has_kbd_selection_rect = false; // TODO where is this info stored? + + auto dims = Gui::getDwarfmodeViewDims().map(); + for (int y = dims.first.y; y <= dims.second.y; ++y) { + for (int x = dims.first.x; x <= dims.second.x; ++x) { + df::coord map_pos(*window_x + x, *window_y + y, *window_z); + + if (!Maps::isValidTilePos(map_pos)) + continue; + + // don't overwrite selection box tiles + if (has_mouse_selection_rect && in_mouse_selection_rect(mouse_sel_rect, map_pos)) { + TRACE(log).print("skipping mouse selection box tile\n"); + continue; + } + + if (!show_hidden && !Maps::isTileVisible(map_pos)) { + TRACE(log).print("skipping hidden tile\n"); + continue; + } + + TRACE(log).print("scanning map tile at (%d, %d, %d) screen offset (%d, %d)\n", + map_pos.x, map_pos.y, map_pos.z, x, y); + + Screen::Pen cur_tile = Screen::readTile(x, y, true); + if (!cur_tile.valid()) { + DEBUG(log).print("cannot read tile at offset %d, %d\n", x, y); + continue; + } + + int color = is_warm(map_pos) ? COLOR_RED : is_damp(map_pos) ? COLOR_BLUE : COLOR_BLACK; + if (color == COLOR_BLACK) { + TRACE(log).print("skipping non-warm, non-damp tile\n"); + continue; + } + + if (cur_tile.fg && cur_tile.ch != ' ') { + cur_tile.fg = color; + cur_tile.bg = 0; + } else { + cur_tile.fg = 0; + cur_tile.bg = color; + } + + cur_tile.bold = false; + + if (cur_tile.tile) + cur_tile.tile_mode = Screen::Pen::CharColor; + + Screen::paintTile(cur_tile, x, y, true); + } + } +} + DFHACK_PLUGIN_LUA_FUNCTIONS { - DFHACK_LUA_FUNCTION(paintScreen), + DFHACK_LUA_FUNCTION(paintScreenPathable), + DFHACK_LUA_FUNCTION(paintScreenWarmDamp), DFHACK_LUA_END }; From 040d2caa956796a1363fe0f0ccc95b1cae199799 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 20 Jul 2023 19:22:30 -0700 Subject: [PATCH 130/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 97bc202fe..92d6aae4d 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 - `3dveins`: reinstated for v50, this plugin replaces vanilla DF's blobby vein generation with veins that flow smoothly and naturally between z-levels - `zone`: new searchable, sortable, filterable screen for assigning units to pastures +- `dig`: new ``dig.asciiwarmdamp`` overlay that highlights warm and damp tiles when in ASCII mode. there is no effect in graphics mode since the tiles are already highlighted there ## Fixes - Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing From a6b304d9b4e02d4ee998d52c3fc25acc8b65b5ca Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 20 Jul 2023 19:28:49 -0700 Subject: [PATCH 131/851] fix box select bounds logic --- plugins/pathable.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index a7f6af0cd..f7bbe2e76 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -126,8 +126,13 @@ static bool init_mouse_selection_rect(rect2d &rect) { } static bool in_mouse_selection_rect(const rect2d &rect, const df::coord &pos) { - return ((pos.y == rect.first.y || pos.y == rect.second.y) && (pos.x >= rect.first.x || pos.x <= rect.second.x)) || - ((pos.x == rect.first.x || pos.x == rect.second.x) && (pos.y >= rect.first.y || pos.y <= rect.second.y)); + return ((pos.y == rect.first.y || pos.y == rect.second.y) && (pos.x >= rect.first.x && pos.x <= rect.second.x)) || + ((pos.x == rect.first.x || pos.x == rect.second.x) && (pos.y >= rect.first.y && pos.y <= rect.second.y)); +} + +static bool in_kbd_selection_rect(const rect2d &rect, const df::coord &pos) { + return pos.y >= rect.first.y && pos.y <= rect.second.y && + pos.x >= rect.first.x && pos.x <= rect.second.x; } static bool is_warm(const df::coord &pos) { @@ -182,6 +187,7 @@ static void paintScreenWarmDamp(bool show_hidden = false) { } bool has_kbd_selection_rect = false; // TODO where is this info stored? + rect2d kbd_sel_rect; auto dims = Gui::getDwarfmodeViewDims().map(); for (int y = dims.first.y; y <= dims.second.y; ++y) { @@ -196,6 +202,10 @@ static void paintScreenWarmDamp(bool show_hidden = false) { TRACE(log).print("skipping mouse selection box tile\n"); continue; } + if (has_kbd_selection_rect && in_kbd_selection_rect(kbd_sel_rect, map_pos)){ + TRACE(log).print("skipping keyboard selection box tile\n"); + continue; + } if (!show_hidden && !Maps::isTileVisible(map_pos)) { TRACE(log).print("skipping hidden tile\n"); From d18a1f12f73ab8a0001417b0e675595dfeb881f7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 20 Jul 2023 19:32:38 -0700 Subject: [PATCH 132/851] allow the color to override box select and cursor --- plugins/pathable.cpp | 42 ++---------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index f7bbe2e76..b4c7f703f 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -114,27 +114,6 @@ static void paintScreenPathable(df::coord target, bool show_hidden = false) { } } -static bool init_mouse_selection_rect(rect2d &rect) { - df::coord mouse_pos = Gui::getMousePos(); - if (!mouse_pos.isValid()) - return false; - rect.first.x = std::min(selection_rect->start_x, (int32_t)mouse_pos.x); - rect.second.x = std::max(selection_rect->start_x, (int32_t)mouse_pos.x); - rect.first.y = std::min(selection_rect->start_y, (int32_t)mouse_pos.y); - rect.second.y = std::max(selection_rect->start_y, (int32_t)mouse_pos.y); - return true; -} - -static bool in_mouse_selection_rect(const rect2d &rect, const df::coord &pos) { - return ((pos.y == rect.first.y || pos.y == rect.second.y) && (pos.x >= rect.first.x && pos.x <= rect.second.x)) || - ((pos.x == rect.first.x || pos.x == rect.second.x) && (pos.y >= rect.first.y && pos.y <= rect.second.y)); -} - -static bool in_kbd_selection_rect(const rect2d &rect, const df::coord &pos) { - return pos.y >= rect.first.y && pos.y <= rect.second.y && - pos.x >= rect.first.x && pos.x <= rect.second.x; -} - static bool is_warm(const df::coord &pos) { auto block = Maps::getTileBlock(pos); if (!block) @@ -180,15 +159,6 @@ static void paintScreenWarmDamp(bool show_hidden = false) { if (Screen::inGraphicsMode()) return; - bool has_mouse_selection_rect = selection_rect->start_x >= 0; - rect2d mouse_sel_rect; - if (has_mouse_selection_rect) { - has_mouse_selection_rect = init_mouse_selection_rect(mouse_sel_rect); - } - - bool has_kbd_selection_rect = false; // TODO where is this info stored? - rect2d kbd_sel_rect; - auto dims = Gui::getDwarfmodeViewDims().map(); for (int y = dims.first.y; y <= dims.second.y; ++y) { for (int x = dims.first.x; x <= dims.second.x; ++x) { @@ -197,16 +167,6 @@ static void paintScreenWarmDamp(bool show_hidden = false) { if (!Maps::isValidTilePos(map_pos)) continue; - // don't overwrite selection box tiles - if (has_mouse_selection_rect && in_mouse_selection_rect(mouse_sel_rect, map_pos)) { - TRACE(log).print("skipping mouse selection box tile\n"); - continue; - } - if (has_kbd_selection_rect && in_kbd_selection_rect(kbd_sel_rect, map_pos)){ - TRACE(log).print("skipping keyboard selection box tile\n"); - continue; - } - if (!show_hidden && !Maps::isTileVisible(map_pos)) { TRACE(log).print("skipping hidden tile\n"); continue; @@ -227,6 +187,8 @@ static void paintScreenWarmDamp(bool show_hidden = false) { continue; } + // this will also change the color of the cursor or any selection box that overlaps + // the tile. this is intentional since it makes the UI more readable if (cur_tile.fg && cur_tile.ch != ' ') { cur_tile.fg = color; cur_tile.bg = 0; From 25301bf93e36b4056ce82d2a0cfc2a4327d26b8f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 20 Jul 2023 19:35:02 -0700 Subject: [PATCH 133/851] update docs --- docs/plugins/dig.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index 46238add6..310bd1647 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -186,4 +186,5 @@ Overlay This tool also provides an overlay that is managed by the `overlay` framework. When the ``dig.asciiwarmdamp`` overlay is enabled and you are in non-graphics (ASCII) mode, warm tiles will be highlighted in red and damp tiles will be -highlighted in blue. +highlighted in blue. Box selection characters and the keyboard cursor will also +change color as appropriate when over the warm or damp tile. From a77a6b5943d36c9aadd6bed38e177b1b59a79024 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 20 Jul 2023 19:40:40 -0700 Subject: [PATCH 134/851] clean up globals --- plugins/pathable.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index b4c7f703f..f60469489 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -18,7 +18,6 @@ using namespace DFHack; DFHACK_PLUGIN("pathable"); REQUIRE_GLOBAL(init); -REQUIRE_GLOBAL(selection_rect); REQUIRE_GLOBAL(window_x); REQUIRE_GLOBAL(window_y); REQUIRE_GLOBAL(window_z); From d276b4a1a16941ab83e850cf7a14d0b0268a4831 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 21 Jul 2023 07:13:26 +0000 Subject: [PATCH 135/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 1ee2a979c..67d4e63da 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 1ee2a979cd341dae0289ad29a97c1bfaed8d5937 +Subproject commit 67d4e63daeb30986e8f318c96c58d105a00c468d From d14054716c634580a97ae514a60fcac6630c11e1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 21 Jul 2023 00:28:05 -0700 Subject: [PATCH 136/851] better name for overlay --- plugins/lua/dig.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/dig.lua b/plugins/lua/dig.lua index c9b8cf62b..43012d5d2 100644 --- a/plugins/lua/dig.lua +++ b/plugins/lua/dig.lua @@ -24,6 +24,6 @@ function WarmDampOverlay:onRenderFrame(dc) pathable.paintScreenWarmDamp() end -OVERLAY_WIDGETS = {overlay=WarmDampOverlay} +OVERLAY_WIDGETS = {asciiwarmdamp=WarmDampOverlay} return _ENV From dff4816287f1a3cd7ba9d1d81570964755d72290 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 21 Jul 2023 04:12:01 -0700 Subject: [PATCH 137/851] update dwarfvet --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 5 + docs/plugins/dwarfvet.rst | 19 +- library/LuaApi.cpp | 1 + library/include/modules/Units.h | 2 +- library/modules/Units.cpp | 38 ++ plugins/CMakeLists.txt | 2 +- plugins/dwarfvet.cpp | 787 +++++--------------------------- plugins/lua/dwarfvet.lua | 180 ++++++++ plugins/lua/zone.lua | 27 +- 10 files changed, 348 insertions(+), 714 deletions(-) create mode 100644 plugins/lua/dwarfvet.lua diff --git a/docs/changelog.txt b/docs/changelog.txt index 97bc202fe..9c5d04a25 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 - `3dveins`: reinstated for v50, this plugin replaces vanilla DF's blobby vein generation with veins that flow smoothly and naturally between z-levels - `zone`: new searchable, sortable, filterable screen for assigning units to pastures +- `dwarfvet`: reinstated and updated for v50's new hospital mechanics; allow your animals to have their wounds treated at hospitals ## Fixes - Fix extra keys appearing in DFHack text boxes when shift (or any other modifier) is released before the other key you were pressing diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 7aea41c55..cd35d9465 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1589,6 +1589,11 @@ Units module Currently only one dream per unit is supported by Dwarf Fortress. Support for multiple dreams may be added in future versions of Dwarf Fortress. +* ``dfhack.units.getReadableName(unit)`` + + Returns a string that includes the language name of the unit (if any), the + race of the unit, and any syndrome-given descriptions (such as "necromancer"). + * ``dfhack.units.getStressCategory(unit)`` Returns a number from 0-6 indicating stress. 0 is most stressed; 6 is least. diff --git a/docs/plugins/dwarfvet.rst b/docs/plugins/dwarfvet.rst index b4dfe0ada..70f92cc79 100644 --- a/docs/plugins/dwarfvet.rst +++ b/docs/plugins/dwarfvet.rst @@ -2,22 +2,19 @@ dwarfvet ======== .. dfhack-tool:: - :summary: Allows animals to be treated at animal hospitals. - :tags: unavailable fort gameplay animals + :summary: Allow animals to be treated at hospitals. + :tags: fort gameplay animals Annoyed that your dragons become useless after a minor injury? Well, with -dwarfvet, injured animals will be treated at an animal hospital, which is simply -a hospital that is also an animal training zone. Dwarfs with the Animal -Caretaker labor enabled will come to the hospital to treat animals. Normal +dwarfvet, injured animals will be treated at a hospital. Dwarfs with the Animal +Caretaker labor enabled will come to the hospital to treat the animals. Normal medical skills are used (and trained), but no experience is given to the Animal Caretaker skill itself. Usage ----- -``enable dwarfvet`` - Enables the plugin. -``dwarfvet report`` - Reports all zones that the game considers animal hospitals. -``dwarfvet report-usage`` - Reports on animals currently being treated. +:: + + enable dwarfvet + dwarfvet [status] diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 050c99b86..c19c10197 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1824,6 +1824,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, getRaceBabyNameById), WRAPM(Units, getRaceChildName), WRAPM(Units, getRaceChildNameById), + WRAPM(Units, getReadableName), WRAPM(Units, getMainSocialActivity), WRAPM(Units, getMainSocialEvent), WRAPM(Units, getStressCategory), diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 23b4647b2..19af4ec9a 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -192,7 +192,7 @@ DFHACK_EXPORT std::string getRaceBabyNameById(int32_t race_id); DFHACK_EXPORT std::string getRaceBabyName(df::unit* unit); DFHACK_EXPORT std::string getRaceChildNameById(int32_t race_id); DFHACK_EXPORT std::string getRaceChildName(df::unit* unit); - +DFHACK_EXPORT std::string getReadableName(df::unit* unit); DFHACK_EXPORT double getAge(df::unit *unit, bool true_age = false); DFHACK_EXPORT int getKillCount(df::unit *unit); diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index f517a07b5..1605a3d06 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -53,6 +53,7 @@ using namespace std; #include "df/activity_entry.h" #include "df/burrow.h" #include "df/caste_raw.h" +#include "df/creature_interaction_effect_display_namest.h" #include "df/creature_raw.h" #include "df/curse_attr_change.h" #include "df/entity_position.h" @@ -74,11 +75,13 @@ using namespace std; #include "df/nemesis_record.h" #include "df/tile_occupancy.h" #include "df/plotinfost.h" +#include "df/syndrome.h" #include "df/unit_inventory_item.h" #include "df/unit_misc_trait.h" #include "df/unit_relationship_type.h" #include "df/unit_skill.h" #include "df/unit_soul.h" +#include "df/unit_syndrome.h" #include "df/unit_wound.h" #include "df/world.h" #include "df/world_data.h" @@ -1218,6 +1221,41 @@ string Units::getRaceChildName(df::unit* unit) return getRaceChildNameById(unit->race); } +static string get_caste_name(df::unit* unit) { + int32_t id = unit->race; + if (id < 0 || (size_t)id >= world->raws.creatures.all.size()) + return ""; + df::creature_raw* raw = world->raws.creatures.all[id]; + int16_t caste = unit->caste; + if (!raw || caste < 0 || (size_t)caste >= raw->caste.size()) + return ""; + return raw->caste[caste]->caste_name[0]; +} + +string Units::getReadableName(df::unit* unit) { + string race_name = isChild(unit) ? getRaceChildName(unit) : get_caste_name(unit); + string name = Translation::TranslateName(getVisibleName(unit)); + if (name.empty()) { + name = race_name; + } else { + name += ", "; + name += race_name; + } + for (auto unit_syndrome : unit->syndromes.active) { + auto syndrome = df::syndrome::find(unit_syndrome->type); + if (!syndrome) + continue; + for (auto effect : syndrome->ce) { + auto cie = strict_virtual_cast(effect); + if (!cie) + continue; + name += " "; + name += cie->name; + break; + } + } + return name; +} double Units::getAge(df::unit *unit, bool true_age) { diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index c037fc4a0..345263f1b 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -106,7 +106,7 @@ dfhack_plugin(dig dig.cpp) dfhack_plugin(dig-now dig-now.cpp LINK_LIBRARIES lua) #dfhack_plugin(digFlood digFlood.cpp) #add_subdirectory(diggingInvaders) -#dfhack_plugin(dwarfvet dwarfvet.cpp) +dfhack_plugin(dwarfvet dwarfvet.cpp LINK_LIBRARIES lua) #dfhack_plugin(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua) #add_subdirectory(embark-assistant) #dfhack_plugin(embark-tools embark-tools.cpp) diff --git a/plugins/dwarfvet.cpp b/plugins/dwarfvet.cpp index 75f015975..dcd8e0f8c 100644 --- a/plugins/dwarfvet.cpp +++ b/plugins/dwarfvet.cpp @@ -20,735 +20,170 @@ * THE SOFTWARE. **/ -#include "Console.h" -#include "Core.h" -#include "DataDefs.h" -#include "Export.h" +#include "Debug.h" +#include "LuaTools.h" #include "PluginManager.h" -#include "modules/EventManager.h" + +#include "modules/Persistence.h" #include "modules/Units.h" -#include "modules/Buildings.h" -#include "modules/Maps.h" -#include "modules/Job.h" +#include "modules/World.h" -#include "df/animal_training_level.h" -#include "df/building_type.h" -#include "df/caste_raw.h" -#include "df/caste_raw_flags.h" -#include "df/creature_raw.h" -#include "df/job.h" -#include "df/general_ref_unit_workerst.h" -#include "df/profession.h" -#include "df/plotinfost.h" -#include "df/unit.h" -#include "df/unit_health_info.h" -#include "df/unit_health_flags.h" #include "df/world.h" -#include -#include -#include - using namespace DFHack; -using namespace DFHack::Units; -using namespace DFHack::Buildings; - -using namespace std; +using std::string; +using std::vector; DFHACK_PLUGIN("dwarfvet"); -DFHACK_PLUGIN_IS_ENABLED(dwarfvet_enabled); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); -REQUIRE_GLOBAL(plotinfo); REQUIRE_GLOBAL(world); -static unordered_set tracked_units; -static int32_t howOften = 100; - -struct hospital_spot { - int32_t x; - int32_t y; - int32_t z; -}; - -class Patient { - public: - // Constructor/Deconstrctor - Patient(int32_t id, size_t spot_index, int32_t x, int32_t y, int32_t z); - int32_t getID() { return this->id; }; - size_t getSpotIndex() { return this->spot_index; }; - int32_t returnX() { return this->spot_in_hospital.x; }; - int32_t returnY() { return this->spot_in_hospital.y; }; - int32_t returnZ() { return this->spot_in_hospital.z; }; - - private: - struct hospital_spot spot_in_hospital; - int32_t id; - size_t spot_index; -}; - -Patient::Patient(int32_t id, size_t spot_index, int32_t x, int32_t y, int32_t z){ - this->id = id; - this->spot_index = spot_index; - this->spot_in_hospital.x = x; - this->spot_in_hospital.y = y; - this->spot_in_hospital.z = z; +namespace DFHack { + // for configuration-related logging + DBG_DECLARE(dwarfvet, status, DebugCategory::LINFO); + // for logging during the periodic scan + DBG_DECLARE(dwarfvet, cycle, DebugCategory::LINFO); } -class AnimalHospital { - - public: - // Constructor - AnimalHospital(df::building *, color_ostream &out); - ~AnimalHospital(); - int32_t getID() { return id; } - bool acceptPatient(int32_t id, color_ostream&); - void processPatients(color_ostream &out); - void dischargePatient(Patient * patient, color_ostream &out); - void calculateHospital(bool force, color_ostream &out); - void reportUsage(color_ostream &out); - - // GC - bool to_be_deleted; - - private: - int spots_open; - int32_t id; - int32_t x1; - int32_t x2; - int32_t y1; - int32_t y2; - int32_t z; - int height; - int length; - - // Doing an actual array in C++ is *annoying*, bloody copy constructors */ - vector spots_in_use; - vector building_in_hospital_notification; /* If present, we already notified about this */ - vector accepted_patients; +static const string CONFIG_KEY = string(plugin_name) + "/config"; +static PersistentDataItem config; +enum ConfigValues { + CONFIG_IS_ENABLED = 0, }; - -AnimalHospital::AnimalHospital(df::building * building, color_ostream &out) { - // Copy in what we need to know - id = building->id; - x1 = building->x1; - x2 = building->x2; - y1 = building->y1; - y2 = building->y2; - z = building->z; - - // Determine how many spots we have for animals - this->length = x2-x1+1; - this->height = y2-y1+1; - - // And calculate the hospital! - this->calculateHospital(true, out); +static int get_config_val(int index) { + if (!config.isValid()) + return -1; + return config.ival(index); } - -AnimalHospital::~AnimalHospital() { - // Go through and delete all the patients - for (Patient* accepted_patient : this->accepted_patients) { - delete accepted_patient; - } +static bool get_config_bool(int index) { + return get_config_val(index) == 1; } - -bool AnimalHospital::acceptPatient(int32_t id, color_ostream &out) { - // This function determines if we can accept a patient, and if we will. - this->calculateHospital(true, out); - - // First, do we have room? - if (!spots_open) return false; - - // Yup, let's find the next open spot, - // and give it to our patient - int spot_cur = 0; - for (vector::iterator spot = this->spots_in_use.begin(); spot != this->spots_in_use.end(); spot++) { - if (*spot == false) { - *spot = true; - break; - } - spot_cur++; - } - - spots_open--; - - // Convert the spot into x/y/z cords. - int offset_y = spot_cur/length; - int offset_x = spot_cur%length; - - // Create the patient! - Patient * patient = new Patient(id, - spot_cur, - this->x1+offset_x, - this->y1+offset_y, - this->z - ); - - accepted_patients.push_back(patient); - return true; +static void set_config_val(int index, int value) { + if (config.isValid()) + config.ival(index) = value; } - -// Before any use of the hospital, we need to make calculate open spots -// and such. This can change (i.e. stuff built in hospital) and -// such so it should be called on each function. -void AnimalHospital::reportUsage(color_ostream &out) { - // Debugging tool to see parts of the hospital in use - int length_cursor = this->length; - - for (bool spot : this->spots_in_use) { - if (spot) out.print("X"); - else out.print("-"); - length_cursor--; - if (length_cursor <= 0) { - out.print("\n"); - length_cursor = this->length; - } - } - out.print("\n"); - +static void set_config_bool(int index, bool value) { + set_config_val(index, value ? 1 : 0); } -void AnimalHospital::calculateHospital(bool force, color_ostream &out) { - // Only calculate out the hospital if we actually have a patient in it - // (acceptPatient will forcibly rerun this to make sure everything OK - - // Should reduce FPS impact of each calculation tick when the hospitals - // are not in use - //if (!force || (spots_open == length*height)) { - // Hospital is idle, don't recalculate - // return; - //} +static const int32_t CYCLE_TICKS = 2459; // a prime number that's around 2 days +static int32_t cycle_timestamp = 0; // world->frame_counter at last cycle - // Calculate out the total area of the hospital - // This can change if a hospital has been resized - this->spots_open = length*height; - this->spots_in_use.assign(this->spots_open, false); - - // The spots_in_use maps one to one with a spot - // starting at the upper-left hand corner, then - // across, then down. i.e. - // - // given hospital zone: - // - // UU - // uU - // - // where U is in use, and u isn't, the array - // would be t,t,f,t - - // Walk the building array and see what stuff is in the hospital, - // then walk the patient array and remark those spots as used. - - // If a patient is in an invalid spot, reassign it - for (df::building *building : world->buildings.all) { - - // Check that we're not comparing ourselves; - if (building->id == this->id) { - continue; - } - - // Check if the building is on our z level, if it isn't - // then it can't overlap the hospital (until Toady implements - // multi-z buildings - if (building->z != this->z) { - continue; - } - - // DF defines activity zones multiple times in the building structure - // If axises agree with each other, we're looking at a reflection of - // ourselves - if (building->x1 == this->x1 && - building->x2 == this->x2 && - building->y1 == this->y1 && - building->y2 == this->y2) { - continue; - } - - // Check for X/Y overlap - // I can't believe I had to look this up -_-; - // http://stackoverflow.com/questions/306316/determine-if-two-rectangles-overlap-each-other - if ((this->x1 > building->x2 || - building->x1 > this->x2 || - this->y1 > building->y2 || - building->y1 > this->y2)) { - continue; - } - - // Crap, building overlaps, we need to figure out where it is in the hospital - // NOTE: under some conditions, this generates a false warning. Not a lot I can do about it - - // Mark spots used by that building as used; FIXME: handle special logic for traction benches and such - int overlap_x1 = std::max(building->x1, this->x1); - int overlap_y1 = std::max(building->y1, this->y1); - int overlap_x2 = std::min(building->x2, this->x2); - int overlap_y2 = std::min(building->y2, this->y2); - for (int x = overlap_x1; x <= overlap_x2; x++) { - for (int y = overlap_y1; y <= overlap_y2; y++) { - int spot_index = (x - this->x1) + (this->length * (y - this->y1)); - spots_in_use.at(spot_index) = true; - } - } - } +static command_result do_command(color_ostream &out, vector ¶meters); +static void dwarfvet_cycle(color_ostream &out); +DFhackCExport command_result plugin_init(color_ostream &out, vector &commands) { + commands.push_back(PluginCommand( + plugin_name, + "Allow animals to be treated at hospitals.", + do_command)); + return CR_OK; } -// Self explanatory -void AnimalHospital::dischargePatient(Patient * patient, color_ostream &out) { - int32_t id = patient->getID(); - - // Remove them from the hospital - - // We can safely iterate here because once we delete the unit - // we no longer use the iterator - for (vector::iterator accepted_patient = this->accepted_patients.begin(); accepted_patient != this->accepted_patients.end(); accepted_patient++) { - if ( (*accepted_patient)->getID() == id) { - out.print("Discharging unit %d from hospital %d\n", id, this->id); - // Reclaim their spot - spots_in_use.at((*accepted_patient)->getSpotIndex()) = false; - this->spots_open++; - delete (*accepted_patient); - this->accepted_patients.erase(accepted_patient); - break; - } +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; } - // And the master list - tracked_units.erase(id); - - return; -} - -void AnimalHospital::processPatients(color_ostream &out) { - // Where the magic happens - for (Patient *patient : this->accepted_patients) { - int id = patient->getID(); - df::unit *real_unit = df::unit::find(id); - - // Check to make sure the unit hasn't expired before assigning a job, or if they've been healed - if (!real_unit || !Units::isActive(real_unit) || !real_unit->health->flags.bits.needs_healthcare) { - // discharge the patient from the hospital - this->dischargePatient(patient, out); - return; - } - - // Give the unit a job if they don't have any - if (!real_unit->job.current_job) { - // Create REST struct - df::job * job = new df::job; - DFHack::Job::linkIntoWorld(job); - - job->pos.x = patient->returnX(); - job->pos.y = patient->returnY(); - job->pos.z = patient->returnZ(); - job->flags.bits.special = 1; - job->job_type = df::enums::job_type::Rest; - df::general_ref *ref = df::allocate(); - ref->setID(real_unit->id); - job->general_refs.push_back(ref); - real_unit->job.current_job = job; - job->wait_timer = 1600; - out.print("Telling intelligent unit %d to report to the hospital!\n", real_unit->id); - } + 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_IS_ENABLED, is_enabled); + } 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_load_data(color_ostream &out) { + cycle_timestamp = 0; + config = World::GetPersistentData(CONFIG_KEY); -static vector animal_hospital_zones; - -void delete_animal_hospital_vector(color_ostream &out) { - if (dwarfvet_enabled) { - out.print("Clearing all animal hospitals\n"); - } - for (AnimalHospital *animal_hospital : animal_hospital_zones) { - delete animal_hospital; + if (!config.isValid()) { + DEBUG(status,out).print("no config found in this save; initializing\n"); + config = World::AddPersistentData(CONFIG_KEY); + set_config_bool(CONFIG_IS_ENABLED, is_enabled); } - animal_hospital_zones.clear(); -} - -command_result dwarfvet(color_ostream &out, std::vector & parameters); - -DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) -{ - commands.push_back(PluginCommand( - "dwarfvet", - "Allows animals to be treated at animal hospitals", - dwarfvet)); - return CR_OK; -} -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ + is_enabled = get_config_bool(CONFIG_IS_ENABLED); + DEBUG(status,out).print("loading persisted enabled state: %s\n", + is_enabled ? "true" : "false"); return CR_OK; } -bool isActiveAnimalHospital(df::building * building) { - if (Buildings::isHospital(building) && Buildings::isAnimalTraining(building) && Buildings::isActive(building)) { - return true; +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 false; + return CR_OK; } -bool compareAnimalHospitalZones(df::building * hospital1, df::building * hospital2) { - // We compare hospitals by checking if positions are identical, not by ID - // since activity zones can easily be changed in size - - if ( hospital1->x1 == hospital2->x1 && - hospital1->x2 == hospital2->x2 && - hospital1->y1 == hospital2->y1 && - hospital1->y2 == hospital2->y2 && - hospital1->z == hospital2->z) { - return true; - } - - return false; +DFhackCExport command_result plugin_onupdate(color_ostream &out) { + if (is_enabled && world->frame_counter - cycle_timestamp >= CYCLE_TICKS) + dwarfvet_cycle(out); + return CR_OK; } -void tickHandler(color_ostream& out, void* data) { - if ( !dwarfvet_enabled ) - return; - CoreSuspender suspend; - int32_t own_race_id = df::global::plotinfo->race_id; - - /** - * Generate a list of animal hospitals on the map - * - * Since activity zones can change any instant given user interaction - * we need to be constantly on the lookout for changed zones, and update - * our cached list on the fly if necessary. - **/ - - vector hospitals_on_map; - - // Because C++ iterators suck, we're going to build a temporary vector with the AHZ, and then - // copy it for my own bloody sanity (and compilance with the STL spec) - vector ahz_scratch; - - // Holding area for things to be added to the scratch - vector to_be_added; - - - // Walk the building tree, and generate a list of animal hospitals on the map - for (df::building* building : df::building::get_vector()) { - if (isActiveAnimalHospital(building)) { - hospitals_on_map.push_back(building); - } - } - - int count_of_hospitals = hospitals_on_map.size(); - int hospitals_cached = animal_hospital_zones.size(); - //out.print ("count_of_Hospitals: %d, hospitals_cached: %d\n", count_of_hospitals, hospitals_cached); - // It's possible our hospital cache is empty, if so, simply copy it, and jump to the main logic - if (!hospitals_cached && count_of_hospitals) { - out.print("Populating hospital cache:\n"); - for (df::building *current_hospital : hospitals_on_map) { - AnimalHospital * hospital = new AnimalHospital(current_hospital, out); - out.print(" Found animal hospital %d at x1: %d, y1: %d, z: %d from valid hospital list\n", - hospital->getID(), - current_hospital->x1, - current_hospital->y1, - current_hospital->z - ); - animal_hospital_zones.push_back(hospital); - } - - goto processUnits; - } - - if (!count_of_hospitals && !hospitals_cached) { - // No hospitals found, cache is empty, just return - goto cleanup; - } - - // Now walk our list of known hospitals, do a bit of checking, then compare - // TODO: this doesn't handle zone resizes at all - - for (AnimalHospital *animal_hospital : animal_hospital_zones) { - // If a zone is changed at all, DF seems to reallocate it. - // - // Each AnimalHospital has a "to_be_deleted" bool. We're going to set that to true, and clear it if we can't - // find a matching hospital. This limits the number of times we need to walk through the AHZ list to twice, and - // lets us cleanly report it later - // - // Surviving hospitals will be copied to scratch which will become the new AHZ vector - - animal_hospital->to_be_deleted = true; - for (df::building *current_hospital : hospitals_on_map) { - - /* Keep the hospital if its still valid */ - if (animal_hospital->getID() == current_hospital->id) { - ahz_scratch.push_back(animal_hospital); - animal_hospital->to_be_deleted = false; - break; - } - - } - } - - // Report what we're deleting by checking the to_be_deleted bool. - // - // Whatsever left is added to the pending add list - for (AnimalHospital *animal_hospital : animal_hospital_zones) { - if (animal_hospital->to_be_deleted) { - out.print("Hospital #%d removed\n", animal_hospital->getID()); - delete animal_hospital; - } - } +static bool call_dwarfvet_lua(color_ostream *out, const char *fn_name, + int nargs = 0, int nres = 0, + Lua::LuaLambda && args_lambda = Lua::DEFAULT_LUA_LAMBDA, + Lua::LuaLambda && res_lambda = Lua::DEFAULT_LUA_LAMBDA) { + DEBUG(status).print("calling dwarfvet lua function: '%s'\n", fn_name); - /* Now we need to walk the scratch and add anything that is a hospital and wasn't in the vector */ + CoreSuspender guard; - for (df::building *current_hospital : hospitals_on_map) { - bool new_hospital = true; - - for (AnimalHospital *animal_hospital : ahz_scratch) { - if (animal_hospital->getID() == current_hospital->id) { - // Next if we're already here - new_hospital = false; - break; - } - } - - // Add it if its new - if (new_hospital == true) to_be_added.push_back(current_hospital); - } - - /* Now add it to the scratch AHZ */ - for (df::building *current_hospital : to_be_added) { - // Add it to the vector - out.print("Adding new hospital #id: %d at x1 %d y1: %d z: %d\n", - current_hospital->id, - current_hospital->x1, - current_hospital->y1, - current_hospital->z - ); - AnimalHospital * hospital = new AnimalHospital(current_hospital, out); - ahz_scratch.push_back(hospital); - } + auto L = Lua::Core::State; + Lua::StackUnwinder top(L); - /* Copy the scratch to the AHZ */ - animal_hospital_zones = ahz_scratch; + if (!out) + out = &Core::getInstance().getConsole(); - // We always recheck the cache instead of counts because someone might have removed then added a hospital -/* if (hospitals_cached != count_of_hospitals) { - out.print("Hospitals on the map changed, rebuilding cache\n"); - - for (vector::iterator current_hospital = hospitals_on_map.begin(); current_hospital != hospitals_on_map.end(); current_hospital++) { - bool add_hospital = true; - - for (vector::iterator map_hospital = animal_hospital_zones.begin(); map_hospital != animal_hospital_zones.end(); map_hospital++) { - if (compareAnimalHospitalZones(*map_hospital, *current_hospital)) { - // Same hospital, we're good - add_hospital = false; - break; - } - } - - // Add it to the list - if (add_hospital) { - out.print("Adding zone at x1: %d, y1: %d to valid hospital list\n", (*current_hospital)->x1, (*current_hospital)->y1); - animal_hospital_zones.push_back(*current_hospital); - } - } - } -*/ -processUnits: - /* Code borrowed from petcapRemover.cpp */ - for (df::unit *unit : df::unit::get_vector()) { - /* As hilarious as it would be, lets not treat FB :) */ - if ( !Units::isActive(unit) || unit->flags1.bits.active_invader || unit->flags2.bits.underworld || unit->flags2.bits.visitor_uninvited || unit->flags2.bits.visitor ) { - continue; - } - - if ( !Units::isTamable(unit)) { - continue; - } - - /** - * So, for a unit to be elligable for the hospital, all the following must be true - * - * 1. It must be a member of our civilization - * 2. It must be tame (semi-wild counts for this) - * 2.1 If its not a dwarf, AND untame clear its civ out so traps work - * 3. It must have a health struct (which is generated by combat) - * 4. health->needs_healthcare must be set to true - * 5. If health->requires_recovery is set, the creature can't move under its own power - * and a Recover Wounded or Pen/Pasture job MUST be created by hand - TODO - * 6. An open spot in the "Animal Hospital" (activity zone with hospital+animal training set) - * must be available - * - * I apologize if this excessively verbose, but the healthcare system is stupidly conplex - * and there's tons of edgecases to watch out for, and I want someone else to ACTUALLY - * beside me able to understand what's going on - */ - - // 1. Make sure its our own civ - if (!Units::isOwnCiv(unit)) { - continue; - } - - // 2. Check for tameness - if (unit->training_level == df::animal_training_level::WildUntamed) { - // We don't IMMEDIATELY continue here, if the unit is - // part of our civ, it indiciates it WAS tamed, and reverted - // from SemiWild. Clear its civ flag so it looses TRAPAVOID - // - // Unfortunately, dwarves (or whatever is CIV_SELECTABLE) - // also have a default taming level of WildUntamed so - // check for this case - // - // Furthermore, it MIGHT be a werebeast, so check THAT too - // and exclude those as well. - // - // Finally, this breaks makeown. I might need to write a patch - // to set the tameness of "makeowned" units so dwarfvet can notice - // it - - if (unit->race == own_race_id || unit->enemy.normal_race == own_race_id) { - continue; - } else { - unit->civ_id = -1; - out.print ("Clearing civ on unit: %d", unit->id); - } - } - - // 3. Check for health struct - if (!unit->health) { - // Unit has not been injured ever; health struct MIA - continue; - } - - // 4. Check the healthcare flags - if (unit->health->flags.bits.needs_healthcare) { - /** - * So, for dwarves to care for a unit it must be resting in - * in a hospital zone. Since non-dwarves never take jobs - * this why animal healthcare doesn't work for animals despite - * animal caretaker being coded in DF itself - * - * How a unit gets there is dependent on several factors. If - * a unit can move under its own power, it will take the rest - * job, with a position of a bed in the hospital, then move - * into that bed and fall asleep. This triggers a doctor to - * treat the unit. - * - * If a unit *can't* move, it will set needs_recovery, which - * creates a "Recover Wounded" job in the job list, and then - * create the "Rest" job as listed above. Another dwarf with - * the right labors will go recover the unit, then the above - * logic kicks off. - * - * The necessary flags seem to be properly set for all units - * on the map, so in theory, we just need to make the jobs and - * we're in business, but from a realism POV, I don't think - * non-sentient animals would be smart enough to go to the - * hospital on their own, so instead, we're going to do the following - * - * If a unit CAN_THINK, and can move let it act like a dwarf, - * it will try and find an open spot in the hospital, and if so, - * go there to be treated. In vanilla, the only tamable animal - * with CAN_THINK are Gremlins, so this is actually an edge case - * but its the easiest to code. - * - * TODO: figure out exact logic for non-thinking critters. - */ - - // Now we need to find if this unit can be accepted at a hospital - bool awareOfUnit = tracked_units.count(unit->id); - // New unit for dwarfvet to be aware of! - if (!awareOfUnit) { - // The master list handles all patients which are accepted - // Check if this is a unit we're already aware of - - for (auto animal_hospital : animal_hospital_zones) { - if (animal_hospital->acceptPatient(unit->id, out)) { - out.print("Accepted patient %d at hospital %d\n", unit->id, animal_hospital->getID()); - tracked_units.insert(unit->id); - break; - } - } - } - } - } - - // The final step, process all patients! - for (AnimalHospital *animal_hospital : animal_hospital_zones) { - animal_hospital->calculateHospital(true, out); - animal_hospital->processPatients(out); - } - -cleanup: - EventManager::unregisterAll(plugin_self); - EventManager::EventHandler handle(tickHandler, howOften); - EventManager::registerTick(handle, howOften, plugin_self); + return Lua::CallLuaModuleFunction(*out, L, "plugins.dwarfvet", fn_name, + nargs, nres, + std::forward(args_lambda), + std::forward(res_lambda)); } -command_result dwarfvet (color_ostream &out, std::vector & parameters) -{ +static command_result do_command(color_ostream &out, vector ¶meters) { CoreSuspender suspend; - for ( size_t a = 0; a < parameters.size(); a++ ) { - if ( parameters[a] == "enable" ) { - out.print("dwarfvet enabled!\n"); - dwarfvet_enabled = true; - } - if ( parameters[a] == "disable") { - out.print("dwarvet disabled!\n"); - dwarfvet_enabled = false; - } - if ( parameters[a] == "report") { - out.print("Current animal hospitals are:\n"); - for (df::building *building : df::building::get_vector()) { - if (isActiveAnimalHospital(building)) { - out.print(" at x1: %d, x2: %d, y1: %d, y2: %d, z: %d\n", building->x1, building->x2, building->y1, building->y2, building->z); - } - } - return CR_OK; - } - if ( parameters[a] == "report-usage") { - out.print("Current animal hospitals are:\n"); - for (AnimalHospital *animal_hospital : animal_hospital_zones) { - animal_hospital->calculateHospital(true, out); - animal_hospital->reportUsage(out); - } - return CR_OK; - } + if (!Core::getInstance().isWorldLoaded()) { + out.printerr("Cannot run %s without a loaded world.\n", plugin_name); + return CR_FAILURE; } - if ( !dwarfvet_enabled ) { - return CR_OK; + bool show_help = false; + if (!call_dwarfvet_lua(&out, "parse_commandline", 1, 1, + [&](lua_State *L) { + Lua::PushVector(L, parameters); + }, + [&](lua_State *L) { + show_help = !lua_toboolean(L, -1); + })) { + return CR_FAILURE; } - EventManager::unregisterAll(plugin_self); - EventManager::EventHandler handle(tickHandler, howOften); - EventManager::registerTick(handle, howOften, plugin_self); - - return CR_OK; + return show_help ? CR_WRONG_USAGE : CR_OK; } -DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) -{ - if (enable && !dwarfvet_enabled) { - dwarfvet_enabled = true; - } - else if (!enable && dwarfvet_enabled) { - delete_animal_hospital_vector(out); - dwarfvet_enabled = false; - } +static void dwarfvet_cycle(color_ostream &out) { + // mark that we have recently run + cycle_timestamp = world->frame_counter; - return CR_OK; + DEBUG(cycle,out).print("running %s cycle\n", plugin_name); + call_dwarfvet_lua(&out, "checkup"); } -DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) -{ - switch (event) - { - case DFHack::SC_MAP_LOADED: - break; - case DFHack::SC_MAP_UNLOADED: - delete_animal_hospital_vector(out); - dwarfvet_enabled = false; - break; - default: - break; - } - return CR_OK; -} +DFHACK_PLUGIN_LUA_FUNCTIONS { + DFHACK_LUA_FUNCTION(dwarfvet_cycle), + DFHACK_LUA_END +}; diff --git a/plugins/lua/dwarfvet.lua b/plugins/lua/dwarfvet.lua new file mode 100644 index 000000000..64538bac0 --- /dev/null +++ b/plugins/lua/dwarfvet.lua @@ -0,0 +1,180 @@ +local _ENV = mkmodule('plugins.dwarfvet') + +local argparse = require('argparse') +local utils = require('utils') + +local function is_valid_animal(unit) + return unit and + dfhack.units.isActive(unit) and + dfhack.units.isAnimal(unit) and + dfhack.units.isFortControlled(unit) and + dfhack.units.isTame(unit) and + not dfhack.units.isDead(unit) +end + +local function get_cur_patients() + local cur_patients = {} + for _,job in utils.listpairs(df.global.world.jobs.list) do + if job.job_type ~= df.job_type.Rest then goto continue end + local unit = dfhack.job.getWorker(job) + print(unit.id) + if is_valid_animal(unit) then + cur_patients[unit] = true + end + ::continue:: + end + return cur_patients +end + +local function get_new_patients(cur_patients) + cur_patients = cur_patients or get_cur_patients() + local new_patients = {} + for _,unit in ipairs(df.global.world.units.active) do + if unit.job.current_job then goto continue end + if cur_patients[unit] or not is_valid_animal(unit) then goto continue end + if not unit.health or not unit.health.flags.needs_healthcare then goto continue end + table.insert(new_patients, unit) + ::continue:: + end + return new_patients +end + +local function print_status() + print(('dwarfvet is %srunning'):format(isEnabled() and '' or 'not ')) + print() + print('The following animals are receiving treatment:') + local cur_patients = get_cur_patients() + if not next(cur_patients) then + print(' None') + else + for unit in pairs(cur_patients) do + print((' %s (%d)'):format(dfhack.units.getReadableName(unit), unit.id)) + end + end + print() + print('The following animals are injured and need treatment:') + local new_patients = get_new_patients(cur_patients) + if #new_patients == 0 then + print(' None') + else + for _,unit in ipairs(new_patients) do + print((' %s (%d)'):format(dfhack.units.getReadableName(unit), unit.id)) + end + end +end + +HospitalZone = defclass(HospitalZone) +HospitalZone.ATTRS{ + zone=DEFAULT_NIL, +} + +local ONE_TILE = xy2pos(1, 1) + +function HospitalZone:find_spot(unit_pos) + self.x = self.x or self.zone.x1 + self.y = self.y or self.zone.y1 + local zone = self.zone + for y=self.y,zone.y2 do + for x=self.x,zone.x2 do + local pos = xyz2pos(x, y, zone.z) + if dfhack.maps.canWalkBetween(unit_pos, pos) and + dfhack.buildings.containsTile(zone, x, y) and + dfhack.buildings.checkFreeTiles(pos, ONE_TILE) + then + return pos + end + end + end +end + +-- TODO: If health.requires_recovery is set, the creature can't move under its own power +-- and a Recover Wounded or Pen/Pasture job must be created by hand +function HospitalZone:assign_spot(unit, unit_pos) + local pos = self:find_spot(unit_pos) + if not pos then return false end + local job = df.new(df.job) + dfhack.job.linkIntoWorld(job) + job.pos.x = pos.x + job.pos.y = pos.y + job.pos.z = pos.z + job.flags.special = true + job.job_type = df.job_type.Rest + job.wait_timer = 1600 + local gref = df.new(df.general_ref_unit_workerst) + gref.unit_id = unit.id + job.general_refs:insert('#', gref) + unit.job.current_job = job + return true +end + +local function get_hospital_zones() + local hospital_zones = {} + local site = df.global.world.world_data.active_site[0] + for _,location in ipairs(site.buildings) do + if not df.abstract_building_hospitalst:is_instance(location) then goto continue end + for _,bld_id in ipairs(location.contents.building_ids) do + local zone = df.building.find(bld_id) + if zone then + table.insert(hospital_zones, HospitalZone{zone=zone}) + end + end + ::continue:: + end + return hospital_zones +end + +local function distance(zone, pos) + return math.abs(zone.x1 - pos.x) + math.abs(zone.y1 - pos.y) + 50*math.abs(zone.z - pos.z) +end + +function checkup() + local new_patients = get_new_patients() + if #new_patients == 0 then return end + local hospital_zones = get_hospital_zones() + local assigned = 0 + for _,unit in ipairs(new_patients) do + local unit_pos = xyz2pos(dfhack.units.getPosition(unit)) + table.sort(hospital_zones, + function(a, b) return distance(a.zone, unit_pos) < distance(b.zone, unit_pos) end) + for _,hospital_zone in ipairs(hospital_zones) do + if hospital_zone:assign_spot(unit, unit_pos) then + assigned = assigned + 1 + break + end + end + end + print(('dwarfvet scheduled treatment for %d of %d injured animals'):format(assigned, #new_patients)) +end + +local function process_args(opts, args) + if args[1] == 'help' then + opts.help = true + return + end + + return argparse.processArgsGetopt(args, { + {'h', 'help', handler=function() opts.help = true end}, + }) +end + +function parse_commandline(args) + local opts = {} + local positionals = process_args(opts, args) + + if opts.help or not positionals then + return false + end + + local command = positionals[1] + if not command or command == 'status' then + print_status() + elseif command == 'now' then + dwarfvet_cycle() + else + return false + end + + return true +end + +return _ENV diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index e8a943381..636f3938e 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -422,29 +422,6 @@ local function make_choice_text(data) } end -local function get_unit_description(unit, raw) - local race = dfhack.units.isChild(unit) and raw.general_child_name[0] or raw.caste[unit.caste].caste_name[0] - local name = dfhack.TranslateName(dfhack.units.getVisibleName(unit)) - if name and #name > 0 then - name = ('%s, %s'):format(name, race) - else - name = race - end - if #unit.syndromes.active > 0 then - for _, unit_syndrome in ipairs(unit.syndromes.active) do - local syndrome = df.syndrome.find(unit_syndrome.type) - if not syndrome then goto continue end - for _, effect in ipairs(syndrome.ce) do - if df.creature_interaction_effect_display_namest:is_instance(effect) then - return name .. ' ' .. effect.name - end - end - ::continue:: - end - end - return name -end - local function get_cage_ref(unit) return dfhack.units.getGeneralRef(unit, df.general_ref_type.CONTAINED_IN_ITEM) end @@ -518,9 +495,9 @@ function Pasture:cache_choices() local raw = df.creature_raw.find(unit.race) local data = { unit=unit, - desc=get_unit_description(unit, raw), + desc=dfhack.units.getReadableName(unit), gender=unit.sex, - race=raw.creature_id, + race=raw and raw.creature_id or -1, status=get_status(unit), disposition=get_disposition(unit), egg=dfhack.units.isEggLayerRace(unit), From b25266367d4384a560ce5343a9bf87075bf015c7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 21 Jul 2023 04:17:57 -0700 Subject: [PATCH 138/851] add examples to the docs --- docs/plugins/dwarfvet.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/plugins/dwarfvet.rst b/docs/plugins/dwarfvet.rst index 70f92cc79..12d77fef8 100644 --- a/docs/plugins/dwarfvet.rst +++ b/docs/plugins/dwarfvet.rst @@ -11,6 +11,9 @@ Caretaker labor enabled will come to the hospital to treat the animals. Normal medical skills are used (and trained), but no experience is given to the Animal Caretaker skill itself. +You can enable ``dwarfvet`` in `gui/control-panel`, and you can choose to start +``dwarfvet`` automatically in new forts in the ``Autostart`` tab. + Usage ----- @@ -18,3 +21,15 @@ Usage enable dwarfvet dwarfvet [status] + dwarfvet now + +Examples +-------- + +``dwarfvet`` + Report on how many animals are being treated and how many are in need of + treatment. + +``dwarfvet now`` + Assign injured animals to a free floor spot in a nearby hospital, + regardless of whether the plugin is enabled. From 8534f4302528b3ac0c3f7f4e566bdf012aae7438 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 21 Jul 2023 21:24:34 +0000 Subject: [PATCH 139/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 67d4e63da..b7e0712fd 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 67d4e63daeb30986e8f318c96c58d105a00c468d +Subproject commit b7e0712fdc97239e301537bd7ee2c102f9ea3551 From c72bf10623f6919681ad8ec2fb40fe0f69b019f8 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 21 Jul 2023 21:30:08 +0000 Subject: [PATCH 140/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index b7e0712fd..087c02656 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit b7e0712fdc97239e301537bd7ee2c102f9ea3551 +Subproject commit 087c026565d056646261aaaef663c53855b36c79 From ac8211a9c76ddfdc619e4d46acfcd3c503cbf071 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 21 Jul 2023 14:35:59 -0700 Subject: [PATCH 141/851] add autobutcher link to pasture screen --- plugins/lua/zone.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 636f3938e..3c70c1e63 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -687,7 +687,7 @@ PastureOverlay.ATTRS{ default_pos={x=7,y=13}, default_enabled=true, viewscreens='dwarfmode/Zone/Some/Pen', - frame={w=32, h=1}, + frame={w=31, h=3}, frame_background=gui.CLEAR_PEN, } @@ -695,10 +695,16 @@ function PastureOverlay:init() self:addviews{ widgets.TextButton{ frame={t=0, l=0}, - label='DFHack search and sort', + label='DFHack manage pasture', key='CUSTOM_CTRL_T', on_activate=function() view = view and view:raise() or PastureScreen{}:show() end, }, + widgets.TextButton{ + frame={t=2, l=0}, + label='DFHack autobutcher', + key='CUSTOM_CTRL_B', + on_activate=function() dfhack.run_script('gui/autobutcher') end, + }, } end From 77d0fb297c2f8d634785eea02dd64a5065593191 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 21 Jul 2023 15:03:06 -0700 Subject: [PATCH 142/851] convert tabs to spaces when getting clipboard text this avoids tab characters being translated to "?" when converted to cp437 --- library/modules/DFSDL.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp index aa54cf66c..72105b2e6 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -151,6 +151,11 @@ DFHACK_EXPORT std::string DFHack::getClipboardTextCp437() { if (!g_sdl_handle || g_SDL_HasClipboardText() != SDL_TRUE) return ""; char *text = g_SDL_GetClipboardText(); + // convert tabs to spaces so they don't get converted to '?' + for (char *c = text; *c; ++c) { + if (*c == '\t') + *c = ' '; + } std::string textcp437 = UTF2DF(text); DFHack::DFSDL::DFSDL_free(text); return textcp437; From 20856a4e6f8379a006f2c232feb5cacfb5aa2905 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 21 Jul 2023 23:35:37 +0000 Subject: [PATCH 143/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 087c02656..c7f66954d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 087c026565d056646261aaaef663c53855b36c79 +Subproject commit c7f66954d77a6551255d378f829f5415ea9a29b3 From 383966511d695f2fabb1349036de61358a8c6b3c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 21 Jul 2023 16:39:36 -0700 Subject: [PATCH 144/851] don't modify container while iterating --- plugins/logistics.cpp | 9 ++++++--- plugins/lua/logistics.lua | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/plugins/logistics.cpp b/plugins/logistics.cpp index 643fb4941..69b864c5c 100644 --- a/plugins/logistics.cpp +++ b/plugins/logistics.cpp @@ -122,6 +122,7 @@ static df::building_stockpilest* find_stockpile(int32_t stockpile_number) { static void validate_stockpile_configs(color_ostream& out, unordered_map &cache) { + vector to_remove; for (auto& entry : watched_stockpiles) { int stockpile_number = entry.first; PersistentDataItem &c = entry.second; @@ -129,13 +130,15 @@ static void validate_stockpile_configs(color_ostream& out, if (!bld || ( !get_config_bool(c, STOCKPILE_CONFIG_MELT) && !get_config_bool(c, STOCKPILE_CONFIG_TRADE) && - !get_config_bool(c, STOCKPILE_CONFIG_DUMP) && - !get_config_bool(c, STOCKPILE_CONFIG_TRAIN))) { - remove_stockpile_config(out, stockpile_number); + !get_config_bool(c, STOCKPILE_CONFIG_DUMP) && + !get_config_bool(c, STOCKPILE_CONFIG_TRAIN))) { + to_remove.push_back(stockpile_number); continue; } cache.emplace(bld, c); } + for (int stockpile_number : to_remove) + remove_stockpile_config(out, stockpile_number); } // remove this function once saves from 50.08 are no longer compatible diff --git a/plugins/lua/logistics.lua b/plugins/lua/logistics.lua index 891332236..0231ce593 100644 --- a/plugins/lua/logistics.lua +++ b/plugins/lua/logistics.lua @@ -75,7 +75,7 @@ local function print_status() print(('Total items marked for melting: %5d'):format(global_stats.total_melt)) print(('Total items marked for trading: %5d'):format(global_stats.total_trade)) print(('Total items marked for dumping: %5d'):format(global_stats.total_dump)) - print(('Total animals marked for training: %5d'):format(global_stats.total_train)) + print(('Total animals marked for training: %2d'):format(global_stats.total_train)) end local function for_stockpiles(opts, fn) From 87a391b2ce8a7fc6bfd8c6f280cef4e1043f49cb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 21 Jul 2023 17:46:38 -0700 Subject: [PATCH 145/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index e8fc5725c..ff171fbb4 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: - `logistics`: don't autotrain domestic animals brought by invaders (they'll get attacked by friendly creatures as soon as you let them out of their cage) - `logistics`: don't bring trade goods to depot if the only caravans present are tribute caravans - `gui/create-item`: when choosing a citizen to create the chosen items, avoid choosing a dead citizen +- `logistics`: fix potential crash when removing stockpiles or turning off stockpile features ## Misc Improvements - `stockpiles`: include exotic pets in the "tameable" filter From eb93f1de0da214009d25300885cef1af5e31ece9 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 22 Jul 2023 01:32:15 +0000 Subject: [PATCH 146/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index c7f66954d..ae03c0d4e 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit c7f66954d77a6551255d378f829f5415ea9a29b3 +Subproject commit ae03c0d4ea87ed4dcc74e49b177ad93c28baf42a From a9df9f92d9017f28e08934abdf7398934102599a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 21 Jul 2023 18:50:15 -0700 Subject: [PATCH 147/851] update for 50.09-r2 --- CMakeLists.txt | 4 ++-- data/blueprints/dreamfort.csv | 3 ++- docs/changelog.txt | 20 ++++++++++++++++++-- library/xml | 2 +- scripts | 2 +- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69a3efed9..9fa7acbe1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.09") -set(DFHACK_RELEASE "r2rc2") -set(DFHACK_PRERELEASE TRUE) +set(DFHACK_RELEASE "r2") +set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_ABI_VERSION 1) diff --git a/data/blueprints/dreamfort.csv b/data/blueprints/dreamfort.csv index 5ac765523..ea783e1e2 100644 --- a/data/blueprints/dreamfort.csv +++ b/data/blueprints/dreamfort.csv @@ -112,7 +112,7 @@ You can save some time by setting up your settings in gui/control-panel before y "" "On the gui/control-panel ""Autostart"" tab, additionally enable:" - autobutcher -- autobutcher target 50 50 14 2 BIRD_GOOSE +- autobutcher target 10 10 14 2 BIRD_GOOSE - autochop - autofarm - autofish @@ -121,6 +121,7 @@ You can save some time by setting up your settings in gui/control-panel before y - ban-cooking all - buildingplan set boulders false - buildingplan set logs false +- dwarfvet - nestboxes - prioritize - seedwatch diff --git a/docs/changelog.txt b/docs/changelog.txt index ff171fbb4..5e65b4909 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -33,6 +33,24 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # Future +## New Plugins + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Internals + +## Lua + +## Removed + +# 50.09-r2 + ## New Plugins - `3dveins`: reinstated for v50, this plugin replaces vanilla DF's blobby vein generation with veins that flow smoothly and naturally between z-levels - `zone`: new searchable, sortable, filterable screen for assigning units to pastures @@ -71,8 +89,6 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - ``dfhack.items.getValue``: gained optional ``caravan`` and ``caravan_buying`` parameters for prices that take trader races and agreements into account - ``widgets.TextButton``: wraps a ``HotkeyLabel`` and decorates it to look more like a button -## Removed - # 50.09-r1 # 50.08-r4 diff --git a/library/xml b/library/xml index 8358a5173..dd2f99f14 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 8358a51735ac1daeaa11d5a008c16301fa6759ce +Subproject commit dd2f99f1498b903bb9ed28542b652e4c00d8188c diff --git a/scripts b/scripts index ae03c0d4e..03bf65057 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ae03c0d4ea87ed4dcc74e49b177ad93c28baf42a +Subproject commit 03bf65057d3a04badee4dfbffd99f85dd33b8e73 From 971dca86044176daeea2463c970327db8a1a56dd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 22 Jul 2023 14:53:36 -0700 Subject: [PATCH 148/851] update scripts ref and a bit of dreamfort help text --- data/blueprints/dreamfort.csv | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/blueprints/dreamfort.csv b/data/blueprints/dreamfort.csv index ea783e1e2..8111c60e9 100644 --- a/data/blueprints/dreamfort.csv +++ b/data/blueprints/dreamfort.csv @@ -42,7 +42,7 @@ 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. Each line is a blueprint that you run with gui/quickfort (default keybinding: Ctrl-Shift-Q), except where we use other tools as noted. If you set ""dreamfort"" as the filter when you open gui/quickfort, you'll conveniently only see Dreamfort blueprints to choose from. See the walkthroughs (the ""help"" blueprints) for context and details." +"Here is the recommended order for Dreamfort commands. Each line is a blueprint that you run with gui/quickfort (default keybinding: Ctrl-Shift-Q), except where we use other tools as noted. If you set ""dreamfort"" as the filter when you open gui/quickfort, you'll conveniently only see Dreamfort blueprints to choose from. See the walkthroughs (the ""help"" blueprints) for context and details. You can also copy text from this spreadsheet online and paste it in gui/launcher with Ctrl-V." "If the checklist indicates that you should generate orders, that means to hit the ""o"" hotkey when the blueprint is loaded in gui/quickfort. You'll get a popup saying which orders were generated. Also remember to read the messages the blueprints display after you run them so you don't miss any important manual steps!" "" -- Preparation (before you embark!) -- diff --git a/scripts b/scripts index 03bf65057..bb9d82c92 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 03bf65057d3a04badee4dfbffd99f85dd33b8e73 +Subproject commit bb9d82c92ed97a8d4131dfd4f6b68d75430a0c5a From 8ec860461a4f37483ccb8abc50bed0123580d5b7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 22 Jul 2023 22:54:21 -0700 Subject: [PATCH 149/851] deploy linux build to steam --- .github/workflows/build.yml | 13 ++++------ .github/workflows/steam.yml | 48 +++++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c0b621c4c..19d876797 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,14 +29,9 @@ jobs: sudo apt-get update sudo apt-get install \ ccache \ - libgtk2.0-0 \ - libncursesw5 \ - libsdl-image1.2-dev \ - libsdl-ttf2.0-dev \ - libsdl1.2-dev \ + libsdl2-dev \ libxml-libxml-perl \ libxml-libxslt-perl \ - lua5.3 \ ninja-build \ zlib1g-dev pip install 'sphinx<4.4.0' @@ -44,7 +39,7 @@ jobs: run: | sudo apt-get install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} - name: Clone DFHack - uses: actions/checkout@v1 + uses: actions/checkout@v3 with: fetch-depth: 0 # unlimited - we need past tags submodules: true @@ -177,7 +172,7 @@ jobs: run: | pip install 'sphinx' - name: Clone DFHack - uses: actions/checkout@v1 + uses: actions/checkout@v3 with: submodules: true - name: Build docs @@ -196,7 +191,7 @@ jobs: sudo apt-get update sudo apt-get install lua5.3 - name: Clone DFHack - uses: actions/checkout@v1 + uses: actions/checkout@v3 with: submodules: true # don't need tags here diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index a67a87b81..f5e1b976a 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -23,10 +23,23 @@ jobs: name: Deploy to Steam runs-on: ubuntu-22.04 steps: + - name: Set up Python 3 + uses: actions/setup-python@v4 + with: + python-version: 3 - name: Install dependencies run: | sudo apt-get update - sudo apt-get install ccache + sudo apt-get install \ + ccache \ + libsdl2-dev \ + libxml-libxml-perl \ + libxml-libxslt-perl \ + ninja-build \ + zlib1g-dev \ + gcc \ + g++ + pip install 'sphinx<4.4.0' - name: Clone DFHack uses: actions/checkout@v3 with: @@ -40,13 +53,43 @@ jobs: ref: main ssh-key: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} path: depends/steam - - name: Fetch ccache + - name: Fetch linux64 ccache + uses: actions/cache@v3 + with: + path: ~/.ccache + key: ccache-ubuntu-22.04-gcc-10-${{ github.sha }} + restore-keys: | + ccache-ubuntu-22.04-gcc-10 + - name: Fetch win64 ccache uses: actions/cache@v3 with: path: build/win64-cross/ccache key: ccache-win64-cross-msvc-${{ github.sha }} restore-keys: | ccache-win64-cross-msvc + - name: Set up environment + id: env_setup + run: | + echo "CCACHE_DIR=${HOME}/.ccache" >> $GITHUB_ENV + - name: Configure DFHack + run: | + cmake \ + -S . \ + -B build \ + -G Ninja \ + -DDFHACK_BUILD_ARCH=64 \ + -DBUILD_STONESENSE:BOOL=1 \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DBUILD_DFLAUNCH:BOOL=1 \ + -DBUILD_DOCS:BOOL=1 \ + -DCMAKE_INSTALL_PREFIX=linux64/output + - name: Build DFHack + run: | + ninja -C build install + ccache --max-size 50M + ccache --cleanup + ccache --show-stats - name: Cross-compile win64 artifacts env: CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1' @@ -72,4 +115,5 @@ jobs: buildDescription: ${{ github.event.inputs.version }} rootPath: build depot1Path: win64-cross/output + depot2Path: linux64/output releaseBranch: ${{ github.event.inputs.release_channel }} From 0f14be32de01ae66ed01aefe33b3a74926a80c5f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Jul 2023 01:24:17 -0700 Subject: [PATCH 150/851] don't build stonesense for now --- .github/workflows/build.yml | 3 --- .github/workflows/steam.yml | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 19d876797..e95cfaf8f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -81,7 +81,6 @@ jobs: -DBUILD_DEV_PLUGINS:BOOL=${{ matrix.plugins == 'all' }} \ -DBUILD_SIZECHECK:BOOL=${{ matrix.plugins == 'all' }} \ -DBUILD_SKELETON:BOOL=${{ matrix.plugins == 'all' }} \ - -DBUILD_STONESENSE:BOOL=${{ matrix.plugins == 'all' }} \ -DBUILD_SUPPORTED:BOOL=1 \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ @@ -143,8 +142,6 @@ jobs: ccache-win64-cross-msvc-${{ github.ref_name }} ccache-win64-cross-msvc - name: Cross-compile win64 artifacts - env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1' run: | cd build bash -x build-win64-from-linux.sh diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index f5e1b976a..e24271f17 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -78,7 +78,6 @@ jobs: -B build \ -G Ninja \ -DDFHACK_BUILD_ARCH=64 \ - -DBUILD_STONESENSE:BOOL=1 \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DBUILD_DFLAUNCH:BOOL=1 \ @@ -92,7 +91,7 @@ jobs: ccache --show-stats - name: Cross-compile win64 artifacts env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1' + CMAKE_EXTRA_ARGS: '-DBUILD_DFLAUNCH:BOOL=1' steam_username: ${{ secrets.STEAM_SDK_USERNAME }} steam_password: ${{ secrets.STEAM_SDK_PASSWORD }} run: | From b8e5dd18fbe6748000c407db52296caffa024899 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Jul 2023 01:46:33 -0700 Subject: [PATCH 151/851] add linux build artifact --- .github/workflows/build.yml | 139 +++++++++++++++++++++++++----------- .github/workflows/steam.yml | 15 ++-- 2 files changed, 103 insertions(+), 51 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e95cfaf8f..ead300c90 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,9 +3,9 @@ name: Build on: [push, pull_request] jobs: - build: + build-test: runs-on: ${{ matrix.os }} - name: build (Linux, GCC ${{ matrix.gcc }}, ${{ matrix.plugins }} plugins) + name: Test (Linux, GCC ${{ matrix.gcc }}, ${{ matrix.plugins }} plugins) strategy: fail-fast: false matrix: @@ -29,11 +29,8 @@ jobs: sudo apt-get update sudo apt-get install \ ccache \ - libsdl2-dev \ - libxml-libxml-perl \ libxml-libxslt-perl \ - ninja-build \ - zlib1g-dev + ninja-build pip install 'sphinx<4.4.0' - name: Install GCC run: | @@ -41,8 +38,8 @@ jobs: - name: Clone DFHack uses: actions/checkout@v3 with: - fetch-depth: 0 # unlimited - we need past tags submodules: true + fetch-depth: 0 - name: Set up environment id: env_setup run: | @@ -51,11 +48,6 @@ jobs: echo "DF_VERSION=${DF_VERSION}" >> $GITHUB_ENV echo "DF_FOLDER=${HOME}/DF/${DF_VERSION}/df_linux" >> $GITHUB_ENV echo "CCACHE_DIR=${HOME}/.ccache" >> $GITHUB_ENV - # - name: Fetch DF cache - # uses: actions/cache@v3 - # with: - # path: ~/DF - # key: dfcache-${{ steps.env_setup.outputs.df_version }}-${{ hashFiles('ci/download-df.sh') }} - name: Fetch ccache uses: actions/cache@v3 with: @@ -64,9 +56,14 @@ jobs: restore-keys: | ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }}-${{ github.ref_name }} ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }} - # - name: Download DF - # run: | - # sh ci/download-df.sh + # - name: Fetch DF cache + # uses: actions/cache@v3 + # with: + # path: ~/DF + # key: df-${{ steps.env_setup.outputs.df_version }}-${{ hashFiles('ci/download-df.sh') }} + # - name: Download DF + # run: | + # sh ci/download-df.sh - name: Configure DFHack env: CC: gcc-${{ matrix.gcc }} @@ -96,32 +93,92 @@ jobs: run: | ninja -C build-ci test exit $? - # - name: Run lua tests - # id: run_tests_lua - # run: | - # export TERM=dumb - # status=0 - # script -qe -c "python ci/run-tests.py --headless --keep-status \"$DF_FOLDER\"" || status=$((status + 1)) - # python ci/check-rpc.py "$DF_FOLDER/dfhack-rpc.txt" || status=$((status + 2)) - # mkdir -p artifacts - # cp "$DF_FOLDER"/test*.json "$DF_FOLDER"/*.log artifacts || status=$((status + 4)) - # exit $status - # - name: Upload test artifacts - # uses: actions/upload-artifact@v1 - # if: (success() || failure()) && steps.run_tests.outcome != 'skipped' - # continue-on-error: true - # with: - # name: test-artifacts-${{ matrix.gcc }} - # path: artifacts - - name: Clean up DF folder - # prevent DFHack-generated files from ending up in the cache - # (download-df.sh also removes them, this is just to save cache space) - if: success() || failure() - run: | - rm -rf "$DF_FOLDER" + # - name: Run lua tests + # id: run_tests_lua + # run: | + # export TERM=dumb + # status=0 + # script -qe -c "python ci/run-tests.py --headless --keep-status \"$DF_FOLDER\"" || status=$((status + 1)) + # python ci/check-rpc.py "$DF_FOLDER/dfhack-rpc.txt" || status=$((status + 2)) + # mkdir -p artifacts + # cp "$DF_FOLDER"/test*.json "$DF_FOLDER"/*.log artifacts || status=$((status + 4)) + # exit $status + # - name: Upload test artifacts + # uses: actions/upload-artifact@v3 + # if: (success() || failure()) && steps.run_tests.outcome != 'skipped' + # continue-on-error: true + # with: + # name: test-artifacts-${{ matrix.gcc }} + # path: artifacts + # - name: Clean up DF folder + # # prevent DFHack-generated files from ending up in the cache + # # (download-df.sh also removes them, this is just to save cache space) + # if: success() || failure() + # run: | + # rm -rf "$DF_FOLDER" + + build-linux64: + name: Linux package + runs-on: ubuntu-22.04 + steps: + - name: Set up Python 3 + uses: actions/setup-python@v4 + with: + python-version: 3 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install \ + ccache \ + libxml-libxslt-perl \ + ninja-build + pip install 'sphinx<4.4.0' + - name: Clone DFHack + uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + - name: Fetch ccache + uses: actions/cache@v3 + with: + path: ~/.ccache + key: ccache-ubuntu-22.04-gcc-11-${{ github.ref_name }}-${{ github.sha }} + restore-keys: | + ccache-ubuntu-22.04-gcc-11-${{ github.ref_name }} + ccache-ubuntu-22.04-gcc-11 + - name: Set up environment + id: env_setup + run: | + echo "CCACHE_DIR=${HOME}/.ccache" >> $GITHUB_ENV + - name: Configure DFHack + run: | + cmake \ + -S . \ + -B build \ + -G Ninja \ + -DDFHACK_BUILD_ARCH=64 \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DBUILD_DOCS:BOOL=1 \ + -DCMAKE_INSTALL_PREFIX=build/output + - name: Build DFHack + run: | + ninja -C build install + ccache --max-size 50M + ccache --cleanup + ccache --show-stats + - name: Format artifact name + id: artifactname + run: | + echo name=$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: dfhack-linux64-build-${{ steps.artifactname.outputs.name }} + path: build/output/* build-cross-win64: - name: Build MSVC win64 + name: Win64 package runs-on: ubuntu-22.04 steps: - name: Install dependencies @@ -141,7 +198,7 @@ jobs: restore-keys: | ccache-win64-cross-msvc-${{ github.ref_name }} ccache-win64-cross-msvc - - name: Cross-compile win64 artifacts + - name: Cross-compile win64 run: | cd build bash -x build-win64-from-linux.sh @@ -152,7 +209,7 @@ jobs: id: artifactname run: | echo name=$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT - - name: Upload win64 artifacts + - name: Upload artifact uses: actions/upload-artifact@v3 with: name: dfhack-win64-build-${{ steps.artifactname.outputs.name }} diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index e24271f17..9718f5b53 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -32,13 +32,8 @@ jobs: sudo apt-get update sudo apt-get install \ ccache \ - libsdl2-dev \ - libxml-libxml-perl \ libxml-libxslt-perl \ - ninja-build \ - zlib1g-dev \ - gcc \ - g++ + ninja-build pip install 'sphinx<4.4.0' - name: Clone DFHack uses: actions/checkout@v3 @@ -57,9 +52,9 @@ jobs: uses: actions/cache@v3 with: path: ~/.ccache - key: ccache-ubuntu-22.04-gcc-10-${{ github.sha }} + key: ccache-ubuntu-22.04-gcc-11-${{ github.sha }} restore-keys: | - ccache-ubuntu-22.04-gcc-10 + ccache-ubuntu-22.04-gcc-11 - name: Fetch win64 ccache uses: actions/cache@v3 with: @@ -82,7 +77,7 @@ jobs: -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DBUILD_DFLAUNCH:BOOL=1 \ -DBUILD_DOCS:BOOL=1 \ - -DCMAKE_INSTALL_PREFIX=linux64/output + -DCMAKE_INSTALL_PREFIX=build/output - name: Build DFHack run: | ninja -C build install @@ -114,5 +109,5 @@ jobs: buildDescription: ${{ github.event.inputs.version }} rootPath: build depot1Path: win64-cross/output - depot2Path: linux64/output + depot2Path: output releaseBranch: ${{ github.event.inputs.release_channel }} From 4411361b935197691968617fb6627cd76bceaeb7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Jul 2023 11:00:44 -0700 Subject: [PATCH 152/851] Revert "don't build stonesense for now" This reverts commit 0f14be32de01ae66ed01aefe33b3a74926a80c5f. --- .github/workflows/build.yml | 3 +++ .github/workflows/steam.yml | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ead300c90..d34085d22 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -78,6 +78,7 @@ jobs: -DBUILD_DEV_PLUGINS:BOOL=${{ matrix.plugins == 'all' }} \ -DBUILD_SIZECHECK:BOOL=${{ matrix.plugins == 'all' }} \ -DBUILD_SKELETON:BOOL=${{ matrix.plugins == 'all' }} \ + -DBUILD_STONESENSE:BOOL=${{ matrix.plugins == 'all' }} \ -DBUILD_SUPPORTED:BOOL=1 \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ @@ -199,6 +200,8 @@ jobs: ccache-win64-cross-msvc-${{ github.ref_name }} ccache-win64-cross-msvc - name: Cross-compile win64 + env: + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE: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 9718f5b53..5507104e0 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -73,6 +73,7 @@ jobs: -B build \ -G Ninja \ -DDFHACK_BUILD_ARCH=64 \ + -DBUILD_STONESENSE:BOOL=1 \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DBUILD_DFLAUNCH:BOOL=1 \ @@ -86,7 +87,7 @@ jobs: ccache --show-stats - name: Cross-compile win64 artifacts env: - CMAKE_EXTRA_ARGS: '-DBUILD_DFLAUNCH:BOOL=1' + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1' steam_username: ${{ secrets.STEAM_SDK_USERNAME }} steam_password: ${{ secrets.STEAM_SDK_PASSWORD }} run: | From 7cccd96599586c55009eb7ba688175f01db4d629 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Jul 2023 11:01:54 -0700 Subject: [PATCH 153/851] update stonesense ref --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index 367d602a2..9831bee5f 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 367d602a2949ab7121e2d9233c29a7fb1b9e6bec +Subproject commit 9831bee5f9aa759a4fd679351eb89c542ef6a2dd From be98d4934e95657b6e8b55921e19f4d2bb483c9c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 23 Jul 2023 11:06:48 -0700 Subject: [PATCH 154/851] add gl headers for allegro --- .github/workflows/build.yml | 2 ++ .github/workflows/steam.yml | 1 + 2 files changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d34085d22..b67b51ead 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,6 +30,7 @@ jobs: sudo apt-get install \ ccache \ libxml-libxslt-perl \ + libgl-dev \ ninja-build pip install 'sphinx<4.4.0' - name: Install GCC @@ -132,6 +133,7 @@ jobs: sudo apt-get install \ ccache \ libxml-libxslt-perl \ + libgl-dev \ ninja-build pip install 'sphinx<4.4.0' - name: Clone DFHack diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 5507104e0..b272dc1c0 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -33,6 +33,7 @@ jobs: sudo apt-get install \ ccache \ libxml-libxslt-perl \ + libgl-dev \ ninja-build pip install 'sphinx<4.4.0' - name: Clone DFHack From f3da973c0990faeab1e59145f67d68d2d5b91bd3 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 24 Jul 2023 07:14:05 +0000 Subject: [PATCH 155/851] 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 367d602a2..9831bee5f 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 367d602a2949ab7121e2d9233c29a7fb1b9e6bec +Subproject commit 9831bee5f9aa759a4fd679351eb89c542ef6a2dd diff --git a/scripts b/scripts index bb9d82c92..f49836f88 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit bb9d82c92ed97a8d4131dfd4f6b68d75430a0c5a +Subproject commit f49836f88936999cca127218c6ec043e3daa51b0 From e8241953952ba7983348a7ec3d63810f23943695 Mon Sep 17 00:00:00 2001 From: plule <630159+plule@users.noreply.github.com> Date: Tue, 25 Jul 2023 21:20:06 +0200 Subject: [PATCH 156/851] Add a separate icon for jobs suspended by suspendmanager --- data/art/unsuspend.png | Bin 971 -> 5180 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/art/unsuspend.png b/data/art/unsuspend.png index c00d3a1ac1c865ce70acaa4c8983cdb33f874876..f1d1d33da6cb7e461cfac5c5163d361c087fec13 100644 GIT binary patch literal 5180 zcmeHKYg7~079L7@l!_o0K`%;(RK=2H@_;-fkw=2W8jTPXZV{X$lMo;elJF2jT0l{( z2vU`zqF#%N7OSm-fDjN7D6L?nMHEF*1VqIr%0qfj0xGWCyY6zW+kYlAnVEgQ{q4QK zv(H(XP5h;cEG=eOKoDff^<(>k>ppN|%uT`X_GHa7aH&oZ1Zn+|IE+fIl*pn`jCPF* z#h~#r2?WJok@LMK8#|ew8O~sNO&6@qyn2e8+}v$vR~&qGX(yCAJsS>fT6CJn@2o0a zEGuA}P!%n1+2K8Ahw9D3zB>^5)Ki)&NbwDFsqNpJFk~Oplh?I5yS?H>(U$WM2w}dX zq&sYK$F;+yQ|f0lSeE^{pHkRLh?;%OdI4h7$QW3*Dkd@Uk2p_Cmi2a{Vk6kbN=3%uc#$W{8Q`L*sM5 z*K#j%7LSDahfldx9lh}SwZ!%c<22v(g_4z%_->7Ub32829o95-N|p5xaZA>@CCqPw z>(6S|UaP5VEuYu)nDxBd+{Glvh?Pw{udTs`&dqN-sl70K4q36|lTJ-%bSmC&q&}vt zi+bVHbd&t)?mza@JK+;ScUPCD2DkAy9ojfMgHKrHpz>*I?5`(f9Inc$)?9n7VEA+l7-wKN>0^JX)du02`O<~V|BXS z$aJr^Am$JLPU|M79&KZG6fUc zU#`PqWMU?Er5g|CseI6InO}k$4M2x{)CJ{&^96;bSYZO`}9;eXE)>Djeuu+XjEmLV_N(DyGi3pW3 zS|%0?#xbw*ldE{V*Ypa_xC%fILOh}(5b-cUE+wa!p`3|{0Qc9tZ=qk+ZU6%mkH=suMKSvHxNIg?ADDqhU!_`(fa#RU5h+SgDWrx0z2FQlK9`9l;m4o`3qK0cN`M1c z12TnJ8K-#z7RcmifELl~Npz>fWDuE1C6X!b?xZ)M6{uPRdQs0xgz;pGVMISM3{Vb` z7SVSqATZcLH4Gm$ifEN;fl?X8#OhPP=sjN#^T2`&8pQLulEH|#6B>@S*uCK16@vd|p|lVQ+LREiLXP~BmikcJAW zun?wGsI<4)HA;y#4pF0CQlKNy3N)xeE6lv{sd9N69~X}5=K)BDgQ>U)l3@ws#S-*8 z#;a;Q2>+pnhXF8QivfOPHn4SposjT)D;(ELzv=vqpYeJ48zTVf_d(uC-}iF8m+PGr zcqj1t?s_lRJ1Ou^;P>72f0N7N&C3+30RMpEz^hVw`U?zr%`z2!zK9L|ssHY)IFth{ zAF2F;H4yaiRQ+iL9dz7Zuwe)O!3-cuRB!s^@xArhfp&G_f1D3-sg)unD}LDF+; z@8+UMA8Y$_w$>-zB30~a$g)lu8G2S7UB;r#YC&(WTuFZVJgj8XgNUbh3T|R_WqD3l z=sqVka}GDwQzxZnZrxhA;%N4J>GzM!%*^G*Ma6r)2;_SvQ2r3Q1)2O_h z&Ym=H^ZDzZ&8&Q3`Qqk)qgRs9+nA4SdScU%KYAyBXYPVFA0FXW*Lpk0G`DR|g9F=> zAA0@df;!$_6Dlmbe6Gn+_rb-;K9b_860!E(ZdU7|!O6hg81LulWT2*1jr zBHZ^yMcjrTTKkU6%VXLsFMQD#O(-vV{PIQH&PVNO?e-pay$PhQzLQo_{coFdJnd+Pyu!yl|a)W(bcX{cf(b)}iIi9-V zJz=3=hwKV>j*eLkkrdFC@(%J3NwZ3e|J6}<_K7o7Czy{&By-ffz(7|Vj@wuwUw{pB z-(@*7`cZp@MQHNfL+L-aYK)QwFN88S@A|yo2%1xCKc_ax)yDMm{(G+e7dTMWg8}Q< zl5}Bq^G;<%gvIX>w$P0-d`RmS&e^pr$Ao*d$qseZ7cVYX%`&sIyFS`W?HXs>ZMwV-`UfuRd#s?y)K>1N+Zd_5{6GX4BH$dENly875-H9 z#VtGUC;5t);Ge4QM$Fj;x-)WGxV^8lE}&v3*)#cichl%UrC+UEHQ?I3H?eqDQrpH@ zi_AXDmmQC7Is3i$ThH*Ay4=tA&z?GX2yw33ZSe_b|KQ-DS>yGg1Tp=On3>RbnPEYm zJF=iEyA!sTC`LC4V744Xey_sg{*j1kxfATDPq`Px&Ye_^wRCt{2nLlXMP#njcW7!Vz#gVNSmRBQ*M6{U+vV|t)cZczL=$P1U`PAud_sJ{<9 zc=;u{@5}xEyu25H`L9Xo_)#e(0f6UuslTzWHT~6$Ne4m*3fpS6T2tM&xW%QEbgz9g z0AK(h^}wy{I`k*cWdHzu6&cWPW={esCB1oT0RXmc>DQ*M9AB+gBj-w`5&^9PAr_>R zG}XO}KHs=TpNyzd$(`bp+7g4qwn8lh(4U8(+4|!{kgFm(d>Gn z+4a6XZv9qc@|LIR>g+o@cIi1CyYyU(wh)3W%OcCNNU^lEt0)$Wa9tO!>jD65+eV>K000yU1;1~aCaFr0j$;4{&+}3PD+_pQRIz_} z4*(!vO9!04D1PE{y{=_0^gJ)sSE=Lm^+SLh0sxE}KLXA_Gt!2MXQ@QqLsZ#sbpFfR z_qA!dt_$0?{o_)pcV(HR7O>F@7Hn{xmFFhAXa`RNY-nk0hY!0=hWpJe72i^agP z<2Y~}2g}RLem{)XDWFGoVPIte11k%GAV`Y&=??T&>gcP~13{1kDhS3$HYDPFMY!~@ zW;%!kwdSAd-W6EywzBKcpBu~3+*mH6-^{K Date: Thu, 27 Jul 2023 23:19:16 -0700 Subject: [PATCH 157/851] alphebetize --- .github/workflows/build.yml | 4 ++-- .github/workflows/steam.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b67b51ead..4caddc40a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,8 +29,8 @@ jobs: sudo apt-get update sudo apt-get install \ ccache \ - libxml-libxslt-perl \ libgl-dev \ + libxml-libxslt-perl \ ninja-build pip install 'sphinx<4.4.0' - name: Install GCC @@ -132,8 +132,8 @@ jobs: sudo apt-get update sudo apt-get install \ ccache \ - libxml-libxslt-perl \ libgl-dev \ + libxml-libxslt-perl \ ninja-build pip install 'sphinx<4.4.0' - name: Clone DFHack diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index b272dc1c0..c1118dddc 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -32,8 +32,8 @@ jobs: sudo apt-get update sudo apt-get install \ ccache \ - libxml-libxslt-perl \ libgl-dev \ + libxml-libxslt-perl \ ninja-build pip install 'sphinx<4.4.0' - name: Clone DFHack From 73427de9946333adf31859aa91577a922ec10525 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 28 Jul 2023 16:16:36 -0700 Subject: [PATCH 158/851] build with gcc-10 for better system compat --- .github/workflows/build.yml | 11 ++++++++--- .github/workflows/steam.yml | 9 +++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4caddc40a..82837ec32 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -132,6 +132,8 @@ jobs: sudo apt-get update sudo apt-get install \ ccache \ + gcc-10 \ + g++-10 \ libgl-dev \ libxml-libxslt-perl \ ninja-build @@ -145,15 +147,18 @@ jobs: uses: actions/cache@v3 with: path: ~/.ccache - key: ccache-ubuntu-22.04-gcc-11-${{ github.ref_name }}-${{ github.sha }} + key: ccache-ubuntu-22.04-gcc-10-${{ github.ref_name }}-${{ github.sha }} restore-keys: | - ccache-ubuntu-22.04-gcc-11-${{ github.ref_name }} - ccache-ubuntu-22.04-gcc-11 + ccache-ubuntu-22.04-gcc-10-${{ github.ref_name }} + ccache-ubuntu-22.04-gcc-10 - name: Set up environment id: env_setup run: | echo "CCACHE_DIR=${HOME}/.ccache" >> $GITHUB_ENV - name: Configure DFHack + env: + CC: gcc-10 + CXX: g++-10 run: | cmake \ -S . \ diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index c1118dddc..973f464bb 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -32,6 +32,8 @@ jobs: sudo apt-get update sudo apt-get install \ ccache \ + gcc-10 \ + g++-10 \ libgl-dev \ libxml-libxslt-perl \ ninja-build @@ -53,9 +55,9 @@ jobs: uses: actions/cache@v3 with: path: ~/.ccache - key: ccache-ubuntu-22.04-gcc-11-${{ github.sha }} + key: ccache-ubuntu-22.04-gcc-10-${{ github.sha }} restore-keys: | - ccache-ubuntu-22.04-gcc-11 + ccache-ubuntu-22.04-gcc-10 - name: Fetch win64 ccache uses: actions/cache@v3 with: @@ -68,6 +70,9 @@ jobs: run: | echo "CCACHE_DIR=${HOME}/.ccache" >> $GITHUB_ENV - name: Configure DFHack + env: + CC: gcc-10 + CXX: g++-10 run: | cmake \ -S . \ From c67e0da25056d0157c4af8e5f0e0465155611359 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 28 Jul 2023 16:58:23 -0700 Subject: [PATCH 159/851] take advantage of cache scoping rules to simplify names --- .github/workflows/build.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 82837ec32..d4e5144df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,9 +53,8 @@ jobs: uses: actions/cache@v3 with: path: ~/.ccache - key: ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }}-${{ github.ref_name }}-${{ github.sha }} + key: ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }}-${{ github.sha }} restore-keys: | - ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }}-${{ github.ref_name }} ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }} # - name: Fetch DF cache # uses: actions/cache@v3 @@ -147,9 +146,8 @@ jobs: uses: actions/cache@v3 with: path: ~/.ccache - key: ccache-ubuntu-22.04-gcc-10-${{ github.ref_name }}-${{ github.sha }} + key: ccache-ubuntu-22.04-gcc-10-${{ github.sha }} restore-keys: | - ccache-ubuntu-22.04-gcc-10-${{ github.ref_name }} ccache-ubuntu-22.04-gcc-10 - name: Set up environment id: env_setup @@ -202,9 +200,8 @@ jobs: uses: actions/cache@v3 with: path: build/win64-cross/ccache - key: ccache-win64-cross-msvc-${{ github.ref_name }}-${{ github.sha }} + key: ccache-win64-cross-msvc-${{ github.sha }} restore-keys: | - ccache-win64-cross-msvc-${{ github.ref_name }} ccache-win64-cross-msvc - name: Cross-compile win64 env: From a27f42d67d9ce4dd5df97f4a558af35b2445f3e4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 28 Jul 2023 19:12:58 -0700 Subject: [PATCH 160/851] split common files into their own depot --- .github/workflows/steam.yml | 33 ++++++++++++++++++++++++++------- CMakeLists.txt | 27 +++++++++++++++++---------- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 973f464bb..11f9d300d 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -69,7 +69,21 @@ jobs: id: env_setup run: | echo "CCACHE_DIR=${HOME}/.ccache" >> $GITHUB_ENV - - name: Configure DFHack + - name: Configure DFHack (common files) + run: | + cmake \ + -S . \ + -B build \ + -G Ninja \ + -DDFHACK_BUILD_ARCH=64 \ + -DBUILD_LIBRARY:BOOL=0 \ + -DBUILD_BINARIES:BOOL=0 \ + -DBUILD_DOCS:BOOL=1 \ + -DCMAKE_INSTALL_PREFIX=build/common-output + - name: Build DFHack (common files) + run: | + ninja -C build install + - name: Configure DFHack (linux build) env: CC: gcc-10 CXX: g++-10 @@ -83,9 +97,13 @@ jobs: -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DBUILD_DFLAUNCH:BOOL=1 \ - -DBUILD_DOCS:BOOL=1 \ - -DCMAKE_INSTALL_PREFIX=build/output - - name: Build DFHack + -DBUILD_LIBRARY:BOOL=1 \ + -DBUILD_BINARIES:BOOL=1 \ + -DBUILD_DOCS:BOOL=0 \ + -DINSTALL_SCRIPTS:BOOL=0 \ + -DINSTALL_DATA_FILES:BOOL=0 \ + -DCMAKE_INSTALL_PREFIX=build/linux-output + - name: Build DFHack (linux build) run: | ninja -C build install ccache --max-size 50M @@ -93,7 +111,7 @@ jobs: ccache --show-stats - name: Cross-compile win64 artifacts env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1' + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1 -DBUILD_DOCS:BOOL=0 -DINSTALL_SCRIPTS:BOOL=0 -DINSTALL_DATA_FILES:BOOL=0' steam_username: ${{ secrets.STEAM_SDK_USERNAME }} steam_password: ${{ secrets.STEAM_SDK_PASSWORD }} run: | @@ -115,6 +133,7 @@ jobs: appId: 2346660 buildDescription: ${{ github.event.inputs.version }} rootPath: build - depot1Path: win64-cross/output - depot2Path: output + depot1Path: common-output + depot2Path: win64-cross/output + depot3Path: linux-output releaseBranch: ${{ github.event.inputs.release_channel }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fa7acbe1..3e1685d4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,17 +210,16 @@ set(DFHACK_BINARY_DESTINATION .) set(DFHACK_PLUGIN_DESTINATION ${DFHACK_DATA_DESTINATION}/plugins) # dfhack lua files go here: set(DFHACK_LUA_DESTINATION ${DFHACK_DATA_DESTINATION}/lua) -# the windows .lib file goes here: -set(DFHACK_DEVLIB_DESTINATION ${DFHACK_DATA_DESTINATION}) # user documentation goes here: set(DFHACK_USERDOC_DESTINATION ${DFHACK_DATA_DESTINATION}) -# developer documentation goes here: -set(DFHACK_DEVDOC_DESTINATION ${DFHACK_DATA_DESTINATION}) # some options for the user/developer to play with option(BUILD_LIBRARY "Build the DFHack library." ON) option(BUILD_PLUGINS "Build the DFHack plugins." ON) +option(BUILD_BINARIES "Build the DFHack binary tools." ON) +option(INSTALL_SCRIPTS "Install DFHack scripts." ON) +option(INSTALL_DATA_FILES "Install DFHack common data files." ON) set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) if(UNIX) @@ -387,11 +386,14 @@ include_directories(depends/lodepng) include_directories(depends/tthread) include_directories(depends/clsocket/src) include_directories(depends/xlsxio/include) -add_subdirectory(depends) + +if(BUILD_LIBRARY) + add_subdirectory(depends) +endif() # Testing with CTest macro(dfhack_test name files) -if(UNIX AND NOT APPLE) # remove this once our MSVC build env has been updated +if(BUILD_LIBRARY AND UNIX AND NOT APPLE) # remove this once our MSVC build env has been updated add_executable(${name} ${files}) target_include_directories(${name} PUBLIC depends/googletest/googletest/include) target_link_libraries(${name} dfhack gtest) @@ -416,12 +418,17 @@ file(WRITE "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" ${DFHACK_SETARCH}) install(FILES "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" DESTINATION "${DFHACK_DATA_DESTINATION}") # build the plugins -if(BUILD_PLUGINS) +if(BUILD_LIBRARY AND BUILD_PLUGINS) add_subdirectory(plugins) endif() -add_subdirectory(data) -add_subdirectory(scripts) +if(INSTALL_DATA_FILES) + add_subdirectory(data) +endif() + +if(INSTALL_SCRIPTS) + add_subdirectory(scripts) +endif() if(BUILD_DOCS) find_package(Python3) @@ -582,7 +589,7 @@ endif() set(DFHACK_BUILD_ARCH_PREV "${DFHACK_BUILD_ARCH}" CACHE STRING "Previous build architecture" FORCE) option(BUILD_SIZECHECK "Build the sizecheck library, for research" OFF) -if(BUILD_SIZECHECK) +if(BUILD_LIBRARY AND BUILD_SIZECHECK) add_subdirectory(depends/sizecheck) add_dependencies(dfhack sizecheck) endif() From ec887aab2f79afd847134f53d446d56175e333b6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 28 Jul 2023 19:33:31 -0700 Subject: [PATCH 161/851] build stonesense in the linux package --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d4e5144df..05c9c2ca4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -166,6 +166,7 @@ jobs: -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DBUILD_DOCS:BOOL=1 \ + -DBUILD_STONESENSE:BOOL=1 \ -DCMAKE_INSTALL_PREFIX=build/output - name: Build DFHack run: | From c11740d43952ea8c8924e5722ff2840a4269d8fd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 28 Jul 2023 19:48:38 -0700 Subject: [PATCH 162/851] update dfhack launcher script --- .github/workflows/steam.yml | 1 - package/linux/dfhack | 53 +++++++++---------------------------- 2 files changed, 12 insertions(+), 42 deletions(-) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 11f9d300d..5cdcebfb1 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -96,7 +96,6 @@ jobs: -DBUILD_STONESENSE:BOOL=1 \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DBUILD_DFLAUNCH:BOOL=1 \ -DBUILD_LIBRARY:BOOL=1 \ -DBUILD_BINARIES:BOOL=1 \ -DBUILD_DOCS:BOOL=0 \ diff --git a/package/linux/dfhack b/package/linux/dfhack index 6b542f405..2e371c8e5 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -1,26 +1,20 @@ #!/bin/sh -# NOTE: This is dfhack's modification of the normal invocation script, -# changed to properly set LD_PRELOAD so as to run DFHACK. -# # You can run DF under gdb by passing -g or --gdb as the first argument. # # If the file ".dfhackrc" exists in the DF directory or your home directory # it will be sourced by this script, to let you set environmental variables. # If it exists in both places it will first source the one in your home -# directory, then the on in the game directory. +# directory, then the one in the game directory. # # Shell variables .dfhackrc can set to affect this script: # DF_GDB_OPTS: Options to pass to gdb, if it's being run # DF_VALGRIND_OPTS: Options to pass to valgrind, if it's being run # DF_HELGRIND_OPTS: Options to pass to helgrind, if it's being run # DF_POST_CMD: Shell command to be run at very end of script -# DFHACK_NO_RENAME_LIBSTDCXX: Non-empty to prevent automatically renaming libstdc++ DF_DIR=$(dirname "$0") cd "${DF_DIR}" -export SDL_DISABLE_LOCK_KEYS=1 # Work around for bug in Debian/Ubuntu SDL patch. -#export SDL_VIDEO_CENTERED=1 # Centre the screen. Messes up resizing. # User config files RC=".dfhackrc" @@ -32,22 +26,6 @@ if [ -r "./$RC" ]; then . "./$RC" fi -# Disable bundled libstdc++ -libcxx_orig="libs/libstdc++.so.6" -libcxx_backup="libs/libstdc++.so.6.backup" -if [ -z "${DFHACK_NO_RENAME_LIBSTDCXX:-}" ] && [ -e "$libcxx_orig" ] && [ ! -e "$libcxx_backup" ]; then - mv "$libcxx_orig" "$libcxx_backup" - cat < /dev/null; then fi PRELOAD_LIB="${PRELOAD_LIB:+$PRELOAD_LIB:}${LIBSAN}${LIB}" -setarch_arch=$(cat hack/dfhack_setarch.txt || printf i386) +setarch_arch=$(cat hack/dfhack_setarch.txt || printf x86_64) if ! setarch "$setarch_arch" -R true 2>/dev/null; then echo "warn: architecture '$setarch_arch' not supported by setarch" >&2 if [ "$setarch_arch" = "i386" ]; then @@ -90,7 +61,7 @@ case "$1" in -g | --gdb) shift echo "set exec-wrapper env LD_LIBRARY_PATH='$LD_LIBRARY_PATH' LD_PRELOAD='$PRELOAD_LIB' MALLOC_PERTURB_=45" > gdbcmd.tmp - gdb $DF_GDB_OPTS -x gdbcmd.tmp --args ./libs/Dwarf_Fortress "$@" + gdb $DF_GDB_OPTS -x gdbcmd.tmp --args ./dwarfort "$@" rm gdbcmd.tmp ret=$? ;; @@ -107,11 +78,11 @@ case "$1" in echo "set environment MALLOC_PERTURB_ 45" >> gdbcmd.tmp echo "set startup-with-shell off" >> gdbcmd.tmp echo "target extended-remote localhost:12345" >> gdbcmd.tmp - echo "set remote exec-file ./libs/Dwarf_Fortress" >> gdbcmd.tmp + echo "set remote exec-file ./dwarfort" >> gdbcmd.tmp # For some reason gdb ignores sysroot setting if it is from same file as # target extended-remote command echo "set sysroot /" > gdbcmd_sysroot.tmp - gdb $DF_GDB_OPTS -x gdbcmd.tmp -x gdbcmd_sysroot.tmp --args ./libs/Dwarf_Fortress "$@" + gdb $DF_GDB_OPTS -x gdbcmd.tmp -x gdbcmd_sysroot.tmp --args ./dwarfort "$@" rm gdbcmd.tmp gdbcmd_sysroot.tmp ret=$? ;; @@ -124,35 +95,35 @@ case "$1" in ;; -h | --helgrind) shift - LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_HELGRIND_OPTS --tool=helgrind --log-file=helgrind.log ./libs/Dwarf_Fortress "$@" + LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_HELGRIND_OPTS --tool=helgrind --log-file=helgrind.log ./dwarfort "$@" ret=$? ;; -v | --valgrind) shift - LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_VALGRIND_OPTS --log-file=valgrind.log ./libs/Dwarf_Fortress "$@" + LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_VALGRIND_OPTS --log-file=valgrind.log ./dwarfort "$@" ret=$? ;; -c | --callgrind) shift - LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_CALLGRIND_OPTS --tool=callgrind --separate-threads=yes --dump-instr=yes --instr-atstart=no --log-file=callgrind.log ./libs/Dwarf_Fortress "$@" + LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_CALLGRIND_OPTS --tool=callgrind --separate-threads=yes --dump-instr=yes --instr-atstart=no --log-file=callgrind.log ./dwarfort "$@" ret=$? ;; --strace) shift - strace -f setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@" 2> strace.log + strace -f setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./dwarfort "$@" 2> strace.log ret=$? ;; -x | --exec) - exec setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@" + exec setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./dwarfort "$@" # script does not resume ;; --sc | --sizecheck) PRELOAD_LIB="${PRELOAD_LIB:+$PRELOAD_LIB:}./hack/libsizecheck.so" - MALLOC_PERTURB_=45 setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@" + MALLOC_PERTURB_=45 setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./dwarfort "$@" ret=$? ;; *) - setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./libs/Dwarf_Fortress "$@" + setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./dwarfort "$@" ret=$? ;; esac From aaf511b5ea8777a2247ec6da4a26eb21c463522d Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 29 Jul 2023 07:12:04 +0000 Subject: [PATCH 163/851] Auto-update submodules plugins/stonesense: master --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index 9831bee5f..808ac3b77 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 9831bee5f9aa759a4fd679351eb89c542ef6a2dd +Subproject commit 808ac3b775ecafca512d583daead9bd1fc567855 From ac633da0504909e97efa8245389a112a2e1a015b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 28 Jul 2023 23:58:54 -0700 Subject: [PATCH 164/851] de-duplicate stonesense resources --- .github/workflows/steam.yml | 28 ++++++++++------ CMakeLists.txt | 5 +-- plugins/Plugins.cmake | 66 +++++++++++++++++++------------------ 3 files changed, 53 insertions(+), 46 deletions(-) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 5cdcebfb1..9fdac4c24 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -70,16 +70,24 @@ jobs: run: | echo "CCACHE_DIR=${HOME}/.ccache" >> $GITHUB_ENV - name: Configure DFHack (common files) + env: + CC: gcc-10 + CXX: g++-10 run: | cmake \ -S . \ -B build \ -G Ninja \ + -DCMAKE_INSTALL_PREFIX=build/common-output \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DDFHACK_BUILD_ARCH=64 \ - -DBUILD_LIBRARY:BOOL=0 \ - -DBUILD_BINARIES:BOOL=0 \ -DBUILD_DOCS:BOOL=1 \ - -DCMAKE_INSTALL_PREFIX=build/common-output + -DBUILD_LIBRARY:BOOL=0 \ + -DBUILD_PLUGINS:BOOL=0 \ + -DBUILD_STONESENSE:BOOL=1 \ + -DINSTALL_DATA_FILES:BOOL=1 \ + -DINSTALL_SCRIPTS:BOOL=1 - name: Build DFHack (common files) run: | ninja -C build install @@ -92,16 +100,16 @@ jobs: -S . \ -B build \ -G Ninja \ - -DDFHACK_BUILD_ARCH=64 \ - -DBUILD_STONESENSE:BOOL=1 \ + -DCMAKE_INSTALL_PREFIX=build/linux-output \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DBUILD_LIBRARY:BOOL=1 \ - -DBUILD_BINARIES:BOOL=1 \ + -DDFHACK_BUILD_ARCH=64 \ -DBUILD_DOCS:BOOL=0 \ - -DINSTALL_SCRIPTS:BOOL=0 \ + -DBUILD_LIBRARY:BOOL=1 \ + -DBUILD_PLUGINS:BOOL=1 \ + -DBUILD_STONESENSE:BOOL=1 \ -DINSTALL_DATA_FILES:BOOL=0 \ - -DCMAKE_INSTALL_PREFIX=build/linux-output + -DINSTALL_SCRIPTS:BOOL=0 - name: Build DFHack (linux build) run: | ninja -C build install @@ -110,7 +118,7 @@ jobs: ccache --show-stats - name: Cross-compile win64 artifacts env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1 -DBUILD_DOCS:BOOL=0 -DINSTALL_SCRIPTS:BOOL=0 -DINSTALL_DATA_FILES:BOOL=0' + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1 -DBUILD_DOCS:BOOL=0 -DINSTALL_DATA_FILES:BOOL=0 -DINSTALL_SCRIPTS:BOOL=0' steam_username: ${{ secrets.STEAM_SDK_USERNAME }} steam_password: ${{ secrets.STEAM_SDK_PASSWORD }} run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e1685d4f..5da7e4aa3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,7 +217,6 @@ set(DFHACK_USERDOC_DESTINATION ${DFHACK_DATA_DESTINATION}) # some options for the user/developer to play with option(BUILD_LIBRARY "Build the DFHack library." ON) option(BUILD_PLUGINS "Build the DFHack plugins." ON) -option(BUILD_BINARIES "Build the DFHack binary tools." ON) option(INSTALL_SCRIPTS "Install DFHack scripts." ON) option(INSTALL_DATA_FILES "Install DFHack common data files." ON) @@ -418,9 +417,7 @@ file(WRITE "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" ${DFHACK_SETARCH}) install(FILES "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" DESTINATION "${DFHACK_DATA_DESTINATION}") # build the plugins -if(BUILD_LIBRARY AND BUILD_PLUGINS) - add_subdirectory(plugins) -endif() +add_subdirectory(plugins) if(INSTALL_DATA_FILES) add_subdirectory(data) diff --git a/plugins/Plugins.cmake b/plugins/Plugins.cmake index a0cea765f..e058d2281 100644 --- a/plugins/Plugins.cmake +++ b/plugins/Plugins.cmake @@ -115,42 +115,44 @@ macro(dfhack_plugin) endif() endif() - add_library(${PLUGIN_NAME} MODULE ${PLUGIN_SOURCES}) - ide_folder(${PLUGIN_NAME} "Plugins") + if(BUILD_LIBRARY AND BUILD_PLUGINS) + 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}) + else() + target_link_libraries(${PLUGIN_NAME} dfhack dfhack-version ${PLUGIN_LINK_LIBRARIES}) + endif() - 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") + add_dependencies(${PLUGIN_NAME} dfhack-version) - if(NUM_PROTO) - add_dependencies(${PLUGIN_NAME} generate_proto_${PLUGIN_NAME}) - target_link_libraries(${PLUGIN_NAME} dfhack protobuf-lite dfhack-version ${PLUGIN_LINK_LIBRARIES}) - else() - target_link_libraries(${PLUGIN_NAME} dfhack dfhack-version ${PLUGIN_LINK_LIBRARIES}) - endif() + # Make sure the source is generated before the executable builds. + add_dependencies(${PLUGIN_NAME} generate_proto) - add_dependencies(${PLUGIN_NAME} dfhack-version) + if(UNIX) + set(PLUGIN_COMPILE_FLAGS "${PLUGIN_COMPILE_FLAGS} ${PLUGIN_COMPILE_FLAGS_GCC}") + else() + set(PLUGIN_COMPILE_FLAGS "${PLUGIN_COMPILE_FLAGS} ${PLUGIN_COMPILE_FLAGS_MSVC}") + endif() + set_target_properties(${PLUGIN_NAME} PROPERTIES COMPILE_FLAGS "${PLUGIN_COMPILE_FLAGS}") - # Make sure the source is generated before the executable builds. - add_dependencies(${PLUGIN_NAME} generate_proto) + if(APPLE) + set_target_properties(${PLUGIN_NAME} PROPERTIES SUFFIX .plug.dylib PREFIX "") + elseif(UNIX) + set_target_properties(${PLUGIN_NAME} PROPERTIES SUFFIX .plug.so PREFIX "") + else() + set_target_properties(${PLUGIN_NAME} PROPERTIES SUFFIX .plug.dll) + endif() - if(UNIX) - set(PLUGIN_COMPILE_FLAGS "${PLUGIN_COMPILE_FLAGS} ${PLUGIN_COMPILE_FLAGS_GCC}") - else() - set(PLUGIN_COMPILE_FLAGS "${PLUGIN_COMPILE_FLAGS} ${PLUGIN_COMPILE_FLAGS_MSVC}") + install(TARGETS ${PLUGIN_NAME} + LIBRARY DESTINATION ${DFHACK_PLUGIN_DESTINATION} + RUNTIME DESTINATION ${DFHACK_PLUGIN_DESTINATION}) endif() - set_target_properties(${PLUGIN_NAME} PROPERTIES COMPILE_FLAGS "${PLUGIN_COMPILE_FLAGS}") - - if(APPLE) - set_target_properties(${PLUGIN_NAME} PROPERTIES SUFFIX .plug.dylib PREFIX "") - elseif(UNIX) - set_target_properties(${PLUGIN_NAME} PROPERTIES SUFFIX .plug.so PREFIX "") - else() - set_target_properties(${PLUGIN_NAME} PROPERTIES SUFFIX .plug.dll) - endif() - - install(TARGETS ${PLUGIN_NAME} - LIBRARY DESTINATION ${DFHACK_PLUGIN_DESTINATION} - RUNTIME DESTINATION ${DFHACK_PLUGIN_DESTINATION}) endmacro() From 6a50ae42ce2f632a9f319a2cf2762ccd0d65442f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 29 Jul 2023 00:34:56 -0700 Subject: [PATCH 165/851] more deduplication of installed files --- CMakeLists.txt | 14 +++++++------- depends/CMakeLists.txt | 2 -- library/CMakeLists.txt | 28 +++++++++++++++++----------- plugins/CMakeLists.txt | 20 +++++++++++--------- plugins/stonesense | 2 +- 5 files changed, 36 insertions(+), 30 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5da7e4aa3..2451b768a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -218,7 +218,7 @@ set(DFHACK_USERDOC_DESTINATION ${DFHACK_DATA_DESTINATION}) option(BUILD_LIBRARY "Build the DFHack library." ON) option(BUILD_PLUGINS "Build the DFHack plugins." ON) option(INSTALL_SCRIPTS "Install DFHack scripts." ON) -option(INSTALL_DATA_FILES "Install DFHack common data files." ON) +option(INSTALL_DATA_FILES "Install DFHack platform independent files." ON) set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) if(UNIX) @@ -407,20 +407,20 @@ if(NOT GIT_FOUND) endif() # build the lib itself +add_subdirectory(library) if(BUILD_LIBRARY) - add_subdirectory(library) - install(FILES LICENSE.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) - install(FILES docs/changelog-placeholder.txt DESTINATION ${DFHACK_USERDOC_DESTINATION} RENAME changelog.txt) + file(WRITE ${CMAKE_BINARY_DIR}/dfhack_setarch.txt ${DFHACK_SETARCH}) + install(FILES ${CMAKE_BINARY_DIR}/dfhack_setarch.txt DESTINATION ${DFHACK_DATA_DESTINATION}) endif() -file(WRITE "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" ${DFHACK_SETARCH}) -install(FILES "${CMAKE_BINARY_DIR}/dfhack_setarch.txt" DESTINATION "${DFHACK_DATA_DESTINATION}") - # build the plugins add_subdirectory(plugins) if(INSTALL_DATA_FILES) add_subdirectory(data) + install(FILES LICENSE.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) + install(FILES docs/changelog-placeholder.txt DESTINATION ${DFHACK_USERDOC_DESTINATION} RENAME changelog.txt) + install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/depends/luacov/src/luacov/ DESTINATION ${DFHACK_DATA_DESTINATION}/lua/luacov) endif() if(INSTALL_SCRIPTS) diff --git a/depends/CMakeLists.txt b/depends/CMakeLists.txt index 0756519ef..d3cfbb415 100644 --- a/depends/CMakeLists.txt +++ b/depends/CMakeLists.txt @@ -39,8 +39,6 @@ option(CLSOCKET_DEP_ONLY "Build for use inside other CMake projects as dependenc add_subdirectory(clsocket) ide_folder(clsocket "Depends") -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/luacov/src/luacov/ DESTINATION ${DFHACK_DATA_DESTINATION}/lua/luacov) - # set the default values of libexpat options - the descriptions are left empty # because later option() calls *do* override those set(EXPAT_BUILD_EXAMPLES OFF CACHE BOOL "") diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 5d2698bb0..8b1b7f65d 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -4,6 +4,8 @@ cmake_minimum_required(VERSION 3.21) # prevent CMake warnings about INTERFACE_LINK_LIBRARIES vs LINK_INTERFACE_LIBRARIES cmake_policy(SET CMP0022 NEW) +if(BUILD_LIBRARY) + # build options if(UNIX) option(CONSOLE_NO_CATCH "Make the console not catch 'CTRL+C' events for easier debugging." OFF) @@ -438,20 +440,24 @@ install(TARGETS dfhack LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION} RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION}) -# install the offset file -install(FILES xml/symbols.xml - DESTINATION ${DFHACK_DATA_DESTINATION}) - install(TARGETS dfhack-run dfhack-client binpatch LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION} RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION}) -install(DIRECTORY lua/ - DESTINATION ${DFHACK_LUA_DESTINATION} - FILES_MATCHING PATTERN "*.lua") +add_subdirectory(xml) -install(DIRECTORY ${dfhack_SOURCE_DIR}/patches - DESTINATION ${DFHACK_DATA_DESTINATION} - FILES_MATCHING PATTERN "*.dif") +endif(BUILD_LIBRARY) -add_subdirectory(xml) +# install the offset file +if(INSTALL_DATA_FILES) + install(FILES xml/symbols.xml + DESTINATION ${DFHACK_DATA_DESTINATION}) + + install(DIRECTORY lua/ + DESTINATION ${DFHACK_LUA_DESTINATION} + FILES_MATCHING PATTERN "*.lua") + + install(DIRECTORY ${dfhack_SOURCE_DIR}/patches + DESTINATION ${DFHACK_DATA_DESTINATION} + FILES_MATCHING PATTERN "*.dif") +endif() diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 345263f1b..e393756a7 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -24,15 +24,17 @@ if(BUILD_DEV_PLUGINS) #add_subdirectory(devel) endif() -install(DIRECTORY lua/ - DESTINATION ${DFHACK_LUA_DESTINATION}/plugins - FILES_MATCHING PATTERN "*.lua") -install(DIRECTORY raw/ - DESTINATION ${DFHACK_DATA_DESTINATION}/raw - FILES_MATCHING PATTERN "*.txt") -install(DIRECTORY raw/ - DESTINATION ${DFHACK_DATA_DESTINATION}/raw - FILES_MATCHING PATTERN "*.diff") +if(INSTALL_DATA_FILES) + install(DIRECTORY lua/ + DESTINATION ${DFHACK_LUA_DESTINATION}/plugins + FILES_MATCHING PATTERN "*.lua") + install(DIRECTORY raw/ + DESTINATION ${DFHACK_DATA_DESTINATION}/raw + FILES_MATCHING PATTERN "*.txt") + install(DIRECTORY raw/ + DESTINATION ${DFHACK_DATA_DESTINATION}/raw + FILES_MATCHING PATTERN "*.diff") +endif() # Protobuf file(GLOB PROJECT_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto) diff --git a/plugins/stonesense b/plugins/stonesense index 808ac3b77..f9fce95fd 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 808ac3b775ecafca512d583daead9bd1fc567855 +Subproject commit f9fce95fd74bf1d5050e891dbd3e0bda2e8a7ce9 From 88a46a1b5b2f2b65857a3c2d299415eb8f3b9a15 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 29 Jul 2023 00:48:17 -0700 Subject: [PATCH 166/851] build Release profile for Linux --- .github/workflows/build.yml | 17 +++++++++-------- .github/workflows/steam.yml | 2 ++ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 05c9c2ca4..354dd13f7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -73,16 +73,16 @@ jobs: -S . \ -B build-ci \ -G Ninja \ + -DCMAKE_INSTALL_PREFIX="$DF_FOLDER" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_C_COMPILER_LAUNCHER=ccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DDFHACK_BUILD_ARCH=64 \ - -DBUILD_TESTS:BOOL=ON \ -DBUILD_DEV_PLUGINS:BOOL=${{ matrix.plugins == 'all' }} \ -DBUILD_SIZECHECK:BOOL=${{ matrix.plugins == 'all' }} \ -DBUILD_SKELETON:BOOL=${{ matrix.plugins == 'all' }} \ -DBUILD_STONESENSE:BOOL=${{ matrix.plugins == 'all' }} \ - -DBUILD_SUPPORTED:BOOL=1 \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DCMAKE_INSTALL_PREFIX="$DF_FOLDER" + -DBUILD_TESTS:BOOL=ON - name: Build DFHack run: | ninja -C build-ci install @@ -162,12 +162,13 @@ jobs: -S . \ -B build \ -G Ninja \ - -DDFHACK_BUILD_ARCH=64 \ + -DCMAKE_INSTALL_PREFIX=build/output \ + -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ + -DDFHACK_BUILD_ARCH=64 \ -DBUILD_DOCS:BOOL=1 \ - -DBUILD_STONESENSE:BOOL=1 \ - -DCMAKE_INSTALL_PREFIX=build/output + -DBUILD_STONESENSE:BOOL=1 - name: Build DFHack run: | ninja -C build install diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 9fdac4c24..d57fa00ac 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -79,6 +79,7 @@ jobs: -B build \ -G Ninja \ -DCMAKE_INSTALL_PREFIX=build/common-output \ + -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DDFHACK_BUILD_ARCH=64 \ @@ -101,6 +102,7 @@ jobs: -B build \ -G Ninja \ -DCMAKE_INSTALL_PREFIX=build/linux-output \ + -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DDFHACK_BUILD_ARCH=64 \ From f65112f871bf2695f7b4db59db86de3156191d28 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 29 Jul 2023 01:03:29 -0700 Subject: [PATCH 167/851] give test actions their own cache namespace since they build a different subset from the package actions --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 354dd13f7..cfa238862 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -53,8 +53,9 @@ jobs: uses: actions/cache@v3 with: path: ~/.ccache - key: ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }}-${{ github.sha }} + key: ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }}-test-${{ github.sha }} restore-keys: | + ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }}-test ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }} # - name: Fetch DF cache # uses: actions/cache@v3 From c797e5b2d21e7090f031b8998101f3d1614d1d8f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 29 Jul 2023 14:03:50 -0700 Subject: [PATCH 168/851] poke at a native windows build and see what happens --- .github/workflows/build.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cfa238862..c182296c5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -186,6 +186,31 @@ jobs: name: dfhack-linux64-build-${{ steps.artifactname.outputs.name }} path: build/output/* + package-win64: + name: Win64 package (native) + runs-on: windows-latest + steps: + - name: Clone DFHack + uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: 0 + - name: Configure DFHack + run: | + cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image + - name: Build DFHack + run: | + cmake --build build --config Release --target install + - name: Format artifact name + id: artifactname + run: | + echo name=$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT + - name: Upload artifact + uses: actions/upload-artifact@v3 + with: + name: dfhack-win64-build-${{ steps.artifactname.outputs.name }} + path: build/image/* + build-cross-win64: name: Win64 package runs-on: ubuntu-22.04 From 37357da64b203d68922a974be9a4a69f1793ca24 Mon Sep 17 00:00:00 2001 From: Myk Date: Sun, 30 Jul 2023 00:08:58 -0700 Subject: [PATCH 169/851] add clcache --- .github/workflows/build.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c182296c5..146666955 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -190,17 +190,27 @@ jobs: name: Win64 package (native) runs-on: windows-latest steps: + - name: Fetch cache + uses: actions/cache@v3 + with: + path: "%HOME%/clcache" + key: clcache-win64-${{ github.sha }} + restore-keys: | + clcache-win64 - name: Clone DFHack uses: actions/checkout@v3 with: submodules: true fetch-depth: 0 + - name: Install dependencies + run: pip install clcache + - run: pip install 'sphinx<4.4.0' - name: Configure DFHack run: | - cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image + cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image -DCMAKE_C_COMPILER_LAUNCHER=clcache -DCMAKE_CXX_COMPILER_LAUNCHER=clcache -DBUILD_DOCS:BOOL=1 -DBUILD_STONESENSE:BOOL=1 - name: Build DFHack run: | - cmake --build build --config Release --target install + cmake --build build -j 2 --config Release --target install - name: Format artifact name id: artifactname run: | From 1d356bf35123050c8ad8c382b2cecd085965aece Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 30 Jul 2023 16:45:01 -0700 Subject: [PATCH 170/851] fix artifact name --- .github/workflows/build.yml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 146666955..8d565db94 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -202,23 +202,18 @@ jobs: with: submodules: true fetch-depth: 0 - - name: Install dependencies - run: pip install clcache + - run: pip install clcache - run: pip install 'sphinx<4.4.0' - name: Configure DFHack - run: | - cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image -DCMAKE_C_COMPILER_LAUNCHER=clcache -DCMAKE_CXX_COMPILER_LAUNCHER=clcache -DBUILD_DOCS:BOOL=1 -DBUILD_STONESENSE:BOOL=1 + run: cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image -DCMAKE_C_COMPILER_LAUNCHER=clcache -DCMAKE_CXX_COMPILER_LAUNCHER=clcache -DBUILD_DOCS:BOOL=1 -DBUILD_STONESENSE:BOOL=1 - name: Build DFHack - run: | - cmake --build build -j 2 --config Release --target install - - name: Format artifact name - id: artifactname - run: | - echo name=$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT + run: cmake --build build -j 2 --config Release --target install + - uses: benjlevesque/short-sha@v2.2 + id: short-sha - name: Upload artifact uses: actions/upload-artifact@v3 with: - name: dfhack-win64-build-${{ steps.artifactname.outputs.name }} + name: dfhack-win64-build-${{ steps.short-sha.outputs.sha }} path: build/image/* build-cross-win64: From 7514dd2cba0b4303ade9486eb5cbdf6a24c93d6b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 30 Jul 2023 16:58:27 -0700 Subject: [PATCH 171/851] name stage --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8d565db94..7875466b9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -208,7 +208,8 @@ jobs: run: cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image -DCMAKE_C_COMPILER_LAUNCHER=clcache -DCMAKE_CXX_COMPILER_LAUNCHER=clcache -DBUILD_DOCS:BOOL=1 -DBUILD_STONESENSE:BOOL=1 - name: Build DFHack run: cmake --build build -j 2 --config Release --target install - - uses: benjlevesque/short-sha@v2.2 + - name: Format artifact name + uses: benjlevesque/short-sha@v2.2 id: short-sha - name: Upload artifact uses: actions/upload-artifact@v3 From 1faf156bfcaab233d1c16c6607e592bebd50e853 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 30 Jul 2023 19:36:12 -0700 Subject: [PATCH 172/851] first attempt at a reusable workflow --- .github/workflows/build-linux.yml | 110 ++++++++++++++ .github/workflows/build.yml | 236 ++++++++---------------------- 2 files changed, 167 insertions(+), 179 deletions(-) create mode 100644 .github/workflows/build-linux.yml diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml new file mode 100644 index 000000000..51c933ef1 --- /dev/null +++ b/.github/workflows/build-linux.yml @@ -0,0 +1,110 @@ +name: build-linux + +on: + workflow_call: + inputs: + artifact-name: + type: string + append-date-and-hash: + type: boolean + default: false + cache-id: + type: string + default: '' + platform-files: + type: boolean + default: true + common-files: + type: boolean + default: true + docs: + type: boolean + default: false + stonesense: + type: boolean + default: true + extras: + type: boolean + default: false + gcc-ver: + type: string + default: "11" + +jobs: + build-linux64: + name: Linux package + runs-on: ubuntu-22.04 + steps: + - name: Install basic build dependencies + run: | + sudo apt-get update + sudo apt-get install ninja-build + - name: Install binary build dependencies + if: inputs.platform-files + run: | + sudo apt-get install \ + ccache \ + gcc-${{ inputs.gcc-ver }} \ + g++-${{ inputs.gcc-ver }} \ + libxml-libxslt-perl + - name: Install stonesense dependencies + if: inputs.stonesense + run: sudo apt-get install libgl-dev + - name: Install doc dependencies + if: inputs.docs + run: pip install 'sphinx<4.4.0' + - name: Clone DFHack + uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} + - name: Fetch ccache + if: inputs.platform-files + uses: actions/cache@v3 + with: + path: ~/.ccache + key: linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }}-${{ github.sha }} + restore-keys: | + linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }} + linux-gcc-${{ inputs.gcc-ver }} + - name: Configure DFHack + env: + CC: gcc-${{ inputs.gcc-ver }} + CXX: g++-${{ inputs.gcc-ver }} + run: | + cmake \ + -S . \ + -B build \ + -G Ninja \ + -DCMAKE_INSTALL_PREFIX=build/image \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_LIBRARY:BOOL=${{ inputs.platform-files }} \ + -DBUILD_PLUGINS:BOOL=${{ inputs.platform-files }} \ + -DBUILD_STONESENSE:BOOL=${{ inputs.platform-files }} \ + -DBUILD_DEV_PLUGINS:BOOL=${{ inputs.extras }} \ + -DBUILD_SIZECHECK:BOOL=${{ inputs.extras }} \ + -DBUILD_SKELETON:BOOL=${{ inputs.extras }} \ + -DBUILD_DOCS:BOOL=${{ inputs.docs }} \ + -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} \ + -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} + - name: Build DFHack + run: ninja -C build install + - name: Run cpp tests + run: ninja -C build test + - name: Trim cache + if: inputs.platform-files + run: | + ccache --max-size 50M + ccache --cleanup + ccache --show-stats + - name: Format artifact name + if: ${{ inputs.append-date-and-hash }} + id: artifactname + run: | + echo name=${{ inputs.artifact-name }}-$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT + - name: Upload artifact + if: inputs.artifact-name + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.append-date-and-hash && inputs.artifact-name || steps.artifactname.outputs.name}} + path: build/image/* diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7875466b9..73038b649 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,98 +3,62 @@ name: Build on: [push, pull_request] jobs: - build-test: - runs-on: ${{ matrix.os }} + build-linux: + name: Build (Linux ${{ matrix.type }}, GCC ${{ matrix.gcc }}) + uses: ./.github/workflows/build-linux.yml + with: + artifact-name: ${{ matrix.artifact-name != 0 && matrix.artifact-name || format('{0}-gcc-{1}', matrix.type, matrix.gcc) }} + append-date-and-hash: ${{ matrix.append-date-and-hash }} + cache-id: ${{ matrix.type }} + stonesense: ${{ matrix.stonesense }} + docs: ${{ matrix.type == 'release' }} + extras: ${{ matrix.extras }} + gcc-ver: ${{ matrix.gcc }} + secrets: inherit + strategy: + fail-fast: false + matrix: + include: + - type: release + gcc: "10" + artifact-name: dfhack-linux64 + append-date-and-hash: true + stonesense: true + extras: false + - type: test + gcc: "10" + stonesense: false + extras: false + - type: test + gcc: "12" + stonesense: true + extras: true + + test-linux: name: Test (Linux, GCC ${{ matrix.gcc }}, ${{ matrix.plugins }} plugins) + needs: build-linux + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: - os: - - ubuntu-22.04 - gcc: - - 10 - plugins: - - default + gcc: [10] + plugins: [default] include: - - os: ubuntu-22.04 - gcc: 12 + - gcc: 12 plugins: all steps: - - name: Set up Python 3 - uses: actions/setup-python@v4 + - name: Download artifact + uses: actions/download-artifact@v3 with: - python-version: 3 - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install \ - ccache \ - libgl-dev \ - libxml-libxslt-perl \ - ninja-build - pip install 'sphinx<4.4.0' - - name: Install GCC - run: | - sudo apt-get install gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} - - name: Clone DFHack - uses: actions/checkout@v3 - with: - submodules: true - fetch-depth: 0 - - name: Set up environment - id: env_setup - run: | - DF_VERSION="$(sh ci/get-df-version.sh)" - echo "df_version=${DF_VERSION}" >> $GITHUB_OUTPUT - echo "DF_VERSION=${DF_VERSION}" >> $GITHUB_ENV - echo "DF_FOLDER=${HOME}/DF/${DF_VERSION}/df_linux" >> $GITHUB_ENV - echo "CCACHE_DIR=${HOME}/.ccache" >> $GITHUB_ENV - - name: Fetch ccache - uses: actions/cache@v3 - with: - path: ~/.ccache - key: ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }}-test-${{ github.sha }} - restore-keys: | - ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }}-test - ccache-${{ matrix.os }}-gcc-${{ matrix.gcc }} + name: test-${{ matrix.gcc }} # - name: Fetch DF cache # uses: actions/cache@v3 # with: # path: ~/DF - # key: df-${{ steps.env_setup.outputs.df_version }}-${{ hashFiles('ci/download-df.sh') }} + # key: df-${{ hashFiles('ci/download-df.sh') }} # - name: Download DF # run: | # sh ci/download-df.sh - - name: Configure DFHack - env: - CC: gcc-${{ matrix.gcc }} - CXX: g++-${{ matrix.gcc }} - run: | - cmake \ - -S . \ - -B build-ci \ - -G Ninja \ - -DCMAKE_INSTALL_PREFIX="$DF_FOLDER" \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DDFHACK_BUILD_ARCH=64 \ - -DBUILD_DEV_PLUGINS:BOOL=${{ matrix.plugins == 'all' }} \ - -DBUILD_SIZECHECK:BOOL=${{ matrix.plugins == 'all' }} \ - -DBUILD_SKELETON:BOOL=${{ matrix.plugins == 'all' }} \ - -DBUILD_STONESENSE:BOOL=${{ matrix.plugins == 'all' }} \ - -DBUILD_TESTS:BOOL=ON - - name: Build DFHack - run: | - ninja -C build-ci install - ccache --max-size 50M - ccache --cleanup - ccache --show-stats - - name: Run cpp unit tests - id: run_tests_cpp - run: | - ninja -C build-ci test - exit $? # - name: Run lua tests # id: run_tests_lua # run: | @@ -119,81 +83,16 @@ jobs: # run: | # rm -rf "$DF_FOLDER" - build-linux64: - name: Linux package - runs-on: ubuntu-22.04 - steps: - - name: Set up Python 3 - uses: actions/setup-python@v4 - with: - python-version: 3 - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install \ - ccache \ - gcc-10 \ - g++-10 \ - libgl-dev \ - libxml-libxslt-perl \ - ninja-build - pip install 'sphinx<4.4.0' - - name: Clone DFHack - uses: actions/checkout@v3 - with: - submodules: true - fetch-depth: 0 - - name: Fetch ccache - uses: actions/cache@v3 - with: - path: ~/.ccache - key: ccache-ubuntu-22.04-gcc-10-${{ github.sha }} - restore-keys: | - ccache-ubuntu-22.04-gcc-10 - - name: Set up environment - id: env_setup - run: | - echo "CCACHE_DIR=${HOME}/.ccache" >> $GITHUB_ENV - - name: Configure DFHack - env: - CC: gcc-10 - CXX: g++-10 - run: | - cmake \ - -S . \ - -B build \ - -G Ninja \ - -DCMAKE_INSTALL_PREFIX=build/output \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DDFHACK_BUILD_ARCH=64 \ - -DBUILD_DOCS:BOOL=1 \ - -DBUILD_STONESENSE:BOOL=1 - - name: Build DFHack - run: | - ninja -C build install - ccache --max-size 50M - ccache --cleanup - ccache --show-stats - - name: Format artifact name - id: artifactname - run: | - echo name=$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: dfhack-linux64-build-${{ steps.artifactname.outputs.name }} - path: build/output/* - package-win64: name: Win64 package (native) runs-on: windows-latest steps: + - run: pip install clcache + - run: pip install 'sphinx<4.4.0' - name: Fetch cache uses: actions/cache@v3 with: - path: "%HOME%/clcache" + path: ~/clcache key: clcache-win64-${{ github.sha }} restore-keys: | clcache-win64 @@ -202,8 +101,6 @@ jobs: with: submodules: true fetch-depth: 0 - - run: pip install clcache - - run: pip install 'sphinx<4.4.0' - name: Configure DFHack run: cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image -DCMAKE_C_COMPILER_LAUNCHER=clcache -DCMAKE_CXX_COMPILER_LAUNCHER=clcache -DBUILD_DOCS:BOOL=1 -DBUILD_STONESENSE:BOOL=1 - name: Build DFHack @@ -257,30 +154,16 @@ jobs: path: build/win64-cross/output/* docs: - runs-on: ubuntu-22.04 - steps: - - name: Set up Python 3 - uses: actions/setup-python@v4 - with: - python-version: 3 - - name: Install dependencies - run: | - pip install 'sphinx' - - name: Clone DFHack - uses: actions/checkout@v3 - with: - submodules: true - - name: Build docs - run: | - sphinx-build -W --keep-going -j auto --color . docs/html + uses: ./.github/workflows/build-linux.yml + with: + platform-files: false + common-files: false + docs: true + secrets: inherit lint: runs-on: ubuntu-22.04 steps: - - name: Set up Python 3 - uses: actions/setup-python@v4 - with: - python-version: 3 - name: Install Lua run: | sudo apt-get update @@ -289,22 +172,17 @@ jobs: uses: actions/checkout@v3 with: submodules: true - # don't need tags here - name: Check whitespace - run: | - python ci/lint.py --git-only --github-actions + run: python ci/lint.py --git-only --github-actions - name: Check Authors.rst - if: success() || failure() - run: | - python ci/authors-rst.py + if: always() + run: python ci/authors-rst.py - name: Check for missing documentation - if: success() || failure() - run: | - python ci/script-docs.py + if: always() + run: python ci/script-docs.py - name: Check Lua syntax - if: success() || failure() - run: | - python ci/script-syntax.py --ext=lua --cmd="luac5.3 -p" --github-actions + if: always() + run: python ci/script-syntax.py --ext=lua --cmd="luac5.3 -p" --github-actions check-pr: runs-on: ubuntu-latest From 0b2877a538db5572514a7f3fa4331098f32958dc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 30 Jul 2023 19:53:46 -0700 Subject: [PATCH 173/851] fixups --- .github/workflows/build-linux.yml | 11 +++++++---- .github/workflows/build.yml | 4 ++-- CMakeLists.txt | 30 ++++++++++++++++-------------- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 51c933ef1..034cfc989 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -22,7 +22,7 @@ on: default: false stonesense: type: boolean - default: true + default: false extras: type: boolean default: false @@ -32,7 +32,7 @@ on: jobs: build-linux64: - name: Linux package + name: Build linux64 runs-on: ubuntu-22.04 steps: - name: Install basic build dependencies @@ -78,6 +78,8 @@ jobs: -G Ninja \ -DCMAKE_INSTALL_PREFIX=build/image \ -DCMAKE_BUILD_TYPE=Release \ + ${{ inputs.platform-files && '-DCMAKE_C_COMPILER_LAUNCHER=ccache' || '' }} \ + ${{ inputs.platform-files && '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache' || '' }} \ -DBUILD_LIBRARY:BOOL=${{ inputs.platform-files }} \ -DBUILD_PLUGINS:BOOL=${{ inputs.platform-files }} \ -DBUILD_STONESENSE:BOOL=${{ inputs.platform-files }} \ @@ -90,6 +92,7 @@ jobs: - name: Build DFHack run: ninja -C build install - name: Run cpp tests + if: inputs.platform-files run: ninja -C build test - name: Trim cache if: inputs.platform-files @@ -98,7 +101,7 @@ jobs: ccache --cleanup ccache --show-stats - name: Format artifact name - if: ${{ inputs.append-date-and-hash }} + if: inputs.append-date-and-hash id: artifactname run: | echo name=${{ inputs.artifact-name }}-$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT @@ -106,5 +109,5 @@ jobs: if: inputs.artifact-name uses: actions/upload-artifact@v3 with: - name: ${{ inputs.append-date-and-hash && inputs.artifact-name || steps.artifactname.outputs.name}} + name: ${{ inputs.append-date-and-hash && steps.artifactname.outputs.name || inputs.artifact-name }} path: build/image/* diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 73038b649..a2567132a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,8 +7,8 @@ jobs: name: Build (Linux ${{ matrix.type }}, GCC ${{ matrix.gcc }}) uses: ./.github/workflows/build-linux.yml with: - artifact-name: ${{ matrix.artifact-name != 0 && matrix.artifact-name || format('{0}-gcc-{1}', matrix.type, matrix.gcc) }} - append-date-and-hash: ${{ matrix.append-date-and-hash }} + artifact-name: ${{ matrix.artifact-name || format('{0}-gcc-{1}', matrix.type, matrix.gcc) }} + append-date-and-hash: ${{ matrix.append-date-and-hash && true || false }} cache-id: ${{ matrix.type }} stonesense: ${{ matrix.stonesense }} docs: ${{ matrix.type == 'release' }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 2451b768a..b15cbf962 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -289,20 +289,22 @@ endif() find_package(ZLIB REQUIRED) include_directories(${ZLIB_INCLUDE_DIRS}) -# Download SDL release and extract into depends in the build dir -# all we need are the header files (including generated headers), so the same release package -# will work for all platforms -# (the above statement is untested for OSX) -set(SDL_VERSION 2.26.2) -set(SDL_ZIP_MD5 574daf26d48de753d0b1e19823c9d8bb) -set(SDL_ZIP_FILE SDL2-devel-${SDL_VERSION}-VC.zip) -set(SDL_ZIP_PATH ${dfhack_SOURCE_DIR}/depends/SDL2/) -download_file("https://github.com/libsdl-org/SDL/releases/download/release-${SDL_VERSION}/${SDL_ZIP_FILE}" - ${SDL_ZIP_PATH}${SDL_ZIP_FILE} - ${SDL_ZIP_MD5}) -file(ARCHIVE_EXTRACT INPUT ${SDL_ZIP_PATH}${SDL_ZIP_FILE} - DESTINATION ${SDL_ZIP_PATH}) -include_directories(${SDL_ZIP_PATH}/SDL2-${SDL_VERSION}/include) +if(BUILD_LIBRARY) + # Download SDL release and extract into depends in the build dir + # all we need are the header files (including generated headers), so the same release package + # will work for all platforms + # (the above statement is untested for OSX) + set(SDL_VERSION 2.26.2) + set(SDL_ZIP_MD5 574daf26d48de753d0b1e19823c9d8bb) + set(SDL_ZIP_FILE SDL2-devel-${SDL_VERSION}-VC.zip) + set(SDL_ZIP_PATH ${dfhack_SOURCE_DIR}/depends/SDL2/) + download_file("https://github.com/libsdl-org/SDL/releases/download/release-${SDL_VERSION}/${SDL_ZIP_FILE}" + ${SDL_ZIP_PATH}${SDL_ZIP_FILE} + ${SDL_ZIP_MD5}) + file(ARCHIVE_EXTRACT INPUT ${SDL_ZIP_PATH}${SDL_ZIP_FILE} + DESTINATION ${SDL_ZIP_PATH}) + include_directories(${SDL_ZIP_PATH}/SDL2-${SDL_VERSION}/include) +endif() if(APPLE) # libstdc++ (GCC 4.8.5 for OS X 10.6) From 872720740aaccebf01a8452d23cc606566341204 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 30 Jul 2023 20:47:59 -0700 Subject: [PATCH 174/851] attempt to get windows build reusable --- .github/workflows/build-linux.yml | 3 +- .github/workflows/build-windows.yml | 65 +++++++++++++++++++++++++++++ .github/workflows/build.yml | 2 +- 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/build-windows.yml diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 034cfc989..4e070e9f0 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -71,6 +71,7 @@ jobs: env: CC: gcc-${{ inputs.gcc-ver }} CXX: g++-${{ inputs.gcc-ver }} + CCACHE_DIR: ${{ env.HOME }}/.ccache run: | cmake \ -S . \ @@ -82,7 +83,7 @@ jobs: ${{ inputs.platform-files && '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache' || '' }} \ -DBUILD_LIBRARY:BOOL=${{ inputs.platform-files }} \ -DBUILD_PLUGINS:BOOL=${{ inputs.platform-files }} \ - -DBUILD_STONESENSE:BOOL=${{ inputs.platform-files }} \ + -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} \ -DBUILD_DEV_PLUGINS:BOOL=${{ inputs.extras }} \ -DBUILD_SIZECHECK:BOOL=${{ inputs.extras }} \ -DBUILD_SKELETON:BOOL=${{ inputs.extras }} \ diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml new file mode 100644 index 000000000..d6a5371b0 --- /dev/null +++ b/.github/workflows/build-windows.yml @@ -0,0 +1,65 @@ +name: build-windows + +on: + workflow_call: + inputs: + artifact-name: + type: string + append-date-and-hash: + type: boolean + default: false + cache-id: + type: string + default: '' + platform-files: + type: boolean + default: true + common-files: + type: boolean + default: true + +jobs: + build-win64: + name: Build win64 + runs-on: windows-latest + steps: + - run: pip install clcache + if: inputs.platform-files + - run: pip install 'sphinx<4.4.0' + if: inputs.common-files + - name: Clone DFHack + uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} + - name: Fetch clcache + if: inputs.platform-files + uses: actions/cache@v3 + with: + path: ${{ env.HOME }}/clcache + key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }} + restore-keys: | + win-msvc-${{ inputs.cache-id }} + win-msvc + - name: Configure DFHack + env: + CLCACHE_DIR: ${{ env.HOME }}/clcache + run: cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image ${{ inputs.platform-files && '-DCMAKE_C_COMPILER_LAUNCHER=clcache' || '' }} ${{ inputs.platform-files && '-DCMAKE_CXX_COMPILER_LAUNCHER=clcache' || '' }} -DBUILD_LIBRARY:BOOL=${{ inputs.platform-files }} -DBUILD_PLUGINS:BOOL=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.platform-files }} -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} + - name: Build DFHack + run: cmake --build build -j 2 --config Release --target install + - name: Trim cache + if: inputs.platform-files + run: | + clcache -M 52428800 + clcache -c + clcache -s + - name: Format artifact name + if: inputs.append-date-and-hash + id: artifactname + run: echo "name=${{ inputs.artifact-name }}-$(date +%Y%m%d)-$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" + - name: Upload artifact + if: inputs.artifact-name + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.append-date-and-hash && steps.artifactname.outputs.name || inputs.artifact-name }} + path: build/image/* diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a2567132a..1c9f4b13f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ on: [push, pull_request] jobs: build-linux: - name: Build (Linux ${{ matrix.type }}, GCC ${{ matrix.gcc }}) + name: Linux ${{ matrix.type }}, GCC ${{ matrix.gcc }} uses: ./.github/workflows/build-linux.yml with: artifact-name: ${{ matrix.artifact-name || format('{0}-gcc-{1}', matrix.type, matrix.gcc) }} From 2bb972ff7734817aef77b8d52ac285d91489a9d4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 30 Jul 2023 20:52:07 -0700 Subject: [PATCH 175/851] fix home ref --- .github/workflows/build-linux.yml | 2 +- .github/workflows/build-windows.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 4e070e9f0..7d389f1e7 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -71,7 +71,7 @@ jobs: env: CC: gcc-${{ inputs.gcc-ver }} CXX: g++-${{ inputs.gcc-ver }} - CCACHE_DIR: ${{ env.HOME }}/.ccache + CCACHE_DIR: ${{ github.env.HOME }}/.ccache run: | cmake \ -S . \ diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index d6a5371b0..34268fc17 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -36,14 +36,14 @@ jobs: if: inputs.platform-files uses: actions/cache@v3 with: - path: ${{ env.HOME }}/clcache + path: ${{ github.env.HOME }}/clcache key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }} restore-keys: | win-msvc-${{ inputs.cache-id }} win-msvc - name: Configure DFHack env: - CLCACHE_DIR: ${{ env.HOME }}/clcache + CLCACHE_DIR: ${{ github.env.HOME }}/clcache run: cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image ${{ inputs.platform-files && '-DCMAKE_C_COMPILER_LAUNCHER=clcache' || '' }} ${{ inputs.platform-files && '-DCMAKE_CXX_COMPILER_LAUNCHER=clcache' || '' }} -DBUILD_LIBRARY:BOOL=${{ inputs.platform-files }} -DBUILD_PLUGINS:BOOL=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.platform-files }} -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} - name: Build DFHack run: cmake --build build -j 2 --config Release --target install From 0364557533c984b7c85785ca5d75fe5f16c1e182 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 30 Jul 2023 21:04:52 -0700 Subject: [PATCH 176/851] actually use the new windows workflow --- .github/workflows/build-linux.yml | 5 ++--- .github/workflows/build.yml | 34 ++++++------------------------- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 7d389f1e7..a32c4b474 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -62,7 +62,7 @@ jobs: if: inputs.platform-files uses: actions/cache@v3 with: - path: ~/.ccache + path: ~/.cache/ccache key: linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }}-${{ github.sha }} restore-keys: | linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }} @@ -71,7 +71,6 @@ jobs: env: CC: gcc-${{ inputs.gcc-ver }} CXX: g++-${{ inputs.gcc-ver }} - CCACHE_DIR: ${{ github.env.HOME }}/.ccache run: | cmake \ -S . \ @@ -100,7 +99,7 @@ jobs: run: | ccache --max-size 50M ccache --cleanup - ccache --show-stats + ccache --show-stats --verbose - name: Format artifact name if: inputs.append-date-and-hash id: artifactname diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1c9f4b13f..6bae140a5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -85,34 +85,12 @@ jobs: package-win64: name: Win64 package (native) - runs-on: windows-latest - steps: - - run: pip install clcache - - run: pip install 'sphinx<4.4.0' - - name: Fetch cache - uses: actions/cache@v3 - with: - path: ~/clcache - key: clcache-win64-${{ github.sha }} - restore-keys: | - clcache-win64 - - name: Clone DFHack - uses: actions/checkout@v3 - with: - submodules: true - fetch-depth: 0 - - name: Configure DFHack - run: cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image -DCMAKE_C_COMPILER_LAUNCHER=clcache -DCMAKE_CXX_COMPILER_LAUNCHER=clcache -DBUILD_DOCS:BOOL=1 -DBUILD_STONESENSE:BOOL=1 - - name: Build DFHack - run: cmake --build build -j 2 --config Release --target install - - name: Format artifact name - uses: benjlevesque/short-sha@v2.2 - id: short-sha - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: dfhack-win64-build-${{ steps.short-sha.outputs.sha }} - path: build/image/* + uses: ./.github/workflows/build-windows.yml + with: + artifact-name: dfhack-win64 + append-date-and-hash: true + cache-id: msvc + secrets: inherit build-cross-win64: name: Win64 package From a0fae55c9031a1fe46a714d1358bf51f7e141575 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 30 Jul 2023 21:39:39 -0700 Subject: [PATCH 177/851] fix windows clcache path --- .github/workflows/build-windows.yml | 14 ++++++-------- .github/workflows/build.yml | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 34268fc17..281ca4f5f 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -27,23 +27,21 @@ jobs: if: inputs.platform-files - run: pip install 'sphinx<4.4.0' if: inputs.common-files - - name: Clone DFHack - uses: actions/checkout@v3 - with: - submodules: true - fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} - name: Fetch clcache if: inputs.platform-files uses: actions/cache@v3 with: - path: ${{ github.env.HOME }}/clcache + path: clcache key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }} restore-keys: | win-msvc-${{ inputs.cache-id }} win-msvc + - name: Clone DFHack + uses: actions/checkout@v3 + with: + submodules: true + fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} - name: Configure DFHack - env: - CLCACHE_DIR: ${{ github.env.HOME }}/clcache run: cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image ${{ inputs.platform-files && '-DCMAKE_C_COMPILER_LAUNCHER=clcache' || '' }} ${{ inputs.platform-files && '-DCMAKE_CXX_COMPILER_LAUNCHER=clcache' || '' }} -DBUILD_LIBRARY:BOOL=${{ inputs.platform-files }} -DBUILD_PLUGINS:BOOL=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.platform-files }} -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} - name: Build DFHack run: cmake --build build -j 2 --config Release --target install diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6bae140a5..e744ed190 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,7 +50,7 @@ jobs: - name: Download artifact uses: actions/download-artifact@v3 with: - name: test-${{ matrix.gcc }} + name: test-gcc-${{ matrix.gcc }} # - name: Fetch DF cache # uses: actions/cache@v3 # with: From b6ececed2d61d954f59ea1d222530fda35498ed0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 30 Jul 2023 23:50:47 -0700 Subject: [PATCH 178/851] another clcache attempt --- .github/workflows/build-windows.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 281ca4f5f..27c5b28a0 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -11,9 +11,6 @@ on: cache-id: type: string default: '' - platform-files: - type: boolean - default: true common-files: type: boolean default: true @@ -24,11 +21,9 @@ jobs: runs-on: windows-latest steps: - run: pip install clcache - if: inputs.platform-files - run: pip install 'sphinx<4.4.0' if: inputs.common-files - name: Fetch clcache - if: inputs.platform-files uses: actions/cache@v3 with: path: clcache @@ -40,13 +35,15 @@ jobs: uses: actions/checkout@v3 with: submodules: true - fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} + fetch-depth: 0 - name: Configure DFHack - run: cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image ${{ inputs.platform-files && '-DCMAKE_C_COMPILER_LAUNCHER=clcache' || '' }} ${{ inputs.platform-files && '-DCMAKE_CXX_COMPILER_LAUNCHER=clcache' || '' }} -DBUILD_LIBRARY:BOOL=${{ inputs.platform-files }} -DBUILD_PLUGINS:BOOL=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.platform-files }} -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} + env: + CC: clcache + CXX: clcache + run: cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image -DBUILD_STONESENSE:BOOL=1 -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} - name: Build DFHack run: cmake --build build -j 2 --config Release --target install - name: Trim cache - if: inputs.platform-files run: | clcache -M 52428800 clcache -c From 1fad6d76f11aa1ca710fd724e285535d95e9cc88 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 00:05:47 -0700 Subject: [PATCH 179/851] split linux package out to simplify matrix --- .github/workflows/build.yml | 52 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e744ed190..7ff1b08c2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,35 +4,23 @@ on: [push, pull_request] jobs: build-linux: - name: Linux ${{ matrix.type }}, GCC ${{ matrix.gcc }} + name: Linux gcc-${{ matrix.gcc }} uses: ./.github/workflows/build-linux.yml with: - artifact-name: ${{ matrix.artifact-name || format('{0}-gcc-{1}', matrix.type, matrix.gcc) }} - append-date-and-hash: ${{ matrix.append-date-and-hash && true || false }} - cache-id: ${{ matrix.type }} - stonesense: ${{ matrix.stonesense }} - docs: ${{ matrix.type == 'release' }} - extras: ${{ matrix.extras }} + artifact-name: test-gcc-${{ matrix.gcc }} + cache-id: test + stonesense: ${{ matrix.plugins == 'all' }} + extras: ${{ matrix.plugins == 'all' }} gcc-ver: ${{ matrix.gcc }} secrets: inherit strategy: fail-fast: false matrix: include: - - type: release - gcc: "10" - artifact-name: dfhack-linux64 - append-date-and-hash: true - stonesense: true - extras: false - - type: test - gcc: "10" - stonesense: false - extras: false - - type: test - gcc: "12" - stonesense: true - extras: true + - gcc: 10 + plugins: "default" + - gcc: 12 + plugins: "all" test-linux: name: Test (Linux, GCC ${{ matrix.gcc }}, ${{ matrix.plugins }} plugins) @@ -41,11 +29,11 @@ jobs: strategy: fail-fast: false matrix: - gcc: [10] - plugins: [default] include: - - gcc: 12 - plugins: all + - gcc: 10 + plugins: "default" + - gcc: 12 + plugins: "all" steps: - name: Download artifact uses: actions/download-artifact@v3 @@ -83,6 +71,18 @@ jobs: # run: | # rm -rf "$DF_FOLDER" + package-linux: + name: Linux package + uses: ./.github/workflows/build-linux.yml + with: + artifact-name: dfhack-linux64 + append-date-and-hash: true + cache-id: release + stonesense: true + docs: true + gcc-ver: "10" + secrets: inherit + package-win64: name: Win64 package (native) uses: ./.github/workflows/build-windows.yml @@ -140,7 +140,7 @@ jobs: secrets: inherit lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - name: Install Lua run: | From 5c664fca1cd9712488e5be2b9cca5d79a0155dcb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 01:49:02 -0700 Subject: [PATCH 180/851] reuse workflows for steam --- .github/workflows/build-linux.yml | 4 + .github/workflows/build-windows.yml | 57 ++++++---- .github/workflows/build.yml | 45 +------- .github/workflows/steam.yml | 164 +++++++++------------------- 4 files changed, 94 insertions(+), 176 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index a32c4b474..77906bbd4 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -3,6 +3,9 @@ name: build-linux on: workflow_call: inputs: + ref: + type: string + default: '' artifact-name: type: string append-date-and-hash: @@ -56,6 +59,7 @@ jobs: - name: Clone DFHack uses: actions/checkout@v3 with: + ref: ${{ inputs.ref }} submodules: true fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} - name: Fetch ccache diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 27c5b28a0..b5a96b12d 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -3,6 +3,9 @@ name: build-windows on: workflow_call: inputs: + ref: + type: string + default: '' artifact-name: type: string append-date-and-hash: @@ -14,40 +17,52 @@ on: common-files: type: boolean default: true + launchdf: + type: boolean + default: false jobs: build-win64: name: Build win64 - runs-on: windows-latest + runs-on: ubuntu-22.04 steps: - - run: pip install clcache - - run: pip install 'sphinx<4.4.0' - if: inputs.common-files - - name: Fetch clcache + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install ccache + - name: Clone DFHack + uses: actions/checkout@v3 + with: + ref: ${{ inputs.ref }} + submodules: true + fetch-depth: 0 + - name: Get 3rd party SDKs + if: inputs.launchdf + uses: actions/checkout@v3 + with: + repository: DFHack/3rdparty + ref: main + ssh-key: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} + path: depends/steam + - name: Fetch ccache uses: actions/cache@v3 with: - path: clcache + path: build/win64-cross/ccache key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }} restore-keys: | win-msvc-${{ inputs.cache-id }} win-msvc - - name: Clone DFHack - uses: actions/checkout@v3 - with: - submodules: true - fetch-depth: 0 - - name: Configure DFHack + - name: Cross-compile env: - CC: clcache - CXX: clcache - run: cmake -S . -B build -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=build/image -DBUILD_STONESENSE:BOOL=1 -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} - - name: Build DFHack - run: cmake --build build -j 2 --config Release --target install + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }}' + run: | + cd build + bash -x build-win64-from-linux.sh - name: Trim cache run: | - clcache -M 52428800 - clcache -c - clcache -s + ccache -d win64-cross/ccache --max-size 50M + ccache -d win64-cross/ccache --cleanup + ccache -d win64-cross/ccache --show-stats --verbose - name: Format artifact name if: inputs.append-date-and-hash id: artifactname @@ -57,4 +72,4 @@ jobs: uses: actions/upload-artifact@v3 with: name: ${{ inputs.append-date-and-hash && steps.artifactname.outputs.name || inputs.artifact-name }} - path: build/image/* + path: build/win64-cross/output/* diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7ff1b08c2..648fd3838 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -75,7 +75,7 @@ jobs: name: Linux package uses: ./.github/workflows/build-linux.yml with: - artifact-name: dfhack-linux64 + artifact-name: dfhack-linux64-build append-date-and-hash: true cache-id: release stonesense: true @@ -84,53 +84,14 @@ jobs: secrets: inherit package-win64: - name: Win64 package (native) + name: Win64 package uses: ./.github/workflows/build-windows.yml with: - artifact-name: dfhack-win64 + artifact-name: dfhack-win64-build append-date-and-hash: true cache-id: msvc secrets: inherit - build-cross-win64: - name: Win64 package - 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: - submodules: true - fetch-depth: 0 - - name: Fetch ccache - uses: actions/cache@v3 - with: - path: build/win64-cross/ccache - key: ccache-win64-cross-msvc-${{ github.sha }} - restore-keys: | - ccache-win64-cross-msvc - - name: Cross-compile win64 - env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1' - run: | - cd build - bash -x build-win64-from-linux.sh - 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: | - echo name=$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: dfhack-win64-build-${{ steps.artifactname.outputs.name }} - path: build/win64-cross/output/* - docs: uses: ./.github/workflows/build-linux.yml with: diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index d57fa00ac..6d4533ee9 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -13,127 +13,65 @@ on: type: string required: true release_channel: - description: Release channel + description: Steam release channel type: string required: true default: staging jobs: + depot-common: + name: Common depot files + uses: ./.github/workflows/build-linux.yml + with: + artifact-name: common-depot + ref: ${{ github.event.inputs.ref }} + platform-files: false + docs: true + stonesense: true + secrets: inherit + + depot-linux: + name: Linux depot files + uses: ./.github/workflows/build-linux.yml + with: + artifact-name: linux64-depot + ref: ${{ github.event.inputs.ref }} + cache-id: depot + common-files: false + stonesense: true + gcc-ver: "10" + secrets: inherit + + depot-win64: + name: Windows depot files + uses: ./.github/workflows/build-windows.yml + with: + artifact-name: win64-depot + ref: ${{ github.event.inputs.ref }} + cache-id: msvc + common-files: false + launchdf: true + secrets: inherit + deploy-to-steam: name: Deploy to Steam - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest steps: - - name: Set up Python 3 - uses: actions/setup-python@v4 - with: - python-version: 3 - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install \ - ccache \ - gcc-10 \ - g++-10 \ - libgl-dev \ - libxml-libxslt-perl \ - ninja-build - pip install 'sphinx<4.4.0' - - name: Clone DFHack - uses: actions/checkout@v3 - with: - submodules: true - fetch-depth: 0 - ref: ${{ github.event.inputs.ref }} - - name: Get 3rd party SDKs - uses: actions/checkout@v3 + - name: Stage common depot files + uses: actions/download-artifact@v3 with: - repository: DFHack/3rdparty - ref: main - ssh-key: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} - path: depends/steam - - name: Fetch linux64 ccache - uses: actions/cache@v3 + name: common-depot + path: common + - name: Stage linux64 depot files + uses: actions/download-artifact@v3 with: - path: ~/.ccache - key: ccache-ubuntu-22.04-gcc-10-${{ github.sha }} - restore-keys: | - ccache-ubuntu-22.04-gcc-10 - - name: Fetch win64 ccache - uses: actions/cache@v3 + name: linux64-depot + path: linux64 + - name: Stage win64 depot files + uses: actions/download-artifact@v3 with: - path: build/win64-cross/ccache - key: ccache-win64-cross-msvc-${{ github.sha }} - restore-keys: | - ccache-win64-cross-msvc - - name: Set up environment - id: env_setup - run: | - echo "CCACHE_DIR=${HOME}/.ccache" >> $GITHUB_ENV - - name: Configure DFHack (common files) - env: - CC: gcc-10 - CXX: g++-10 - run: | - cmake \ - -S . \ - -B build \ - -G Ninja \ - -DCMAKE_INSTALL_PREFIX=build/common-output \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DDFHACK_BUILD_ARCH=64 \ - -DBUILD_DOCS:BOOL=1 \ - -DBUILD_LIBRARY:BOOL=0 \ - -DBUILD_PLUGINS:BOOL=0 \ - -DBUILD_STONESENSE:BOOL=1 \ - -DINSTALL_DATA_FILES:BOOL=1 \ - -DINSTALL_SCRIPTS:BOOL=1 - - name: Build DFHack (common files) - run: | - ninja -C build install - - name: Configure DFHack (linux build) - env: - CC: gcc-10 - CXX: g++-10 - run: | - cmake \ - -S . \ - -B build \ - -G Ninja \ - -DCMAKE_INSTALL_PREFIX=build/linux-output \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_C_COMPILER_LAUNCHER=ccache \ - -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ - -DDFHACK_BUILD_ARCH=64 \ - -DBUILD_DOCS:BOOL=0 \ - -DBUILD_LIBRARY:BOOL=1 \ - -DBUILD_PLUGINS:BOOL=1 \ - -DBUILD_STONESENSE:BOOL=1 \ - -DINSTALL_DATA_FILES:BOOL=0 \ - -DINSTALL_SCRIPTS:BOOL=0 - - name: Build DFHack (linux build) - run: | - ninja -C build install - ccache --max-size 50M - ccache --cleanup - ccache --show-stats - - name: Cross-compile win64 artifacts - env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DFLAUNCH:BOOL=1 -DBUILD_DOCS:BOOL=0 -DINSTALL_DATA_FILES:BOOL=0 -DINSTALL_SCRIPTS:BOOL=0' - steam_username: ${{ secrets.STEAM_SDK_USERNAME }} - steam_password: ${{ secrets.STEAM_SDK_PASSWORD }} - run: | - echo "ref: ${{ github.event.inputs.ref }}" - echo "sha: ${{ github.sha }}" - echo "version: ${{ github.event.inputs.version }}" - echo "release_channel: ${{ github.event.inputs.release_channel }}" - echo - cd build - bash -x build-win64-from-linux.sh - ccache -d win64-cross/ccache --max-size 200M - ccache -d win64-cross/ccache --cleanup - ccache -d win64-cross/ccache --show-stats + name: win64-depot + path: win64 - name: Steam deploy uses: game-ci/steam-deploy@v3 with: @@ -142,7 +80,7 @@ jobs: appId: 2346660 buildDescription: ${{ github.event.inputs.version }} rootPath: build - depot1Path: common-output - depot2Path: win64-cross/output - depot3Path: linux-output + depot1Path: common + depot2Path: win64 + depot3Path: linux64 releaseBranch: ${{ github.event.inputs.release_channel }} From 737ff8b3abf0f04c50f693e1142c713e0ae35ac7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 02:50:32 -0700 Subject: [PATCH 181/851] more cache tuning --- .github/workflows/build-linux.yml | 13 +++++++++++-- .github/workflows/build-windows.yml | 13 +++++++++++-- .github/workflows/build.yml | 2 +- .github/workflows/steam.yml | 6 ++++-- 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 77906bbd4..b504403ee 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -14,6 +14,9 @@ on: cache-id: type: string default: '' + cache-readonly: + type: boolean + default: false platform-files: type: boolean default: true @@ -64,7 +67,7 @@ jobs: fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} - name: Fetch ccache if: inputs.platform-files - uses: actions/cache@v3 + uses: actions/cache/restore@v3 with: path: ~/.cache/ccache key: linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }}-${{ github.sha }} @@ -101,9 +104,15 @@ jobs: - name: Trim cache if: inputs.platform-files run: | - ccache --max-size 50M + ccache --max-size 40M ccache --cleanup ccache --show-stats --verbose + - name: Save ccache + if: inputs.platform-files && !inputs.cache-readonly + uses: actions/cache/save@v3 + with: + path: ~/.cache/ccache + key: linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }}-${{ github.sha }} - name: Format artifact name if: inputs.append-date-and-hash id: artifactname diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index b5a96b12d..8fe4502e4 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -14,6 +14,9 @@ on: cache-id: type: string default: '' + cache-readonly: + type: boolean + default: false common-files: type: boolean default: true @@ -45,7 +48,7 @@ jobs: ssh-key: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} path: depends/steam - name: Fetch ccache - uses: actions/cache@v3 + uses: actions/cache/restore@v3 with: path: build/win64-cross/ccache key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }} @@ -60,9 +63,15 @@ jobs: bash -x build-win64-from-linux.sh - name: Trim cache run: | - ccache -d win64-cross/ccache --max-size 50M + cd build + ccache -d win64-cross/ccache --max-size 200M ccache -d win64-cross/ccache --cleanup ccache -d win64-cross/ccache --show-stats --verbose + - name: Save ccache + uses: actions/cache/save@v3 + with: + path: build/win64-cross/ccache + key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }} - name: Format artifact name if: inputs.append-date-and-hash id: artifactname diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 648fd3838..f6116b3c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -89,7 +89,7 @@ jobs: with: artifact-name: dfhack-win64-build append-date-and-hash: true - cache-id: msvc + cache-id: release secrets: inherit docs: diff --git a/.github/workflows/steam.yml b/.github/workflows/steam.yml index 6d4533ee9..1801ad33f 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -36,7 +36,8 @@ jobs: with: artifact-name: linux64-depot ref: ${{ github.event.inputs.ref }} - cache-id: depot + cache-id: release + cache-readonly: true common-files: false stonesense: true gcc-ver: "10" @@ -48,7 +49,8 @@ jobs: with: artifact-name: win64-depot ref: ${{ github.event.inputs.ref }} - cache-id: msvc + cache-id: release + cache-readonly: true common-files: false launchdf: true secrets: inherit From a509bb5e61d4a37a063a2d4488ec09b0c90590cf Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 03:01:11 -0700 Subject: [PATCH 182/851] always build launchdf --- .github/workflows/build-windows.yml | 6 +----- .github/workflows/steam.yml | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 8fe4502e4..e1076b161 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -20,9 +20,6 @@ on: common-files: type: boolean default: true - launchdf: - type: boolean - default: false jobs: build-win64: @@ -40,7 +37,6 @@ jobs: submodules: true fetch-depth: 0 - name: Get 3rd party SDKs - if: inputs.launchdf uses: actions/checkout@v3 with: repository: DFHack/3rdparty @@ -57,7 +53,7 @@ jobs: win-msvc - name: Cross-compile env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }}' + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -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 1801ad33f..cbf311c7d 100644 --- a/.github/workflows/steam.yml +++ b/.github/workflows/steam.yml @@ -52,7 +52,6 @@ jobs: cache-id: release cache-readonly: true common-files: false - launchdf: true secrets: inherit deploy-to-steam: From 52a478d1d74fe2a454aa33e2996437953132ff77 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 03:03:25 -0700 Subject: [PATCH 183/851] rename steam workflow file --- .github/workflows/{steam.yml => steam-deploy.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{steam.yml => steam-deploy.yml} (100%) diff --git a/.github/workflows/steam.yml b/.github/workflows/steam-deploy.yml similarity index 100% rename from .github/workflows/steam.yml rename to .github/workflows/steam-deploy.yml From bbe7dbb0b8698395e34c0103f3917c8e7ba7154f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 03:56:11 -0700 Subject: [PATCH 184/851] build with gcc 10 by default --- .github/workflows/build-linux.yml | 2 +- .github/workflows/build.yml | 3 +- .github/workflows/clean-cache.yml | 1 + .github/workflows/steam-deploy.yml | 77 ++++++++++++++++-------------- 4 files changed, 43 insertions(+), 40 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index b504403ee..b6c4e5aa5 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -34,7 +34,7 @@ on: default: false gcc-ver: type: string - default: "11" + default: "10" jobs: build-linux64: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f6116b3c9..e10894696 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,7 +25,7 @@ jobs: test-linux: name: Test (Linux, GCC ${{ matrix.gcc }}, ${{ matrix.plugins }} plugins) needs: build-linux - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest strategy: fail-fast: false matrix: @@ -80,7 +80,6 @@ jobs: cache-id: release stonesense: true docs: true - gcc-ver: "10" secrets: inherit package-win64: diff --git a/.github/workflows/clean-cache.yml b/.github/workflows/clean-cache.yml index d3e12959d..0a4bddf64 100644 --- a/.github/workflows/clean-cache.yml +++ b/.github/workflows/clean-cache.yml @@ -1,4 +1,5 @@ name: Clean up PR caches + on: pull_request_target: types: diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index cbf311c7d..006c05ec1 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -30,58 +30,61 @@ jobs: stonesense: true secrets: inherit - depot-linux: - name: Linux depot files - uses: ./.github/workflows/build-linux.yml + depot-win64: + name: Windows depot files + uses: ./.github/workflows/build-windows.yml with: - artifact-name: linux64-depot + artifact-name: win64-depot ref: ${{ github.event.inputs.ref }} cache-id: release cache-readonly: true common-files: false - stonesense: true - gcc-ver: "10" secrets: inherit - depot-win64: - name: Windows depot files - uses: ./.github/workflows/build-windows.yml + depot-linux64: + name: Linux depot files + uses: ./.github/workflows/build-linux.yml with: - artifact-name: win64-depot + artifact-name: linux64-depot ref: ${{ github.event.inputs.ref }} cache-id: release cache-readonly: true common-files: false + stonesense: true secrets: inherit deploy-to-steam: name: Deploy to Steam + needs: + - depot-common + - depot-win64 + - depot-linux64 runs-on: ubuntu-latest steps: - - name: Stage common depot files - uses: actions/download-artifact@v3 - with: - name: common-depot - path: common - - name: Stage linux64 depot files - uses: actions/download-artifact@v3 - with: - name: linux64-depot - path: linux64 - - name: Stage win64 depot files - uses: actions/download-artifact@v3 - with: - name: win64-depot - path: win64 - - name: Steam deploy - uses: game-ci/steam-deploy@v3 - with: - username: ${{ secrets.STEAM_USERNAME }} - configVdf: ${{ secrets.STEAM_CONFIG_VDF}} - appId: 2346660 - buildDescription: ${{ github.event.inputs.version }} - rootPath: build - depot1Path: common - depot2Path: win64 - depot3Path: linux64 - releaseBranch: ${{ github.event.inputs.release_channel }} + - name: Stage common depot files + uses: actions/download-artifact@v3 + with: + name: common-depot + path: common + - name: Stage win64 depot files + uses: actions/download-artifact@v3 + with: + name: win64-depot + path: win64 + - name: Stage linux64 depot files + uses: actions/download-artifact@v3 + with: + name: linux64-depot + path: linux64 + - name: Steam deploy + uses: game-ci/steam-deploy@v3 + with: + username: ${{ secrets.STEAM_USERNAME }} + configVdf: ${{ secrets.STEAM_CONFIG_VDF}} + appId: 2346660 + buildDescription: ${{ github.event.inputs.version }} + rootPath: build + depot1Path: common + depot2Path: win64 + depot3Path: linux64 + releaseBranch: ${{ github.event.inputs.release_channel }} From e3a8009717c90b26927fbabd8441baf448560625 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 03:56:26 -0700 Subject: [PATCH 185/851] initial draft of automated github release --- .github/release_template.md | 65 ++++++++++++++++++++++ .github/workflows/github-release.yml | 83 ++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 .github/release_template.md create mode 100644 .github/workflows/github-release.yml diff --git a/.github/release_template.md b/.github/release_template.md new file mode 100644 index 000000000..a47628b3c --- /dev/null +++ b/.github/release_template.md @@ -0,0 +1,65 @@ +#### Q: How do I download DFHack? +**A:** Either add to your Steam library from our [Steam page](https://store.steampowered.com/app/2346660/DFHack) or scroll to the latest release on our [GitHub releases page](https://github.com/DFHack/dfhack/releases), expand the "Assets" list, and download the file for your platform (e.g. `dfhack-XX.XX-rX-Windows-64bit.zip`. + +------------- + +This release is compatible with all distributions of Dwarf Fortress: [Steam](https://store.steampowered.com/app/975370/Dwarf_Fortress/), [Itch](https://kitfoxgames.itch.io/dwarf-fortress), and [Classic](https://www.bay12games.com/dwarves/). + +- [Install DFHack from Steam](https://store.steampowered.com/app/2346660/DFHack) +- [Manual install](https://docs.dfhack.org/en/stable/docs/Installing.html#installing) +- [Quickstart guide (for players)](https://docs.dfhack.org/en/stable/docs/Quickstart.html#quickstart) +- [Modding guide (for modders)](https://docs.dfhack.org/en/stable/docs/guides/modding-guide.html) + +Please report any issues (or feature requests) on the DFHack [GitHub issue tracker](https://github.com/DFHack/dfhack/issues). When reporting issues, please upload a zip file of your savegame and a zip file of your `mods` directory to the cloud and add links to the GitHub issue. Make sure your files are downloadable by "everyone with the link". We need your savegame to reproduce the problem and test the fix, and we need your active mods so we can load your savegame. Issues with savegames and mods attached get fixed first! + +Announcements +---------------------------------- + +
+Annc 1, PSAs + +### Annc 1 + + + +### PSAs + +As always, remember that, just like the vanilla DF game, DFHack tools can also have bugs. It is a good idea to **save often and keep backups** of the forts that you care about. + +Many DFHack tools that worked in previous (pre-Steam) versions of DF have not been updated yet and are marked with the "unavailable" tag in their docs. If you try to run them, they will show a warning and exit immediately. You can run the command again to override the warning (though of course the tools may not work). We make no guarantees of reliability for the tools that are marked as "unavailable". + +The in-game interface for running DFHack commands (`gui/launcher`) will not show "unavailable" tools by default. You can still run them if you know their names, or you can turn on dev mode by hitting Ctrl-D while in `gui/launcher` and they will be added to the autocomplete list. Some tools do not compile yet and are not available at all, even when in dev mode. + +If you see a tool complaining about the lack of a cursor, know that it's referring to the **keyboard** cursor (which used to be the only real option in Dwarf Fortress). You can enable the keyboard cursor by entering mining mode or selecting the dump/forbid tool and hitting Alt-K (the DFHack keybinding for `toggle-kbd-cursor`. We're working on making DFHack tools more mouse-aware and accessible so this step isn't necessary in the future. + +
+ +Highlights +---------------------------------- + +
+Highlight 1, Highlight 2 + +### Highlight 1 + +Demo screenshot/vidcap + +Text + +### Highlight 2 + +Demo screenshot/vidcap + +Text + +
+ +Generated release notes +==================== + +
+ New tools, fixes, and improvements + +RELEASE NOTES HERE + +
diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml new file mode 100644 index 000000000..e37960ef1 --- /dev/null +++ b/.github/workflows/github-release.yml @@ -0,0 +1,83 @@ +name: Releases + +on: + push: + tags: + - '*-r[0-9]+' + workflow_dispatch: + inputs: + tag: + description: tag + required: true + +jobs: + package-win64: + name: Windows release + uses: ./.github/workflows/build-windows.yml + with: + artifact-name: win64-release + ref: ${{ github.event.inputs.tag }} + cache-id: release + cache-readonly: true + stonesense: true + docs: true + secrets: inherit + + package-linux64: + name: Linux release + uses: ./.github/workflows/build-linux.yml + with: + artifact-name: linux64-release + ref: ${{ github.event.inputs.tag }} + cache-id: release + cache-readonly: true + stonesense: true + docs: true + secrets: inherit + + create-update-release: + name: GitHub release + needs: + - package-win64 + - package-linux64 + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Clone DFHack + uses: actions/checkout@v3 + with: + ref: ${{ github.event.inputs.tag }} + - name: Stage win64 release + uses: actions/download-artifact@v3 + with: + name: win64-release + path: win64 + - name: Create win64 release archive + run: | + cd win64 + zip -r ../dfhack-${{ github.event.inputs.tag }}-Windows-64bit.zip . + - name: Stage linux64 release + uses: actions/download-artifact@v3 + with: + name: linux64-release + path: linux64 + - name: Create linux64 release archive + run: | + cd linux64 + tar cjf ../dfhack-${{ github.event.inputs.tag }}-Linux-64bit.tar.bz2 . + - name: Create or update GitHub release + uses: ncipollo/release-action@v1 + with: + artifacts: "dfhack-*" + bodyFile: ".github/release_template.md" + allowUpdates: true + artifactErrorsFailBuild: true + draft: true + name: "DFHack ${{ github.event.inputs.tag }}" + omitBodyDuringUpdate: true + omitDraftDuringUpdate: true + omitNameDuringUpdate: true + omitPrereleaseDuringUpdate: true + replacesArtifacts: true + tag: ${{ github.event.inputs.tag }} From cf0b87fbc463b0c5f65b4b16dc8134d991598a7f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 04:02:12 -0700 Subject: [PATCH 186/851] Revert "always build launchdf" This reverts commit a509bb5e61d4a37a063a2d4488ec09b0c90590cf. --- .github/workflows/build-windows.yml | 6 +++++- .github/workflows/steam-deploy.yml | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index e1076b161..8fe4502e4 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -20,6 +20,9 @@ on: common-files: type: boolean default: true + launchdf: + type: boolean + default: false jobs: build-win64: @@ -37,6 +40,7 @@ jobs: submodules: true fetch-depth: 0 - name: Get 3rd party SDKs + if: inputs.launchdf uses: actions/checkout@v3 with: repository: DFHack/3rdparty @@ -53,7 +57,7 @@ jobs: win-msvc - name: Cross-compile env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=1' + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }}' run: | cd build bash -x build-win64-from-linux.sh diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index 006c05ec1..ef1433212 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -39,6 +39,7 @@ jobs: cache-id: release cache-readonly: true common-files: false + launchdf: true secrets: inherit depot-linux64: From 97ea3f3d671bf5f0374733b37a5069cc06f1cc17 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 04:43:43 -0700 Subject: [PATCH 187/851] generate release notes changelog text --- .github/release_template.md | 6 +++--- .github/workflows/github-release.yml | 12 +++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/release_template.md b/.github/release_template.md index a47628b3c..eb1c43146 100644 --- a/.github/release_template.md +++ b/.github/release_template.md @@ -20,7 +20,7 @@ Announcements ### Annc 1 - +Text ### PSAs @@ -58,8 +58,8 @@ Generated release notes ====================
- New tools, fixes, and improvements +New tools, fixes, and improvements -RELEASE NOTES HERE +%RELEASE_NOTES%
diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index e37960ef1..3adec790a 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -48,6 +48,16 @@ jobs: uses: actions/checkout@v3 with: ref: ${{ github.event.inputs.tag }} + submodules: true + - name: Generate release text + run: | + python docs/gen_changelog.py -a + TOKEN_LINE=$(grep -Fhne '%RELEASE_NOTES%' .github/release_template.md | sed 's/:.*//') + head -n $((TOKEN_LINE - 1)) .github/release_template.md > release_body.md + CHANGELOG_LINES=$(wc -l > release_body.md + tail -n 2 .github/release_template.md >> release_body.md + cat release_body.md - name: Stage win64 release uses: actions/download-artifact@v3 with: @@ -70,7 +80,7 @@ jobs: uses: ncipollo/release-action@v1 with: artifacts: "dfhack-*" - bodyFile: ".github/release_template.md" + bodyFile: "release_body.md" allowUpdates: true artifactErrorsFailBuild: true draft: true From 9b59fc6440ab82a120c90764ce6f3b5ae175dab5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 04:51:44 -0700 Subject: [PATCH 188/851] use the actual tag of the checkout --- .github/workflows/github-release.yml | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 3adec790a..6a4110710 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -21,6 +21,7 @@ jobs: cache-readonly: true stonesense: true docs: true + launchdf: true secrets: inherit package-linux64: @@ -49,13 +50,16 @@ jobs: with: ref: ${{ github.event.inputs.tag }} submodules: true + - name: Get tag + id: gettag + run: echo name=$(git describe --tags --abbrev=0 --exact-match) >> $GITHUB_OUTPUT - name: Generate release text run: | python docs/gen_changelog.py -a TOKEN_LINE=$(grep -Fhne '%RELEASE_NOTES%' .github/release_template.md | sed 's/:.*//') head -n $((TOKEN_LINE - 1)) .github/release_template.md > release_body.md - CHANGELOG_LINES=$(wc -l > release_body.md + CHANGELOG_LINES=$(wc -l > release_body.md tail -n 2 .github/release_template.md >> release_body.md cat release_body.md - name: Stage win64 release @@ -66,7 +70,7 @@ jobs: - name: Create win64 release archive run: | cd win64 - zip -r ../dfhack-${{ github.event.inputs.tag }}-Windows-64bit.zip . + zip -r ../dfhack-${{ steps.gettag.outputs.name }}-Windows-64bit.zip . - name: Stage linux64 release uses: actions/download-artifact@v3 with: @@ -75,7 +79,7 @@ jobs: - name: Create linux64 release archive run: | cd linux64 - tar cjf ../dfhack-${{ github.event.inputs.tag }}-Linux-64bit.tar.bz2 . + tar cjf ../dfhack-${{ steps.gettag.outputs.name }}-Linux-64bit.tar.bz2 . - name: Create or update GitHub release uses: ncipollo/release-action@v1 with: @@ -84,10 +88,10 @@ jobs: allowUpdates: true artifactErrorsFailBuild: true draft: true - name: "DFHack ${{ github.event.inputs.tag }}" + name: "DFHack ${{ steps.gettag.outputs.name }}" omitBodyDuringUpdate: true omitDraftDuringUpdate: true omitNameDuringUpdate: true omitPrereleaseDuringUpdate: true replacesArtifacts: true - tag: ${{ github.event.inputs.tag }} + tag: ${{ steps.gettag.outputs.name }} From 9b8bd8dbf7f5555a075cc943edb5885f8707f285 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 05:37:57 -0700 Subject: [PATCH 189/851] names --- .github/workflows/build-linux.yml | 2 +- .github/workflows/build-windows.yml | 2 +- .github/workflows/clean-cache.yml | 2 +- .github/workflows/github-release.yml | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index b6c4e5aa5..a29204a30 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -1,4 +1,4 @@ -name: build-linux +name: Build linux64 on: workflow_call: diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 8fe4502e4..59737f0a7 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -1,4 +1,4 @@ -name: build-windows +name: Build win64 on: workflow_call: diff --git a/.github/workflows/clean-cache.yml b/.github/workflows/clean-cache.yml index 0a4bddf64..36984a6a1 100644 --- a/.github/workflows/clean-cache.yml +++ b/.github/workflows/clean-cache.yml @@ -19,7 +19,7 @@ jobs: 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) + cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1) set +e echo "Deleting caches..." diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 6a4110710..04118ed71 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -1,4 +1,4 @@ -name: Releases +name: Deploy to GitHub on: push: @@ -12,7 +12,7 @@ on: jobs: package-win64: - name: Windows release + name: Build win64 release uses: ./.github/workflows/build-windows.yml with: artifact-name: win64-release @@ -25,7 +25,7 @@ jobs: secrets: inherit package-linux64: - name: Linux release + name: Build linux64 release uses: ./.github/workflows/build-linux.yml with: artifact-name: linux64-release @@ -37,7 +37,7 @@ jobs: secrets: inherit create-update-release: - name: GitHub release + name: Draft GitHub release needs: - package-win64 - package-linux64 From 80d19ec42d9ba774f49aab53d9b6062d8ba3b2cc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 10:07:23 -0700 Subject: [PATCH 190/851] fix paths for steam deploy --- .github/workflows/build-windows.yml | 1 + .github/workflows/steam-deploy.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 59737f0a7..e41431f4f 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -68,6 +68,7 @@ jobs: ccache -d win64-cross/ccache --cleanup ccache -d win64-cross/ccache --show-stats --verbose - name: Save ccache + if: !inputs.cache-readonly uses: actions/cache/save@v3 with: path: build/win64-cross/ccache diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index ef1433212..1b9898c76 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -84,7 +84,7 @@ jobs: configVdf: ${{ secrets.STEAM_CONFIG_VDF}} appId: 2346660 buildDescription: ${{ github.event.inputs.version }} - rootPath: build + rootPath: . depot1Path: common depot2Path: win64 depot3Path: linux64 From 67e5aa08d03e522ddaedcfe62e00f956ac5cfcb1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 31 Jul 2023 10:13:29 -0700 Subject: [PATCH 191/851] fix syntax --- .github/workflows/build-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index e41431f4f..22c1e8210 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -68,7 +68,7 @@ jobs: ccache -d win64-cross/ccache --cleanup ccache -d win64-cross/ccache --show-stats --verbose - name: Save ccache - if: !inputs.cache-readonly + if: '!inputs.cache-readonly' uses: actions/cache/save@v3 with: path: build/win64-cross/ccache From 17ca9e0132e407aca65d15008c1ec501f3b943f3 Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 31 Jul 2023 17:20:38 -0700 Subject: [PATCH 192/851] Update Textures.h --- library/include/modules/Textures.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index f16acec4b..3b9d32541 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -52,7 +52,7 @@ DFHACK_EXPORT long getOnOffTexposStart(); DFHACK_EXPORT long getMapPathableTexposStart(); /** - * Get the first texpos for the unsuspend 32x32 sprites. It's a 4x1 grid. + * Get the first texpos for the unsuspend 32x32 sprites. It's a 5x1 grid. */ DFHACK_EXPORT long getMapUnsuspendTexposStart(); From e55984c529d818e5ca756eb982a3a988e40ead0d Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 1 Aug 2023 00:05:02 -0400 Subject: [PATCH 193/851] Fix startup crashes when global addresses are missing Useful for initial research. Can be tested with `DFHACK_NO_GLOBALS=1` --- library/Core.cpp | 10 ++++++---- library/LuaTools.cpp | 14 ++++++++------ library/lua/argparse.lua | 2 +- library/lua/gui.lua | 2 +- library/modules/Textures.cpp | 3 +++ 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index c4b03a7ac..9df45a869 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1896,8 +1896,8 @@ void Core::doUpdate(color_ostream &out) strict_virtual_cast(screen); // save data (do this before updating last_world_data_ptr and triggering unload events) - if ((df::global::game->main_interface.options.do_manual_save && !d->last_manual_save_request) || - (df::global::plotinfo->main.autosave_request && !d->last_autosave_request) || + if ((df::global::game && df::global::game->main_interface.options.do_manual_save && !d->last_manual_save_request) || + (df::global::plotinfo && df::global::plotinfo->main.autosave_request && !d->last_autosave_request) || (is_load_save && !d->was_load_save && strict_virtual_cast(screen))) { doSaveData(out); @@ -1959,8 +1959,10 @@ void Core::doUpdate(color_ostream &out) // Execute per-frame handlers onUpdate(out); - d->last_autosave_request = df::global::plotinfo->main.autosave_request; - d->last_manual_save_request = df::global::game->main_interface.options.do_manual_save; + if (df::global::game && df::global::plotinfo) { + d->last_autosave_request = df::global::plotinfo->main.autosave_request; + d->last_manual_save_request = df::global::game->main_interface.options.do_manual_save; + } d->was_load_save = is_load_save; out << std::flush; diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index a1bf855d6..ffeb4980a 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -2172,10 +2172,12 @@ void DFHack::Lua::Core::Reset(color_ostream &out, const char *where) inhibit_m_down = true; } - if (!df::global::enabler->mouse_lbut) - inhibit_l_down = false; - if (!df::global::enabler->mouse_rbut) - inhibit_r_down = false; - if (!df::global::enabler->mouse_mbut) - inhibit_m_down = false; + if (df::global::enabler) { + if (!df::global::enabler->mouse_lbut) + inhibit_l_down = false; + if (!df::global::enabler->mouse_rbut) + inhibit_r_down = false; + if (!df::global::enabler->mouse_mbut) + inhibit_m_down = false; + } } diff --git a/library/lua/argparse.lua b/library/lua/argparse.lua index e094bbb57..36b80feb1 100644 --- a/library/lua/argparse.lua +++ b/library/lua/argparse.lua @@ -3,7 +3,6 @@ local _ENV = mkmodule('argparse') local getopt = require('3rdparty.alt_getopt') -local guidm = require('gui.dwarfmode') function processArgs(args, validArgs) local result = {} @@ -174,6 +173,7 @@ end function coords(arg, arg_name, skip_validation) if arg == 'here' then + local guidm = require('gui.dwarfmode') -- globals may not be available yet local cursor = guidm.getCursorPos() if not cursor then arg_error(arg_name, diff --git a/library/lua/gui.lua b/library/lua/gui.lua index e22ddae20..ca3b212f0 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=df.global.init.texpos_border_interior, ch=32, fg=0, bg=0, write_to_lower=true} +CLEAR_PEN = to_pen{tile=dfhack.internal.getAddress('init') and 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/modules/Textures.cpp b/library/modules/Textures.cpp index 46dd0a4c5..d29cf02fb 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -121,6 +121,9 @@ static size_t load_textures(color_ostream & out, const char * fname, // unloaded. // void Textures::init(color_ostream &out) { + if (!enabler) + return; + auto & textures = enabler->textures; long num_textures = textures.raws.size(); if (num_textures <= g_dfhack_logo_texpos_start) From 95753f618c5096b2e9254ffdc486f59a53a57ca5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 1 Aug 2023 00:10:46 -0400 Subject: [PATCH 194/851] memscan: check for new Linux executable name --- library/lua/memscan.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua index 34b030d4e..4a9824010 100644 --- a/library/lua/memscan.lua +++ b/library/lua/memscan.lua @@ -243,6 +243,7 @@ local function find_data_segment() end elseif mem.read and mem.write and (string.match(mem.name,'/dwarfort%.exe$') + or string.match(mem.name,'/dwarfort$') or string.match(mem.name,'/Dwarf_Fortress$') or string.match(mem.name,'Dwarf Fortress%.exe')) then From e2ca506e2393d8bdfbc005d526438ac3246da779 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 1 Aug 2023 00:13:09 -0400 Subject: [PATCH 195/851] Fix off-by-one error in Textures::cleanup() In a ASCII-only configuration, I was seeing `textures.raws.size() == 164` and `texpos_end == 164`. This resulted in reading one item past the end of the vector. This may not be occurring in configurations with graphics enabled, or Windows/WINE may be more permissive. --- library/modules/Textures.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 46dd0a4c5..ae0836ffe 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -175,7 +175,7 @@ void Textures::cleanup() { auto & textures = enabler->textures; auto &raws = textures.raws; - size_t texpos_end = g_dfhack_logo_texpos_start + g_num_dfhack_textures; + size_t texpos_end = g_dfhack_logo_texpos_start + g_num_dfhack_textures - 1; for (size_t idx = g_dfhack_logo_texpos_start; idx <= texpos_end; ++idx) { DFSDL_FreeSurface((SDL_Surface *)raws[idx]); raws[idx] = NULL; From f44bbe15816d7a70297e86f9a7c32f7f2ae10bd7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 1 Aug 2023 04:21:22 +0000 Subject: [PATCH 196/851] [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.23.2 → 0.23.3](https://github.com/python-jsonschema/check-jsonschema/compare/0.23.2...0.23.3) --- .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 1d481edce..e7d0e23cf 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.23.2 + rev: 0.23.3 hooks: - id: check-github-workflows - repo: https://github.com/Lucas-C/pre-commit-hooks From 73f96209daa8fc7c43bef887179849de37b0f9fb Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 1 Aug 2023 00:08:30 -0400 Subject: [PATCH 197/851] Fix mangling of `plugin_globals` with GCC's C++11 ABI Without being declared with `extern "C"`, `plugin_globals` is mangled, with a `cxx11` suffix. We can't add `extern "C"` to the `DFhackDataExport` macro because GCC does not allow initializing any `extern` variables inline, including `extern "C"`. --- library/include/PluginManager.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/library/include/PluginManager.h b/library/include/PluginManager.h index f67023f93..5cf8bb390 100644 --- a/library/include/PluginManager.h +++ b/library/include/PluginManager.h @@ -298,14 +298,16 @@ namespace DFHack }; #define DFHACK_PLUGIN_AUX(m_plugin_name, is_dev) \ +extern "C" { \ DFhackDataExport const char * plugin_name = m_plugin_name;\ DFhackDataExport const char * plugin_version = DFHack::Version::dfhack_version();\ DFhackDataExport const char * plugin_git_description = DFHack::Version::git_description();\ DFhackDataExport int plugin_abi_version = DFHack::Version::dfhack_abi_version();\ DFhackDataExport DFHack::Plugin *plugin_self = NULL;\ - std::vector _plugin_globals;\ - DFhackDataExport std::vector* plugin_globals = &_plugin_globals; \ - DFhackDataExport bool plugin_dev = is_dev; + std::vector plugin_globals_noptr;\ + DFhackDataExport std::vector* plugin_globals = &plugin_globals_noptr; \ + DFhackDataExport bool plugin_dev = is_dev; \ +} /// You have to include DFHACK_PLUGIN("plugin_name") in every plugin you write - just once. Ideally at the top of the main file. #ifdef DEV_PLUGIN From 031a61a436e47dfb87910f34672b8fba6bf46e30 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 1 Aug 2023 00:18:28 -0400 Subject: [PATCH 198/851] Re-enable devel plugins that compile --- plugins/CMakeLists.txt | 2 +- plugins/devel/CMakeLists.txt | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index e393756a7..1b17ba0e5 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -21,7 +21,7 @@ endif() option(BUILD_DEV_PLUGINS "Build developer plugins." OFF) if(BUILD_DEV_PLUGINS) - #add_subdirectory(devel) + add_subdirectory(devel) endif() if(INSTALL_DATA_FILES) diff --git a/plugins/devel/CMakeLists.txt b/plugins/devel/CMakeLists.txt index febf169ca..c121d977f 100644 --- a/plugins/devel/CMakeLists.txt +++ b/plugins/devel/CMakeLists.txt @@ -14,16 +14,16 @@ dfhack_plugin(frozen frozen.cpp) dfhack_plugin(kittens kittens.cpp LINK_LIBRARIES ${CMAKE_THREAD_LIBS_INIT} COMPILE_FLAGS_MSVC "/wd4316") dfhack_plugin(memview memview.cpp memutils.cpp LINK_LIBRARIES lua) dfhack_plugin(onceExample onceExample.cpp) -dfhack_plugin(renderer-msg renderer-msg.cpp) -dfhack_plugin(rprobe rprobe.cpp) -dfhack_plugin(stepBetween stepBetween.cpp) +# dfhack_plugin(renderer-msg renderer-msg.cpp) +# dfhack_plugin(rprobe rprobe.cpp) +# dfhack_plugin(stepBetween stepBetween.cpp) dfhack_plugin(stockcheck stockcheck.cpp) dfhack_plugin(stripcaged stripcaged.cpp) dfhack_plugin(tilesieve tilesieve.cpp) -dfhack_plugin(zoom zoom.cpp) +# dfhack_plugin(zoom zoom.cpp) if(UNIX) dfhack_plugin(ref-index ref-index.cpp) endif() -add_subdirectory(check-structures-sanity) +# add_subdirectory(check-structures-sanity) From 199191e9d470a8c5a7d24716d9e0026e1be04b8d Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 1 Aug 2023 00:18:39 -0400 Subject: [PATCH 199/851] Re-add BUILD_SUPPORTED flag so that devel plugins can be built by themselves --- plugins/CMakeLists.txt | 195 +++++++++++++++++++++-------------------- 1 file changed, 99 insertions(+), 96 deletions(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 1b17ba0e5..6759225d1 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -75,102 +75,105 @@ set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) # If you are adding a plugin that you do not intend to commit to the DFHack repo, # 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(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(autodump autodump.cpp) -dfhack_plugin(autofarm autofarm.cpp) -#dfhack_plugin(autogems autogems.cpp LINK_LIBRARIES jsoncpp_static) -add_subdirectory(autolabor) -dfhack_plugin(autonestbox autonestbox.cpp LINK_LIBRARIES lua) -dfhack_plugin(autoslab autoslab.cpp) -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(changelayer changelayer.cpp) -dfhack_plugin(changevein changevein.cpp) -add_subdirectory(channel-safely) -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(cursecheck cursecheck.cpp) -dfhack_plugin(cxxrandom cxxrandom.cpp LINK_LIBRARIES lua) -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) -#dfhack_plugin(digFlood digFlood.cpp) -#add_subdirectory(diggingInvaders) -dfhack_plugin(dwarfvet dwarfvet.cpp LINK_LIBRARIES lua) -#dfhack_plugin(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua) -#add_subdirectory(embark-assistant) -#dfhack_plugin(embark-tools embark-tools.cpp) -dfhack_plugin(eventful eventful.cpp LINK_LIBRARIES lua) -dfhack_plugin(fastdwarf fastdwarf.cpp) -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(follow follow.cpp) -#dfhack_plugin(forceequip forceequip.cpp) -#dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp) -dfhack_plugin(getplants getplants.cpp) -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(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua) -dfhack_plugin(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) -dfhack_plugin(logistics logistics.cpp LINK_LIBRARIES lua) -#dfhack_plugin(manipulator manipulator.cpp) -#dfhack_plugin(map-render map-render.cpp LINK_LIBRARIES lua) -dfhack_plugin(misery misery.cpp LINK_LIBRARIES lua) -#dfhack_plugin(mode mode.cpp) -#dfhack_plugin(mousequery mousequery.cpp) -dfhack_plugin(nestboxes nestboxes.cpp) -dfhack_plugin(orders orders.cpp LINK_LIBRARIES jsoncpp_static lua) -dfhack_plugin(overlay overlay.cpp LINK_LIBRARIES lua) -dfhack_plugin(pathable pathable.cpp LINK_LIBRARIES lua) -#dfhack_plugin(petcapRemover petcapRemover.cpp) -#dfhack_plugin(plants plants.cpp) -dfhack_plugin(probe probe.cpp) -dfhack_plugin(prospector prospector.cpp LINK_LIBRARIES lua) -#dfhack_plugin(power-meter power-meter.cpp LINK_LIBRARIES lua) -dfhack_plugin(regrass regrass.cpp) -add_subdirectory(remotefortressreader) -#dfhack_plugin(rename rename.cpp LINK_LIBRARIES lua PROTOBUFS rename) -#add_subdirectory(rendermax) -dfhack_plugin(reveal reveal.cpp LINK_LIBRARIES lua) -#dfhack_plugin(search search.cpp) -dfhack_plugin(seedwatch seedwatch.cpp LINK_LIBRARIES lua) -dfhack_plugin(showmood showmood.cpp) -#dfhack_plugin(siege-engine siege-engine.cpp LINK_LIBRARIES lua) -#dfhack_plugin(sort sort.cpp LINK_LIBRARIES lua) -#dfhack_plugin(steam-engine steam-engine.cpp) -#add_subdirectory(spectate) -#dfhack_plugin(stockflow stockflow.cpp LINK_LIBRARIES lua) -add_subdirectory(stockpiles) -#dfhack_plugin(stocks stocks.cpp) -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(trackstop trackstop.cpp) -#dfhack_plugin(tubefill tubefill.cpp) -#add_subdirectory(tweak) -#dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua) -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 LINK_LIBRARIES lua) +option(BUILD_SUPPORTED "Build the supported plugins (reveal, probe, etc.)." ON) +if(BUILD_SUPPORTED) + dfhack_plugin(3dveins 3dveins.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) + dfhack_plugin(design design.cpp LINK_LIBRARIES lua) + dfhack_plugin(autodump autodump.cpp) + dfhack_plugin(autofarm autofarm.cpp) + #dfhack_plugin(autogems autogems.cpp LINK_LIBRARIES jsoncpp_static) + add_subdirectory(autolabor) + dfhack_plugin(autonestbox autonestbox.cpp LINK_LIBRARIES lua) + dfhack_plugin(autoslab autoslab.cpp) + 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(changelayer changelayer.cpp) + dfhack_plugin(changevein changevein.cpp) + add_subdirectory(channel-safely) + 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(cursecheck cursecheck.cpp) + dfhack_plugin(cxxrandom cxxrandom.cpp LINK_LIBRARIES lua) + 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) + #dfhack_plugin(digFlood digFlood.cpp) + #add_subdirectory(diggingInvaders) + dfhack_plugin(dwarfvet dwarfvet.cpp LINK_LIBRARIES lua) + #dfhack_plugin(dwarfmonitor dwarfmonitor.cpp LINK_LIBRARIES lua) + #add_subdirectory(embark-assistant) + #dfhack_plugin(embark-tools embark-tools.cpp) + dfhack_plugin(eventful eventful.cpp LINK_LIBRARIES lua) + dfhack_plugin(fastdwarf fastdwarf.cpp) + 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(follow follow.cpp) + #dfhack_plugin(forceequip forceequip.cpp) + #dfhack_plugin(generated-creature-renamer generated-creature-renamer.cpp) + dfhack_plugin(getplants getplants.cpp) + 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(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua) + dfhack_plugin(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) + dfhack_plugin(logistics logistics.cpp LINK_LIBRARIES lua) + #dfhack_plugin(manipulator manipulator.cpp) + #dfhack_plugin(map-render map-render.cpp LINK_LIBRARIES lua) + dfhack_plugin(misery misery.cpp LINK_LIBRARIES lua) + #dfhack_plugin(mode mode.cpp) + #dfhack_plugin(mousequery mousequery.cpp) + dfhack_plugin(nestboxes nestboxes.cpp) + dfhack_plugin(orders orders.cpp LINK_LIBRARIES jsoncpp_static lua) + dfhack_plugin(overlay overlay.cpp LINK_LIBRARIES lua) + dfhack_plugin(pathable pathable.cpp LINK_LIBRARIES lua) + #dfhack_plugin(petcapRemover petcapRemover.cpp) + #dfhack_plugin(plants plants.cpp) + dfhack_plugin(probe probe.cpp) + dfhack_plugin(prospector prospector.cpp LINK_LIBRARIES lua) + #dfhack_plugin(power-meter power-meter.cpp LINK_LIBRARIES lua) + dfhack_plugin(regrass regrass.cpp) + add_subdirectory(remotefortressreader) + #dfhack_plugin(rename rename.cpp LINK_LIBRARIES lua PROTOBUFS rename) + #add_subdirectory(rendermax) + dfhack_plugin(reveal reveal.cpp LINK_LIBRARIES lua) + #dfhack_plugin(search search.cpp) + dfhack_plugin(seedwatch seedwatch.cpp LINK_LIBRARIES lua) + dfhack_plugin(showmood showmood.cpp) + #dfhack_plugin(siege-engine siege-engine.cpp LINK_LIBRARIES lua) + #dfhack_plugin(sort sort.cpp LINK_LIBRARIES lua) + #dfhack_plugin(steam-engine steam-engine.cpp) + #add_subdirectory(spectate) + #dfhack_plugin(stockflow stockflow.cpp LINK_LIBRARIES lua) + add_subdirectory(stockpiles) + #dfhack_plugin(stocks stocks.cpp) + 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(trackstop trackstop.cpp) + #dfhack_plugin(tubefill tubefill.cpp) + #add_subdirectory(tweak) + #dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua) + 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 LINK_LIBRARIES lua) +endif(BUILD_SUPPORTED) # If you are adding a plugin that you do not intend to commit to the DFHack repo, # see instructions for adding "external" plugins at the end of this file. From 94dae7a1f119c290431685267cd7068c50aa7765 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 1 Aug 2023 00:59:26 -0400 Subject: [PATCH 200/851] dts::make_unique -> std::make_unique in unbuilt plugins Followup to #3537 --- plugins/devel/check-structures-sanity/types.cpp | 4 ++-- plugins/dwarfmonitor.cpp | 8 ++++---- plugins/embark-assistant/finder_ui.cpp | 2 +- plugins/embark-assistant/help_ui.cpp | 2 +- plugins/embark-tools.cpp | 2 +- plugins/manipulator.cpp | 10 +++++----- plugins/stocks.cpp | 8 ++++---- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/plugins/devel/check-structures-sanity/types.cpp b/plugins/devel/check-structures-sanity/types.cpp index 86d691f1d..3e6ae5a2d 100644 --- a/plugins/devel/check-structures-sanity/types.cpp +++ b/plugins/devel/check-structures-sanity/types.cpp @@ -162,7 +162,7 @@ type_identity *Checker::wrap_in_stl_ptr_vector(type_identity *base) { return it->second.get(); } - return (wrappers[base] = dts::make_unique(base, nullptr)).get(); + return (wrappers[base] = std::make_unique(base, nullptr)).get(); } type_identity *Checker::wrap_in_pointer(type_identity *base) @@ -173,7 +173,7 @@ type_identity *Checker::wrap_in_pointer(type_identity *base) { return it->second.get(); } - return (wrappers[base] = dts::make_unique(base)).get(); + return (wrappers[base] = std::make_unique(base)).get(); } std::map> known_types_by_size; diff --git a/plugins/dwarfmonitor.cpp b/plugins/dwarfmonitor.cpp index 2b546bfad..27e5b87e0 100644 --- a/plugins/dwarfmonitor.cpp +++ b/plugins/dwarfmonitor.cpp @@ -951,7 +951,7 @@ public: { df::unit *selected_unit = (selected_column == 1) ? dwarf_activity_column.getFirstSelectedElem() : nullptr; Screen::dismiss(this); - Screen::show(dts::make_unique(selected_unit), plugin_self); + Screen::show(std::make_unique(selected_unit), plugin_self); } else if (input->count(interface_key::CUSTOM_SHIFT_Z)) { @@ -1676,7 +1676,7 @@ private: static void open_stats_screen() { - Screen::show(dts::make_unique(), plugin_self); + Screen::show(std::make_unique(), plugin_self); } static void add_work_history(df::unit *unit, activity_type type) { @@ -1776,12 +1776,12 @@ static command_result dwarfmonitor_cmd(color_ostream &, vector & parame if (cmd == 's' || cmd == 'S') { CoreSuspender guard; if(Maps::IsValid()) - Screen::show(dts::make_unique(), plugin_self); + Screen::show(std::make_unique(), plugin_self); } else if (cmd == 'p' || cmd == 'P') { CoreSuspender guard; if(Maps::IsValid()) - Screen::show(dts::make_unique(), plugin_self); + Screen::show(std::make_unique(), plugin_self); } else return CR_WRONG_USAGE; diff --git a/plugins/embark-assistant/finder_ui.cpp b/plugins/embark-assistant/finder_ui.cpp index 6501f7f21..9a76794c2 100644 --- a/plugins/embark-assistant/finder_ui.cpp +++ b/plugins/embark-assistant/finder_ui.cpp @@ -1805,7 +1805,7 @@ void embark_assist::finder_ui::init(DFHack::Plugin *plugin_self, embark_assist:: embark_assist::finder_ui::ui_setup(find_callback, max_inorganic); } if (!fileresult) { - Screen::show(dts::make_unique(), plugin_self); + Screen::show(std::make_unique(), plugin_self); } else { diff --git a/plugins/embark-assistant/help_ui.cpp b/plugins/embark-assistant/help_ui.cpp index a49a9b5e0..804617d92 100644 --- a/plugins/embark-assistant/help_ui.cpp +++ b/plugins/embark-assistant/help_ui.cpp @@ -411,5 +411,5 @@ namespace embark_assist{ //=============================================================================== void embark_assist::help_ui::init(DFHack::Plugin *plugin_self) { - Screen::show(dts::make_unique(), plugin_self); + Screen::show(std::make_unique(), plugin_self); } diff --git a/plugins/embark-tools.cpp b/plugins/embark-tools.cpp index 924def798..19e4ef7b6 100644 --- a/plugins/embark-tools.cpp +++ b/plugins/embark-tools.cpp @@ -694,7 +694,7 @@ struct choose_start_site_hook : df::viewscreen_choose_start_sitest void display_settings() { - Screen::show(dts::make_unique(), plugin_self); + Screen::show(std::make_unique(), plugin_self); } inline bool is_valid_page() diff --git a/plugins/manipulator.cpp b/plugins/manipulator.cpp index b8f6ce706..0a8e18a27 100644 --- a/plugins/manipulator.cpp +++ b/plugins/manipulator.cpp @@ -1875,14 +1875,14 @@ void viewscreen_unitlaborsst::feed(set *events) if (events->count(interface_key::CUSTOM_B)) { - Screen::show(dts::make_unique(units, true, &do_refresh_names), plugin_self); + Screen::show(std::make_unique(units, true, &do_refresh_names), plugin_self); } if (events->count(interface_key::CUSTOM_E)) { vector tmp; tmp.push_back(cur); - Screen::show(dts::make_unique(tmp, false, &do_refresh_names), plugin_self); + Screen::show(std::make_unique(tmp, false, &do_refresh_names), plugin_self); } if (events->count(interface_key::CUSTOM_P)) @@ -1893,11 +1893,11 @@ void viewscreen_unitlaborsst::feed(set *events) has_selected = true; if (has_selected) { - Screen::show(dts::make_unique(units, true), plugin_self); + Screen::show(std::make_unique(units, true), plugin_self); } else { vector tmp; tmp.push_back(cur); - Screen::show(dts::make_unique(tmp, false), plugin_self); + Screen::show(std::make_unique(tmp, false), plugin_self); } } @@ -2286,7 +2286,7 @@ struct unitlist_hook : df::viewscreen_unitlistst { if (units[page].size()) { - Screen::show(dts::make_unique(units[page], cursor_pos[page]), plugin_self); + Screen::show(std::make_unique(units[page], cursor_pos[page]), plugin_self); return; } } diff --git a/plugins/stocks.cpp b/plugins/stocks.cpp index 8cc27067c..40ebdc960 100644 --- a/plugins/stocks.cpp +++ b/plugins/stocks.cpp @@ -685,7 +685,7 @@ public: } else if (input->count(interface_key::HELP)) { - Screen::show(dts::make_unique(), plugin_self); + Screen::show(std::make_unique(), plugin_self); } bool key_processed = false; @@ -1350,7 +1350,7 @@ struct stocks_hook : public df::viewscreen_storesst if (input->count(interface_key::CUSTOM_E)) { Screen::dismiss(this); - Screen::show(dts::make_unique(), plugin_self); + Screen::show(std::make_unique(), plugin_self); return; } INTERPOSE_NEXT(feed)(input); @@ -1385,7 +1385,7 @@ struct stocks_stockpile_hook : public df::viewscreen_dwarfmodest if (input->count(interface_key::CUSTOM_I)) { - Screen::show(dts::make_unique(sp), plugin_self); + Screen::show(std::make_unique(sp), plugin_self); return true; } @@ -1459,7 +1459,7 @@ static command_result stocks_cmd(color_ostream &out, vector & parameter } else if (toLower(parameters[0])[0] == 's') { - Screen::show(dts::make_unique(), plugin_self); + Screen::show(std::make_unique(), plugin_self); return CR_OK; } } From 0c6441619f5264069c9f636024c620ea14af38f6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 1 Aug 2023 00:59:52 -0400 Subject: [PATCH 201/851] Re-enable build of check-structures-sanity --- plugins/devel/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/devel/CMakeLists.txt b/plugins/devel/CMakeLists.txt index c121d977f..210669a75 100644 --- a/plugins/devel/CMakeLists.txt +++ b/plugins/devel/CMakeLists.txt @@ -26,4 +26,4 @@ if(UNIX) dfhack_plugin(ref-index ref-index.cpp) endif() -# add_subdirectory(check-structures-sanity) +add_subdirectory(check-structures-sanity) From a3916cdbb65054f242489682f6074e007122e4da Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 1 Aug 2023 01:54:35 -0400 Subject: [PATCH 202/851] check-structures-sanity: update detection for GCC C++11 std::string --- .../check-structures-sanity/dispatch.cpp | 64 +++++++------------ 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/plugins/devel/check-structures-sanity/dispatch.cpp b/plugins/devel/check-structures-sanity/dispatch.cpp index 05dcc0377..1dcc63193 100644 --- a/plugins/devel/check-structures-sanity/dispatch.cpp +++ b/plugins/devel/check-structures-sanity/dispatch.cpp @@ -1,5 +1,7 @@ #include "check-structures-sanity.h" +#include + #include "df/large_integer.h" Checker::Checker(color_ostream & out) : @@ -845,69 +847,51 @@ void Checker::check_stl_string(const QueueItem & item) #else struct string_data { - struct string_data_inner + uintptr_t start; + size_t length; + union { - size_t length; + char local_data[16]; size_t capacity; - int32_t refcount; - } *ptr; + }; }; #endif auto string = reinterpret_cast(item.ptr); #ifdef WIN32 - bool is_local = string->capacity < 16; + const bool is_gcc = false; + const bool is_local = string->capacity < 16; +#else + const bool is_gcc = true; + const bool is_local = string->start == reinterpret_cast(&string->local_data[0]); +#endif const char *start = is_local ? &string->local_data[0] : reinterpret_cast(string->start); ptrdiff_t length = string->length; ptrdiff_t capacity = string->capacity; -#else - if (!is_valid_dereference(QueueItem(item, "?ptr?", string->ptr), 1)) + + (void)start; + if (length < 0) { - // nullptr is NOT okay here - FAIL("invalid string pointer " << stl_sprintf("%p", string->ptr)); - return; + FAIL("string length is negative (" << length << ")"); } - if (!is_valid_dereference(QueueItem(item, "?hdr?", string->ptr - 1), sizeof(*string->ptr))) + else if (is_gcc && length > 0 && !is_valid_dereference(QueueItem(item, "?start?", reinterpret_cast(string->start)), 1)) { + // nullptr is NOT okay here + FAIL("invalid string pointer " << stl_sprintf("0x%" PRIxPTR, string->start)); return; } - const char *start = reinterpret_cast(string->ptr); - ptrdiff_t length = (string->ptr - 1)->length; - ptrdiff_t capacity = (string->ptr - 1)->capacity; -#endif - - (void)start; - if (length < 0) + else if (is_local && length >= 16) { - FAIL("string length is negative (" << length << ")"); + FAIL("string length is too large for small string (" << length << ")"); } - else if (capacity < 0) + else if ((!is_gcc || !is_local) && capacity < 0) { FAIL("string capacity is negative (" << capacity << ")"); } - else if (capacity < length) + else if ((!is_gcc || !is_local) && capacity < length) { FAIL("string capacity (" << capacity << ") is less than length (" << length << ")"); } - -#ifndef WIN32 - const std::string empty_string; - auto empty_string_data = reinterpret_cast(&empty_string); - if (sizes && string->ptr != empty_string_data->ptr) - { - size_t allocated_size = get_allocated_size(QueueItem(item, "?hdr?", string->ptr - 1)); - size_t expected_size = sizeof(*string->ptr) + capacity + 1; - - if (!allocated_size) - { - FAIL("pointer does not appear to be a string"); - } - else if (allocated_size != expected_size) - { - FAIL("allocated string data size (" << allocated_size << ") does not match expected size (" << expected_size << ")"); - } - } -#endif } void Checker::check_possible_pointer(const QueueItem & item, const CheckedStructure & cs) { From a299f0b5fb1f36047c60352b1a775010edf15d9c Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 1 Aug 2023 06:33:09 +0000 Subject: [PATCH 203/851] 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 dd2f99f14..fc4961f51 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit dd2f99f1498b903bb9ed28542b652e4c00d8188c +Subproject commit fc4961f51f2773cff0dfe76e3ad719c027051046 diff --git a/scripts b/scripts index f49836f88..8a6528e90 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit f49836f88936999cca127218c6ec043e3daa51b0 +Subproject commit 8a6528e9084eda4b9fd19c19ffc412ab3e67d016 From 69986a4bf7a01939dabd687c791f277821893151 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 1 Aug 2023 00:11:46 -0700 Subject: [PATCH 204/851] autodeploy to steam on tag --- .github/workflows/github-release.yml | 11 ++++++----- .github/workflows/steam-deploy.yml | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 04118ed71..b2d8e3a0d 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -4,10 +4,11 @@ on: push: tags: - '*-r[0-9]+' + workflow_dispatch: inputs: - tag: - description: tag + ref: + description: Tag required: true jobs: @@ -16,7 +17,7 @@ jobs: uses: ./.github/workflows/build-windows.yml with: artifact-name: win64-release - ref: ${{ github.event.inputs.tag }} + ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} cache-id: release cache-readonly: true stonesense: true @@ -29,7 +30,7 @@ jobs: uses: ./.github/workflows/build-linux.yml with: artifact-name: linux64-release - ref: ${{ github.event.inputs.tag }} + ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} cache-id: release cache-readonly: true stonesense: true @@ -48,7 +49,7 @@ jobs: - name: Clone DFHack uses: actions/checkout@v3 with: - ref: ${{ github.event.inputs.tag }} + ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} submodules: true - name: Get tag id: gettag diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index 1b9898c76..88d28d679 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -1,6 +1,10 @@ name: Deploy to Steam on: + push: + tags: + - '*' + workflow_dispatch: inputs: ref: @@ -24,7 +28,7 @@ jobs: uses: ./.github/workflows/build-linux.yml with: artifact-name: common-depot - ref: ${{ github.event.inputs.ref }} + ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} platform-files: false docs: true stonesense: true @@ -35,7 +39,7 @@ jobs: uses: ./.github/workflows/build-windows.yml with: artifact-name: win64-depot - ref: ${{ github.event.inputs.ref }} + ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} cache-id: release cache-readonly: true common-files: false @@ -47,7 +51,7 @@ jobs: uses: ./.github/workflows/build-linux.yml with: artifact-name: linux64-depot - ref: ${{ github.event.inputs.ref }} + ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} cache-id: release cache-readonly: true common-files: false @@ -61,7 +65,10 @@ jobs: - depot-win64 - depot-linux64 runs-on: ubuntu-latest + concurrency: steam steps: + - name: Set env + run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Stage common depot files uses: actions/download-artifact@v3 with: @@ -83,9 +90,9 @@ jobs: username: ${{ secrets.STEAM_USERNAME }} configVdf: ${{ secrets.STEAM_CONFIG_VDF}} appId: 2346660 - buildDescription: ${{ github.event.inputs.version }} + buildDescription: ${{ github.event.inputs && github.event.inputs.version || env.TAG }} rootPath: . depot1Path: common depot2Path: win64 depot3Path: linux64 - releaseBranch: ${{ github.event.inputs.release_channel }} + releaseBranch: ${{ github.event.inputs && github.event.inputs.release_channel || 'staging' }} From e5bc4b32214f42cd5d25f5e6480a6f5d16bc65fc Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 28 May 2023 02:50:39 -0400 Subject: [PATCH 205/851] Add identity for std::mutex --- library/include/DataIdentity.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index fd47429b9..c5ce0fb73 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -25,10 +25,11 @@ distribution. #pragma once #include -#include +#include +#include #include +#include #include -#include #include "DataDefs.h" @@ -570,6 +571,11 @@ namespace df static opaque_identity *get() { return &identity; } }; + template<> struct DFHACK_EXPORT identity_traits { + static opaque_identity identity; + static opaque_identity *get() { return &identity; } + }; + template<> struct DFHACK_EXPORT identity_traits { static ptr_string_identity identity; static ptr_string_identity *get() { return &identity; } From 7c4d9364a25a1c2be8111221db08d4b3e691a6e5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 28 May 2023 02:51:06 -0400 Subject: [PATCH 206/851] Make allocator_fn compile for non-copy-assignable types like std::mutex --- library/include/DataDefs.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index 174156e76..7d840a9ad 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -497,11 +497,25 @@ namespace df using DFHack::DfLinkedList; using DFHack::DfOtherVectors; + template + typename std::enable_if< + std::is_copy_assignable::value + >::type allocator_try_assign(void *out, const void *in) { + *(T*)out = *(const T*)in; + } + + template + typename std::enable_if< + !std::is_copy_assignable::value + >::type allocator_try_assign(void *out, const void *in) { + // assignment is not possible; do nothing + } + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" template void *allocator_fn(void *out, const void *in) { - if (out) { *(T*)out = *(const T*)in; return out; } + if (out) { allocator_try_assign(out, in); return out; } else if (in) { delete (T*)in; return (T*)in; } else return new T(); } From 6fbb22e9127ae9e43e2346457167f43acf1712cf Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 28 May 2023 13:07:21 -0400 Subject: [PATCH 207/851] Add missing instantion for identity_traits, refactor code shared with fstream identity --- library/DataStaticsFields.cpp | 12 +++++------- library/include/DataDefs.h | 7 +++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp index 8318b523d..ac2b415eb 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataStaticsFields.cpp @@ -17,6 +17,9 @@ namespace df { category##_identity identity_traits::identity(name); #define INTEGER_IDENTITY_TRAITS(type, name) NUMBER_IDENTITY_TRAITS(integer, type, name) #define FLOAT_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(float, type, #type) +#define OPAQUE_IDENTITY_TRAITS_NAME(type, name) \ + opaque_identity identity_traits::identity(sizeof(type), allocator_noassign_fn, name) +#define STL_OPAQUE_IDENTITY_TRAITS(type) OPAQUE_IDENTITY_TRAITS_NAME(std::type, #type) #ifndef STATIC_FIELDS_GROUP INTEGER_IDENTITY_TRAITS(char, "char"); @@ -42,13 +45,8 @@ namespace df { stl_bit_vector_identity identity_traits >::identity; bit_array_identity identity_traits >::identity; - static void *fstream_allocator_fn(void *out, const void *in) { - if (out) { /* *(T*)out = *(const T*)in;*/ return NULL; } - else if (in) { delete (std::fstream*)in; return (std::fstream*)in; } - else return new std::fstream(); - } - opaque_identity identity_traits::identity( - sizeof(std::fstream), fstream_allocator_fn, "fstream"); + STL_OPAQUE_IDENTITY_TRAITS(fstream); + STL_OPAQUE_IDENTITY_TRAITS(mutex); buffer_container_identity buffer_container_identity::base_instance; #endif diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index 7d840a9ad..0109f0fd0 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -528,6 +528,13 @@ namespace df else return new T(); } + template + void *allocator_noassign_fn(void *out, const void *in) { + if (out) { return NULL; } + else if (in) { delete (T*)in; return (T*)in; } + else return new T(); + } + template struct identity_traits { static compound_identity *get() { return &T::_identity; } From d0250ae4261ad009167d12ec36b5d56a330f903a Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 28 May 2023 13:08:06 -0400 Subject: [PATCH 208/851] Update allocator_try_assign() to match behavior of fstream allocator for non-copyable types Looks like the choice we have made here previously is to return NULL if attempting to allocate types that we cannot allocate. --- library/include/DataDefs.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index 0109f0fd0..e03e9a0a8 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -499,23 +499,27 @@ namespace df template typename std::enable_if< - std::is_copy_assignable::value + std::is_copy_assignable::value, + void* >::type allocator_try_assign(void *out, const void *in) { *(T*)out = *(const T*)in; + return out; } template typename std::enable_if< - !std::is_copy_assignable::value + !std::is_copy_assignable::value, + void* >::type allocator_try_assign(void *out, const void *in) { // assignment is not possible; do nothing + return NULL; } #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" template void *allocator_fn(void *out, const void *in) { - if (out) { allocator_try_assign(out, in); return out; } + if (out) { return allocator_try_assign(out, in); } else if (in) { delete (T*)in; return (T*)in; } else return new T(); } From eb12ff17f6fc71a8b7c78c91ad46959c2e640555 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 28 May 2023 13:21:49 -0400 Subject: [PATCH 209/851] Refactor: move static identity_traits to their own file, simplify field defs DataStaticsFields.cpp used to contain identity_traits specializations for primitive and opaque STL types, as well as macros used for the generated struct field definitions. Only one of these were actually used in any compilation unit, and the identity_traits definitions were hidden behind a guard to prevent them from being compiled at all when building the struct field definitions. Now, the identity_traits specializations live in their own file, DataIdentity.cpp (matching their declarations, which live in DataIdentity.h). This speeds up build times because modifying these specializations no longer requires rebuilding all of the field definitions unnecessarily. --- library/CMakeLists.txt | 11 +++++----- ...DataStaticsFields.cpp => DataIdentity.cpp} | 22 +++---------------- library/include/DataStaticsFields.inc | 15 +++++++++++++ library/modules/Screen.cpp | 3 +-- 4 files changed, 24 insertions(+), 27 deletions(-) rename library/{DataStaticsFields.cpp => DataIdentity.cpp} (74%) create mode 100644 library/include/DataStaticsFields.inc diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 8b1b7f65d..2ea2d830f 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -62,6 +62,7 @@ set(MAIN_SOURCES ColorText.cpp CompilerWorkAround.cpp DataDefs.cpp + DataIdentity.cpp Debug.cpp Error.cpp VTableInterpose.cpp @@ -71,7 +72,6 @@ set(MAIN_SOURCES LuaApi.cpp DataStatics.cpp DataStaticsCtor.cpp - DataStaticsFields.cpp MiscUtils.cpp Types.cpp PluginManager.cpp @@ -186,8 +186,7 @@ foreach(GROUP other a b c d e f g h i j k l m n o p q r s t u v w x y z) set(STATIC_FIELDS_INC_FILENAME "df/static.fields-${GROUP}.inc") endif() file(WRITE ${STATIC_FIELDS_FILENAME}.tmp - "#define STATIC_FIELDS_GROUP\n" - "#include \"../DataStaticsFields.cpp\"\n" + "#include \"DataStaticsFields.inc\"\n" "#include \"${STATIC_FIELDS_INC_FILENAME}\"\n" ) execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different @@ -294,15 +293,15 @@ add_custom_target(generate_headers if(REMOVE_SYMBOLS_FROM_DF_STUBS) if(UNIX) # Don't produce debug info for generated stubs - set_source_files_properties(DataStatics.cpp DataStaticsCtor.cpp DataStaticsFields.cpp ${STATIC_FIELDS_FILES} + set_source_files_properties(DataStatics.cpp DataStaticsCtor.cpp ${STATIC_FIELDS_FILES} PROPERTIES COMPILE_FLAGS "-g0 -O1") else(WIN32) - set_source_files_properties(DataStatics.cpp DataStaticsCtor.cpp DataStaticsFields.cpp ${STATIC_FIELDS_FILES} + set_source_files_properties(DataStatics.cpp DataStaticsCtor.cpp ${STATIC_FIELDS_FILES} PROPERTIES COMPILE_FLAGS "/O1 /bigobj") endif() else() if(WIN32) - set_source_files_properties(DataStatics.cpp DataStaticsCtor.cpp DataStaticsFields.cpp ${STATIC_FIELDS_FILES} + set_source_files_properties(DataStatics.cpp DataStaticsCtor.cpp ${STATIC_FIELDS_FILES} PROPERTIES COMPILE_FLAGS "/Od /bigobj") endif() endif() diff --git a/library/DataStaticsFields.cpp b/library/DataIdentity.cpp similarity index 74% rename from library/DataStaticsFields.cpp rename to library/DataIdentity.cpp index ac2b415eb..f6a1c2de8 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataIdentity.cpp @@ -1,17 +1,12 @@ #include #include - -#ifndef STATIC_FIELDS_GROUP -#include "DataDefs.h" -#endif +#include +#include +#include #include "DataFuncs.h" -#ifdef __GNUC__ -#pragma GCC diagnostic ignored "-Winvalid-offsetof" -#endif - namespace df { #define NUMBER_IDENTITY_TRAITS(category, type, name) \ category##_identity identity_traits::identity(name); @@ -50,15 +45,4 @@ namespace df { buffer_container_identity buffer_container_identity::base_instance; #endif -#undef NUMBER_IDENTITY_TRAITS -#undef INTEGER_IDENTITY_TRAITS -#undef FLOAT_IDENTITY_TRAITS } - -#define TID(type) (&identity_traits< type >::identity) - -#define FLD(mode, name) struct_field_info::mode, #name, offsetof(CUR_STRUCT, name) -#define GFLD(mode, name) struct_field_info::mode, #name, (size_t)&df::global::name -#define METHOD(mode, name) struct_field_info::mode, #name, 0, wrap_function(&CUR_STRUCT::name) -#define METHOD_N(mode, func, name) struct_field_info::mode, #name, 0, wrap_function(&CUR_STRUCT::func) -#define FLD_END struct_field_info::END diff --git a/library/include/DataStaticsFields.inc b/library/include/DataStaticsFields.inc new file mode 100644 index 000000000..97a036b58 --- /dev/null +++ b/library/include/DataStaticsFields.inc @@ -0,0 +1,15 @@ +#include + +#include "DataFuncs.h" + +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif + +#define TID(type) (&identity_traits< type >::identity) + +#define FLD(mode, name) struct_field_info::mode, #name, offsetof(CUR_STRUCT, name) +#define GFLD(mode, name) struct_field_info::mode, #name, (size_t)&df::global::name +#define METHOD(mode, name) struct_field_info::mode, #name, 0, wrap_function(&CUR_STRUCT::name) +#define METHOD_N(mode, func, name) struct_field_info::mode, #name, 0, wrap_function(&CUR_STRUCT::func) +#define FLD_END struct_field_info::END diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index c7ef88c60..2ee91a089 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -1092,8 +1092,7 @@ df::plant *dfhack_lua_viewscreen::getSelectedPlant() return Lua::GetDFObject(Lua::Core::State, -1); } -#define STATIC_FIELDS_GROUP -#include "../DataStaticsFields.cpp" +#include "DataStaticsFields.inc" using df::identity_traits; From 2f427451758e6d3467e94da8dd3f202dfbe36e5e Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 29 May 2023 01:09:59 -0400 Subject: [PATCH 210/851] Add identity_traits, add macro for opaque identities --- library/DataIdentity.cpp | 1 + library/include/DataIdentity.h | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/library/DataIdentity.cpp b/library/DataIdentity.cpp index f6a1c2de8..0f85e5d95 100644 --- a/library/DataIdentity.cpp +++ b/library/DataIdentity.cpp @@ -40,6 +40,7 @@ namespace df { stl_bit_vector_identity identity_traits >::identity; bit_array_identity identity_traits >::identity; + STL_OPAQUE_IDENTITY_TRAITS(condition_variable); STL_OPAQUE_IDENTITY_TRAITS(fstream); STL_OPAQUE_IDENTITY_TRAITS(mutex); diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index c5ce0fb73..232b32108 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -24,6 +24,7 @@ distribution. #pragma once +#include #include #include #include @@ -542,6 +543,12 @@ namespace df #define INTEGER_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(integer, type) #define FLOAT_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(float, type) +#define OPAQUE_IDENTITY_TRAITS(type) \ + template<> struct DFHACK_EXPORT identity_traits { \ + static opaque_identity identity; \ + static opaque_identity *get() { return &identity; } \ + }; + INTEGER_IDENTITY_TRAITS(char); INTEGER_IDENTITY_TRAITS(signed char); INTEGER_IDENTITY_TRAITS(unsigned char); @@ -555,6 +562,9 @@ namespace df INTEGER_IDENTITY_TRAITS(unsigned long long); FLOAT_IDENTITY_TRAITS(float); FLOAT_IDENTITY_TRAITS(double); + OPAQUE_IDENTITY_TRAITS(std::condition_variable); + OPAQUE_IDENTITY_TRAITS(std::fstream); + OPAQUE_IDENTITY_TRAITS(std::mutex); template<> struct DFHACK_EXPORT identity_traits { static bool_identity identity; @@ -566,16 +576,6 @@ namespace df static stl_string_identity *get() { return &identity; } }; - template<> struct DFHACK_EXPORT identity_traits { - static opaque_identity identity; - static opaque_identity *get() { return &identity; } - }; - - template<> struct DFHACK_EXPORT identity_traits { - static opaque_identity identity; - static opaque_identity *get() { return &identity; } - }; - template<> struct DFHACK_EXPORT identity_traits { static ptr_string_identity identity; static ptr_string_identity *get() { return &identity; } @@ -604,6 +604,7 @@ namespace df #undef NUMBER_IDENTITY_TRAITS #undef INTEGER_IDENTITY_TRAITS #undef FLOAT_IDENTITY_TRAITS +#undef OPAQUE_IDENTITY_TRAITS // Container declarations From 8b786b43446d3e50d3e0d906bc70ba65b70742bf Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 29 May 2023 01:12:35 -0400 Subject: [PATCH 211/851] Forward-declare types only used in DataIdentity.cpp --- library/DataIdentity.cpp | 2 ++ library/include/DataIdentity.h | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/library/DataIdentity.cpp b/library/DataIdentity.cpp index 0f85e5d95..03851520c 100644 --- a/library/DataIdentity.cpp +++ b/library/DataIdentity.cpp @@ -1,11 +1,13 @@ #include +#include #include #include #include #include #include "DataFuncs.h" +#include "DataIdentity.h" namespace df { #define NUMBER_IDENTITY_TRAITS(category, type, name) \ diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index 232b32108..be5466444 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -24,16 +24,19 @@ distribution. #pragma once -#include #include #include -#include #include #include #include #include "DataDefs.h" +namespace std { + class condition_variable; + class mutex; +}; + /* * Definitions of DFHack namespace structs used by generated headers. */ From 5c4175e3c3175e90903b10d425d0fcebd7b84934 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 2 Aug 2023 22:58:09 -0400 Subject: [PATCH 212/851] Update xml --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index fc4961f51..c87d2263c 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit fc4961f51f2773cff0dfe76e3ad719c027051046 +Subproject commit c87d2263c4e801d2b2b1d619a84ae5ba535fd453 From 1f9b248f8a8be439c62d4c6e515e33ac441a95d2 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 2 Aug 2023 23:49:10 -0400 Subject: [PATCH 213/851] check-structures-sanity: add no-op handler for std::map --- plugins/devel/check-structures-sanity/dispatch.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/devel/check-structures-sanity/dispatch.cpp b/plugins/devel/check-structures-sanity/dispatch.cpp index 1dcc63193..37e4757fa 100644 --- a/plugins/devel/check-structures-sanity/dispatch.cpp +++ b/plugins/devel/check-structures-sanity/dispatch.cpp @@ -377,6 +377,10 @@ void Checker::dispatch_container(const QueueItem & item, const CheckedStructure { // TODO: check DfArray } + else if (base_container.substr(0, 4) == "map<") + { + // TODO: check map + } else { UNEXPECTED; From 794bcc67b0fadf90b026c198f2e93e79e893567e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 2 Aug 2023 20:52:05 -0700 Subject: [PATCH 214/851] fix windows build vars for github release --- .github/workflows/github-release.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index b2d8e3a0d..3adabe0db 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -20,8 +20,6 @@ jobs: ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} cache-id: release cache-readonly: true - stonesense: true - docs: true launchdf: true secrets: inherit From 88dd2738038ebba0fc5b62bb9a22fa886be1c37f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 2 Aug 2023 23:33:07 -0700 Subject: [PATCH 215/851] remove buildmaster integration files --- .github/workflows/buildmaster-rebuild.yml | 35 ----------- ci/buildmaster-rebuild-pr.py | 71 ----------------------- 2 files changed, 106 deletions(-) delete mode 100644 .github/workflows/buildmaster-rebuild.yml delete mode 100755 ci/buildmaster-rebuild-pr.py diff --git a/.github/workflows/buildmaster-rebuild.yml b/.github/workflows/buildmaster-rebuild.yml deleted file mode 100644 index d4c7a70e6..000000000 --- a/.github/workflows/buildmaster-rebuild.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Buildmaster rebuild - -on: - workflow_dispatch: - inputs: - pull_request: - description: Pull request ID - type: string - required: true # remove if we support commit rebuilds later - -jobs: - rebuild: - runs-on: ubuntu-latest - name: Trigger Buildmaster - steps: - - name: Set up Python 3 - uses: actions/setup-python@v4 - with: - python-version: 3 - - name: Install dependencies - run: | - pip install requests - - name: Clone DFHack - uses: actions/checkout@v1 - with: - fetch-depth: 1 - submodules: false - - name: Run - env: - DFHACK_BUILDMASTER_WEBHOOK_URL: ${{ secrets.DFHACK_BUILDMASTER_WEBHOOK_URL }} - DFHACK_BUILDMASTER_WEBHOOK_SECRET: ${{ secrets.DFHACK_BUILDMASTER_WEBHOOK_SECRET }} - GITHUB_REPO: ${{ github.repository }} - GITHUB_TOKEN: ${{ github.token }} - run: | - python ci/buildmaster-rebuild-pr.py --pull-request ${{ github.event.inputs.pull_request }} diff --git a/ci/buildmaster-rebuild-pr.py b/ci/buildmaster-rebuild-pr.py deleted file mode 100755 index 7ce988683..000000000 --- a/ci/buildmaster-rebuild-pr.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import hashlib -import hmac -import json -import logging -import os -import uuid - -import requests - -logging.basicConfig(level=logging.DEBUG) - - -def get_required_env(name): - value = os.environ.get(name) - if not value: - raise ValueError(f'Expected environment variable {name!r} to be non-empty') - return value - - -def make_sig(body, secret, algorithm): - return hmac.new(secret.encode(), body.encode(), algorithm).hexdigest() - - -webhook_url = get_required_env('DFHACK_BUILDMASTER_WEBHOOK_URL') -secret = get_required_env('DFHACK_BUILDMASTER_WEBHOOK_SECRET') -api_token = get_required_env('GITHUB_TOKEN') -repo = get_required_env('GITHUB_REPO') - - -parser = argparse.ArgumentParser() -target_group = parser.add_mutually_exclusive_group(required=True) -target_group.add_argument('--pull-request', type=int, help='Pull request to rebuild') -args = parser.parse_args() - - -response = requests.get( - f'https://api.github.com/repos/{repo}/pulls/{args.pull_request}', - headers={ - 'Authorization': f'Bearer {api_token}', - }, -) -response.raise_for_status() -pull_request_data = response.json() - - -body = json.dumps({ - 'action': 'synchronize', - 'number': args.pull_request, - 'pull_request': pull_request_data, -}) - -response = requests.post( - 'https://lubar-webhook-proxy.appspot.com/github/buildmaster', - headers={ - 'Content-Type': 'application/json', - 'User-Agent': 'GitHub-Hookshot/' + requests.utils.default_user_agent(), - 'X-GitHub-Delivery': 'dfhack-rebuild-' + str(uuid.uuid4()), - 'X-GitHub-Event': 'pull_request', - 'X-Hub-Signature': 'sha1=' + make_sig(body, secret, hashlib.sha1), - 'X-Hub-Signature-256': 'sha256=' + make_sig(body, secret, hashlib.sha256), - }, - data=body, - timeout=15, -) - -print(response) -print(str(response.text)) -response.raise_for_status() From 38d17cbdceba8e6f9c37697a3898efcb35bff14a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 00:25:20 -0700 Subject: [PATCH 216/851] make lint job reusable --- .github/workflows/build.yml | 25 ++++----------------- .github/workflows/lint.yml | 45 +++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 21 deletions(-) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e10894696..454b530fa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -100,27 +100,10 @@ jobs: secrets: inherit lint: - runs-on: ubuntu-latest - steps: - - name: Install Lua - run: | - sudo apt-get update - sudo apt-get install lua5.3 - - name: Clone DFHack - uses: actions/checkout@v3 - with: - submodules: true - - name: Check whitespace - run: python ci/lint.py --git-only --github-actions - - name: Check Authors.rst - if: always() - run: python ci/authors-rst.py - - name: Check for missing documentation - if: always() - run: python ci/script-docs.py - - name: Check Lua syntax - if: always() - run: python ci/script-syntax.py --ext=lua --cmd="luac5.3 -p" --github-actions + uses: ./.github/workflows/lint.yml + with: + dfhack_ref: ${{ github.ref }} + secrets: inherit check-pr: runs-on: ubuntu-latest diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..348068c0a --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,45 @@ +name: Lint + +on: + workflow_call: + inputs: + dfhack_ref: + type: string + required: true + scripts_ref: + type: string + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - name: Install Lua + run: | + sudo apt-get update + sudo apt-get install lua5.3 + - name: Clone DFHack + uses: actions/checkout@v3 + with: + repository: 'DFHack/dfhack' + ref: ${{ inputs.dfhack_ref }} + - name: Get scripts submodule ref + if: '!inputs.scripts_ref' + id: scriptssubmoduleref + run: echo ref=$(git submodule | fgrep scripts | cut -c2-41) >> $GITHUB_OUTPUT + - name: Clone scripts + uses: actions/checkout@v3 + with: + repository: 'DFHack/scripts' + ref: ${{ inputs.scripts_ref || steps.scriptssubmoduleref.outputs.ref }} + path: scripts + - name: Check whitespace + run: python ci/lint.py --git-only --github-actions + - name: Check Authors.rst + if: always() + run: python ci/authors-rst.py + - name: Check for missing documentation + if: always() + run: python ci/script-docs.py + - name: Check Lua syntax + if: always() + run: python ci/script-syntax.py --ext=lua --cmd="luac5.3 -p" --github-actions From 0baa60506991c74b18a58d027f19ecf74ce3490c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 00:48:38 -0700 Subject: [PATCH 217/851] make linux build reusable for scripts repo --- .github/workflows/build-linux.yml | 21 ++++++++++++++++----- .github/workflows/build.yml | 2 -- .github/workflows/lint.yml | 1 - 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index a29204a30..5fea4e2bb 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -3,9 +3,10 @@ name: Build linux64 on: workflow_call: inputs: - ref: + dfhack_ref: + type: string + scripts_ref: type: string - default: '' artifact-name: type: string append-date-and-hash: @@ -62,9 +63,20 @@ jobs: - name: Clone DFHack uses: actions/checkout@v3 with: - ref: ${{ inputs.ref }} + repository: 'DFHack/dfhack' + ref: ${{ inputs.dfhack_ref }} submodules: true fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} + - name: Get scripts submodule ref + if: '!inputs.scripts_ref' + id: scriptssubmoduleref + run: echo ref=$(git submodule | fgrep scripts | cut -c2-41) >> $GITHUB_OUTPUT + - name: Clone scripts + uses: actions/checkout@v3 + with: + repository: 'DFHack/scripts' + ref: ${{ inputs.scripts_ref || steps.scriptssubmoduleref.outputs.ref }} + path: scripts - name: Fetch ccache if: inputs.platform-files uses: actions/cache/restore@v3 @@ -116,8 +128,7 @@ jobs: - name: Format artifact name if: inputs.append-date-and-hash id: artifactname - run: | - echo name=${{ inputs.artifact-name }}-$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT + run: echo name=${{ inputs.artifact-name }}-$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT - name: Upload artifact if: inputs.artifact-name uses: actions/upload-artifact@v3 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 454b530fa..803e29295 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -101,8 +101,6 @@ jobs: lint: uses: ./.github/workflows/lint.yml - with: - dfhack_ref: ${{ github.ref }} secrets: inherit check-pr: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 348068c0a..d299da573 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,7 +5,6 @@ on: inputs: dfhack_ref: type: string - required: true scripts_ref: type: string From fbbadf76ff276990398f8f889cbd4d18dde6fb5a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 00:53:39 -0700 Subject: [PATCH 218/851] only explicitly clone the scripts repo if a ref is given --- .github/workflows/build-linux.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 5fea4e2bb..d9ead04ce 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -67,15 +67,12 @@ jobs: ref: ${{ inputs.dfhack_ref }} submodules: true fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} - - name: Get scripts submodule ref - if: '!inputs.scripts_ref' - id: scriptssubmoduleref - run: echo ref=$(git submodule | fgrep scripts | cut -c2-41) >> $GITHUB_OUTPUT - name: Clone scripts + if: inputs.scripts_ref uses: actions/checkout@v3 with: repository: 'DFHack/scripts' - ref: ${{ inputs.scripts_ref || steps.scriptssubmoduleref.outputs.ref }} + ref: ${{ inputs.scripts_ref }} path: scripts - name: Fetch ccache if: inputs.platform-files From f5dfa03c4984ff45fd0c09f93caaf30265ed5522 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 00:57:55 -0700 Subject: [PATCH 219/851] use new var names in deploy actions --- .github/workflows/github-release.yml | 2 +- .github/workflows/steam-deploy.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 3adabe0db..7ec362dec 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -28,7 +28,7 @@ jobs: uses: ./.github/workflows/build-linux.yml with: artifact-name: linux64-release - ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} + dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} cache-id: release cache-readonly: true stonesense: true diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index 88d28d679..d33ad3588 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -28,7 +28,7 @@ jobs: uses: ./.github/workflows/build-linux.yml with: artifact-name: common-depot - ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} + dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} platform-files: false docs: true stonesense: true @@ -51,7 +51,7 @@ jobs: uses: ./.github/workflows/build-linux.yml with: artifact-name: linux64-depot - ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} + dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} cache-id: release cache-readonly: true common-files: false From 088c7a17b779cd19a0109ea4db352af836746602 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 01:09:57 -0700 Subject: [PATCH 220/851] prep for building from structures repo --- .github/workflows/build-linux.yml | 9 +++++++++ .github/workflows/build-windows.yml | 14 +++++++++++--- .github/workflows/github-release.yml | 2 +- .github/workflows/steam-deploy.yml | 2 +- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index d9ead04ce..ac0ee3308 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -7,6 +7,8 @@ on: type: string scripts_ref: type: string + structures_ref: + type: string artifact-name: type: string append-date-and-hash: @@ -74,6 +76,13 @@ jobs: repository: 'DFHack/scripts' ref: ${{ inputs.scripts_ref }} path: scripts + - name: Clone structures + if: inputs.structures_ref + uses: actions/checkout@v3 + with: + repository: 'DFHack/df-structures' + ref: ${{ inputs.structures_ref }} + path: library/xml - name: Fetch ccache if: inputs.platform-files uses: actions/cache/restore@v3 diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 22c1e8210..acd7db7ce 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -3,9 +3,10 @@ name: Build win64 on: workflow_call: inputs: - ref: + dfhack_ref: + type: string + structures_ref: type: string - default: '' artifact-name: type: string append-date-and-hash: @@ -36,9 +37,16 @@ jobs: - name: Clone DFHack uses: actions/checkout@v3 with: - ref: ${{ inputs.ref }} + ref: ${{ inputs.dfhack_ref }} submodules: true fetch-depth: 0 + - name: Clone structures + if: inputs.structures_ref + uses: actions/checkout@v3 + with: + repository: 'DFHack/df-structures' + ref: ${{ inputs.structures_ref }} + path: library/xml - name: Get 3rd party SDKs if: inputs.launchdf uses: actions/checkout@v3 diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 7ec362dec..692292125 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -17,7 +17,7 @@ jobs: uses: ./.github/workflows/build-windows.yml with: artifact-name: win64-release - ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} + dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} cache-id: release cache-readonly: true launchdf: true diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index d33ad3588..a44c0295f 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -39,7 +39,7 @@ jobs: uses: ./.github/workflows/build-windows.yml with: artifact-name: win64-depot - ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} + dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} cache-id: release cache-readonly: true common-files: false From 07ba950252ca63f0910bb708af8b4d133a97b816 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 01:23:36 -0700 Subject: [PATCH 221/851] make tests reusable --- .github/workflows/build.yml | 68 +----------------------------- .github/workflows/test.yml | 83 +++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 66 deletions(-) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 803e29295..4227c3f04 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,73 +3,9 @@ name: Build on: [push, pull_request] jobs: - build-linux: - name: Linux gcc-${{ matrix.gcc }} - uses: ./.github/workflows/build-linux.yml - with: - artifact-name: test-gcc-${{ matrix.gcc }} - cache-id: test - stonesense: ${{ matrix.plugins == 'all' }} - extras: ${{ matrix.plugins == 'all' }} - gcc-ver: ${{ matrix.gcc }} + test: + uses: ./.github/workflows/test.yml secrets: inherit - strategy: - fail-fast: false - matrix: - include: - - gcc: 10 - plugins: "default" - - gcc: 12 - plugins: "all" - - test-linux: - name: Test (Linux, GCC ${{ matrix.gcc }}, ${{ matrix.plugins }} plugins) - needs: build-linux - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - gcc: 10 - plugins: "default" - - gcc: 12 - plugins: "all" - steps: - - name: Download artifact - uses: actions/download-artifact@v3 - with: - name: test-gcc-${{ matrix.gcc }} - # - name: Fetch DF cache - # uses: actions/cache@v3 - # with: - # path: ~/DF - # key: df-${{ hashFiles('ci/download-df.sh') }} - # - name: Download DF - # run: | - # sh ci/download-df.sh - # - name: Run lua tests - # id: run_tests_lua - # run: | - # export TERM=dumb - # status=0 - # script -qe -c "python ci/run-tests.py --headless --keep-status \"$DF_FOLDER\"" || status=$((status + 1)) - # python ci/check-rpc.py "$DF_FOLDER/dfhack-rpc.txt" || status=$((status + 2)) - # mkdir -p artifacts - # cp "$DF_FOLDER"/test*.json "$DF_FOLDER"/*.log artifacts || status=$((status + 4)) - # exit $status - # - name: Upload test artifacts - # uses: actions/upload-artifact@v3 - # if: (success() || failure()) && steps.run_tests.outcome != 'skipped' - # continue-on-error: true - # with: - # name: test-artifacts-${{ matrix.gcc }} - # path: artifacts - # - name: Clean up DF folder - # # prevent DFHack-generated files from ending up in the cache - # # (download-df.sh also removes them, this is just to save cache space) - # if: success() || failure() - # run: | - # rm -rf "$DF_FOLDER" package-linux: name: Linux package diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..0fb019abf --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,83 @@ +name: Test + +on: + workflow_call: + inputs: + dfhack_ref: + type: string + scripts_ref: + type: string + structures_ref: + type: string + +jobs: + build-linux: + name: Linux gcc-${{ matrix.gcc }} + uses: ./.github/workflows/build-linux.yml + with: + dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_ref: ${{ inputs.scripts_ref }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: test-gcc-${{ matrix.gcc }} + cache-id: test + stonesense: ${{ matrix.plugins == 'all' }} + extras: ${{ matrix.plugins == 'all' }} + gcc-ver: ${{ matrix.gcc }} + secrets: inherit + strategy: + fail-fast: false + matrix: + include: + - gcc: 10 + plugins: "default" + - gcc: 12 + plugins: "all" + + test-linux: + name: Test (Linux, GCC ${{ matrix.gcc }}, ${{ matrix.plugins }} plugins) + needs: build-linux + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - gcc: 10 + plugins: "default" + - gcc: 12 + plugins: "all" + steps: + - name: Download artifact + uses: actions/download-artifact@v3 + with: + name: test-gcc-${{ matrix.gcc }} + # - name: Fetch DF cache + # uses: actions/cache@v3 + # with: + # path: ~/DF + # key: df-${{ hashFiles('ci/download-df.sh') }} + # - name: Download DF + # run: | + # sh ci/download-df.sh + # - name: Run lua tests + # id: run_tests_lua + # run: | + # export TERM=dumb + # status=0 + # script -qe -c "python ci/run-tests.py --headless --keep-status \"$DF_FOLDER\"" || status=$((status + 1)) + # python ci/check-rpc.py "$DF_FOLDER/dfhack-rpc.txt" || status=$((status + 2)) + # mkdir -p artifacts + # cp "$DF_FOLDER"/test*.json "$DF_FOLDER"/*.log artifacts || status=$((status + 4)) + # exit $status + # - name: Upload test artifacts + # uses: actions/upload-artifact@v3 + # if: (success() || failure()) && steps.run_tests.outcome != 'skipped' + # continue-on-error: true + # with: + # name: test-artifacts-${{ matrix.gcc }} + # path: artifacts + # - name: Clean up DF folder + # # prevent DFHack-generated files from ending up in the cache + # # (download-df.sh also removes them, this is just to save cache space) + # if: success() || failure() + # run: | + # rm -rf "$DF_FOLDER" From 8511775dbbf201d4d6e76d613c01a44f0b761240 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 4 Aug 2023 01:12:50 -0400 Subject: [PATCH 222/851] Add separators for readability --- ci/check-rpc.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ci/check-rpc.py b/ci/check-rpc.py index aba3e3811..03bccb552 100755 --- a/ci/check-rpc.py +++ b/ci/check-rpc.py @@ -3,6 +3,7 @@ import glob import sys actual = {'': {}} +SEP = ('=' * 80) with open(sys.argv[1]) as f: plugin_name = '' @@ -53,6 +54,7 @@ for plugin_name in actual: methods = actual[plugin_name] if plugin_name not in expected: + print(SEP) print('Missing documentation for plugin proto files: ' + plugin_name) print('Add the following lines:') print('// Plugin: ' + plugin_name) @@ -73,12 +75,14 @@ for plugin_name in actual: missing.append('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1]) if len(missing) > 0: + print(SEP) print('Incomplete documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Add the following lines:') for m in missing: print(m) error_count += 1 if len(wrong) > 0: + print(SEP) print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Replace the following comments:') for m in wrong: print(m) @@ -88,6 +92,7 @@ for plugin_name in expected: methods = expected[plugin_name] if plugin_name not in actual: + print(SEP) print('Incorrect documentation for plugin proto files: ' + plugin_name) print('The following methods are documented, but the plugin does not provide any RPC methods:') for m in methods: @@ -102,6 +107,7 @@ for plugin_name in expected: missing.append('// RPC ' + m + ' : ' + io[0] + ' -> ' + io[1]) if len(missing) > 0: + print(SEP) print('Incorrect documentation for ' + ('core' if plugin_name == '' else 'plugin "' + plugin_name + '"') + ' proto files. Remove the following lines:') for m in missing: print(m) From b17ca80d27ab86d2d0a6c0e6a35a17a0fabe4d72 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 4 Aug 2023 01:18:21 -0400 Subject: [PATCH 223/851] Also parse .proto files in plugin subdirectories Followup fix for #3184 --- ci/check-rpc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/check-rpc.py b/ci/check-rpc.py index 03bccb552..be7d07986 100755 --- a/ci/check-rpc.py +++ b/ci/check-rpc.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 import glob +import itertools import sys actual = {'': {}} @@ -27,7 +28,7 @@ for p in glob.iglob('library/proto/*.proto'): parts = line.split(' ') expected[''][parts[2]] = (parts[4], parts[6]) -for p in glob.iglob('plugins/proto/*.proto'): +for p in itertools.chain(glob.iglob('plugins/proto/*.proto'), glob.iglob('plugins/*/proto/*.proto')): plugin_name = '' with open(p) as f: for line in f: From 1411c5e8aa7c91ec6d1f2271a9ff3361da836a86 Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 4 Aug 2023 01:28:15 -0400 Subject: [PATCH 224/851] Disable RPC API docs for plugins that aren't currently built This allows ci/check-rpc.py to pass, and will cause it to fail if the plugins are re-enabled and we forget to un-disable the docs. --- plugins/proto/isoworldremote.proto | 8 ++++---- plugins/proto/rename.proto | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/proto/isoworldremote.proto b/plugins/proto/isoworldremote.proto index f53aa6aea..ebe5ef545 100644 --- a/plugins/proto/isoworldremote.proto +++ b/plugins/proto/isoworldremote.proto @@ -5,7 +5,7 @@ package isoworldremote; option optimize_for = LITE_RUNTIME; -// Plugin: isoworldremote +// DISABLED Plugin: isoworldremote enum BasicMaterial { AIR = 0; @@ -54,7 +54,7 @@ message EmbarkTile { optional bool is_valid = 7; } -// RPC GetEmbarkTile : TileRequest -> EmbarkTile +// DISABLED RPC GetEmbarkTile : TileRequest -> EmbarkTile message TileRequest { optional int32 want_x = 1; optional int32 want_y = 2; @@ -64,7 +64,7 @@ message MapRequest { optional string save_folder = 1; } -// RPC GetEmbarkInfo : MapRequest -> MapReply +// DISABLED RPC GetEmbarkInfo : MapRequest -> MapReply message MapReply { required bool available = 1; optional int32 region_x = 2; @@ -75,7 +75,7 @@ message MapReply { optional int32 current_season = 7; } -// RPC GetRawNames : MapRequest -> RawNames +// DISABLED RPC GetRawNames : MapRequest -> RawNames message RawNames { required bool available = 1; repeated string inorganic = 2; diff --git a/plugins/proto/rename.proto b/plugins/proto/rename.proto index 4391ecc10..ef3f57423 100644 --- a/plugins/proto/rename.proto +++ b/plugins/proto/rename.proto @@ -4,9 +4,9 @@ package dfproto; option optimize_for = LITE_RUNTIME; -// Plugin: rename +// DISABLED Plugin: rename -// RPC RenameSquad : RenameSquadIn -> EmptyMessage +// DISABLED RPC RenameSquad : RenameSquadIn -> EmptyMessage message RenameSquadIn { required int32 squad_id = 1; @@ -14,7 +14,7 @@ message RenameSquadIn { optional string alias = 3; } -// RPC RenameUnit : RenameUnitIn -> EmptyMessage +// DISABLED RPC RenameUnit : RenameUnitIn -> EmptyMessage message RenameUnitIn { required int32 unit_id = 1; @@ -22,7 +22,7 @@ message RenameUnitIn { optional string profession = 3; } -// RPC RenameBuilding : RenameBuildingIn -> EmptyMessage +// DISABLED RPC RenameBuilding : RenameBuildingIn -> EmptyMessage message RenameBuildingIn { required int32 building_id = 1; From 55f1b0d48e8b69b8a71fffa1e5f45367ad3793aa Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 03:59:50 -0700 Subject: [PATCH 225/851] first attempt to run tests on windows --- .github/workflows/test.yml | 58 ++++++++++++++++++++++++++++ ci/download-df.sh | 78 ++++++++++++++++++-------------------- 2 files changed, 95 insertions(+), 41 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0fb019abf..e5c884e64 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,6 +11,15 @@ on: type: string jobs: + build-windows: + name: Windows MSVC + uses: ./.github/workflows/build-windows.yml + with: + dfhack_ref: ${{ inputs.dfhack_ref }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: test-msvc + cache-id: test + build-linux: name: Linux gcc-${{ matrix.gcc }} uses: ./.github/workflows/build-linux.yml @@ -33,6 +42,55 @@ jobs: - gcc: 12 plugins: "all" + test-windows: + name: Test (Windows, MSVC, default plugins) + needs: build-windows + runs-on: windows-latest + steps: + - name: Set env + run: echo "DF_FOLDER=DF" >> $GITHUB_ENV + - name: Clone DFHack + uses: actions/checkout@v3 + with: + repository: 'DFHack/dfhack' + ref: ${{ inputs.dfhack_ref }} + sparse-checkout: CMakeLists.txt + - name: Detect DF version + id: get-df-version + run: echo ver="$(sh ci/get-df-version.sh)" >> $GITHUB_OUTPUT + - name: Fetch DF cache + id: restore-df + uses: actions/cache/restore@v3 + with: + path: ${{ env.DF_FOLDER }} + key: df-windows-${{ steps.get-df-version.outputs.ver }}-${{ hashFiles('ci/download-df.sh') }} + - name: Download DF + if: steps.restore-df.outputs.cache-hit != 'true' + run: sh ci/download-df.sh ${{ env.DF_FOLDER }} windows ${{ steps.get-df-version.outputs.ver }} + - name: Save DF cache + if: steps.restore-df.outputs.cache-hit != 'true' + uses: actions/cache/save@v3 + with: + path: ${{ env.DF_FOLDER }} + key: df-windows-${{ steps.get-df-version.outputs.ver }}-${{ hashFiles('ci/download-df.sh') }} + - name: Download DFHack + uses: actions/download-artifact@v3 + with: + name: test-msvc + path: ${{ env.DF_FOLDER }} + - name: Run lua tests + id: run-tests + run: python ci/run-tests.py --keep-status "${{ env.DF_FOLDER }}" + - name: Upload test artifacts + uses: actions/upload-artifact@v3 + if: always() + continue-on-error: true + with: + name: test-artifacts-msvc + path: | + ${{ env.DF_FOLDER }}/test*.json + ${{ env.DF_FOLDER }}/*.log + test-linux: name: Test (Linux, GCC ${{ matrix.gcc }}, ${{ matrix.plugins }} plugins) needs: build-linux diff --git a/ci/download-df.sh b/ci/download-df.sh index 8d94d54dd..0f7a5517b 100755 --- a/ci/download-df.sh +++ b/ci/download-df.sh @@ -1,52 +1,48 @@ #!/bin/sh +DF_FOLDER=$1 +OS_TARGET=$2 +DF_VERSION=$3 + set -e -df_tardest="df.tar.bz2" -save_tardest="test_save.tgz" - -cd "$(dirname "$0")" -echo "DF_VERSION: $DF_VERSION" -echo "DF_FOLDER: $DF_FOLDER" -mkdir -p "$DF_FOLDER" -# back out of df_linux -cd "$DF_FOLDER/.." - -if ! test -f "$df_tardest"; then - minor=$(echo "$DF_VERSION" | cut -d. -f2) - patch=$(echo "$DF_VERSION" | cut -d. -f3) - echo "Downloading DF $DF_VERSION" - while read url; do - echo "Attempting download: ${url}" - if wget -v "$url" -O "$df_tardest"; then - break - fi - done < Date: Thu, 3 Aug 2023 04:13:06 -0700 Subject: [PATCH 226/851] trim windows test build --- .github/workflows/build-windows.yml | 17 ++++++++++++++++- .github/workflows/build.yml | 2 ++ .github/workflows/github-release.yml | 2 ++ .github/workflows/steam-deploy.yml | 1 + .github/workflows/test.yml | 5 ++++- 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index acd7db7ce..fd1ac3e13 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -5,6 +5,8 @@ on: inputs: dfhack_ref: type: string + scripts_ref: + type: string structures_ref: type: string artifact-name: @@ -21,6 +23,12 @@ on: common-files: type: boolean default: true + docs: + type: boolean + default: false + stonesense: + type: boolean + default: false launchdf: type: boolean default: false @@ -40,6 +48,13 @@ jobs: ref: ${{ inputs.dfhack_ref }} submodules: true fetch-depth: 0 + - name: Clone scripts + if: inputs.scripts_ref + uses: actions/checkout@v3 + with: + repository: 'DFHack/scripts' + ref: ${{ inputs.scripts_ref }} + path: scripts - name: Clone structures if: inputs.structures_ref uses: actions/checkout@v3 @@ -65,7 +80,7 @@ jobs: win-msvc - name: Cross-compile env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=1 -DBUILD_DOCS:BOOL=${{ inputs.common-files }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }}' + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }}' run: | cd build bash -x build-win64-from-linux.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4227c3f04..051fc55b7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,6 +25,8 @@ jobs: artifact-name: dfhack-win64-build append-date-and-hash: true cache-id: release + stonesense: true + docs: true secrets: inherit docs: diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 692292125..56bc26702 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -20,6 +20,8 @@ jobs: dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} cache-id: release cache-readonly: true + stonesense: true + docs: true launchdf: true secrets: inherit diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index a44c0295f..5b14d0bc8 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -43,6 +43,7 @@ jobs: cache-id: release cache-readonly: true common-files: false + stonesense: true launchdf: true secrets: inherit diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e5c884e64..219273350 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,6 +16,7 @@ jobs: uses: ./.github/workflows/build-windows.yml with: dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_ref: ${{ inputs.scripts_ref }} structures_ref: ${{ inputs.structures_ref }} artifact-name: test-msvc cache-id: test @@ -54,7 +55,9 @@ jobs: with: repository: 'DFHack/dfhack' ref: ${{ inputs.dfhack_ref }} - sparse-checkout: CMakeLists.txt + sparse-checkout: | + CMakeLists.txt + ci/ - name: Detect DF version id: get-df-version run: echo ver="$(sh ci/get-df-version.sh)" >> $GITHUB_OUTPUT From 59a2d3a5244a3f01fde969dae19a3319a274dfac Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 04:24:23 -0700 Subject: [PATCH 227/851] fix env setting on windows --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 219273350..357196181 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,7 +49,7 @@ jobs: runs-on: windows-latest steps: - name: Set env - run: echo "DF_FOLDER=DF" >> $GITHUB_ENV + run: echo "DF_FOLDER=DF" >> $env:GITHUB_ENV - name: Clone DFHack uses: actions/checkout@v3 with: From 27b5d1e02279716e6f799064d1ca5c563e35f3d1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 04:37:13 -0700 Subject: [PATCH 228/851] more windows fixups --- .github/workflows/test.yml | 2 +- ci/download-df.sh | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 357196181..3490ff6a6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -60,7 +60,7 @@ jobs: ci/ - name: Detect DF version id: get-df-version - run: echo ver="$(sh ci/get-df-version.sh)" >> $GITHUB_OUTPUT + run: echo ver="$(sh ci/get-df-version.sh)" >> $env:GITHUB_OUTPUT - name: Fetch DF cache id: restore-df uses: actions/cache/restore@v3 diff --git a/ci/download-df.sh b/ci/download-df.sh index 0f7a5517b..13c432798 100755 --- a/ci/download-df.sh +++ b/ci/download-df.sh @@ -10,10 +10,12 @@ minor=$(echo "$DF_VERSION" | cut -d. -f1) patch=$(echo "$DF_VERSION" | cut -d. -f2) df_url="https://www.bay12games.com/dwarves/df_${minor}_${patch}" if test "$OS_TARGET" = "windows"; then + WGET="C:/msys64/usr/bin/wget.exe" df_url="${df_url}_win_s.zip" df_archive_name="df.zip" df_extract_cmd="unzip -d ${DF_FOLDER}" elif test "$OS_TARGET" = "linux"; then + WGET=wget df_url="${df_url}_linux.tar.bz2" df_archive_name="df.tar.bz2" df_extract_cmd="tar -x -j --strip-components=1 -f" @@ -22,7 +24,7 @@ else exit 1 fi -if ! wget -v "$df_url" -O "$df_archive_name"; then +if ! $WGET -v "$df_url" -O "$df_archive_name"; then echo "Failed to download DF from $df_url" exit 1 fi @@ -31,7 +33,7 @@ save_url="https://dffd.bay12games.com/download.php?id=15434&f=dreamfort.7z" save_archive_name="test_save.7z" save_extract_cmd="7z x -oDF/save" -if ! wget -v "$save_url" -O "$save_archive_name"; then +if ! $WGET -v "$save_url" -O "$save_archive_name"; then echo "Failed to download test save from $save_url" exit 1 fi From 556c1eff9241169e292b8285fae7cfd79bbc2ed2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 04:55:31 -0700 Subject: [PATCH 229/851] adapt to new DF init paths --- ci/run-tests.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ci/run-tests.py b/ci/run-tests.py index a6a35bc76..7dccddcd4 100755 --- a/ci/run-tests.py +++ b/ci/run-tests.py @@ -55,7 +55,18 @@ if os.path.exists(test_status_file): os.remove(test_status_file) print('Backing up init.txt to init.txt.orig') -init_txt_path = 'data/init/init.txt' +default_init_txt_path = 'data/init/init_default.txt' +prefs_path = 'prefs' +init_txt_path = 'prefs/init.txt' +if not os.path.exists(init_txt_path): + try: + os.mkdir(prefs_path) + except OSError as error: + # ignore already exists errors + pass + shutil.copyfile(default_init_txt_path, init_txt_path) + +print('Backing up init.txt to init.txt.orig') shutil.copyfile(init_txt_path, init_txt_path + '.orig') with open(init_txt_path) as f: init_contents = f.read() From 775c60bed3602bb4bb83f515b07a70a4eca90fab Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 04:55:40 -0700 Subject: [PATCH 230/851] reduce windows cache size --- .github/workflows/build-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index fd1ac3e13..97398933d 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -87,7 +87,7 @@ jobs: - name: Trim cache run: | cd build - ccache -d win64-cross/ccache --max-size 200M + ccache -d win64-cross/ccache --max-size 150M ccache -d win64-cross/ccache --cleanup ccache -d win64-cross/ccache --show-stats --verbose - name: Save ccache From 5f5981f067eb6cba5fbff72d0016eb636d3183ae Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 05:07:21 -0700 Subject: [PATCH 231/851] fix path creation --- ci/run-tests.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/ci/run-tests.py b/ci/run-tests.py index 7dccddcd4..9785e607c 100755 --- a/ci/run-tests.py +++ b/ci/run-tests.py @@ -33,7 +33,7 @@ if args.test_dir is not None: MAX_TRIES = 5 -dfhack = 'Dwarf Fortress.exe' if sys.platform == 'win32' else './dfhack' +dfhack = 'Dwarf Fortress.exe' if sys.platform == 'win32' else './dwarfort' test_status_file = 'test_status.json' class TestStatus(enum.Enum): @@ -59,14 +59,9 @@ default_init_txt_path = 'data/init/init_default.txt' prefs_path = 'prefs' init_txt_path = 'prefs/init.txt' if not os.path.exists(init_txt_path): - try: - os.mkdir(prefs_path) - except OSError as error: - # ignore already exists errors - pass + os.makedirs(prefs_path, exist_ok=True) shutil.copyfile(default_init_txt_path, init_txt_path) -print('Backing up init.txt to init.txt.orig') shutil.copyfile(init_txt_path, init_txt_path + '.orig') with open(init_txt_path) as f: init_contents = f.read() @@ -83,11 +78,7 @@ init_path = 'dfhack-config/init' if not os.path.isdir('hack/init'): # we're on an old branch that still reads init files from the root dir init_path = '.' -try: - os.mkdir(init_path) -except OSError as error: - # ignore already exists errors - pass +os.makedirs(init_path, exist_ok=True) test_init_file = os.path.join(init_path, 'dfhackzzz_test.init') # Core sorts these alphabetically with open(test_init_file, 'w') as f: f.write(''' From 2b7865a0e4f0c379b921959e850e163b55f9c0f4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 08:05:13 -0700 Subject: [PATCH 232/851] actually install the tests for the test action --- .github/workflows/build-linux.yml | 4 ++++ .github/workflows/build-windows.yml | 5 ++++- .github/workflows/test.yml | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index ac0ee3308..b5ff9aa39 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -35,6 +35,9 @@ on: extras: type: boolean default: false + tests: + type: boolean + default: false gcc-ver: type: string default: "10" @@ -112,6 +115,7 @@ jobs: -DBUILD_SIZECHECK:BOOL=${{ inputs.extras }} \ -DBUILD_SKELETON:BOOL=${{ inputs.extras }} \ -DBUILD_DOCS:BOOL=${{ inputs.docs }} \ + -DBUILD_TESTS:BOOL=${{ inputs.tests }} \ -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} \ -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} - name: Build DFHack diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 97398933d..16a947fb4 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -29,6 +29,9 @@ on: stonesense: type: boolean default: false + tests: + type: boolean + default: false launchdf: type: boolean default: false @@ -80,7 +83,7 @@ jobs: win-msvc - name: Cross-compile env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }}' + CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} -DBUILD_TESTS:BOOL=${{ inputs.tests }}' run: | cd build bash -x build-win64-from-linux.sh diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3490ff6a6..6b0882d8d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,6 +20,7 @@ jobs: structures_ref: ${{ inputs.structures_ref }} artifact-name: test-msvc cache-id: test + tests: true build-linux: name: Linux gcc-${{ matrix.gcc }} @@ -32,6 +33,7 @@ jobs: cache-id: test stonesense: ${{ matrix.plugins == 'all' }} extras: ${{ matrix.plugins == 'all' }} + tests: true gcc-ver: ${{ matrix.gcc }} secrets: inherit strategy: From 6c4662d12c51d0618cfeed068be59e740bafc85b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 08:22:27 -0700 Subject: [PATCH 233/851] set a timeout for the test step --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6b0882d8d..8b8eaa3f4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -85,6 +85,7 @@ jobs: path: ${{ env.DF_FOLDER }} - name: Run lua tests id: run-tests + timeout-minutes: 10 run: python ci/run-tests.py --keep-status "${{ env.DF_FOLDER }}" - name: Upload test artifacts uses: actions/upload-artifact@v3 From 43a1fdc69c079724e74294cd2f2eb418396ad659 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 20:16:48 -0700 Subject: [PATCH 234/851] only run tests for registered and available targets --- ci/test.lua | 160 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 68 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index aca78e851..0a482da80 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -1,11 +1,12 @@ -- DFHack developer test harness --@ module = true -local expect = require 'test_util.expect' -local json = require 'json' -local mock = require 'test_util.mock' -local script = require 'gui.script' -local utils = require 'utils' +local expect = require('test_util.expect') +local helpdb = require('helpdb') +local json = require('json') +local mock = require('test_util.mock') +local script = require('gui.script') +local utils = require('utils') local help_text = [====[ @@ -13,49 +14,59 @@ local help_text = test ==== -Run DFHack tests. +Tags: dev -Usage: +Command: "test" + + Run DFHack regression tests. + +Discover DFHack functionality that has broken due to recent changes in DF or DFHack. + +Usage +----- test [] [] If a done_command is specified, it will be run after the tests complete. -Options: - - -h, --help display this help message and exit. - -d, --test_dir specifies which directory to look in for tests. defaults to - the "hack/scripts/test" folder in your DF installation. - -m, --modes only run tests in the given comma separated list of modes. - see the next section for a list of valid modes. if not - specified, the tests are not filtered by modes. - -r, --resume skip tests that have already been run. remove the - test_status.json file to reset the record. - -s, --save_dir the save folder to load for "fortress" mode tests. this - save is only loaded if a fort is not already loaded when - a "fortress" mode test is run. if not specified, defaults to - 'region1'. - -t, --tests only run tests that match one of the comma separated list of - patterns. if not specified, no tests are filtered. - -Modes: - - none the test can be run on any screen - title the test must be run on the DF title screen. note that if the game - has a map loaded, "title" mode tests cannot be run - fortress the test must be run while a map is loaded. if the game is - currently on the title screen, the save specified by the save_dir - parameter will be loaded. - -Examples: - - test runs all tests - test -r runs all tests that haven't been run before - test -m none runs tests that don't need the game to be in a - specific mode - test -t quickfort runs quickfort tests - test -d /path/to/dfhack-scripts/repo/test - runs tests in your dev scripts repo +Options +------- + +-d, --test_dir specifies which directory to look in for tests. defaults to + the "hack/scripts/test" folder in your DF installation. +-m, --modes only run tests in the given comma separated list of modes. + see the next section for a list of valid modes. if not + specified, the tests are not filtered by modes. +-r, --resume skip tests that have already been run. remove the + test_status.json file to reset the record. +-s, --save_dir the save folder to load for "fortress" mode tests. this + save is only loaded if a fort is not already loaded when + a "fortress" mode test is run. if not specified, defaults to + 'region1'. +-t, --tests only run tests that match one of the comma separated list of + patterns. if not specified, no tests are filtered and all tessts + are run. + +Modes +----- + +none the test can be run on any screen +title the test must be run on the DF title screen. note that if the game + has a map loaded, "title" mode tests cannot be run +fortress the test must be run while a map is loaded. if the game is + currently on the title screen, the save specified by the save_dir + parameter will be loaded. + +Examples +-------- + +test runs all tests +test -r runs all tests that haven't been run before +test -m none runs tests that don't need the game to be in a + specific mode +test -t quickfort runs quickfort tests +test -d /path/to/dfhack-scripts/repo/test + runs tests in your dev scripts repo Default values for the options may be set in a file named test_config.json in your DF folder. Options with comma-separated values should be written as json @@ -352,33 +363,46 @@ local function load_tests(file, tests) if not code then dfhack.printerr('Failed to load file: ' .. tostring(err)) return false - else - dfhack.internal.IN_TEST = true - local ok, err = dfhack.pcall(code) - dfhack.internal.IN_TEST = false - if not ok then - dfhack.printerr('Error when running file: ' .. tostring(err)) + end + dfhack.internal.IN_TEST = true + local ok, err = dfhack.pcall(code) + dfhack.internal.IN_TEST = false + if not ok then + dfhack.printerr('Error when running file: ' .. tostring(err)) + return false + end + if not MODES[env.config.mode] then + dfhack.printerr('Invalid config.mode: ' .. tostring(env.config.mode)) + return false + end + if not env.config.targets then + dfhack.printerr('Test target(s) not specified in ' .. file) + return false + end + local targets = type(env.config.targets) == table and env.config.targets or {env.config.targets} + for _,target in ipairs(targets) do + if target == 'core' then goto continue end + if type(target) ~= 'string' or not helpdb.is_entry(target) or + helpdb.get_entry_tags(target).unavailable + then + dfhack.printerr('Skipping tests for unavailable target: ' .. target) return false - else - if not MODES[env.config.mode] then - dfhack.printerr('Invalid config.mode: ' .. tostring(env.config.mode)) - return false - end - for name, test_func in pairs(env.test) do - if env.config.wrapper then - local fn = test_func - test_func = function() env.config.wrapper(fn) end - end - local test_data = { - full_name = short_filename .. ':' .. name, - func = test_func, - private = env_private, - config = env.config, - } - test_data.name = test_data.full_name:gsub('test/', ''):gsub('.lua', '') - table.insert(tests, test_data) - end end + ::continue:: + end + for name, test_func in pairs(env.test) do + if env.config.wrapper then + local fn = test_func + test_func = function() env.config.wrapper(fn) end + end + local test_data = { + full_name = short_filename .. ':' .. name, + func = test_func, + private = env_private, + config = env.config, + } + test_data.name = test_data.full_name:gsub('test/', ''):gsub('.lua', '') + table.insert(tests, test_data) end return true end @@ -575,7 +599,7 @@ local function dump_df_state() enabler = { fps = df.global.enabler.fps, gfps = df.global.enabler.gfps, - fullscreen = df.global.enabler.fullscreen, + fullscreen_state = df.global.enabler.fullscreen_state.whole, }, gps = { dimx = df.global.gps.dimx, From ec461bcce52b7047753d105d18a9d0e00faa235f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 20:48:15 -0700 Subject: [PATCH 235/851] zero tests mean pass --- ci/test.lua | 6 +++--- plugins/CMakeLists.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index 0a482da80..3f7f8c77b 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -376,8 +376,8 @@ local function load_tests(file, tests) return false end if not env.config.targets then - dfhack.printerr('Test target(s) not specified in ' .. file) - return false + dfhack.printerr('Skipping tests for unspecified target in ' .. file) + return true -- TODO: change to false once existing tests have targets specified end local targets = type(env.config.targets) == table and env.config.targets or {env.config.targets} for _,target in ipairs(targets) do @@ -386,7 +386,7 @@ local function load_tests(file, tests) helpdb.get_entry_tags(target).unavailable then dfhack.printerr('Skipping tests for unavailable target: ' .. target) - return false + return true end ::continue:: end diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 6759225d1..b3b69fb12 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -169,7 +169,7 @@ if(BUILD_SUPPORTED) #dfhack_plugin(trackstop trackstop.cpp) #dfhack_plugin(tubefill tubefill.cpp) #add_subdirectory(tweak) - #dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua) + dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua) 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 LINK_LIBRARIES lua) From 081e9383017af32af0c6839a49424965d53cacdf Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 21:04:46 -0700 Subject: [PATCH 236/851] test RPC interface --- .github/workflows/test.yml | 35 ++++------------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8b8eaa3f4..0184350b4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -87,6 +87,8 @@ jobs: id: run-tests timeout-minutes: 10 run: python ci/run-tests.py --keep-status "${{ env.DF_FOLDER }}" + - name: Check RPC interface + run: python ci/check-rpc.py "${{ env.DF_FOLDER }}/dfhack-rpc.txt" - name: Upload test artifacts uses: actions/upload-artifact@v3 if: always() @@ -94,6 +96,7 @@ jobs: with: name: test-artifacts-msvc path: | + ${{ env.DF_FOLDER }}/dfhack-rpc.txt ${{ env.DF_FOLDER }}/test*.json ${{ env.DF_FOLDER }}/*.log @@ -114,34 +117,4 @@ jobs: uses: actions/download-artifact@v3 with: name: test-gcc-${{ matrix.gcc }} - # - name: Fetch DF cache - # uses: actions/cache@v3 - # with: - # path: ~/DF - # key: df-${{ hashFiles('ci/download-df.sh') }} - # - name: Download DF - # run: | - # sh ci/download-df.sh - # - name: Run lua tests - # id: run_tests_lua - # run: | - # export TERM=dumb - # status=0 - # script -qe -c "python ci/run-tests.py --headless --keep-status \"$DF_FOLDER\"" || status=$((status + 1)) - # python ci/check-rpc.py "$DF_FOLDER/dfhack-rpc.txt" || status=$((status + 2)) - # mkdir -p artifacts - # cp "$DF_FOLDER"/test*.json "$DF_FOLDER"/*.log artifacts || status=$((status + 4)) - # exit $status - # - name: Upload test artifacts - # uses: actions/upload-artifact@v3 - # if: (success() || failure()) && steps.run_tests.outcome != 'skipped' - # continue-on-error: true - # with: - # name: test-artifacts-${{ matrix.gcc }} - # path: artifacts - # - name: Clean up DF folder - # # prevent DFHack-generated files from ending up in the cache - # # (download-df.sh also removes them, this is just to save cache space) - # if: success() || failure() - # run: | - # rm -rf "$DF_FOLDER" + # TODO: share windows test logic once there is a Linux DF build to test From f28b46922c3bb4243a3aec136a6933ff48fca9dc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 21:49:26 -0700 Subject: [PATCH 237/851] put all tests in a matrix --- .github/workflows/test.yml | 70 ++++++++++++++++++++------------------ ci/download-df.sh | 2 +- 2 files changed, 37 insertions(+), 35 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0184350b4..17a0872fc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,45 +46,66 @@ jobs: plugins: "all" test-windows: - name: Test (Windows, MSVC, default plugins) - needs: build-windows - runs-on: windows-latest + name: Test (${{ matrix.os }}, ${{ matrix.compiler }}, ${{ matrix.plugins }} plugins) + needs: + - build-windows + - build-linux + runs-on: ${{ matrix.os }}-latest + strategy: + fail-fast: false + matrix: + include: + - os: windows + compiler: msvc + plugins: "default" + # TODO: uncomment once we have a linux build we can download from bay12 + # - os: ubuntu + # compiler: gcc-10 + # gcc: 10 + # plugins: "default" + # - os: ubuntu + # compiler: gcc-10 + # gcc: 12 + # plugins: "all" steps: - - name: Set env + - name: Set env (windows) + if: matrix.os == 'windows' run: echo "DF_FOLDER=DF" >> $env:GITHUB_ENV + - name: Set env (posix) + if: matrix.os != 'windows' + run: echo "DF_FOLDER=DF" >> $GITHUB_ENV - name: Clone DFHack uses: actions/checkout@v3 with: repository: 'DFHack/dfhack' ref: ${{ inputs.dfhack_ref }} - sparse-checkout: | - CMakeLists.txt - ci/ - - name: Detect DF version - id: get-df-version - run: echo ver="$(sh ci/get-df-version.sh)" >> $env:GITHUB_OUTPUT + - name: Detect DF version (windows) + if: matrix.os == 'windows' + run: echo DF_VERSION="$(sh ci/get-df-version.sh)" >> $env:GITHUB_ENV + - name: Detect DF version (posix) + if: matrix.os != 'windows' + run: echo DF_VERSION="$(sh ci/get-df-version.sh)" >> $GITHUB_ENV - name: Fetch DF cache id: restore-df uses: actions/cache/restore@v3 with: path: ${{ env.DF_FOLDER }} - key: df-windows-${{ steps.get-df-version.outputs.ver }}-${{ hashFiles('ci/download-df.sh') }} + key: df-${{ matrix.os }}-${{ env.DF_VERSION }}-${{ hashFiles('ci/download-df.sh') }} - name: Download DF if: steps.restore-df.outputs.cache-hit != 'true' - run: sh ci/download-df.sh ${{ env.DF_FOLDER }} windows ${{ steps.get-df-version.outputs.ver }} + run: sh ci/download-df.sh ${{ env.DF_FOLDER }} ${{ matrix.os }} ${{ env.DF_VERSION }} - name: Save DF cache if: steps.restore-df.outputs.cache-hit != 'true' uses: actions/cache/save@v3 with: path: ${{ env.DF_FOLDER }} - key: df-windows-${{ steps.get-df-version.outputs.ver }}-${{ hashFiles('ci/download-df.sh') }} + key: df-${{ matrix.os }}-${{ env.DF_VERSION }}-${{ hashFiles('ci/download-df.sh') }} - name: Download DFHack uses: actions/download-artifact@v3 with: - name: test-msvc + name: test-${{ matrix.compiler }} path: ${{ env.DF_FOLDER }} - name: Run lua tests - id: run-tests timeout-minutes: 10 run: python ci/run-tests.py --keep-status "${{ env.DF_FOLDER }}" - name: Check RPC interface @@ -99,22 +120,3 @@ jobs: ${{ env.DF_FOLDER }}/dfhack-rpc.txt ${{ env.DF_FOLDER }}/test*.json ${{ env.DF_FOLDER }}/*.log - - test-linux: - name: Test (Linux, GCC ${{ matrix.gcc }}, ${{ matrix.plugins }} plugins) - needs: build-linux - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - gcc: 10 - plugins: "default" - - gcc: 12 - plugins: "all" - steps: - - name: Download artifact - uses: actions/download-artifact@v3 - with: - name: test-gcc-${{ matrix.gcc }} - # TODO: share windows test logic once there is a Linux DF build to test diff --git a/ci/download-df.sh b/ci/download-df.sh index 13c432798..12e9a41e3 100755 --- a/ci/download-df.sh +++ b/ci/download-df.sh @@ -14,7 +14,7 @@ if test "$OS_TARGET" = "windows"; then df_url="${df_url}_win_s.zip" df_archive_name="df.zip" df_extract_cmd="unzip -d ${DF_FOLDER}" -elif test "$OS_TARGET" = "linux"; then +elif test "$OS_TARGET" = "ubuntu"; then WGET=wget df_url="${df_url}_linux.tar.bz2" df_archive_name="df.tar.bz2" From e3161b8a4d15ecb69e0a6e41b6fcda2b291ab352 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 22:38:49 -0700 Subject: [PATCH 238/851] enable some core tests --- test/core.lua | 2 ++ test/encoding.lua | 2 ++ test/test.lua | 2 ++ 3 files changed, 6 insertions(+) diff --git a/test/core.lua b/test/core.lua index ba104c90a..0d21fa38f 100644 --- a/test/core.lua +++ b/test/core.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local function clean_path(p) -- todo: replace with dfhack.filesystem call? return p:gsub('\\', '/'):gsub('//', '/'):gsub('/$', '') diff --git a/test/encoding.lua b/test/encoding.lua index cb0a72664..afed4bf8b 100644 --- a/test/encoding.lua +++ b/test/encoding.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + function test.toSearchNormalized() expect.eq(dfhack.toSearchNormalized(''), '') expect.eq(dfhack.toSearchNormalized('abcd'), 'abcd') diff --git a/test/test.lua b/test/test.lua index 11f038d66..679325d2e 100644 --- a/test/test.lua +++ b/test/test.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + function test.internal_in_test() expect.true_(dfhack.internal.IN_TEST) end From d3884bd7077311ef030ba38e30b390c6548fe6a4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 22:52:17 -0700 Subject: [PATCH 239/851] run ./dfhack instead of ./dwarfort on linux so we can see output since we set the tty params --- ci/run-tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/run-tests.py b/ci/run-tests.py index 9785e607c..a55bf3051 100755 --- a/ci/run-tests.py +++ b/ci/run-tests.py @@ -33,7 +33,7 @@ if args.test_dir is not None: MAX_TRIES = 5 -dfhack = 'Dwarf Fortress.exe' if sys.platform == 'win32' else './dwarfort' +dfhack = 'Dwarf Fortress.exe' if sys.platform == 'win32' else './dfhack' test_status_file = 'test_status.json' class TestStatus(enum.Enum): From 10525aa6ae5de16afad0eee1f970015bf6099d29 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 23:53:45 -0700 Subject: [PATCH 240/851] fix name of job --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 17a0872fc..40f497b78 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,7 +45,7 @@ jobs: - gcc: 12 plugins: "all" - test-windows: + run-tests: name: Test (${{ matrix.os }}, ${{ matrix.compiler }}, ${{ matrix.plugins }} plugins) needs: - build-windows From 4c2e7721e1fd66b2a9dfd4c0f6689bccaad8c5c6 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 4 Aug 2023 07:12:54 +0000 Subject: [PATCH 241/851] 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 c87d2263c..ba27f3b18 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit c87d2263c4e801d2b2b1d619a84ae5ba535fd453 +Subproject commit ba27f3b18b36d64f6655ae242c87452f63689a69 diff --git a/scripts b/scripts index 8a6528e90..c0b17a57f 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 8a6528e9084eda4b9fd19c19ffc412ab3e67d016 +Subproject commit c0b17a57f36fd37eaf76eff2162bd6379f8f7e42 From 66107b40e3128c511c4f3b3d20b921352895b208 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 10:04:55 -0700 Subject: [PATCH 242/851] fix windows build when called from other repos --- .github/workflows/build-windows.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 16a947fb4..4e385802e 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -48,6 +48,7 @@ jobs: - name: Clone DFHack uses: actions/checkout@v3 with: + repository: 'DFHack/dfhack' ref: ${{ inputs.dfhack_ref }} submodules: true fetch-depth: 0 From 1cf3f6223785c79f6acdb8982eaf94a868fe9d9a Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 4 Aug 2023 17:10:51 +0000 Subject: [PATCH 243/851] 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 ba27f3b18..c5e1ca2bf 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ba27f3b18b36d64f6655ae242c87452f63689a69 +Subproject commit c5e1ca2bfdd9bdc05a884c5624a5fa20bc72c49a From f8dd09200f057b4d15cc5482569e33781d035070 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 3 Aug 2023 23:54:14 -0700 Subject: [PATCH 244/851] enable remaining core and structures tests --- test/gui.lua | 4 +++- test/structures/find.lua | 1 + test/structures/misc.lua | 2 ++ test/structures/other_vectors.lua | 2 ++ test/structures/primitive_refs.lua | 2 ++ test/structures/ref_target.lua | 2 ++ test/structures/types_meta.lua | 2 ++ test/structures/unions.lua | 2 ++ 8 files changed, 16 insertions(+), 1 deletion(-) diff --git a/test/gui.lua b/test/gui.lua index 1550fc1de..ac350ea1b 100644 --- a/test/gui.lua +++ b/test/gui.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + function test.getCurViewscreen() local scr = dfhack.gui.getCurViewscreen() local scr2 = df.global.gview.view @@ -18,7 +20,7 @@ function test.getViewscreenByType() local bad_type = df.viewscreen_titlest if scr._type == bad_type then - bad_type = df.viewscreen_optionst + bad_type = df.viewscreen_dwarfmodest end local scr_bad = dfhack.gui.getViewscreenByType(bad_type) expect.eq(scr_bad, nil) diff --git a/test/structures/find.lua b/test/structures/find.lua index c01f071e1..471220479 100644 --- a/test/structures/find.lua +++ b/test/structures/find.lua @@ -1,4 +1,5 @@ config.mode = 'title' +config.targets = 'core' local function clean_vec(vec) while #vec > 0 do diff --git a/test/structures/misc.lua b/test/structures/misc.lua index 5c9f41561..277457dfe 100644 --- a/test/structures/misc.lua +++ b/test/structures/misc.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + function test.overlappingGlobals() local globals = {} for name, _ in pairs(df.global) do diff --git a/test/structures/other_vectors.lua b/test/structures/other_vectors.lua index bfc6086a4..453ab1dca 100644 --- a/test/structures/other_vectors.lua +++ b/test/structures/other_vectors.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + function test.index_name() for _, k in ipairs(df.units_other_id) do expect.eq(df.global.world.units.other[k]._kind, 'container') diff --git a/test/structures/primitive_refs.lua b/test/structures/primitive_refs.lua index 74abd02b9..77049b673 100644 --- a/test/structures/primitive_refs.lua +++ b/test/structures/primitive_refs.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + utils = require('utils') function with_temp_ref(...) diff --git a/test/structures/ref_target.lua b/test/structures/ref_target.lua index b9c568805..56bfdbfc7 100644 --- a/test/structures/ref_target.lua +++ b/test/structures/ref_target.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + function test.get() dfhack.with_temp_object(df.unit:new(), function(unit) expect.eq(unit:_field('hist_figure_id').ref_target, df.historical_figure) diff --git a/test/structures/types_meta.lua b/test/structures/types_meta.lua index 212e9c7ed..5809960bf 100644 --- a/test/structures/types_meta.lua +++ b/test/structures/types_meta.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + function test.struct() expect.eq(df.coord._kind, 'struct-type') expect.eq(tostring(df.coord), '') diff --git a/test/structures/unions.lua b/test/structures/unions.lua index 714786a96..9e4c767db 100644 --- a/test/structures/unions.lua +++ b/test/structures/unions.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local utils = require('utils') function test.unit_action_fields() From a6de9a21fac2d5e0d9d23ce30c443eb2730a8f31 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 01:35:51 -0700 Subject: [PATCH 245/851] enable most core tests --- library/lua/gui/widgets.lua | 2 +- library/lua/helpdb.lua | 2 +- test/library/argparse.lua | 2 ++ test/library/gui.lua | 3 +++ test/library/gui/dialogs.lua | 2 ++ test/library/gui/widgets.EditField.lua | 22 ++++++++++++---------- test/library/gui/widgets.Label.lua | 2 ++ test/library/gui/widgets.Scrollbar.lua | 6 ++++-- test/library/gui/widgets.lua | 2 ++ test/library/helpdb.lua | 2 ++ test/library/misc.lua | 2 ++ test/library/print.lua | 2 ++ test/library/string.lua | 2 ++ test/library/test_util/expect_unit.lua | 2 ++ test/library/test_util/mock.lua | 2 ++ test/library/utils.lua | 4 +++- test/structures/misc.lua | 5 +++-- 17 files changed, 47 insertions(+), 17 deletions(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 74d193025..e1b71d186 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -992,7 +992,7 @@ function Scrollbar:onInput(keys) return false end - if self.parent_view:getMousePos() then + if self.parent_view and self.parent_view:getMousePos() then if keys.CONTEXT_SCROLL_UP then self.on_scroll('up_small') return true diff --git a/library/lua/helpdb.lua b/library/lua/helpdb.lua index 4ce078a22..a4e75ff0c 100644 --- a/library/lua/helpdb.lua +++ b/library/lua/helpdb.lua @@ -789,7 +789,7 @@ function ls(filter_str, skip_tags, show_dev_commands, exclude_strs) end if not show_dev_commands then local dev_tags = {'dev', 'unavailable'} - if dfhack.getHideArmokTools() then + if filter_str ~= 'armok' and dfhack.getHideArmokTools() then table.insert(dev_tags, 'armok') end table.insert(excludes, {tag=dev_tags}) diff --git a/test/library/argparse.lua b/test/library/argparse.lua index 5e85e6465..33891a834 100644 --- a/test/library/argparse.lua +++ b/test/library/argparse.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local argparse = require('argparse') local guidm = require('gui.dwarfmode') diff --git a/test/library/gui.lua b/test/library/gui.lua index fe04614d6..af8b15b6d 100644 --- a/test/library/gui.lua +++ b/test/library/gui.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local gui = require('gui') function test.getKeyDisplay() @@ -10,6 +12,7 @@ end function test.clear_pen() expect.table_eq(gui.CLEAR_PEN, { + tile = df.global.init.texpos_border_interior, ch = string.byte(' '), fg = COLOR_BLACK, bg = COLOR_BLACK, diff --git a/test/library/gui/dialogs.lua b/test/library/gui/dialogs.lua index 0d3724c2e..4ee16027e 100644 --- a/test/library/gui/dialogs.lua +++ b/test/library/gui/dialogs.lua @@ -1,3 +1,5 @@ +--config.targets = 'core' + local gui = require('gui') local function send_keys(...) local keys = {...} diff --git a/test/library/gui/widgets.EditField.lua b/test/library/gui/widgets.EditField.lua index 23558987b..eb35bb22c 100644 --- a/test/library/gui/widgets.EditField.lua +++ b/test/library/gui/widgets.EditField.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local widgets = require('gui.widgets') function test.editfield_cursor() @@ -20,18 +22,18 @@ function test.editfield_cursor() expect.eq('ones two threes', e.text) expect.eq(5, e.cursor) - e:onInput{CURSOR_LEFT=true} + e:onInput{KEYBOARD_CURSOR_LEFT=true} expect.eq(4, e.cursor) - e:onInput{CURSOR_RIGHT=true} + e:onInput{KEYBOARD_CURSOR_RIGHT=true} expect.eq(5, e.cursor) - e:onInput{A_CARE_MOVE_W=true} - expect.eq(1, e.cursor, 'interpret alt-left as home') - e:onInput{A_MOVE_E_DOWN=true} - expect.eq(6, e.cursor, 'interpret ctrl-right as goto beginning of next word') - e:onInput{A_CARE_MOVE_E=true} - expect.eq(16, e.cursor, 'interpret alt-right as end') - e:onInput{A_MOVE_W_DOWN=true} - expect.eq(9, e.cursor, 'interpret ctrl-left as goto end of previous word') + -- e:onInput{A_CARE_MOVE_W=true} + -- expect.eq(1, e.cursor, 'interpret alt-left as home') -- uncomment when we have a home key + e:onInput{CUSTOM_CTRL_F=true} + expect.eq(6, e.cursor, 'interpret Ctrl-f as goto beginning of next word') + e:onInput{CUSTOM_CTRL_E=true} + expect.eq(16, e.cursor, 'interpret Ctrl-e as end') + e:onInput{CUSTOM_CTRL_B=true} + expect.eq(9, e.cursor, 'interpret Ctrl-b as goto end of previous word') end function test.editfield_click() diff --git a/test/library/gui/widgets.Label.lua b/test/library/gui/widgets.Label.lua index 4693d3d0d..bb6e06235 100644 --- a/test/library/gui/widgets.Label.lua +++ b/test/library/gui/widgets.Label.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local gui = require('gui') local widgets = require('gui.widgets') diff --git a/test/library/gui/widgets.Scrollbar.lua b/test/library/gui/widgets.Scrollbar.lua index dbe033ba4..d1024a1cf 100644 --- a/test/library/gui/widgets.Scrollbar.lua +++ b/test/library/gui/widgets.Scrollbar.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local gui = require('gui') local widgets = require('gui.widgets') @@ -10,7 +12,7 @@ function test.update() expect.eq(1, s.elems_per_page) expect.eq(1, s.num_elems) expect.eq(0, s.bar_offset) - expect.eq(1, s.bar_height) + expect.eq(2, s.bar_height) -- top_elem, elems_per_page, num_elems s:update(1, 10, 0) @@ -18,7 +20,7 @@ function test.update() expect.eq(10, s.elems_per_page) expect.eq(0, s.num_elems) expect.eq(0, s.bar_offset) - expect.eq(1, s.bar_height) + expect.eq(2, s.bar_height) -- first 10 of 50 shown s:update(1, 10, 50) diff --git a/test/library/gui/widgets.lua b/test/library/gui/widgets.lua index 51622e691..8f58076e6 100644 --- a/test/library/gui/widgets.lua +++ b/test/library/gui/widgets.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local widgets = require('gui.widgets') function test.hotkeylabel_click() diff --git a/test/library/helpdb.lua b/test/library/helpdb.lua index 1f1e58ba9..29bc14f41 100644 --- a/test/library/helpdb.lua +++ b/test/library/helpdb.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local h = require('helpdb') local mock_plugin_db = { diff --git a/test/library/misc.lua b/test/library/misc.lua index e746ec1a6..dd1dae2c6 100644 --- a/test/library/misc.lua +++ b/test/library/misc.lua @@ -1,5 +1,7 @@ -- tests misc functions added by dfhack.lua +config.targets = 'core' + function test.safe_pairs() for k,v in safe_pairs(nil) do expect.fail('nil should not be iterable') diff --git a/test/library/print.lua b/test/library/print.lua index 3f9b5a78c..3a839168e 100644 --- a/test/library/print.lua +++ b/test/library/print.lua @@ -1,5 +1,7 @@ -- tests print-related functions added by dfhack.lua +config.targets = 'core' + local dfhack = dfhack local mock_print = mock.func() diff --git a/test/library/string.lua b/test/library/string.lua index d22f262bf..8854fa21c 100644 --- a/test/library/string.lua +++ b/test/library/string.lua @@ -1,5 +1,7 @@ -- tests string functions added by dfhack.lua +config.targets = 'core' + function test.startswith() expect.true_(('abcd'):startswith('')) expect.true_(('abcd'):startswith('abc')) diff --git a/test/library/test_util/expect_unit.lua b/test/library/test_util/expect_unit.lua index 1c3bd51e8..7f1fa3146 100644 --- a/test/library/test_util/expect_unit.lua +++ b/test/library/test_util/expect_unit.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local expect_raw = require('test_util.expect') function test.str_find() diff --git a/test/library/test_util/mock.lua b/test/library/test_util/mock.lua index 1031a496a..93c24e160 100644 --- a/test/library/test_util/mock.lua +++ b/test/library/test_util/mock.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local mock = require('test_util.mock') local test_table = { diff --git a/test/library/utils.lua b/test/library/utils.lua index cf2024618..c33e53a7f 100644 --- a/test/library/utils.lua +++ b/test/library/utils.lua @@ -1,3 +1,5 @@ +config.targets = 'core' + local utils = require 'utils' function test.OrderedTable() @@ -102,7 +104,7 @@ function test.df_expr_to_ref() expect.eq(df.reinterpret_cast(df.world, utils.df_expr_to_ref('unit[0]').value), df.global.world) expect.eq(utils.df_expr_to_ref('unit[1]'), utils.df_expr_to_ref('unit.1')) - expect.eq(df.reinterpret_cast(df.ui, utils.df_expr_to_ref('unit[1]').value), df.global.plotinfo) + expect.eq(df.reinterpret_cast(df.plotinfost, utils.df_expr_to_ref('unit[1]').value), df.global.plotinfo) expect.error_match('index out of bounds', function() utils.df_expr_to_ref('unit.2') end) expect.error_match('index out of bounds', function() utils.df_expr_to_ref('unit[2]') end) diff --git a/test/structures/misc.lua b/test/structures/misc.lua index 277457dfe..ebfe8edd4 100644 --- a/test/structures/misc.lua +++ b/test/structures/misc.lua @@ -1,8 +1,9 @@ -config.targets = 'core' +-- TODO: fix crash in test.viewscreenDtors with viewscreen_legendsst +--config.targets = 'core' function test.overlappingGlobals() local globals = {} - for name, _ in pairs(df.global) do + for name in pairs(df.global) do local gvar = df.global:_field(name) local size, addr = gvar:sizeof() table.insert(globals, { From 4c89af7c20f0cf0f8fe6a4857f245a6eb974e11a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 09:59:08 -0700 Subject: [PATCH 246/851] targets -> target --- ci/test.lua | 2 +- test/core.lua | 2 +- test/encoding.lua | 2 +- test/gui.lua | 2 +- test/library/argparse.lua | 2 +- test/library/gui.lua | 2 +- test/library/gui/dialogs.lua | 2 +- test/library/gui/widgets.EditField.lua | 2 +- test/library/gui/widgets.Label.lua | 2 +- test/library/gui/widgets.Scrollbar.lua | 2 +- test/library/gui/widgets.lua | 2 +- test/library/helpdb.lua | 2 +- test/library/misc.lua | 2 +- test/library/print.lua | 2 +- test/library/string.lua | 2 +- test/library/test_util/expect_unit.lua | 2 +- test/library/test_util/mock.lua | 2 +- test/library/utils.lua | 2 +- test/structures/find.lua | 2 +- test/structures/misc.lua | 3 +-- test/structures/other_vectors.lua | 2 +- test/structures/primitive_refs.lua | 2 +- test/structures/ref_target.lua | 2 +- test/structures/types_meta.lua | 2 +- test/structures/unions.lua | 2 +- test/test.lua | 2 +- 26 files changed, 26 insertions(+), 27 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index 3f7f8c77b..81ed19344 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -379,7 +379,7 @@ local function load_tests(file, tests) dfhack.printerr('Skipping tests for unspecified target in ' .. file) return true -- TODO: change to false once existing tests have targets specified end - local targets = type(env.config.targets) == table and env.config.targets or {env.config.targets} + local targets = type(env.config.target) == table and env.config.target or {env.config.target} for _,target in ipairs(targets) do if target == 'core' then goto continue end if type(target) ~= 'string' or not helpdb.is_entry(target) or diff --git a/test/core.lua b/test/core.lua index 0d21fa38f..cc102984e 100644 --- a/test/core.lua +++ b/test/core.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local function clean_path(p) -- todo: replace with dfhack.filesystem call? diff --git a/test/encoding.lua b/test/encoding.lua index afed4bf8b..7a81f0ec4 100644 --- a/test/encoding.lua +++ b/test/encoding.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' function test.toSearchNormalized() expect.eq(dfhack.toSearchNormalized(''), '') diff --git a/test/gui.lua b/test/gui.lua index ac350ea1b..6bbb34117 100644 --- a/test/gui.lua +++ b/test/gui.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' function test.getCurViewscreen() local scr = dfhack.gui.getCurViewscreen() diff --git a/test/library/argparse.lua b/test/library/argparse.lua index 33891a834..437f1ea2b 100644 --- a/test/library/argparse.lua +++ b/test/library/argparse.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local argparse = require('argparse') local guidm = require('gui.dwarfmode') diff --git a/test/library/gui.lua b/test/library/gui.lua index af8b15b6d..80c91198c 100644 --- a/test/library/gui.lua +++ b/test/library/gui.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local gui = require('gui') diff --git a/test/library/gui/dialogs.lua b/test/library/gui/dialogs.lua index 4ee16027e..524a8b144 100644 --- a/test/library/gui/dialogs.lua +++ b/test/library/gui/dialogs.lua @@ -1,4 +1,4 @@ ---config.targets = 'core' +--config.target = 'core' local gui = require('gui') local function send_keys(...) diff --git a/test/library/gui/widgets.EditField.lua b/test/library/gui/widgets.EditField.lua index eb35bb22c..88625a7bf 100644 --- a/test/library/gui/widgets.EditField.lua +++ b/test/library/gui/widgets.EditField.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local widgets = require('gui.widgets') diff --git a/test/library/gui/widgets.Label.lua b/test/library/gui/widgets.Label.lua index bb6e06235..75acba490 100644 --- a/test/library/gui/widgets.Label.lua +++ b/test/library/gui/widgets.Label.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local gui = require('gui') local widgets = require('gui.widgets') diff --git a/test/library/gui/widgets.Scrollbar.lua b/test/library/gui/widgets.Scrollbar.lua index d1024a1cf..548792b3d 100644 --- a/test/library/gui/widgets.Scrollbar.lua +++ b/test/library/gui/widgets.Scrollbar.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local gui = require('gui') local widgets = require('gui.widgets') diff --git a/test/library/gui/widgets.lua b/test/library/gui/widgets.lua index 8f58076e6..88d3ac952 100644 --- a/test/library/gui/widgets.lua +++ b/test/library/gui/widgets.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local widgets = require('gui.widgets') diff --git a/test/library/helpdb.lua b/test/library/helpdb.lua index 29bc14f41..bc482582c 100644 --- a/test/library/helpdb.lua +++ b/test/library/helpdb.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local h = require('helpdb') diff --git a/test/library/misc.lua b/test/library/misc.lua index dd1dae2c6..58afed967 100644 --- a/test/library/misc.lua +++ b/test/library/misc.lua @@ -1,6 +1,6 @@ -- tests misc functions added by dfhack.lua -config.targets = 'core' +config.target = 'core' function test.safe_pairs() for k,v in safe_pairs(nil) do diff --git a/test/library/print.lua b/test/library/print.lua index 3a839168e..28a2e7037 100644 --- a/test/library/print.lua +++ b/test/library/print.lua @@ -1,6 +1,6 @@ -- tests print-related functions added by dfhack.lua -config.targets = 'core' +config.target = 'core' local dfhack = dfhack diff --git a/test/library/string.lua b/test/library/string.lua index 8854fa21c..f6374f652 100644 --- a/test/library/string.lua +++ b/test/library/string.lua @@ -1,6 +1,6 @@ -- tests string functions added by dfhack.lua -config.targets = 'core' +config.target = 'core' function test.startswith() expect.true_(('abcd'):startswith('')) diff --git a/test/library/test_util/expect_unit.lua b/test/library/test_util/expect_unit.lua index 7f1fa3146..320e49707 100644 --- a/test/library/test_util/expect_unit.lua +++ b/test/library/test_util/expect_unit.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local expect_raw = require('test_util.expect') diff --git a/test/library/test_util/mock.lua b/test/library/test_util/mock.lua index 93c24e160..ce25e6e69 100644 --- a/test/library/test_util/mock.lua +++ b/test/library/test_util/mock.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local mock = require('test_util.mock') diff --git a/test/library/utils.lua b/test/library/utils.lua index c33e53a7f..ac40bea1a 100644 --- a/test/library/utils.lua +++ b/test/library/utils.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local utils = require 'utils' diff --git a/test/structures/find.lua b/test/structures/find.lua index 471220479..e93b2cc7f 100644 --- a/test/structures/find.lua +++ b/test/structures/find.lua @@ -1,5 +1,5 @@ config.mode = 'title' -config.targets = 'core' +config.target = 'core' local function clean_vec(vec) while #vec > 0 do diff --git a/test/structures/misc.lua b/test/structures/misc.lua index ebfe8edd4..e93491d66 100644 --- a/test/structures/misc.lua +++ b/test/structures/misc.lua @@ -1,5 +1,4 @@ --- TODO: fix crash in test.viewscreenDtors with viewscreen_legendsst ---config.targets = 'core' +config.target = 'core' function test.overlappingGlobals() local globals = {} diff --git a/test/structures/other_vectors.lua b/test/structures/other_vectors.lua index 453ab1dca..aea00c27c 100644 --- a/test/structures/other_vectors.lua +++ b/test/structures/other_vectors.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' function test.index_name() for _, k in ipairs(df.units_other_id) do diff --git a/test/structures/primitive_refs.lua b/test/structures/primitive_refs.lua index 77049b673..7bd7daf3c 100644 --- a/test/structures/primitive_refs.lua +++ b/test/structures/primitive_refs.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' utils = require('utils') diff --git a/test/structures/ref_target.lua b/test/structures/ref_target.lua index 56bfdbfc7..560a5e4f7 100644 --- a/test/structures/ref_target.lua +++ b/test/structures/ref_target.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' function test.get() dfhack.with_temp_object(df.unit:new(), function(unit) diff --git a/test/structures/types_meta.lua b/test/structures/types_meta.lua index 5809960bf..79395575f 100644 --- a/test/structures/types_meta.lua +++ b/test/structures/types_meta.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' function test.struct() expect.eq(df.coord._kind, 'struct-type') diff --git a/test/structures/unions.lua b/test/structures/unions.lua index 9e4c767db..a664506df 100644 --- a/test/structures/unions.lua +++ b/test/structures/unions.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' local utils = require('utils') diff --git a/test/test.lua b/test/test.lua index 679325d2e..fbad06003 100644 --- a/test/test.lua +++ b/test/test.lua @@ -1,4 +1,4 @@ -config.targets = 'core' +config.target = 'core' function test.internal_in_test() expect.true_(dfhack.internal.IN_TEST) From d93bf65115e431ea16f3c90584d79e75bc59dab5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 10:25:49 -0700 Subject: [PATCH 247/851] fix typo --- ci/test.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test.lua b/ci/test.lua index 81ed19344..de9389b00 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -379,7 +379,7 @@ local function load_tests(file, tests) dfhack.printerr('Skipping tests for unspecified target in ' .. file) return true -- TODO: change to false once existing tests have targets specified end - local targets = type(env.config.target) == table and env.config.target or {env.config.target} + local targets = type(env.config.target) == 'table' and env.config.target or {env.config.target} for _,target in ipairs(targets) do if target == 'core' then goto continue end if type(target) ~= 'string' or not helpdb.is_entry(target) or From 415a2f654b611d79ddad69d4c940be24d06e3562 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 12:23:48 -0700 Subject: [PATCH 248/851] update stonesense ref --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index f9fce95fd..9080becf8 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit f9fce95fd74bf1d5050e891dbd3e0bda2e8a7ce9 +Subproject commit 9080becf81ee93a069dff48f13aa0f0f7df8c51d From 02fae5afd4e1bf0ef1d265ae01b009727a757fd1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 12:38:51 -0700 Subject: [PATCH 249/851] treat doc warnings as errors --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b15cbf962..d3db43a6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -487,7 +487,7 @@ if(BUILD_DOCS) ) add_custom_command(OUTPUT ${SPHINX_OUTPUT} COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/docs/build.py" - html text --sphinx="${SPHINX_EXECUTABLE}" -- -q + html text --sphinx="${SPHINX_EXECUTABLE}" -- -q -W DEPENDS ${SPHINX_DEPS} COMMENT "Building documentation with Sphinx" ) From 91afb7ed1be7f4bc1ee118fb820faf28a33def7f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 12:57:44 -0700 Subject: [PATCH 250/851] make clean-cache workflow reusable --- .github/workflows/clean-cache.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/clean-cache.yml b/.github/workflows/clean-cache.yml index 36984a6a1..e88e46c01 100644 --- a/.github/workflows/clean-cache.yml +++ b/.github/workflows/clean-cache.yml @@ -1,6 +1,7 @@ name: Clean up PR caches on: + workflow_call: pull_request_target: types: - closed From f507bd7e38c2354282e152064b5f735cfe20ce37 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 4 Aug 2023 20:22:58 +0000 Subject: [PATCH 251/851] 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 c5e1ca2bf..f037dc64f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit c5e1ca2bfdd9bdc05a884c5624a5fa20bc72c49a +Subproject commit f037dc64fc2538eee6d2841141b6a278c04b2175 From 6ff5ab9f39156e7a662b5d3607e3f3b7882b7c05 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 13:31:21 -0700 Subject: [PATCH 252/851] avoid platform-specific steps by using same shell --- .github/workflows/test.yml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 40f497b78..61eb70aad 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -68,22 +68,16 @@ jobs: # gcc: 12 # plugins: "all" steps: - - name: Set env (windows) - if: matrix.os == 'windows' - run: echo "DF_FOLDER=DF" >> $env:GITHUB_ENV - - name: Set env (posix) - if: matrix.os != 'windows' + - name: Set env + shell: bash run: echo "DF_FOLDER=DF" >> $GITHUB_ENV - name: Clone DFHack uses: actions/checkout@v3 with: repository: 'DFHack/dfhack' ref: ${{ inputs.dfhack_ref }} - - name: Detect DF version (windows) - if: matrix.os == 'windows' - run: echo DF_VERSION="$(sh ci/get-df-version.sh)" >> $env:GITHUB_ENV - - name: Detect DF version (posix) - if: matrix.os != 'windows' + - name: Detect DF version + shell: bash run: echo DF_VERSION="$(sh ci/get-df-version.sh)" >> $GITHUB_ENV - name: Fetch DF cache id: restore-df From 7aa6aa317a9bbd89bce469797cf151c422f5a21c Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 4 Aug 2023 17:09:50 -0400 Subject: [PATCH 253/851] targets -> target part 2 --- ci/test.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/test.lua b/ci/test.lua index de9389b00..bb12f6be1 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -375,7 +375,7 @@ local function load_tests(file, tests) dfhack.printerr('Invalid config.mode: ' .. tostring(env.config.mode)) return false end - if not env.config.targets then + if not env.config.target then dfhack.printerr('Skipping tests for unspecified target in ' .. file) return true -- TODO: change to false once existing tests have targets specified end From 47b4773786d8dd96878e05ea7084d922b3da42bb Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 4 Aug 2023 17:14:08 -0400 Subject: [PATCH 254/851] df.new(): catch errors thrown by allocate() This can include DFHack::Error::VTableMissing exceptions if the vtable of a member field is unknown. Fixes #3627 --- docs/changelog.txt | 1 + library/LuaWrapper.cpp | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 5e65b4909..0559b2dde 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: ## Internals ## Lua +- ``new()``: improved error handling so that certain errors that were previously uncatchable (creating objects with members with unknown vtables) are now catchable with ``pcall()`` ## Removed diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 59bd96732..1ea4865bd 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -685,7 +685,8 @@ static int meta_new(lua_State *state) type_identity *id = get_object_identity(state, 1, "df.new()", true); - void *ptr; + void *ptr = nullptr; + std::string err_context; // Support arrays of primitive types if (argc == 2) @@ -703,11 +704,22 @@ static int meta_new(lua_State *state) } else { - ptr = id->allocate(); + try { + ptr = id->allocate(); + } + catch (std::exception &e) { + if (e.what()) { + err_context = e.what(); + } + } } if (!ptr) - luaL_error(state, "Cannot allocate %s", id->getFullName().c_str()); + luaL_error(state, "Cannot allocate %s%s%s", + id->getFullName().c_str(), + err_context.empty() ? "" : ": ", + err_context.c_str() + ); if (lua_isuserdata(state, 1)) { From 0ef1a475e40946fc5cf7d20e266d1a5e56ab840c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 16:43:58 -0700 Subject: [PATCH 255/851] allow code to be generated even when the library isn't being built --- library/CMakeLists.txt | 62 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index 2ea2d830f..e9ec8f717 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -4,15 +4,16 @@ cmake_minimum_required(VERSION 3.21) # prevent CMake warnings about INTERFACE_LINK_LIBRARIES vs LINK_INTERFACE_LIBRARIES cmake_policy(SET CMP0022 NEW) -if(BUILD_LIBRARY) - # build options if(UNIX) option(CONSOLE_NO_CATCH "Make the console not catch 'CTRL+C' events for easier debugging." OFF) endif() -include_directories(proto) -include_directories(include) +# Generation +set(CODEGEN_OUT ${dfapi_SOURCE_DIR}/include/df/codegen.out.xml) + +file(GLOB GENERATE_INPUT_SCRIPTS ${dfapi_SOURCE_DIR}/xml/*.pm ${dfapi_SOURCE_DIR}/xml/*.xslt) +file(GLOB GENERATE_INPUT_XMLS ${dfapi_SOURCE_DIR}/xml/df.*.xml) execute_process(COMMAND ${PERL_EXECUTABLE} xml/list.pl xml ${dfapi_SOURCE_DIR}/include/df ";" WORKING_DIRECTORY ${dfapi_SOURCE_DIR} @@ -20,6 +21,32 @@ execute_process(COMMAND ${PERL_EXECUTABLE} xml/list.pl xml ${dfapi_SOURCE_DIR}/i set_source_files_properties(${GENERATED_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE GENERATED TRUE) +add_custom_command( + OUTPUT ${CODEGEN_OUT} + BYPRODUCTS ${GENERATED_HDRS} + COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/xml/codegen.pl + ${CMAKE_CURRENT_SOURCE_DIR}/xml + ${CMAKE_CURRENT_SOURCE_DIR}/include/df + MAIN_DEPENDENCY ${dfapi_SOURCE_DIR}/xml/codegen.pl + COMMENT "Generating codegen.out.xml and df/headers" + DEPENDS ${GENERATE_INPUT_XMLS} ${GENERATE_INPUT_SCRIPTS} +) + +if(NOT("${CMAKE_GENERATOR}" STREQUAL Ninja)) + # use BYPRODUCTS instead under Ninja to avoid rebuilds + list(APPEND CODEGEN_OUT ${GENERATED_HDRS}) +endif() + +add_custom_target(generate_headers DEPENDS ${CODEGEN_OUT}) + +include_directories(include) + +add_subdirectory(xml) + +if(BUILD_LIBRARY) + +include_directories(proto) + set(MAIN_HEADERS include/Internal.h include/DFHack.h @@ -263,33 +290,8 @@ add_custom_target(generate_proto_core DEPENDS ${PROJECT_PROTO_TMP_FILES}) # Merge headers into sources set_source_files_properties( ${PROJECT_HEADERS} PROPERTIES HEADER_FILE_ONLY TRUE ) list(APPEND PROJECT_SOURCES ${PROJECT_HEADERS}) - -# Generation list(APPEND PROJECT_SOURCES ${GENERATED_HDRS}) -file(GLOB GENERATE_INPUT_SCRIPTS ${dfapi_SOURCE_DIR}/xml/*.pm ${dfapi_SOURCE_DIR}/xml/*.xslt) -file(GLOB GENERATE_INPUT_XMLS ${dfapi_SOURCE_DIR}/xml/df.*.xml) - -set(CODEGEN_OUT ${dfapi_SOURCE_DIR}/include/df/codegen.out.xml) -if(NOT("${CMAKE_GENERATOR}" STREQUAL Ninja)) - # use BYPRODUCTS instead under Ninja to avoid rebuilds - list(APPEND CODEGEN_OUT ${GENERATED_HDRS}) -endif() - -add_custom_command( - OUTPUT ${CODEGEN_OUT} - BYPRODUCTS ${GENERATED_HDRS} - COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/xml/codegen.pl - ${CMAKE_CURRENT_SOURCE_DIR}/xml - ${CMAKE_CURRENT_SOURCE_DIR}/include/df - MAIN_DEPENDENCY ${dfapi_SOURCE_DIR}/xml/codegen.pl - COMMENT "Generating codegen.out.xml and df/headers" - DEPENDS ${GENERATE_INPUT_XMLS} ${GENERATE_INPUT_SCRIPTS} -) - -add_custom_target(generate_headers - DEPENDS ${dfapi_SOURCE_DIR}/include/df/codegen.out.xml) - if(REMOVE_SYMBOLS_FROM_DF_STUBS) if(UNIX) # Don't produce debug info for generated stubs @@ -443,8 +445,6 @@ install(TARGETS dfhack-run dfhack-client binpatch LIBRARY DESTINATION ${DFHACK_LIBRARY_DESTINATION} RUNTIME DESTINATION ${DFHACK_LIBRARY_DESTINATION}) -add_subdirectory(xml) - endif(BUILD_LIBRARY) # install the offset file From c5ad5d09136820888fb283e469a99924aa9cad1e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 16:56:06 -0700 Subject: [PATCH 256/851] allow the reusable workflows to build xml-dump-type-sizes --- .github/workflows/build-linux.yml | 6 +++++- .github/workflows/build-windows.yml | 11 +++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index b5ff9aa39..a4609128b 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -38,6 +38,9 @@ on: tests: type: boolean default: false + xml-dump-type-sizes: + type: boolean + default: false gcc-ver: type: string default: "10" @@ -52,7 +55,7 @@ jobs: sudo apt-get update sudo apt-get install ninja-build - name: Install binary build dependencies - if: inputs.platform-files + if: inputs.platform-files || inputs.xml-dump-type-sizes run: | sudo apt-get install \ ccache \ @@ -116,6 +119,7 @@ jobs: -DBUILD_SKELETON:BOOL=${{ inputs.extras }} \ -DBUILD_DOCS:BOOL=${{ inputs.docs }} \ -DBUILD_TESTS:BOOL=${{ inputs.tests }} \ + -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }} \ -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} \ -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} - name: Build DFHack diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 4e385802e..987dfc562 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -20,6 +20,9 @@ on: cache-readonly: type: boolean default: false + platform-files: + type: boolean + default: true common-files: type: boolean default: true @@ -32,6 +35,9 @@ on: tests: type: boolean default: false + xml-dump-type-sizes: + type: boolean + default: false launchdf: type: boolean default: false @@ -75,6 +81,7 @@ jobs: ssh-key: ${{ secrets.DFHACK_3RDPARTY_TOKEN }} path: depends/steam - name: Fetch ccache + if: inputs.platform-files uses: actions/cache/restore@v3 with: path: build/win64-cross/ccache @@ -84,7 +91,7 @@ jobs: win-msvc - name: Cross-compile env: - CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} -DBUILD_TESTS:BOOL=${{ inputs.tests }}' + CMAKE_EXTRA_ARGS: '-DBUILD_LIBRARY=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} -DBUILD_TESTS:BOOL=${{ inputs.tests }} -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }}' run: | cd build bash -x build-win64-from-linux.sh @@ -95,7 +102,7 @@ jobs: ccache -d win64-cross/ccache --cleanup ccache -d win64-cross/ccache --show-stats --verbose - name: Save ccache - if: '!inputs.cache-readonly' + if: inputs.platform-files && !inputs.cache-readonly uses: actions/cache/save@v3 with: path: build/win64-cross/ccache From ba0df782339bd5ffbc8617a22d3aed46dc581b8c Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Fri, 4 Aug 2023 20:00:29 -0500 Subject: [PATCH 257/851] DataIdentity support for `std::future` --- library/DataIdentity.cpp | 6 +++++- library/include/DataIdentity.h | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/library/DataIdentity.cpp b/library/DataIdentity.cpp index 03851520c..ba7c7f4a6 100644 --- a/library/DataIdentity.cpp +++ b/library/DataIdentity.cpp @@ -9,13 +9,16 @@ #include "DataFuncs.h" #include "DataIdentity.h" +// the space after the uses of "type" in OPAQUE_IDENTITY_TRAITS_NAME is _required_ +// without it the macro generates a syntax error when type is a template specification + namespace df { #define NUMBER_IDENTITY_TRAITS(category, type, name) \ category##_identity identity_traits::identity(name); #define INTEGER_IDENTITY_TRAITS(type, name) NUMBER_IDENTITY_TRAITS(integer, type, name) #define FLOAT_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(float, type, #type) #define OPAQUE_IDENTITY_TRAITS_NAME(type, name) \ - opaque_identity identity_traits::identity(sizeof(type), allocator_noassign_fn, name) + opaque_identity identity_traits::identity(sizeof(type), allocator_noassign_fn, name) #define STL_OPAQUE_IDENTITY_TRAITS(type) OPAQUE_IDENTITY_TRAITS_NAME(std::type, #type) #ifndef STATIC_FIELDS_GROUP @@ -45,6 +48,7 @@ namespace df { STL_OPAQUE_IDENTITY_TRAITS(condition_variable); STL_OPAQUE_IDENTITY_TRAITS(fstream); STL_OPAQUE_IDENTITY_TRAITS(mutex); + STL_OPAQUE_IDENTITY_TRAITS(future); buffer_container_identity buffer_container_identity::base_instance; #endif diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index be5466444..07e85e8a8 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -29,6 +29,7 @@ distribution. #include #include #include +#include #include "DataDefs.h" @@ -546,8 +547,11 @@ namespace df #define INTEGER_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(integer, type) #define FLOAT_IDENTITY_TRAITS(type) NUMBER_IDENTITY_TRAITS(float, type) +// the space after the use of "type" in OPAQUE_IDENTITY_TRAITS is _required_ +// without it the macro generates a syntax error when type is a template specification + #define OPAQUE_IDENTITY_TRAITS(type) \ - template<> struct DFHACK_EXPORT identity_traits { \ + template<> struct DFHACK_EXPORT identity_traits { \ static opaque_identity identity; \ static opaque_identity *get() { return &identity; } \ }; @@ -568,6 +572,7 @@ namespace df OPAQUE_IDENTITY_TRAITS(std::condition_variable); OPAQUE_IDENTITY_TRAITS(std::fstream); OPAQUE_IDENTITY_TRAITS(std::mutex); + OPAQUE_IDENTITY_TRAITS(std::future); template<> struct DFHACK_EXPORT identity_traits { static bool_identity identity; From 1864090bda1444597966db226d482cd9b0f46d13 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 5 Aug 2023 02:56:08 +0000 Subject: [PATCH 258/851] 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 f037dc64f..a5405ed29 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f037dc64fc2538eee6d2841141b6a278c04b2175 +Subproject commit a5405ed296a97fb64b272986b850b289f2064ac1 diff --git a/scripts b/scripts index c0b17a57f..8bd85f707 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit c0b17a57f36fd37eaf76eff2162bd6379f8f7e42 +Subproject commit 8bd85f7078bf38788825507df2271986454ad74a From 3358a2b51609b6510b6e971e1e8ba844af978acb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 20:40:24 -0700 Subject: [PATCH 259/851] enable more tests --- ci/test.lua | 1 + plugins/lua/blueprint.lua | 2 +- test/library/gui/widgets.Label.lua | 2 +- test/library/helpdb.lua | 2 +- test/plugins/blueprint.lua | 26 ++++++++++++++------------ test/plugins/cxxrandom.lua | 2 ++ test/plugins/orders.lua | 1 + test/plugins/workflow.lua | 2 ++ test/quickfort/ecosystem.lua | 1 + test/structures/misc.lua | 2 +- 10 files changed, 25 insertions(+), 16 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index bb12f6be1..01168800b 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -553,6 +553,7 @@ local function run_tests(tests, status, counts, config) goto skip end if not MODES[test.config.mode].detect() then + print(('Switching to %s mode for test: %s'):format(test.config.mode, test.name)) local ok, err = pcall(MODES[test.config.mode].navigate, config) if not ok then MODES[test.config.mode].failed = true diff --git a/plugins/lua/blueprint.lua b/plugins/lua/blueprint.lua index 57dee31fc..6aa154d2d 100644 --- a/plugins/lua/blueprint.lua +++ b/plugins/lua/blueprint.lua @@ -207,7 +207,7 @@ end -- returns the name of the output file for the given context function get_filename(opts, phase, ordinal) local fullname = 'dfhack-config/blueprints/' .. opts.name - local _,_,basename = fullname:find('/([^/]+)/?$') + local _,_,basename = opts.name:find('([^/]+)/*$') if not basename then -- should not happen since opts.name should already be validated error(('could not parse basename out of "%s"'):format(fullname)) diff --git a/test/library/gui/widgets.Label.lua b/test/library/gui/widgets.Label.lua index 75acba490..09ead7ad5 100644 --- a/test/library/gui/widgets.Label.lua +++ b/test/library/gui/widgets.Label.lua @@ -3,7 +3,7 @@ config.target = 'core' local gui = require('gui') local widgets = require('gui.widgets') -local fs = defclass(fs, gui.FramedScreen) +local fs = defclass(nil, gui.FramedScreen) fs.ATTRS = { frame_style = gui.GREY_LINE_FRAME, frame_title = 'TestFramedScreen', diff --git a/test/library/helpdb.lua b/test/library/helpdb.lua index bc482582c..7be2488df 100644 --- a/test/library/helpdb.lua +++ b/test/library/helpdb.lua @@ -1,4 +1,4 @@ -config.target = 'core' +--config.target = 'core' local h = require('helpdb') diff --git a/test/plugins/blueprint.lua b/test/plugins/blueprint.lua index 6146aea3f..35d32e1ff 100644 --- a/test/plugins/blueprint.lua +++ b/test/plugins/blueprint.lua @@ -1,3 +1,5 @@ +config.target = 'blueprint' + local b = require('plugins.blueprint') -- also covers code shared between parse_gui_commandline and parse_commandline @@ -117,9 +119,9 @@ function test.parse_gui_commandline() function() b.parse_gui_commandline({}, {''}) end) opts = {} - b.parse_gui_commandline(opts, {'imaname', 'dig', 'query'}) + b.parse_gui_commandline(opts, {'imaname', 'dig', 'place'}) expect.table_eq({auto_phase=false, format='minimal', split_strategy='none', - name='imaname', dig=true, query=true}, + name='imaname', dig=true, place=true}, opts) expect.error_match('unknown phase', @@ -203,9 +205,9 @@ function test.do_phase_positive_dims() function() local spos = {x=10, y=20, z=30} local epos = {x=11, y=21, z=31} - b.query(spos, epos, 'imaname') + b.place(spos, epos, 'imaname') expect.eq(1, mock_run.call_count) - expect.table_eq({'2', '2', '2', 'imaname', 'query', + expect.table_eq({'2', '2', '2', 'imaname', 'place', '--cursor=10,20,30'}, mock_run.call_args[1]) end) @@ -217,9 +219,9 @@ function test.do_phase_negative_dims() function() local spos = {x=11, y=21, z=31} local epos = {x=10, y=20, z=30} - b.query(spos, epos, 'imaname') + b.place(spos, epos, 'imaname') expect.eq(1, mock_run.call_count) - expect.table_eq({'2', '2', '-2', 'imaname', 'query', + expect.table_eq({'2', '2', '-2', 'imaname', 'place', '--cursor=10,20,31'}, mock_run.call_args[1]) end) @@ -231,9 +233,9 @@ function test.do_phase_ensure_cursor_is_at_upper_left() function() local spos = {x=11, y=20, z=30} local epos = {x=10, y=21, z=31} - b.query(spos, epos, 'imaname') + b.place(spos, epos, 'imaname') expect.eq(1, mock_run.call_count) - expect.table_eq({'2', '2', '2', 'imaname', 'query', + expect.table_eq({'2', '2', '2', 'imaname', 'place', '--cursor=10,20,30'}, mock_run.call_args[1]) end) @@ -241,16 +243,16 @@ end function test.get_filename() local opts = {name='a', split_strategy='none'} - expect.eq('blueprints/a.csv', b.get_filename(opts, 'dig', 1)) + expect.eq('dfhack-config/blueprints/a.csv', b.get_filename(opts, 'dig', 1)) opts = {name='a/', split_strategy='none'} - expect.eq('blueprints/a/a.csv', b.get_filename(opts, 'dig', 1)) + expect.eq('dfhack-config/blueprints/a/a.csv', b.get_filename(opts, 'dig', 1)) opts = {name='a', split_strategy='phase'} - expect.eq('blueprints/a-1-dig.csv', b.get_filename(opts, 'dig', 1)) + expect.eq('dfhack-config/blueprints/a-1-dig.csv', b.get_filename(opts, 'dig', 1)) opts = {name='a/', split_strategy='phase'} - expect.eq('blueprints/a/a-5-dig.csv', b.get_filename(opts, 'dig', 5)) + expect.eq('dfhack-config/blueprints/a/a-5-dig.csv', b.get_filename(opts, 'dig', 5)) expect.error_match('could not parse basename', function() b.get_filename({name='', split_strategy='none'}) diff --git a/test/plugins/cxxrandom.lua b/test/plugins/cxxrandom.lua index 6b11e1937..997cb2cb3 100644 --- a/test/plugins/cxxrandom.lua +++ b/test/plugins/cxxrandom.lua @@ -1,3 +1,5 @@ +config.target = 'cxxrandom' + local rng = require('plugins.cxxrandom') function test.cxxrandom_distributions() diff --git a/test/plugins/orders.lua b/test/plugins/orders.lua index a0959ae94..c5fae8eb2 100644 --- a/test/plugins/orders.lua +++ b/test/plugins/orders.lua @@ -1,4 +1,5 @@ config.mode = 'fortress' +--config.target = 'orders' local FILE_PATH_PATTERN = 'dfhack-config/orders/%s.json' diff --git a/test/plugins/workflow.lua b/test/plugins/workflow.lua index a03d1c2f6..8d0c69c68 100644 --- a/test/plugins/workflow.lua +++ b/test/plugins/workflow.lua @@ -1,3 +1,5 @@ +config.target = 'workflow' + local workflow = require('plugins.workflow') function test.job_outputs() diff --git a/test/quickfort/ecosystem.lua b/test/quickfort/ecosystem.lua index 3a4c014e4..bbe16319f 100644 --- a/test/quickfort/ecosystem.lua +++ b/test/quickfort/ecosystem.lua @@ -26,6 +26,7 @@ -- crashing the game. config.mode = 'fortress' +config.target = {'quickfort', 'blueprint', 'dig-now', 'tiletypes', 'gui/quantum'} local argparse = require('argparse') local gui = require('gui') diff --git a/test/structures/misc.lua b/test/structures/misc.lua index e93491d66..13febff56 100644 --- a/test/structures/misc.lua +++ b/test/structures/misc.lua @@ -28,7 +28,7 @@ function test.viewscreenDtors() for name, type in pairs(df) do if name:startswith('viewscreen') then print('testing', name) - v = type:new() + local v = type:new() expect.true_(v:delete(), "destructor returned false: " .. name) end end From c323576c1e364e995a5e072c7a6582e549e06dd3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 23:31:01 -0700 Subject: [PATCH 260/851] build docs for tests so the harness can identify unavailables --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 61eb70aad..c74b559ea 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,6 +20,7 @@ jobs: structures_ref: ${{ inputs.structures_ref }} artifact-name: test-msvc cache-id: test + docs: true tests: true build-linux: @@ -33,6 +34,7 @@ jobs: cache-id: test stonesense: ${{ matrix.plugins == 'all' }} extras: ${{ matrix.plugins == 'all' }} + docs: true tests: true gcc-ver: ${{ matrix.gcc }} secrets: inherit From 7981624792ff1510f29eedd57fcc61542fd4156e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 4 Aug 2023 23:59:04 -0700 Subject: [PATCH 261/851] don't build html docs unless we have to --- .github/workflows/build-linux.yml | 4 ++++ .github/workflows/build-windows.yml | 5 ++++- .github/workflows/test.yml | 2 ++ CMakeLists.txt | 23 +++++++++++++++++------ 4 files changed, 27 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index a4609128b..f7088a234 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -29,6 +29,9 @@ on: docs: type: boolean default: false + html: + type: boolean + default: true stonesense: type: boolean default: false @@ -118,6 +121,7 @@ jobs: -DBUILD_SIZECHECK:BOOL=${{ inputs.extras }} \ -DBUILD_SKELETON:BOOL=${{ inputs.extras }} \ -DBUILD_DOCS:BOOL=${{ inputs.docs }} \ + -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} \ -DBUILD_TESTS:BOOL=${{ inputs.tests }} \ -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }} \ -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} \ diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 987dfc562..50d7f6936 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -29,6 +29,9 @@ on: docs: type: boolean default: false + html: + type: boolean + default: true stonesense: type: boolean default: false @@ -91,7 +94,7 @@ jobs: win-msvc - name: Cross-compile env: - CMAKE_EXTRA_ARGS: '-DBUILD_LIBRARY=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} -DBUILD_TESTS:BOOL=${{ inputs.tests }} -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }}' + CMAKE_EXTRA_ARGS: '-DBUILD_LIBRARY=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} -DBUILD_TESTS:BOOL=${{ inputs.tests }} -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }}' run: | cd build bash -x build-win64-from-linux.sh diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c74b559ea..0934d6d00 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,6 +21,7 @@ jobs: artifact-name: test-msvc cache-id: test docs: true + html: false tests: true build-linux: @@ -35,6 +36,7 @@ jobs: stonesense: ${{ matrix.plugins == 'all' }} extras: ${{ matrix.plugins == 'all' }} docs: true + html: false tests: true gcc-ver: ${{ matrix.gcc }} secrets: inherit diff --git a/CMakeLists.txt b/CMakeLists.txt index d3db43a6c..4e0e30f44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,7 @@ else(CMAKE_CONFIGURATION_TYPES) endif(CMAKE_CONFIGURATION_TYPES) option(BUILD_DOCS "Choose whether to build the documentation (requires python and Sphinx)." OFF) +option(BUILD_DOCS_NO_HTML "Don't build the HTML docs, only the in-game docs." OFF) option(REMOVE_SYMBOLS_FROM_DF_STUBS "Remove debug symbols from DF stubs. (Reduces libdfhack size to about half but removes a few useful symbols)" ON) macro(CHECK_GCC compiler_path) @@ -468,7 +469,14 @@ if(BUILD_DOCS) "${CMAKE_CURRENT_SOURCE_DIR}/conf.py" ) - set(SPHINX_OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/docs/html/.buildinfo") + if(BUILD_DOCS_NO_HTML) + set(SPHINX_OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/docs/text/index.txt") + set(SPHINX_BUILD_TARGETS text) + else() + set(SPHINX_OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/docs/html/.buildinfo") + set(SPHINX_BUILD_TARGETS html text) + endif() + set_property( DIRECTORY PROPERTY ADDITIONAL_CLEAN_FILES TRUE "${CMAKE_CURRENT_SOURCE_DIR}/docs/changelogs" @@ -485,9 +493,10 @@ if(BUILD_DOCS) "${CMAKE_BINARY_DIR}/docs/text" "${CMAKE_BINARY_DIR}/docs/xml" ) + add_custom_command(OUTPUT ${SPHINX_OUTPUT} COMMAND "${Python3_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/docs/build.py" - html text --sphinx="${SPHINX_EXECUTABLE}" -- -q -W + ${SPHINX_BUILD_TARGETS} --sphinx="${SPHINX_EXECUTABLE}" -- -q -W DEPENDS ${SPHINX_DEPS} COMMENT "Building documentation with Sphinx" ) @@ -500,10 +509,12 @@ if(BUILD_DOCS) add_custom_command(TARGET dfhack_docs POST_BUILD COMMAND ${CMAKE_COMMAND} -E touch ${SPHINX_OUTPUT}) - install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/html/ - DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs - FILES_MATCHING PATTERN "*" - PATTERN html/_sources EXCLUDE) + if(NOT BUILD_DOCS_NO_HTML) + install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/html/ + DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs + FILES_MATCHING PATTERN "*" + PATTERN html/_sources EXCLUDE) + endif() install(DIRECTORY ${dfhack_SOURCE_DIR}/docs/text/ DESTINATION ${DFHACK_USERDOC_DESTINATION}/docs) install(FILES docs/changelogs/news.rst docs/changelogs/news-dev.rst DESTINATION ${DFHACK_USERDOC_DESTINATION}) From 5e1854edae5415bc154eb680f2cfedeab18d3120 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 5 Aug 2023 07:11:36 +0000 Subject: [PATCH 262/851] 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 a5405ed29..88e95e3b9 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit a5405ed296a97fb64b272986b850b289f2064ac1 +Subproject commit 88e95e3b9282b83d5134839f3bd7fc021f0ba53e diff --git a/scripts b/scripts index 8bd85f707..b0ac91f37 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 8bd85f7078bf38788825507df2271986454ad74a +Subproject commit b0ac91f37fe85ac2538caff3d507c861e99dc803 From 9552d145b6782030f5e445997415ed9f798916eb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 5 Aug 2023 00:56:16 -0700 Subject: [PATCH 263/851] clean up steam deployment code --- .github/workflows/steam-deploy.yml | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index 5b14d0bc8..70d061221 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -68,23 +68,10 @@ jobs: runs-on: ubuntu-latest concurrency: steam steps: - - name: Set env + - name: Get tag run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - - name: Stage common depot files + - name: Stage depot files uses: actions/download-artifact@v3 - with: - name: common-depot - path: common - - name: Stage win64 depot files - uses: actions/download-artifact@v3 - with: - name: win64-depot - path: win64 - - name: Stage linux64 depot files - uses: actions/download-artifact@v3 - with: - name: linux64-depot - path: linux64 - name: Steam deploy uses: game-ci/steam-deploy@v3 with: @@ -93,7 +80,7 @@ jobs: appId: 2346660 buildDescription: ${{ github.event.inputs && github.event.inputs.version || env.TAG }} rootPath: . - depot1Path: common - depot2Path: win64 - depot3Path: linux64 + depot1Path: common-depot + depot2Path: win64-depot + depot3Path: linux64-depot releaseBranch: ${{ github.event.inputs && github.event.inputs.release_channel || 'staging' }} From 6357aa2419416b82e51218a7be58d1dd49ef91da Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 5 Aug 2023 00:58:09 -0700 Subject: [PATCH 264/851] factor out release package logic --- .github/workflows/build.yml | 22 ++---------- .github/workflows/github-release.yml | 40 ++++------------------ .github/workflows/package.yml | 51 ++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 52 deletions(-) create mode 100644 .github/workflows/package.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 051fc55b7..3f2017324 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,26 +7,10 @@ jobs: uses: ./.github/workflows/test.yml secrets: inherit - package-linux: - name: Linux package - uses: ./.github/workflows/build-linux.yml - with: - artifact-name: dfhack-linux64-build - append-date-and-hash: true - cache-id: release - stonesense: true - docs: true - secrets: inherit - - package-win64: - name: Win64 package - uses: ./.github/workflows/build-windows.yml + package: + uses: ./.github/workflows/package.yml with: - artifact-name: dfhack-win64-build - append-date-and-hash: true - cache-id: release - stonesense: true - docs: true + dfhack_ref: ${{ github.ref }} secrets: inherit docs: diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 56bc26702..2d8e55335 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -12,36 +12,18 @@ on: required: true jobs: - package-win64: - name: Build win64 release - uses: ./.github/workflows/build-windows.yml + package: + uses: ./.github/workflows/package.yml with: - artifact-name: win64-release dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} - cache-id: release + append-date-and-hash: false cache-readonly: true - stonesense: true - docs: true launchdf: true secrets: inherit - package-linux64: - name: Build linux64 release - uses: ./.github/workflows/build-linux.yml - with: - artifact-name: linux64-release - dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} - cache-id: release - cache-readonly: true - stonesense: true - docs: true - secrets: inherit - create-update-release: name: Draft GitHub release - needs: - - package-win64 - - package-linux64 + needs: package runs-on: ubuntu-latest permissions: contents: write @@ -63,23 +45,15 @@ jobs: tail -n $((CHANGELOG_LINES - 3)) docs/changelogs/${{ steps.gettag.outputs.name }}-github.txt >> release_body.md tail -n 2 .github/release_template.md >> release_body.md cat release_body.md - - name: Stage win64 release + - name: Stage release uses: actions/download-artifact@v3 - with: - name: win64-release - path: win64 - name: Create win64 release archive run: | - cd win64 + cd dfhack-windows64-build zip -r ../dfhack-${{ steps.gettag.outputs.name }}-Windows-64bit.zip . - - name: Stage linux64 release - uses: actions/download-artifact@v3 - with: - name: linux64-release - path: linux64 - name: Create linux64 release archive run: | - cd linux64 + cd dfhack-linux64-build tar cjf ../dfhack-${{ steps.gettag.outputs.name }}-Linux-64bit.tar.bz2 . - name: Create or update GitHub release uses: ncipollo/release-action@v1 diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml new file mode 100644 index 000000000..eba2f4f71 --- /dev/null +++ b/.github/workflows/package.yml @@ -0,0 +1,51 @@ +name: Package + +on: + workflow_call: + inputs: + dfhack_ref: + type: string + scripts_ref: + type: string + structures_ref: + type: string + append-date-and-hash: + type: boolean + default: true + cache-readonly: + type: boolean + default: false + launchdf: + type: boolean + default: false + +jobs: + package-win64: + name: Windows + uses: ./.github/workflows/build-windows.yml + with: + dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_ref: ${{ inputs.scripts_ref }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: dfhack-windows64-build + append-date-and-hash: ${{ inputs.append-date-and-hash }} + cache-id: release + cache-readonly: ${{ inputs.cache-readonly }} + stonesense: true + docs: true + secrets: inherit + + package-linux: + name: Linux + uses: ./.github/workflows/build-linux.yml + with: + dfhack_ref: ${{ inputs.dfhack_ref }} + scripts_ref: ${{ inputs.scripts_ref }} + structures_ref: ${{ inputs.structures_ref }} + artifact-name: dfhack-linux64-build + append-date-and-hash: ${{ inputs.append-date-and-hash }} + cache-id: release + cache-readonly: ${{ inputs.cache-readonly }} + stonesense: true + docs: true + secrets: inherit From d152e86013b7215b359afa53e867ede215c12ecd Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 5 Aug 2023 17:03:18 -0400 Subject: [PATCH 265/851] check-structures-sanity: Set debugger-friendly compiler options --- plugins/devel/check-structures-sanity/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/devel/check-structures-sanity/CMakeLists.txt b/plugins/devel/check-structures-sanity/CMakeLists.txt index f3eab5da6..69e326309 100644 --- a/plugins/devel/check-structures-sanity/CMakeLists.txt +++ b/plugins/devel/check-structures-sanity/CMakeLists.txt @@ -5,4 +5,4 @@ set(PLUGIN_SRCS validate.cpp ) -dfhack_plugin(check-structures-sanity ${PLUGIN_SRCS} LINK_LIBRARIES lua) +dfhack_plugin(check-structures-sanity ${PLUGIN_SRCS} LINK_LIBRARIES lua COMPILE_FLAGS_GCC "-O0 -ggdb3" COMPILE_FLAGS_MSVC "/Od") From 8dc13b8b258864b5eff1734e692e1a569958dfac Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 5 Aug 2023 23:46:07 -0400 Subject: [PATCH 266/851] check-structures-sanity: also skip temp_save vectors --- plugins/devel/check-structures-sanity/dispatch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/devel/check-structures-sanity/dispatch.cpp b/plugins/devel/check-structures-sanity/dispatch.cpp index 37e4757fa..d57beb0cb 100644 --- a/plugins/devel/check-structures-sanity/dispatch.cpp +++ b/plugins/devel/check-structures-sanity/dispatch.cpp @@ -821,7 +821,7 @@ void Checker::check_stl_vector(const QueueItem & item, type_identity *item_ident auto vec_items = validate_vector_size(item, CheckedStructure(item_identity)); // skip bad pointer vectors - if (item.path.length() > 4 && item.path.substr(item.path.length() - 4) == ".bad" && item_identity->type() == IDTYPE_POINTER) + if ((item.path.ends_with(".bad") || item.path.ends_with(".temp_save")) && item_identity->type() == IDTYPE_POINTER) { return; } From 996688c4aed6872b41d3bcec157cc8e5acca1cc9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 5 Aug 2023 23:25:10 -0700 Subject: [PATCH 267/851] make the workflows repository agnostic --- .github/workflows/build-linux.yml | 6 +++--- .github/workflows/build-windows.yml | 6 +++--- .github/workflows/build.yml | 5 +++++ .github/workflows/lint.yml | 4 ++-- .github/workflows/steam-deploy.yml | 4 +--- .github/workflows/test.yml | 2 +- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index f7088a234..96d57a41d 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -74,7 +74,7 @@ jobs: - name: Clone DFHack uses: actions/checkout@v3 with: - repository: 'DFHack/dfhack' + repository: ${{ inputs.dfhack_ref && github.repository || 'DFHack/dfhack' }} ref: ${{ inputs.dfhack_ref }} submodules: true fetch-depth: ${{ !inputs.platform-files && 1 || 0 }} @@ -82,14 +82,14 @@ jobs: if: inputs.scripts_ref uses: actions/checkout@v3 with: - repository: 'DFHack/scripts' + repository: ${{ inputs.scripts_ref && github.repository || 'DFHack/scripts' }} ref: ${{ inputs.scripts_ref }} path: scripts - name: Clone structures if: inputs.structures_ref uses: actions/checkout@v3 with: - repository: 'DFHack/df-structures' + repository: ${{ inputs.structures_ref && github.repository || 'DFHack/df-structures' }} ref: ${{ inputs.structures_ref }} path: library/xml - name: Fetch ccache diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 50d7f6936..f73900c26 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -57,7 +57,7 @@ jobs: - name: Clone DFHack uses: actions/checkout@v3 with: - repository: 'DFHack/dfhack' + repository: ${{ inputs.dfhack_ref && github.repository || 'DFHack/dfhack' }} ref: ${{ inputs.dfhack_ref }} submodules: true fetch-depth: 0 @@ -65,14 +65,14 @@ jobs: if: inputs.scripts_ref uses: actions/checkout@v3 with: - repository: 'DFHack/scripts' + repository: ${{ inputs.scripts_ref && github.repository || 'DFHack/scripts' }} ref: ${{ inputs.scripts_ref }} path: scripts - name: Clone structures if: inputs.structures_ref uses: actions/checkout@v3 with: - repository: 'DFHack/df-structures' + repository: ${{ inputs.structures_ref && github.repository || 'DFHack/df-structures' }} ref: ${{ inputs.structures_ref }} path: library/xml - name: Get 3rd party SDKs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3f2017324..10a6d332d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,6 +5,8 @@ on: [push, pull_request] jobs: test: uses: ./.github/workflows/test.yml + with: + dfhack_ref: ${{ github.ref }} secrets: inherit package: @@ -16,6 +18,7 @@ jobs: docs: uses: ./.github/workflows/build-linux.yml with: + dfhack_ref: ${{ github.ref }} platform-files: false common-files: false docs: true @@ -23,6 +26,8 @@ jobs: lint: uses: ./.github/workflows/lint.yml + with: + dfhack_ref: ${{ github.ref }} secrets: inherit check-pr: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index d299da573..77be37f37 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,7 +19,7 @@ jobs: - name: Clone DFHack uses: actions/checkout@v3 with: - repository: 'DFHack/dfhack' + repository: ${{ inputs.dfhack_ref && github.repository || 'DFHack/dfhack' }} ref: ${{ inputs.dfhack_ref }} - name: Get scripts submodule ref if: '!inputs.scripts_ref' @@ -28,7 +28,7 @@ jobs: - name: Clone scripts uses: actions/checkout@v3 with: - repository: 'DFHack/scripts' + repository: ${{ inputs.scripts_ref && github.repository || 'DFHack/scripts' }} ref: ${{ inputs.scripts_ref || steps.scriptssubmoduleref.outputs.ref }} path: scripts - name: Check whitespace diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index 70d061221..2df81d45d 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -68,8 +68,6 @@ jobs: runs-on: ubuntu-latest concurrency: steam steps: - - name: Get tag - run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Stage depot files uses: actions/download-artifact@v3 - name: Steam deploy @@ -78,7 +76,7 @@ jobs: username: ${{ secrets.STEAM_USERNAME }} configVdf: ${{ secrets.STEAM_CONFIG_VDF}} appId: 2346660 - buildDescription: ${{ github.event.inputs && github.event.inputs.version || env.TAG }} + buildDescription: ${{ github.event.inputs && github.event.inputs.version || github.ref_name }} rootPath: . depot1Path: common-depot depot2Path: win64-depot diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0934d6d00..9e58a649e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -78,7 +78,7 @@ jobs: - name: Clone DFHack uses: actions/checkout@v3 with: - repository: 'DFHack/dfhack' + repository: ${{ inputs.dfhack_ref && github.repository || 'DFHack/dfhack' }} ref: ${{ inputs.dfhack_ref }} - name: Detect DF version shell: bash From a7129cad042e6f7c6a39c0813ca61a849f235bc3 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 6 Aug 2023 07:12:09 +0000 Subject: [PATCH 268/851] 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 88e95e3b9..b2e673a23 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 88e95e3b9282b83d5134839f3bd7fc021f0ba53e +Subproject commit b2e673a23eb9813b6a7c6fe8f3046732ca6786b5 diff --git a/scripts b/scripts index b0ac91f37..dcf03eb32 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit b0ac91f37fe85ac2538caff3d507c861e99dc803 +Subproject commit dcf03eb329fae6feae19a3925c9e46e50bf08315 From db48e0eba0e15fdcb0a16fba5964caabcab62b85 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 6 Aug 2023 17:38:34 -0700 Subject: [PATCH 269/851] remove caravan_buying param from getValue call the identity of the selling party doesn't actually affect the value! --- docs/changelog.txt | 2 ++ docs/dev/Lua API.rst | 7 ++----- library/include/modules/Items.h | 2 +- library/modules/Items.cpp | 17 +++++++---------- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0559b2dde..a114aa521 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -42,11 +42,13 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Documentation ## API +- ``Items::getValue()``: remove ``caravan_buying`` parameter since the identity of the selling party doesn't actually affect the item value ## Internals ## Lua - ``new()``: improved error handling so that certain errors that were previously uncatchable (creating objects with members with unknown vtables) are now catchable with ``pcall()`` +- ``dfhack.items.getValue()``: remove ``caravan_buying`` param as per C++ API change ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index cd35d9465..dbd837e25 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1773,15 +1773,12 @@ Items module Calculates the base value for an item of the specified type and material. -* ``dfhack.items.getValue(item[, caravan_state, caravan_buying])`` +* ``dfhack.items.getValue(item[, caravan_state])`` Calculates the value of an item. If a ``df.caravan_state`` object is given (from ``df.global.plotinfo.caravans`` or ``df.global.main_interface.trade.mer``), then the value is modified by civ - properties and any trade agreements that might be in effect. In this case, - specify ``caravan_buying`` as ``true`` to get the price the caravan will pay - for the item and ``false`` to get the price that the caravan will sell the - item for. + properties and any trade agreements that might be in effect. * ``dfhack.items.isRequestedTradeGood(item[, caravan_state])`` diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h index beccd669a..9daac1feb 100644 --- a/library/include/modules/Items.h +++ b/library/include/modules/Items.h @@ -191,7 +191,7 @@ DFHACK_EXPORT df::proj_itemst *makeProjectile(MapExtras::MapCache &mc, df::item DFHACK_EXPORT int getItemBaseValue(int16_t item_type, int16_t item_subtype, int16_t mat_type, int32_t mat_subtype); /// Gets the value of a specific item, taking into account civ values and trade agreements if a caravan is given -DFHACK_EXPORT int getValue(df::item *item, df::caravan_state *caravan = NULL, bool caravan_buying = false); +DFHACK_EXPORT int getValue(df::item *item, df::caravan_state *caravan = NULL); DFHACK_EXPORT int32_t createItem(df::item_type type, int16_t item_subtype, int16_t mat_type, int32_t mat_index, df::unit* creator); diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 3694e0203..0b91bdd47 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -1910,13 +1910,6 @@ static int32_t get_sell_request_multiplier(df::item *item, const df::caravan_sta return get_sell_request_multiplier(item, caravan_he->resources, &sell_prices->price[0]); } -static int32_t get_trade_agreement_multiplier(df::item *item, const df::caravan_state *caravan, bool caravan_buying) { - if (!caravan) - return DEFAULT_AGREEMENT_MULTIPLIER; - return caravan_buying ? get_buy_request_multiplier(item, caravan->buy_prices) - : get_sell_request_multiplier(item, caravan); -} - static bool is_requested_trade_good(df::item *item, df::caravan_state *caravan) { auto trade_state = caravan->trade_state; if (caravan->time_remaining <= 0 || @@ -1942,7 +1935,7 @@ bool Items::isRequestedTradeGood(df::item *item, df::caravan_state *caravan) { return false; } -int Items::getValue(df::item *item, df::caravan_state *caravan, bool caravan_buying) +int Items::getValue(df::item *item, df::caravan_state *caravan) { CHECK_NULL_POINTER(item); @@ -2011,8 +2004,12 @@ int Items::getValue(df::item *item, df::caravan_state *caravan, bool caravan_buy value *= 10; // modify buy/sell prices - value *= get_trade_agreement_multiplier(item, caravan, caravan_buying); - value >>= 7; + if (caravan) { + value *= get_buy_request_multiplier(item, caravan->buy_prices); + value >>= 7; + value *= get_sell_request_multiplier(item, caravan); + value >>= 7; + } // Boost value from stack size value *= item->getStackSize(); From dce08e8d80d2a50ef446f480e1188e9ad92ce87b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 6 Aug 2023 22:39:05 -0700 Subject: [PATCH 270/851] do a test run with blank init scripts --- .github/workflows/test.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9e58a649e..550e8d11e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -50,7 +50,7 @@ jobs: plugins: "all" run-tests: - name: Test (${{ matrix.os }}, ${{ matrix.compiler }}, ${{ matrix.plugins }} plugins) + name: Test (${{ matrix.os }}, ${{ matrix.compiler }}, ${{ matrix.plugins }} plugins, ${{ matrix.config }} config) needs: - build-windows - build-linux @@ -62,15 +62,20 @@ jobs: - os: windows compiler: msvc plugins: "default" + config: "default" + - os: windows + compiler: msvc + plugins: "default" + config: "empty" # TODO: uncomment once we have a linux build we can download from bay12 # - os: ubuntu # compiler: gcc-10 - # gcc: 10 # plugins: "default" + # config: "default" # - os: ubuntu - # compiler: gcc-10 - # gcc: 12 + # compiler: gcc-12 # plugins: "all" + # config: "default" steps: - name: Set env shell: bash @@ -98,6 +103,13 @@ jobs: with: path: ${{ env.DF_FOLDER }} key: df-${{ matrix.os }}-${{ env.DF_VERSION }}-${{ hashFiles('ci/download-df.sh') }} + - name: Install blank DFHack init scripts + if: matrix.config == 'empty' + shell: bash + run: | + mkdir -p dfhack-config/init + cd data/dfhack-config/init + for fname in *.init; do touch ../../../dfhack-config/init/$fname; done - name: Download DFHack uses: actions/download-artifact@v3 with: From 488ad0f82764838a5d39f04c7e8619cd9f568e1b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 6 Aug 2023 23:02:45 -0700 Subject: [PATCH 271/851] add changelog template for new verions and mark unused headers as deprecated --- docs/changelog.txt | 22 +++++++++++++++++++++- docs/sphinx_extensions/dfhack/changelog.py | 8 ++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0559b2dde..eca35b2e8 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -22,6 +22,26 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: spans multiple lines. Three ``]`` characters indicate the end of such a block. - ``!`` immediately before a phrase set up to be replaced (see gen_changelog.py) stops that occurrence from being replaced. +Template for new versions: + +# Future + +## New Features + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Internals + +## Lua + +## Removed + ===end ]]] @@ -33,7 +53,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: # Future -## New Plugins +## New Features ## Fixes diff --git a/docs/sphinx_extensions/dfhack/changelog.py b/docs/sphinx_extensions/dfhack/changelog.py index dd59fa9d5..cc309e425 100644 --- a/docs/sphinx_extensions/dfhack/changelog.py +++ b/docs/sphinx_extensions/dfhack/changelog.py @@ -16,11 +16,11 @@ CHANGELOG_PATHS = ( CHANGELOG_PATHS = (os.path.join(DFHACK_ROOT, p) for p in CHANGELOG_PATHS) CHANGELOG_SECTIONS = [ - 'New Plugins', - 'New Scripts', - 'New Tweaks', + 'New Plugins', # deprecated + 'New Scripts', # deprecated + 'New Tweaks', # deprecated 'New Features', - 'New Internal Commands', + 'New Internal Commands', # deprecated 'Fixes', 'Misc Improvements', 'Removed', From 568e4b4725ee04dc4ba9b8724d1c34bb8c84ee72 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 6 Aug 2023 23:07:08 -0700 Subject: [PATCH 272/851] differentiate test output artifacts --- .github/workflows/test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 550e8d11e..d06708778 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -107,9 +107,9 @@ jobs: if: matrix.config == 'empty' shell: bash run: | - mkdir -p dfhack-config/init + mkdir -p ${{ env.DF_FOLDER }}/dfhack-config/init cd data/dfhack-config/init - for fname in *.init; do touch ../../../dfhack-config/init/$fname; done + for fname in *.init; do touch ../../../${{ env.DF_FOLDER }}/dfhack-config/init/$fname; done - name: Download DFHack uses: actions/download-artifact@v3 with: @@ -125,7 +125,7 @@ jobs: if: always() continue-on-error: true with: - name: test-artifacts-msvc + name: test-output-${{ matrix.compiler }}-${{ matrix.plugins }}_plugins-${{ matrix.config }}_config path: | ${{ env.DF_FOLDER }}/dfhack-rpc.txt ${{ env.DF_FOLDER }}/test*.json From 6f3843e375317c953392d5df20ab3a47e9aa62d6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 6 Aug 2023 23:41:18 -0700 Subject: [PATCH 273/851] the test script is no longer in the hack path; remove extra script dir --- ci/run-tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ci/run-tests.py b/ci/run-tests.py index a55bf3051..3d646a2f7 100755 --- a/ci/run-tests.py +++ b/ci/run-tests.py @@ -83,7 +83,6 @@ test_init_file = os.path.join(init_path, 'dfhackzzz_test.init') # Core sorts th with open(test_init_file, 'w') as f: f.write(''' devel/dump-rpc dfhack-rpc.txt - :lua dfhack.internal.addScriptPath(dfhack.getHackPath()) test --resume -- lua scr.breakdown_level=df.interface_breakdown_types.%s ''' % ('NONE' if args.no_quit else 'QUIT')) From 386608fa0270318d89da52b7055616e779b25c9a Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 7 Aug 2023 07:13:17 +0000 Subject: [PATCH 274/851] 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 b2e673a23..08e5c077b 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit b2e673a23eb9813b6a7c6fe8f3046732ca6786b5 +Subproject commit 08e5c077b7c73ddfedcc9890505554241604adeb diff --git a/scripts b/scripts index dcf03eb32..836c12348 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit dcf03eb329fae6feae19a3925c9e46e50bf08315 +Subproject commit 836c12348de035c5ad07dac650a39457aebdeeae From 03edea82575743d6e098252db8f75da64642ca47 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 7 Aug 2023 02:50:37 -0700 Subject: [PATCH 275/851] add focus string support for legends mode --- library/modules/Gui.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 102fef9d6..a8941fee7 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -69,6 +69,7 @@ using namespace DFHack; #include "df/item_corpsepiecest.h" #include "df/item_corpsest.h" #include "df/job.h" +#include "df/legend_pagest.h" #include "df/occupation.h" #include "df/plant.h" #include "df/popup_message.h" @@ -84,6 +85,7 @@ using namespace DFHack; #include "df/unit.h" #include "df/unit_inventory_item.h" #include "df/viewscreen_dwarfmodest.h" +#include "df/viewscreen_legendsst.h" #include "df/viewscreen_new_regionst.h" #include "df/viewscreen_titlest.h" #include "df/world.h" @@ -170,6 +172,16 @@ DEFINE_GET_FOCUS_STRING_HANDLER(new_region) focusStrings.push_back(baseFocus); } +DEFINE_GET_FOCUS_STRING_HANDLER(legends) +{ + if (screen->init_stage != -1) + focusStrings.push_back(baseFocus + "/Loading"); + else if (screen->page.size() <= 1) + focusStrings.push_back(baseFocus + "/Default"); + else + focusStrings.push_back(baseFocus + '/' + screen->page[screen->active_page_index]->header); +} + DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) { std::string newFocusString; From 959e6fdad6a5de01bfccfee4da1f95f4e3bba57f Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 7 Aug 2023 17:48:32 +0000 Subject: [PATCH 276/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 836c12348..6e4c56386 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 836c12348de035c5ad07dac650a39457aebdeeae +Subproject commit 6e4c56386601acd7bea5c1a6323c2e33e7c61ca2 From e57a5d665ff144b0b60d7fc56434e66a45de1821 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 7 Aug 2023 11:01:42 -0700 Subject: [PATCH 277/851] rename some workflow steps --- .github/workflows/build-linux.yml | 2 +- .github/workflows/build-windows.yml | 2 +- .github/workflows/test.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 96d57a41d..2f052b53e 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -131,7 +131,7 @@ jobs: - name: Run cpp tests if: inputs.platform-files run: ninja -C build test - - name: Trim cache + - name: Finalize cache if: inputs.platform-files run: | ccache --max-size 40M diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index f73900c26..6469d5be7 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -98,7 +98,7 @@ jobs: run: | cd build bash -x build-win64-from-linux.sh - - name: Trim cache + - name: Finalize cache run: | cd build ccache -d win64-cross/ccache --max-size 150M diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d06708778..131229adc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -110,7 +110,7 @@ jobs: mkdir -p ${{ env.DF_FOLDER }}/dfhack-config/init cd data/dfhack-config/init for fname in *.init; do touch ../../../${{ env.DF_FOLDER }}/dfhack-config/init/$fname; done - - name: Download DFHack + - name: Install DFHack uses: actions/download-artifact@v3 with: name: test-${{ matrix.compiler }} From e80884459c27f6033655df8558e4f7fd67ea01dd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 7 Aug 2023 12:39:20 -0700 Subject: [PATCH 278/851] don't display dfhack logo in legends mode --- docs/changelog.txt | 1 + plugins/lua/hotkeys.lua | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 8d5e18467..f5aeb814b 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,6 +58,7 @@ Template for new versions: ## Fixes ## Misc Improvements +- `hotkeys`: don't display DFHack logo in legends mode since it covers up important interface elements. the Ctrl-Shift-C hotkey to bring up the menu and the mouseover hotspot still function, though. ## Documentation diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index fca0f1f27..373b2945f 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -28,13 +28,14 @@ HotspotMenuWidget.ATTRS{ default_enabled=true, hotspot=true, viewscreens={ - -- 'choose_start_site', -- conflicts with vanilla panel layouts + 'adopt_region', 'choose_game_type', + -- 'choose_start_site', -- conflicts with vanilla panel layouts 'dwarfmode', 'export_region', 'game_cleaner', 'initial_prep', - 'legends', + --'legends', -- conflicts with vanilla export button and info text 'loadgame', -- 'new_region', -- conflicts with vanilla panel layouts 'savegame', From 8c166935d58d21ac00bc37066b63e51f6305ed0d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 7 Aug 2023 12:40:48 -0700 Subject: [PATCH 279/851] factor banner out into reusable panel class --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 16 ++++++++++++---- library/lua/gui/widgets.lua | 34 ++++++++++++++++++---------------- plugins/lua/zone.lua | 4 ++-- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 8d5e18467..db25afecd 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -69,6 +69,7 @@ Template for new versions: ## Lua - ``new()``: improved error handling so that certain errors that were previously uncatchable (creating objects with members with unknown vtables) are now catchable with ``pcall()`` - ``dfhack.items.getValue()``: remove ``caravan_buying`` param as per C++ API change +- ``widgets.BannerPanel``: panel with distinctive border for marking DFHack UI elements on otherwise vanilla screens ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index dbd837e25..970aa06a9 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5077,13 +5077,21 @@ This is a specialized subclass of CycleHotkeyLabel that has two options: ``On`` (with a value of ``true``) and ``Off`` (with a value of ``false``). The ``On`` option is rendered in green. +BannerPanel class +----------------- + +This is a Panel subclass that prints a distinctive banner along the far left +and right columns of the widget frame. Note that this is not a "proper" frame +since it doesn't have top or bottom borders. Subviews of this panel should +inset their frames one tile from the left and right edges. + TextButton class ---------------- -This is a Panel subclass that wraps a HotkeyLabel with some decorators on the -sides to make it look more like a button, suitable for both graphics and ASCII -mdoes. All HotkeyLabel parameters passed to the constructor are passed through -to the wrapped HotkeyLabel. +This is a BannerPanel subclass that wraps a HotkeyLabel with some decorators on +the sides to make it look more like a button, suitable for both graphics and +ASCII modes. All HotkeyLabel parameters passed to the constructor are passed +through to the wrapped HotkeyLabel. List class ---------- diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index e1b71d186..6623211e4 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1489,13 +1489,27 @@ function HotkeyLabel:onInput(keys) end end +----------------- +-- BannerPanel -- +----------------- + +BannerPanel = defclass(BannerPanel, Panel) + +local BANNER_PEN = dfhack.pen.parse{fg=COLOR_YELLOW, bg=COLOR_RED} + +function BannerPanel:onRenderBody(dc) + dc:pen(BANNER_PEN) + for y=0,self.frame_rect.height-1 do + dc:seek(0, y):char(string.char(221)) -- half-width stripe on left + dc:seek(self.frame_rect.width-1):char(string.char(222)) -- half-width stripe on right + end +end + ---------------- -- TextButton -- ---------------- -TextButton = defclass(TextButton, Panel) - -local BUTTON_PEN = dfhack.pen.parse{fg=COLOR_YELLOW, bg=COLOR_RED} +TextButton = defclass(TextButton, BannerPanel) function TextButton:init(info) self.label = HotkeyLabel{ @@ -1516,19 +1530,7 @@ function TextButton:init(info) scroll_keys=info.scroll_keys, } - self:addviews{ - Label{ - frame={t=0, l=0, w=1}, - text=string.char(221), -- half-width stripe on left - text_pen=BUTTON_PEN, - }, - self.label, - Label{ - frame={t=0, r=0, w=1}, - text=string.char(222), -- half-width stripe on right - text_pen=BUTTON_PEN, - } - } + self:addviews{self.label} end function TextButton:setLabel(label) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 3c70c1e63..46cae3d24 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -694,13 +694,13 @@ PastureOverlay.ATTRS{ function PastureOverlay:init() self:addviews{ widgets.TextButton{ - frame={t=0, l=0}, + frame={t=0, l=0, r=0, h=1}, label='DFHack manage pasture', key='CUSTOM_CTRL_T', on_activate=function() view = view and view:raise() or PastureScreen{}:show() end, }, widgets.TextButton{ - frame={t=2, l=0}, + frame={t=2, l=0, r=0, h=1}, label='DFHack autobutcher', key='CUSTOM_CTRL_B', on_activate=function() dfhack.run_script('gui/autobutcher') end, From 5fbff18d64451f4625640738006181b95343bbe5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 7 Aug 2023 16:01:56 -0700 Subject: [PATCH 280/851] correctly fire on_resize_end events from Panel --- library/lua/gui/widgets.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 6623211e4..b742f6dff 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -236,8 +236,9 @@ local function Panel_end_drag(self, frame, success) else self:setFocus(false) end + local resize_edge = self.resize_edge Panel_update_frame(self, frame, true) - if self.resize_edge then + if resize_edge then if self.on_resize_end then self.on_resize_end(success) end else if self.on_drag_end then self.on_drag_end(success) end From 8bff1399d43a1abae98533a2667dec20c340e91e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 7 Aug 2023 17:02:55 -0700 Subject: [PATCH 281/851] add functions to Panel in addition to attributes --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 20 +++++++++++++++++--- library/lua/gui/widgets.lua | 25 ++++++++++++++++++++----- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1f9574ea8..d48be6be6 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -71,6 +71,7 @@ Template for new versions: - ``new()``: improved error handling so that certain errors that were previously uncatchable (creating objects with members with unknown vtables) are now catchable with ``pcall()`` - ``dfhack.items.getValue()``: remove ``caravan_buying`` param as per C++ API change - ``widgets.BannerPanel``: panel with distinctive border for marking DFHack UI elements on otherwise vanilla screens +- ``widgets.Panel``: new functions to override instead of setting corresponding properties (useful when subclassing instead of just setting attributes): ``onDragBegin``, ``onDragEnd``, ``onResizeBegin``, ``onResizeEnd`` ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 970aa06a9..d8383ac00 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4559,7 +4559,7 @@ Has attributes: * ``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``) +* ``on_drag_end = function(success, new_frame)`` (default: ``nil``) If ``draggable`` is set to ``true``, then the above attributes come into play when the panel is dragged around the screen, either with the mouse or the @@ -4573,13 +4573,15 @@ Has attributes: otherwise. Dragging can be canceled by right clicking while dragging with the mouse, hitting :kbd:`Esc` (while dragging with the mouse or keyboard), or by calling ``Panel:setKeyboaredDragEnabled(false)`` (while dragging with the - keyboard). + keyboard). If it is more convenient to do so, you can choose to override the + ``panel:onDragBegin`` and/or the ``panel:onDragEnd`` methods instead of + setting the ``on_drag_begin`` and/or ``on_drag_end`` attributes. * ``resizable = bool`` (default: ``false``) * ``resize_anchors = {}`` (default: ``{t=false, l=true, r=true, b=true}`` * ``resize_min = {}`` (default: w and h from the ``frame``, or ``{w=5, h=5}``) * ``on_resize_begin = function()`` (default: ``nil``) -* ``on_resize_end = function(bool)`` (default: ``nil``) +* ``on_resize_end = function(success, new_frame)`` (default: ``nil``) If ``resizable`` is set to ``true``, then the player can click the mouse on any edge specified in ``resize_anchors`` and drag the border to resize the @@ -4593,6 +4595,9 @@ Has attributes: Dragging can be canceled by right clicking while resizing with the mouse, hitting :kbd:`Esc` (while resizing with the mouse or keyboard), or by calling ``Panel:setKeyboardResizeEnabled(false)`` (while resizing with the keyboard). + If it is more convenient to do so, you can choose to override the + ``panel:onResizeBegin`` and/or the ``panel:onResizeEnd`` methods instead of + setting the ``on_resize_begin`` and/or ``on_resize_end`` attributes. * ``autoarrange_subviews = bool`` (default: ``false``) * ``autoarrange_gap = int`` (default: ``0``) @@ -4637,6 +4642,15 @@ Has functions: commit the new window size or :kbd:`Esc` to cancel. If resizing is canceled, then the window size from before the resize operation is restored. +* ``panel:onDragBegin()`` +* ``panel:onDragEnd(success, new_frame)`` +* ``panel:onResizeBegin()`` +* ``panel:onResizeEnd(success, new_frame)`` + +The default implementations of these methods call the associated attribute (if +set). You can override them in a subclass if that is more convenient than +setting the attributes. + Double clicking: If the panel is resizable and the user double-clicks on the top edge (the frame diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index b742f6dff..52a3a6352 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -6,7 +6,6 @@ local gui = require('gui') local guidm = require('gui.dwarfmode') local utils = require('utils') -local dscreen = dfhack.screen local getval = utils.getval local to_pen = dfhack.pen.parse @@ -223,9 +222,9 @@ local function Panel_begin_drag(self, drag_offset, resize_edge) self.prev_focus_owner = self.focus_group.cur self:setFocus(true) if self.resize_edge then - if self.on_resize_begin then self.on_resize_begin(success) end + self:onResizeBegin() else - if self.on_drag_begin then self.on_drag_begin(success) end + self:onDragBegin() end end @@ -239,9 +238,9 @@ local function Panel_end_drag(self, frame, success) local resize_edge = self.resize_edge Panel_update_frame(self, frame, true) if resize_edge then - if self.on_resize_end then self.on_resize_end(success) end + self:onResizeEnd(success, self.frame) else - if self.on_drag_end then self.on_drag_end(success) end + self:onDragEnd(success, self.frame) end end @@ -495,6 +494,22 @@ function Panel:onRenderFrame(dc, rect) end end +function Panel:onDragBegin() + if self.on_drag_begin then self.on_drag_begin() end +end + +function Panel:onDragEnd(success, new_frame) + if self.on_drag_end then self.on_drag_end(success, new_frame) end +end + +function Panel:onResizeBegin() + if self.on_resize_begin then self.on_resize_begin() end +end + +function Panel:onResizeEnd(success, new_frame) + if self.on_resize_end then self.on_resize_end(success, new_frame) end +end + ------------ -- Window -- ------------ From 62a1bd6970332cff890d64c88626833ee5ca4b60 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 7 Aug 2023 17:18:00 -0700 Subject: [PATCH 282/851] ensure active mod scripts are properly reloaded --- docs/changelog.txt | 1 + library/lua/script-manager.lua | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1f9574ea8..40449b302 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -56,6 +56,7 @@ Template for new versions: ## New Features ## Fixes +- Core: properly reload scripts in mods when a world is unloaded and immediately loaded again ## Misc Improvements - `hotkeys`: don't display DFHack logo in legends mode since it covers up important interface elements. the Ctrl-Shift-C hotkey to bring up the menu and the mouseover hotspot still function, though. diff --git a/library/lua/script-manager.lua b/library/lua/script-manager.lua index 91b4985ac..c5d9fb364 100644 --- a/library/lua/script-manager.lua +++ b/library/lua/script-manager.lua @@ -51,9 +51,10 @@ function reload(refresh_active_mod_scripts) enabled_map = utils.OrderedTable() local force_refresh_fn = refresh_active_mod_scripts and function(script_path, script_name) if script_path:find('scripts_modactive') then - internal_script = dfhack.internal.scripts[script_path..'/'..script_name] + local full_path = script_path..'/'..script_name + internal_script = dfhack.internal.scripts[full_path] if internal_script then - internal_script.env = nil + dfhack.internal.scripts[full_path] = nil end end end or nil From 99517fcd818018b1680cb797cbb80cffbb1ae185 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 7 Aug 2023 17:20:58 -0700 Subject: [PATCH 283/851] use square brackets instead of color blocks --- docs/changelog.txt | 1 + library/lua/gui/widgets.lua | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1f9574ea8..0ecfa52f1 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,6 +58,7 @@ Template for new versions: ## Fixes ## Misc Improvements +- Surround DFHack-specific UI elements with square brackets instead of red-yellow blocks for better readability - `hotkeys`: don't display DFHack logo in legends mode since it covers up important interface elements. the Ctrl-Shift-C hotkey to bring up the menu and the mouseover hotspot still function, though. ## Documentation diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index b742f6dff..b168c61a7 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1496,13 +1496,11 @@ end BannerPanel = defclass(BannerPanel, Panel) -local BANNER_PEN = dfhack.pen.parse{fg=COLOR_YELLOW, bg=COLOR_RED} - function BannerPanel:onRenderBody(dc) - dc:pen(BANNER_PEN) + dc:pen(COLOR_RED) for y=0,self.frame_rect.height-1 do - dc:seek(0, y):char(string.char(221)) -- half-width stripe on left - dc:seek(self.frame_rect.width-1):char(string.char(222)) -- half-width stripe on right + dc:seek(0, y):char('[') + dc:seek(self.frame_rect.width-1):char(']') end end From 8b5321fe8614646724462baf9ba156e390a4c383 Mon Sep 17 00:00:00 2001 From: David Li Date: Sun, 6 Aug 2023 13:32:07 -0700 Subject: [PATCH 284/851] Add option to force-fetch world blocks in RemoteFortressReader The current behavior of GetBlockList in the RemoteFortressReader Protobuf RPC API is to only return blocks that have changed since the last fetch. This causes problems when the RPC client (i.e. a world renderer) wants to restart, as it can no longer fetch the full world state. This patch adds a `force_reload` option to BlockRequest, defaulting to `false` (the current behavior). When passed, it returns all requested blocks regardless of whether they have changed or not. Signed-off-by: David Li --- docs/changelog.txt | 1 + .../proto/RemoteFortressReader.proto | 1 + plugins/remotefortressreader/remotefortressreader.cpp | 9 +++++---- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0559b2dde..9d0f8aee3 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: ## Documentation ## API +- `RemoteFortressReader`: add a `force_reload` option to the GetBlockList RPC API to return blocks regardless of whether they have changed since the last request ## Internals diff --git a/plugins/remotefortressreader/proto/RemoteFortressReader.proto b/plugins/remotefortressreader/proto/RemoteFortressReader.proto index a64e64d0b..f341031dc 100644 --- a/plugins/remotefortressreader/proto/RemoteFortressReader.proto +++ b/plugins/remotefortressreader/proto/RemoteFortressReader.proto @@ -526,6 +526,7 @@ message BlockRequest optional int32 max_y = 5; optional int32 min_z = 6; optional int32 max_z = 7; + optional bool force_reload = 8; } message BlockList diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 6ca69d1a7..6b5733970 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -1393,6 +1393,7 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in int max_y = in->max_y(); int min_z = in->min_z(); int max_z = in->max_z(); + bool forceReload = in->force_reload(); bool firstBlock = true; //Always send all the buildings needed on the first block, and none on the rest. //stream.print("Got request for blocks from (%d, %d, %d) to (%d, %d, %d).\n", in->min_x(), in->min_y(), in->min_z(), in->max_x(), in->max_y(), in->max_z()); for (int zz = max_z - 1; zz >= min_z; zz--) @@ -1440,19 +1441,19 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in bool itemsChanged = block->items.size() > 0; bool flows = block->flows.size() > 0; RemoteFortressReader::MapBlock *net_block = nullptr; - if (tileChanged || desChanged || spatterChanged || firstBlock || itemsChanged || flows) + if (tileChanged || desChanged || spatterChanged || firstBlock || itemsChanged || flows || forceReload) { net_block = out->add_map_blocks(); net_block->set_map_x(block->map_pos.x); net_block->set_map_y(block->map_pos.y); net_block->set_map_z(block->map_pos.z); } - if (tileChanged) + if (tileChanged || forceReload) { CopyBlock(block, net_block, &MC, pos); blocks_sent++; } - if (desChanged) + if (desChanged || forceReload) CopyDesignation(block, net_block, &MC, pos); if (firstBlock) { @@ -1460,7 +1461,7 @@ static command_result GetBlockList(color_ostream &stream, const BlockRequest *in CopyProjectiles(net_block); firstBlock = false; } - if (spatterChanged) + if (spatterChanged || forceReload) Copyspatters(block, net_block, &MC, pos); if (itemsChanged) CopyItems(block, net_block, &MC, pos); From 031191ae9a69b09eb6149205fc427cc5480b6097 Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 7 Aug 2023 19:40:48 -0700 Subject: [PATCH 285/851] Update docs/changelog.txt --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 9d0f8aee3..a2ba0145a 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -42,7 +42,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## Documentation ## API -- `RemoteFortressReader`: add a `force_reload` option to the GetBlockList RPC API to return blocks regardless of whether they have changed since the last request +- `RemoteFortressReader`: add a ``force_reload`` option to the GetBlockList RPC API to return blocks regardless of whether they have changed since the last request ## Internals From 6bd7d97625f567e49a3196b9160604e5c589f1f1 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 8 Aug 2023 07:12:52 +0000 Subject: [PATCH 286/851] 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 08e5c077b..403e293fd 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 08e5c077b7c73ddfedcc9890505554241604adeb +Subproject commit 403e293fdf88127db90146b53db8124b59cd8bd7 diff --git a/scripts b/scripts index 6e4c56386..ff8d1489b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 6e4c56386601acd7bea5c1a6323c2e33e7c61ca2 +Subproject commit ff8d1489b1ca4ffaa97d39edadec1c8af44c9b2a From ca71c8c5f8c224be5296213c0920ce08efa552bf Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 9 Aug 2023 07:13:34 +0000 Subject: [PATCH 287/851] 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 403e293fd..c99b20a44 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 403e293fdf88127db90146b53db8124b59cd8bd7 +Subproject commit c99b20a44c2755b3eecfa321a80b75fbef6886d4 From 21edf51aa60dbfedbad5453082aa1793d6832052 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 10 Aug 2023 01:01:58 +0000 Subject: [PATCH 288/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index ff8d1489b..313523a02 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ff8d1489b1ca4ffaa97d39edadec1c8af44c9b2a +Subproject commit 313523a026e00e80c0e5a2aeaa2f78272755e223 From 98485af4cfaacc58cbecd443716802f53fb91855 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 10 Aug 2023 07:13:28 +0000 Subject: [PATCH 289/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 313523a02..8e9d0405d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 313523a026e00e80c0e5a2aeaa2f78272755e223 +Subproject commit 8e9d0405da11b8ef55feebcc26d6e76d189f15c1 From 46499a66cca55a6f8d181257fac8620532c78c32 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 10 Aug 2023 15:01:19 -0400 Subject: [PATCH 290/851] Add cxx_demangle() and Lua wrapper --- docs/dev/Lua API.rst | 5 +++++ library/LuaApi.cpp | 19 +++++++++++++++++++ library/MiscUtils.cpp | 27 +++++++++++++++++++++++++++ library/include/MiscUtils.h | 2 ++ 4 files changed, 53 insertions(+) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index cd35d9465..a18b00480 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2735,6 +2735,11 @@ and are only documented here for completeness: The oldval, newval or delta arguments may be used to specify additional constraints. Returns: *found_index*, or *nil* if end reached. +* ``dfhack.internal.cxxDemangle(mangled_name)`` + + Decodes a mangled C++ symbol name. Returns the demangled name on success, or + ``nil, error_message`` on failure. + * ``dfhack.internal.getDir(path)`` Lists files/directories in a directory. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index c19c10197..578bb4746 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -3333,6 +3333,24 @@ static int internal_diffscan(lua_State *L) return 1; } +static int internal_cxxDemangle(lua_State *L) +{ + std::string mangled = luaL_checkstring(L, 1); + std::string status; + std::string demangled = cxx_demangle(mangled, &status); + if (demangled.length()) + { + lua_pushstring(L, demangled.c_str()); + return 1; + } + else + { + lua_pushnil(L); + lua_pushstring(L, status.c_str()); + return 2; + } +} + static int internal_runCommand(lua_State *L) { color_ostream *out = NULL; @@ -3637,6 +3655,7 @@ static const luaL_Reg dfhack_internal_funcs[] = { { "memcmp", internal_memcmp }, { "memscan", internal_memscan }, { "diffscan", internal_diffscan }, + { "cxxDemangle", internal_cxxDemangle }, { "getDir", filesystem_listdir }, { "runCommand", internal_runCommand }, { "getModifiers", internal_getModifiers }, diff --git a/library/MiscUtils.cpp b/library/MiscUtils.cpp index 7ffd4e1c6..a90cf1208 100644 --- a/library/MiscUtils.cpp +++ b/library/MiscUtils.cpp @@ -36,6 +36,7 @@ distribution. #else #include #include + #include #endif #include @@ -472,3 +473,29 @@ DFHACK_EXPORT std::string DF2CONSOLE(DFHack::color_ostream &out, const std::stri { return out.is_console() ? DF2CONSOLE(in) : in; } + +DFHACK_EXPORT std::string cxx_demangle(const std::string &mangled_name, std::string *status_out) +{ +#ifdef __GNUC__ + int status; + char *demangled = abi::__cxa_demangle(mangled_name.c_str(), nullptr, nullptr, &status); + std::string out; + if (demangled) { + out = demangled; + free(demangled); + } + if (status_out) { + if (status == 0) *status_out = "success"; + else if (status == -1) *status_out = "memory allocation failure"; + else if (status == -2) *status_out = "invalid mangled name"; + else if (status == -3) *status_out = "invalid arguments"; + else *status_out = "unknown error"; + } + return out; +#else + if (status_out) { + *status_out = "not implemented on this platform"; + } + return ""; +#endif +} diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index 59adcdbe5..06915fde5 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -474,3 +474,5 @@ DFHACK_EXPORT std::string UTF2DF(const std::string &in); DFHACK_EXPORT std::string DF2UTF(const std::string &in); DFHACK_EXPORT std::string DF2CONSOLE(const std::string &in); DFHACK_EXPORT std::string DF2CONSOLE(DFHack::color_ostream &out, const std::string &in); + +DFHACK_EXPORT std::string cxx_demangle(const std::string &mangled_name, std::string *status_out); From 0ac7d23bcf69346374d9ff25470a1bb6866ae5da Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 10 Aug 2023 15:06:24 -0400 Subject: [PATCH 291/851] Add memscan.read_global_table() and memscan.read_c_string() --- library/lua/memscan.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua index 4a9824010..a8c265adb 100644 --- a/library/lua/memscan.lua +++ b/library/lua/memscan.lua @@ -533,4 +533,32 @@ function get_screen_size() return w,h end +-- Global table + +function read_c_string(char_ptr) + local s = '' + local i = 0 + while char_ptr[i] ~= 0 do + s = s .. string.char(char_ptr[i]) + i = i + 1 + end + return s +end + +function read_global_table(global_table) + global_table = global_table or df.global.global_table + local out = {} + local i = 0 + while true do + -- use _displace() so we can read past the bounds of the array set in structures, if necessary + local entry = global_table[0]:_displace(i) + if not entry.name or not entry.address then + break + end + out[read_c_string(entry.name)] = entry + i = i + 1 + end + return out +end + return _ENV From ea43d6c801f07c27be49c02c4933ad7ff550645b Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 10 Aug 2023 15:06:45 -0400 Subject: [PATCH 292/851] get_code_segment(): update check for DF executable on Linux --- library/lua/memscan.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/library/lua/memscan.lua b/library/lua/memscan.lua index a8c265adb..a4c07d38c 100644 --- a/library/lua/memscan.lua +++ b/library/lua/memscan.lua @@ -217,6 +217,7 @@ function get_code_segment() for i,mem in ipairs(dfhack.internal.getMemRanges()) do if mem.read and mem.execute and (string.match(mem.name,'/dwarfort%.exe$') + or string.match(mem.name,'/dwarfort$') or string.match(mem.name,'/Dwarf_Fortress$') or string.match(mem.name,'Dwarf Fortress%.exe')) then From 5677a0faf70fcd0e1284f1f9623b1718bd762ab2 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Fri, 11 Aug 2023 00:07:20 -0500 Subject: [PATCH 293/851] allow msvc 17.7.0 (1937) for builds --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e0e30f44..4d39943a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,9 +62,9 @@ endif() if(WIN32) if(NOT MSVC) - message(SEND_ERROR "No MSVC found! MSVC 2022 version 1930 to 1936 is required.") - elseif((MSVC_VERSION LESS 1930) OR (MSVC_VERSION GREATER 1936)) - message(SEND_ERROR "MSVC 2022 version 1930 to 1936 is required, Version Found: ${MSVC_VERSION}") + message(SEND_ERROR "No MSVC found! MSVC 2022 version 1930 to 1937 is required.") + elseif((MSVC_VERSION LESS 1930) OR (MSVC_VERSION GREATER 1937)) + message(SEND_ERROR "MSVC 2022 version 1930 to 1937 is required, Version Found: ${MSVC_VERSION}") endif() endif() From e21f0f2b69ac945e1ffbffa829c4b32f7b53d2ea Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Fri, 11 Aug 2023 09:14:05 +0300 Subject: [PATCH 294/851] dynamic texture loading --- library/include/modules/Textures.h | 21 ++- library/modules/Textures.cpp | 236 ++++++++++++++++++++++++----- 2 files changed, 217 insertions(+), 40 deletions(-) diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 3b9d32541..7b2ac78d3 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -1,8 +1,14 @@ #pragma once +#include + #include "Export.h" #include "ColorText.h" +#include + +using TexposHandle = uintptr_t; + namespace DFHack { /** @@ -12,6 +18,19 @@ namespace DFHack { */ namespace Textures { +/** + * Load texture and get handle. + * Keep it to obtain valid texpos. + */ +DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); + +/** + * Get texpos by handle. + * Always use this function, if you need to get valid texpos for your texure. + * Texpos can change on game textures reset, but handle will be the same. + */ +DFHACK_EXPORT std::optional getTexposByHandle(TexposHandle handle); + /** * Call this on DFHack init and on every viewscreen change so we can reload * and reindex textures as needed. @@ -71,4 +90,4 @@ DFHACK_EXPORT long getPanelBordersTexposStart(); DFHACK_EXPORT long getWindowBordersTexposStart(); } -} +} \ No newline at end of file diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 9976a3c4f..c3ec15f89 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -1,3 +1,6 @@ +#include +#include + #include "Internal.h" #include "modules/DFSDL.h" @@ -5,10 +8,13 @@ #include "Debug.h" #include "PluginManager.h" +#include "VTableInterpose.h" #include "df/enabler.h" - -#include +#include "df/viewscreen_adopt_regionst.h" +#include "df/viewscreen_loadgamest.h" +#include "df/viewscreen_new_regionst.h" +#include "df/viewscreen_new_arenast.h" using df::global::enabler; using namespace DFHack; @@ -19,6 +25,7 @@ namespace DFHack { } static bool g_loaded = false; +static bool g_dynamic_loaded = false; static long g_num_dfhack_textures = 0; static long g_dfhack_logo_texpos_start = -1; static long g_green_pin_texpos_start = -1; @@ -34,6 +41,10 @@ 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 std::unordered_map g_handle_to_texpos; +static std::unordered_map g_handle_to_surface; +static std::mutex g_adding_mutex; + // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -41,7 +52,7 @@ static long g_window_borders_texpos_start = -1; // // It uses the same pixel format (RGBA, R at lowest address) regardless of // hardware. -SDL_Surface * canonicalize_format(SDL_Surface *src) { +SDL_Surface* canonicalize_format(SDL_Surface *src) { SDL_PixelFormat fmt; fmt.palette = NULL; fmt.BitsPerPixel = 32; @@ -57,7 +68,7 @@ SDL_Surface * canonicalize_format(SDL_Surface *src) { fmt.Bmask = 255 << fmt.Bshift; fmt.Amask = 255 << fmt.Ashift; - SDL_Surface *tgt = DFSDL_ConvertSurface(src, &fmt, SDL_SWSURFACE); + SDL_Surface* tgt = DFSDL_ConvertSurface(src, &fmt, SDL_SWSURFACE); DFSDL_FreeSurface(src); for (int x = 0; x < tgt->w; ++x) { for (int y = 0; y < tgt->h; ++y) { @@ -72,13 +83,148 @@ SDL_Surface * canonicalize_format(SDL_Surface *src) { return tgt; } +// register surface in texture raws, get a texpos +static long add_texture(SDL_Surface* surface) { + std::lock_guard lg_add_texture(g_adding_mutex); + auto texpos = enabler->textures.raws.size(); + enabler->textures.raws.push_back(surface); + return texpos; +} + +TexposHandle Textures::loadTexture(SDL_Surface* surface) { + if (!surface) + return 0; // should be some error, i guess + + auto handle = reinterpret_cast(surface); // not the best way? + g_handle_to_surface.emplace(handle, surface); + surface->refcount++; // prevent destruct on next FreeSurface by game + auto texpos = add_texture(surface); + g_handle_to_texpos.emplace(handle, texpos); + return handle; +} + +std::optional Textures::getTexposByHandle(TexposHandle handle) { + if (!handle) + return std::nullopt; + + if (auto it = g_handle_to_texpos.find(handle); it != g_handle_to_texpos.end()) + return it->second; + + if (auto it = g_handle_to_surface.find(handle); it != g_handle_to_surface.end()) { + it->second->refcount++; // prevent destruct on next FreeSurface by game + auto texpos = add_texture(it->second); + g_handle_to_texpos.emplace(handle, texpos); + return texpos; + } + + return std::nullopt; +} + +static void reset_texpos() { + g_handle_to_texpos.clear(); +} + +static void reset_surface() { + for (auto& entry : g_handle_to_surface) { + DFSDL_FreeSurface(entry.second); + } + g_handle_to_surface.clear(); +} + +// reset point on New Game +struct tracking_stage_new_region : df::viewscreen_new_regionst { + typedef df::viewscreen_new_regionst interpose_base; + + DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { + if (this->m_raw_load_stage != this->raw_load_stage) { + this->m_raw_load_stage = this->raw_load_stage; + if (this->m_raw_load_stage == 1) + reset_texpos(); + } + INTERPOSE_NEXT(logic)(); + } + + private: + inline static int m_raw_load_stage = -2; // not valid state at the start +}; +IMPLEMENT_VMETHOD_INTERPOSE(tracking_stage_new_region, logic); + +// reset point on New Game in Existing World +struct tracking_stage_adopt_region : df::viewscreen_adopt_regionst { + typedef df::viewscreen_adopt_regionst interpose_base; + + DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { + if (this->m_cur_step != this->cur_step) { + this->m_cur_step = this->cur_step; + if (this->m_cur_step == df::viewscreen_adopt_regionst::T_cur_step::ProcessingRawData) + reset_texpos(); + } + INTERPOSE_NEXT(logic)(); + } + + private: + inline static int m_cur_step = -2; // not valid state at the start +}; +IMPLEMENT_VMETHOD_INTERPOSE(tracking_stage_adopt_region, logic); + +// reset point on Load Game +struct tracking_stage_load_region : df::viewscreen_loadgamest { + typedef df::viewscreen_loadgamest interpose_base; + + DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { + if (this->m_cur_step != this->cur_step) { + this->m_cur_step = this->cur_step; + if (this->m_cur_step == df::viewscreen_loadgamest::T_cur_step::ProcessingRawData) + reset_texpos(); + } + INTERPOSE_NEXT(logic)(); + } + + private: + inline static int m_cur_step = -2; // not valid state at the start +}; +IMPLEMENT_VMETHOD_INTERPOSE(tracking_stage_load_region, logic); + +// reset point on New Arena +struct tracking_stage_new_arena : df::viewscreen_new_arenast { + typedef df::viewscreen_new_arenast interpose_base; + + DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { + if (this->m_cur_step != this->cur_step) { + this->m_cur_step = this->cur_step; + if (this->m_cur_step == 0) + reset_texpos(); + } + INTERPOSE_NEXT(logic)(); + } + + private: + inline static int m_cur_step = -2; // not valid state at the start +}; +IMPLEMENT_VMETHOD_INTERPOSE(tracking_stage_new_arena, logic); + +static void + install_reset_point() { + INTERPOSE_HOOK(tracking_stage_new_region, logic).apply(); + INTERPOSE_HOOK(tracking_stage_adopt_region, logic).apply(); + INTERPOSE_HOOK(tracking_stage_load_region, logic).apply(); + INTERPOSE_HOOK(tracking_stage_new_arena, logic).apply(); +} + +static void uninstall_reset_point() { + INTERPOSE_HOOK(tracking_stage_new_region, logic).remove(); + INTERPOSE_HOOK(tracking_stage_adopt_region, logic).remove(); + INTERPOSE_HOOK(tracking_stage_load_region, logic).remove(); + INTERPOSE_HOOK(tracking_stage_new_arena, logic).remove(); +} + const uint32_t TILE_WIDTH_PX = 8; const uint32_t TILE_HEIGHT_PX = 12; -static size_t load_textures(color_ostream & out, const char * fname, - long *texpos_start, - int tile_w = TILE_WIDTH_PX, - int tile_h = TILE_HEIGHT_PX) { +static size_t load_tiles_from_image(color_ostream& out, const char* fname, + long* texpos_start, + int tile_w = TILE_WIDTH_PX, + int tile_h = TILE_HEIGHT_PX) { SDL_Surface *s = DFIMG_Load(fname); if (!s) { out.printerr("unable to load textures from '%s'\n", fname); @@ -91,7 +237,7 @@ static size_t load_textures(color_ostream & out, const char * fname, long count = 0; for (int y = 0; y < dimy; y++) { for (int x = 0; x < dimx; x++) { - SDL_Surface *tile = DFSDL_CreateRGBSurface(0, // SDL_SWSURFACE + SDL_Surface* tile = DFSDL_CreateRGBSurface(0, // SDL_SWSURFACE tile_w, tile_h, 32, s->format->Rmask, s->format->Gmask, s->format->Bmask, s->format->Amask); @@ -120,7 +266,12 @@ static size_t load_textures(color_ostream & out, const char * fname, // texture count so our textures will no longer be freed when worlds are // unloaded. // -void Textures::init(color_ostream &out) { +void Textures::init(color_ostream& out) { + if (!g_dynamic_loaded) { + g_dynamic_loaded = true; + install_reset_point(); + } + if (!enabler) return; @@ -134,32 +285,32 @@ void Textures::init(color_ostream &out) { bool is_pre_world = num_textures == textures.init_texture_size; - g_num_dfhack_textures = load_textures(out, "hack/data/art/dfhack.png", - &g_dfhack_logo_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/green-pin.png", - &g_green_pin_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/red-pin.png", - &g_red_pin_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/icons.png", - &g_icons_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/on-off.png", - &g_on_off_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/pathable.png", - &g_pathable_texpos_start, 32, 32); - g_num_dfhack_textures += load_textures(out, "hack/data/art/unsuspend.png", - &g_unsuspend_texpos_start, 32, 32); - 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_num_dfhack_textures += load_textures(out, "hack/data/art/border-medium.png", - &g_medium_borders_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/border-bold.png", - &g_bold_borders_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/border-panel.png", - &g_panel_borders_texpos_start); - g_num_dfhack_textures += load_textures(out, "hack/data/art/border-window.png", - &g_window_borders_texpos_start); + g_num_dfhack_textures = load_tiles_from_image(out, "hack/data/art/dfhack.png", + &g_dfhack_logo_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/green-pin.png", + &g_green_pin_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/red-pin.png", + &g_red_pin_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/icons.png", + &g_icons_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/on-off.png", + &g_on_off_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/pathable.png", + &g_pathable_texpos_start, 32, 32); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/unsuspend.png", + &g_unsuspend_texpos_start, 32, 32); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/control-panel.png", + &g_control_panel_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-thin.png", + &g_thin_borders_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-medium.png", + &g_medium_borders_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-bold.png", + &g_bold_borders_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-panel.png", + &g_panel_borders_texpos_start); + g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-window.png", + &g_window_borders_texpos_start); DEBUG(textures,out).print("loaded %ld textures\n", g_num_dfhack_textures); @@ -176,8 +327,8 @@ void Textures::cleanup() { if (!g_loaded) return; - auto & textures = enabler->textures; - auto &raws = textures.raws; + auto& textures = enabler->textures; + auto& raws = textures.raws; size_t texpos_end = g_dfhack_logo_texpos_start + g_num_dfhack_textures - 1; for (size_t idx = g_dfhack_logo_texpos_start; idx <= texpos_end; ++idx) { DFSDL_FreeSurface((SDL_Surface *)raws[idx]); @@ -190,6 +341,13 @@ void Textures::cleanup() { g_loaded = false; g_num_dfhack_textures = 0; g_dfhack_logo_texpos_start = -1; + + if (g_dynamic_loaded) { + g_dynamic_loaded = false; + reset_texpos(); + reset_surface(); + uninstall_reset_point(); + } } long Textures::getDfhackLogoTexposStart() { @@ -242,4 +400,4 @@ long Textures::getPanelBordersTexposStart() { long Textures::getWindowBordersTexposStart() { return g_window_borders_texpos_start; -} +} \ No newline at end of file From 6bd08196351eef39c6728ea1e9b67b14be56306d Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 11 Aug 2023 02:31:54 -0400 Subject: [PATCH 295/851] Fix crash in df.global:_field() when global address is unknown and add a test --- library/LuaTypes.cpp | 3 +++ test/structures/globals.lua | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 test/structures/globals.lua diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index ef69958e0..ddc166abc 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -664,6 +664,9 @@ static int meta_global_field_reference(lua_State *state) auto field = (struct_field_info*)find_field(state, 2, "reference"); if (!field) field_error(state, 2, "builtin property or method", "reference"); + void *ptr = *(void**)field->offset; + if (!ptr) + field_error(state, 2, "global address not known", "reference"); field_reference(state, field, *(void**)field->offset); return 1; } diff --git a/test/structures/globals.lua b/test/structures/globals.lua new file mode 100644 index 000000000..6b278af96 --- /dev/null +++ b/test/structures/globals.lua @@ -0,0 +1,33 @@ +config.mode = 'title' +config.target = 'core' + +local function with_temp_global_address(name, addr, callback, ...) + dfhack.call_with_finalizer(2, true, + dfhack.internal.setAddress, name, dfhack.internal.getAddress(name), + function(...) + dfhack.internal.setAddress(name, addr) + callback(...) + end, ...) +end + +function test.unknown_global_address() + expect.ne(dfhack.internal.getAddress('army_next_id'), 0) + local old_id = df.global.army_next_id + + with_temp_global_address('army_next_id', 0, function() + expect.error_match('Cannot read field global.army_next_id: global address not known.', function() + local _ = df.global.army_next_id + end) + + expect.error_match('Cannot write field global.army_next_id: global address not known.', function() + df.global.army_next_id = old_id + end) + + expect.error_match('Cannot reference field global.army_next_id: global address not known.', function() + local _ = df.global:_field('army_next_id') + end) + end) + + expect.gt(dfhack.internal.getAddress('army_next_id'), 0) + expect.eq(df.global.army_next_id, old_id) +end From 4bbcc7b05de2af3898b03848970c85043b97b62c Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Fri, 11 Aug 2023 09:48:03 +0300 Subject: [PATCH 296/851] eof fix --- library/modules/Textures.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index c3ec15f89..a05056a2d 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -400,4 +400,4 @@ long Textures::getPanelBordersTexposStart() { long Textures::getWindowBordersTexposStart() { return g_window_borders_texpos_start; -} \ No newline at end of file +} From 3e18e2f6fe8ee67addc58e7b94881fd3327a5b5a Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Fri, 11 Aug 2023 09:50:51 +0300 Subject: [PATCH 297/851] eof fix one more time --- library/include/modules/Textures.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 7b2ac78d3..17e28c099 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -90,4 +90,4 @@ DFHACK_EXPORT long getPanelBordersTexposStart(); DFHACK_EXPORT long getWindowBordersTexposStart(); } -} \ No newline at end of file +} From 3a143e0601ab052986f7d629dd2958d2b3cdf0a7 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 11 Aug 2023 07:12:32 +0000 Subject: [PATCH 298/851] 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 c99b20a44..ec4baa972 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit c99b20a44c2755b3eecfa321a80b75fbef6886d4 +Subproject commit ec4baa9722233c6d2ec494318586f994bf215b42 diff --git a/scripts b/scripts index 8e9d0405d..e5b30497c 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 8e9d0405da11b8ef55feebcc26d6e76d189f15c1 +Subproject commit e5b30497c384cc72b91484bfc94ba2321690459c From 9aee332fbda8f17866bda63b2c5f88711451117a Mon Sep 17 00:00:00 2001 From: lethosor Date: Fri, 11 Aug 2023 12:52:28 -0400 Subject: [PATCH 299/851] Widen and clarify structures test mode restrictions --- test/structures/find.lua | 2 +- test/structures/globals.lua | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/structures/find.lua b/test/structures/find.lua index e93b2cc7f..590df8971 100644 --- a/test/structures/find.lua +++ b/test/structures/find.lua @@ -1,4 +1,4 @@ -config.mode = 'title' +config.mode = 'title' -- not safe to run when a world is loaded config.target = 'core' local function clean_vec(vec) diff --git a/test/structures/globals.lua b/test/structures/globals.lua index 6b278af96..81d77f8c7 100644 --- a/test/structures/globals.lua +++ b/test/structures/globals.lua @@ -1,4 +1,3 @@ -config.mode = 'title' config.target = 'core' local function with_temp_global_address(name, addr, callback, ...) From e81a90821a3e27338e352cda713a08ef19fdf1c8 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Fri, 11 Aug 2023 21:40:41 +0300 Subject: [PATCH 300/851] review --- library/Core.cpp | 1 + library/include/modules/Textures.h | 20 +++++-- library/modules/Textures.cpp | 91 +++++++++++++++++++----------- 3 files changed, 76 insertions(+), 36 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 9df45a869..d2ef1174b 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1692,6 +1692,7 @@ bool Core::InitSimulationThread() } std::cerr << "Initializing textures.\n"; Textures::init(con); + Textures::initDynamic(con); // create mutex for syncing with interactive tasks std::cerr << "Initializing plugins.\n"; // create plugin manager diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 17e28c099..ff1007dad 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -1,13 +1,14 @@ #pragma once -#include +#include +#include #include "Export.h" #include "ColorText.h" #include -using TexposHandle = uintptr_t; +typedef typename void* TexposHandle; namespace DFHack { @@ -24,18 +25,29 @@ namespace Textures { */ DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); +/** + * Load tileset from image file. + * Return vector of handles to obtain valid texposes. + */ +DFHACK_EXPORT std::vector loadTileset(const std::string& file, int tile_px_w, int tile_px_h); + /** * Get texpos by handle. * Always use this function, if you need to get valid texpos for your texure. * Texpos can change on game textures reset, but handle will be the same. */ -DFHACK_EXPORT std::optional getTexposByHandle(TexposHandle handle); +DFHACK_EXPORT long getTexposByHandle(TexposHandle handle); /** * Call this on DFHack init and on every viewscreen change so we can reload * and reindex textures as needed. */ -void init(DFHack::color_ostream &out); +void init(DFHack::color_ostream& out); + +/** + * Call this on DFHack init just once to setup interposed handlers. + */ +void initDynamic(DFHack::color_ostream& out); /** * Call this when DFHack is being unloaded. diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index a05056a2d..ec9fa41f1 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -25,7 +25,6 @@ namespace DFHack { } static bool g_loaded = false; -static bool g_dynamic_loaded = false; static long g_num_dfhack_textures = 0; static long g_dfhack_logo_texpos_start = -1; static long g_green_pin_texpos_start = -1; @@ -45,6 +44,9 @@ static std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_surface; static std::mutex g_adding_mutex; +const uint32_t TILE_WIDTH_PX = 8; +const uint32_t TILE_HEIGHT_PX = 12; + // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -52,7 +54,7 @@ static std::mutex g_adding_mutex; // // It uses the same pixel format (RGBA, R at lowest address) regardless of // hardware. -SDL_Surface* canonicalize_format(SDL_Surface *src) { +SDL_Surface* canonicalize_format(SDL_Surface* src) { SDL_PixelFormat fmt; fmt.palette = NULL; fmt.BitsPerPixel = 32; @@ -95,7 +97,7 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { if (!surface) return 0; // should be some error, i guess - auto handle = reinterpret_cast(surface); // not the best way? + auto handle = reinterpret_cast(surface); g_handle_to_surface.emplace(handle, surface); surface->refcount++; // prevent destruct on next FreeSurface by game auto texpos = add_texture(surface); @@ -103,21 +105,53 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { return handle; } -std::optional Textures::getTexposByHandle(TexposHandle handle) { +std::vector Textures::loadTileset(const std::string& file, + int tile_px_w = TILE_WIDTH_PX, + int tile_px_h = TILE_HEIGHT_PX) { + std::vector handles{}; + + SDL_Surface* surface = DFIMG_Load(file.c_str()); + if (!surface) { + ERR(textures).printerr("unable to load textures from '%s'\n", file.c_str()); + return handles; + } + + surface = canonicalize_format(surface); + int dimx = surface->w / tile_px_w; + int dimy = surface->h / tile_px_h; + for (int y = 0; y < dimy; y++) { + for (int x = 0; x < dimx; x++) { + SDL_Surface* tile = DFSDL_CreateRGBSurface(0, tile_px_w, tile_px_h, 32, + surface->format->Rmask, surface->format->Gmask, + surface->format->Bmask, surface->format->Amask); + SDL_Rect vp{ tile_px_w * x, tile_px_h * y, tile_px_w, tile_px_h }; + DFSDL_UpperBlit(surface, &vp, tile, NULL); + auto handle = Textures::loadTexture(tile); + handles.push_back(handle); + } + } + + DFSDL_FreeSurface(surface); + DEBUG(textures).print("loaded %ld textures from '%s'\n", handles.size(), file.c_str()); + + return handles; +} + +long Textures::getTexposByHandle(TexposHandle handle) { if (!handle) - return std::nullopt; + return -1; - if (auto it = g_handle_to_texpos.find(handle); it != g_handle_to_texpos.end()) - return it->second; + if (g_handle_to_texpos.contains(handle)) + return g_handle_to_texpos[handle]; - if (auto it = g_handle_to_surface.find(handle); it != g_handle_to_surface.end()) { - it->second->refcount++; // prevent destruct on next FreeSurface by game - auto texpos = add_texture(it->second); - g_handle_to_texpos.emplace(handle, texpos); - return texpos; + if (g_handle_to_surface.contains(handle)) { + g_handle_to_surface[handle]->refcount++; // prevent destruct on next FreeSurface by game + auto texpos = add_texture(g_handle_to_surface[handle]); + g_handle_to_texpos.emplace(handle, texpos); + return texpos; } - return std::nullopt; + return -1; } static void reset_texpos() { @@ -203,8 +237,7 @@ struct tracking_stage_new_arena : df::viewscreen_new_arenast { }; IMPLEMENT_VMETHOD_INTERPOSE(tracking_stage_new_arena, logic); -static void - install_reset_point() { +static void install_reset_point() { INTERPOSE_HOOK(tracking_stage_new_region, logic).apply(); INTERPOSE_HOOK(tracking_stage_adopt_region, logic).apply(); INTERPOSE_HOOK(tracking_stage_load_region, logic).apply(); @@ -218,14 +251,11 @@ static void uninstall_reset_point() { INTERPOSE_HOOK(tracking_stage_new_arena, logic).remove(); } -const uint32_t TILE_WIDTH_PX = 8; -const uint32_t TILE_HEIGHT_PX = 12; - static size_t load_tiles_from_image(color_ostream& out, const char* fname, long* texpos_start, int tile_w = TILE_WIDTH_PX, int tile_h = TILE_HEIGHT_PX) { - SDL_Surface *s = DFIMG_Load(fname); + SDL_Surface* s = DFIMG_Load(fname); if (!s) { out.printerr("unable to load textures from '%s'\n", fname); return 0; @@ -258,6 +288,11 @@ static size_t load_tiles_from_image(color_ostream& out, const char* fname, return count; } +void Textures::initDynamic(color_ostream& out) { + install_reset_point(); + DEBUG(textures, out).print("dynamic texture reset points installed"); +} + // DFHack could conceivably be loaded at any time, so we need to be able to // handle loading textures before or after a world is loaded. // If a world is already loaded, then append our textures to the raws. they'll @@ -267,15 +302,10 @@ static size_t load_tiles_from_image(color_ostream& out, const char* fname, // unloaded. // void Textures::init(color_ostream& out) { - if (!g_dynamic_loaded) { - g_dynamic_loaded = true; - install_reset_point(); - } - if (!enabler) return; - auto & textures = enabler->textures; + auto& textures = enabler->textures; long num_textures = textures.raws.size(); if (num_textures <= g_dfhack_logo_texpos_start) g_loaded = false; @@ -324,6 +354,10 @@ void Textures::init(color_ostream& out) { // It's ok to leave NULLs in the raws list (according to usage in g_src) void Textures::cleanup() { + reset_texpos(); + reset_surface(); + uninstall_reset_point(); + if (!g_loaded) return; @@ -341,13 +375,6 @@ void Textures::cleanup() { g_loaded = false; g_num_dfhack_textures = 0; g_dfhack_logo_texpos_start = -1; - - if (g_dynamic_loaded) { - g_dynamic_loaded = false; - reset_texpos(); - reset_surface(); - uninstall_reset_point(); - } } long Textures::getDfhackLogoTexposStart() { From aaf223effd868c60f9dd30e3d7cce39732ea3763 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 11 Aug 2023 12:53:46 -0700 Subject: [PATCH 301/851] scope `spotclean` to dwarfmode --- data/init/dfhack.keybindings.init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/init/dfhack.keybindings.init b/data/init/dfhack.keybindings.init index f677ca301..22dc931f4 100644 --- a/data/init/dfhack.keybindings.init +++ b/data/init/dfhack.keybindings.init @@ -38,7 +38,7 @@ keybinding add Ctrl-V@dwarfmode digv keybinding add Ctrl-Shift-V@dwarfmode "digv x" # clean the selected tile of blood etc -keybinding add Ctrl-C spotclean +keybinding add Ctrl-C@dwarfmode spotclean # destroy the selected item keybinding add Ctrl-K@dwarfmode autodump-destroy-item From fa22f9521a41cb5b8621a8f62b53ceb852d294a7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 11 Aug 2023 12:54:18 -0700 Subject: [PATCH 302/851] never suppress sdl key events when modifier keys are active --- library/Core.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 9df45a869..ec64e6231 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2400,9 +2400,13 @@ bool Core::DFH_SDL_Event(SDL_Event* ev) DEBUG(keybinding).print("key down: sym=%d (%c)\n", sym, sym); bool handled = SelectHotkey(sym, modstate); if (handled) { + hotkey_states[sym] = true; + if (modstate & (DFH_MOD_CTRL | DFH_MOD_ALT)) { + DEBUG(keybinding).print("modifier key detected; not inhibiting SDL key down event\n"); + return false; + } DEBUG(keybinding).print("%sinhibiting SDL key down event\n", suppress_duplicate_keyboard_events ? "" : "not "); - hotkey_states[sym] = true; return suppress_duplicate_keyboard_events; } } @@ -2414,7 +2418,11 @@ bool Core::DFH_SDL_Event(SDL_Event* ev) } else if (ev->type == SDL_TEXTINPUT) { auto &te = ev->text; - DEBUG(keybinding).print("text input: '%s'\n", te.text); + DEBUG(keybinding).print("text input: '%s' (modifiers: %s%s%s)\n", + te.text, + modstate & DFH_MOD_SHIFT ? "Shift" : "", + modstate & DFH_MOD_CTRL ? "Ctrl" : "", + modstate & DFH_MOD_ALT ? "Alt" : ""); if (strlen(te.text) == 1 && hotkey_states[te.text[0]]) { DEBUG(keybinding).print("%sinhibiting SDL text event\n", suppress_duplicate_keyboard_events ? "" : "not "); From 8d8c139ccb652bfc2c802ede4b2a66f598ab953e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 11 Aug 2023 12:54:49 -0700 Subject: [PATCH 303/851] don't add keys as text when ctrl or alt are pressed --- library/modules/Screen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 2ee91a089..9cc7104d8 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -589,7 +589,7 @@ std::set Screen::normalize_text_keys(const std::set combined_keys; std::copy_if(keys.begin(), keys.end(), std::inserter(combined_keys, combined_keys.begin()), [](df::interface_key k){ return k <= df::interface_key::STRING_A000 || k > df::interface_key::STRING_A255; } ); - if (df::global::enabler->last_text_input[0]) { + if (!(Core::getInstance().getModstate() & (DFH_MOD_CTRL | DFH_MOD_ALT)) && df::global::enabler->last_text_input[0]) { char c = df::global::enabler->last_text_input[0]; df::interface_key key = charToKey(c); DEBUG(screen).print("adding character %c as interface key %ld\n", c, key); From a6ec77b584393e886ec9e46293c5c17d929d2953 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 11 Aug 2023 12:58:44 -0700 Subject: [PATCH 304/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 45d0e4d2d..58caf80ee 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,6 +58,7 @@ Template for new versions: ## Fixes - Core: properly reload scripts in mods when a world is unloaded and immediately loaded again +- Core: fix text getting added to DFHack text entry widgets when Alt- or Ctrl- keys are hit ## Misc Improvements - Surround DFHack-specific UI elements with square brackets instead of red-yellow blocks for better readability From a9f47e5680a8b7cf1af342d884dba8e10dadf5f6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 11 Aug 2023 15:31:37 -0700 Subject: [PATCH 305/851] add New Tools as a valid changelog header and add to default template --- docs/changelog.txt | 6 ++++-- docs/sphinx_extensions/dfhack/changelog.py | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 45d0e4d2d..617de1e96 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -24,7 +24,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: Template for new versions: -# Future +## New Tools ## New Features @@ -35,7 +35,6 @@ Template for new versions: ## Documentation ## API -- `RemoteFortressReader`: add a ``force_reload`` option to the GetBlockList RPC API to return blocks regardless of whether they have changed since the last request ## Internals @@ -54,6 +53,8 @@ Template for new versions: # Future +## New Tools + ## New Features ## Fixes @@ -67,6 +68,7 @@ Template for new versions: ## API - ``Items::getValue()``: remove ``caravan_buying`` parameter since the identity of the selling party doesn't actually affect the item value +- `RemoteFortressReader`: add a ``force_reload`` option to the GetBlockList RPC API to return blocks regardless of whether they have changed since the last request ## Internals diff --git a/docs/sphinx_extensions/dfhack/changelog.py b/docs/sphinx_extensions/dfhack/changelog.py index cc309e425..a981bf984 100644 --- a/docs/sphinx_extensions/dfhack/changelog.py +++ b/docs/sphinx_extensions/dfhack/changelog.py @@ -16,6 +16,7 @@ CHANGELOG_PATHS = ( CHANGELOG_PATHS = (os.path.join(DFHACK_ROOT, p) for p in CHANGELOG_PATHS) CHANGELOG_SECTIONS = [ + 'New Tools', 'New Plugins', # deprecated 'New Scripts', # deprecated 'New Tweaks', # deprecated From 214b78ba3c4a9b01eed0e1baaefce7ad246ac53b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 10 Aug 2023 14:20:15 -0700 Subject: [PATCH 306/851] add unit assignment screens for pits/cages/chains refactor the existing Pasture assignment screen to handle variations --- plugins/lua/zone.lua | 621 ++++++++++++++++++++++++++++++++----------- 1 file changed, 461 insertions(+), 160 deletions(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 46cae3d24..4637f1b3f 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -2,26 +2,14 @@ local _ENV = mkmodule('plugins.zone') local gui = require('gui') local overlay = require('plugins.overlay') +local utils = require('utils') local widgets = require('gui.widgets') local CH_UP = string.char(30) local CH_DN = string.char(31) local CH_MALE = string.char(11) local CH_FEMALE = string.char(12) - -local STATUS = { - NONE={label='Unknown', value=0}, - PASTURED_HERE={label='Pastured here', value=1}, - PASTURED_ELSEWHERE={label='Pastured elsewhere', value=2}, - RESTRAINT={label='On restraint', value=3}, - BUILT_CAGE={label='On display in cage', value=4}, - ITEM_CAGE={label='In movable cage', value=5}, - ROAMING={label='Roaming', value=6}, -} -local STATUS_REVMAP = {} -for k, v in pairs(STATUS) do - STATUS_REVMAP[v.value] = k -end +local CH_NEUTER = '?' local DISPOSITION = { NONE={label='Unknown', value=0}, @@ -38,7 +26,7 @@ for k, v in pairs(DISPOSITION) do end -- ------------------- --- Pasture +-- AssignAnimal -- local STATUS_COL_WIDTH = 18 @@ -47,12 +35,20 @@ local GENDER_COL_WIDTH = 6 local SLIDER_LABEL_WIDTH = math.max(STATUS_COL_WIDTH, DISPOSITION_COL_WIDTH) + 4 local SLIDER_WIDTH = 48 -Pasture = defclass(Pasture, widgets.Window) -Pasture.ATTRS { - frame_title='Assign units to pasture', +AssignAnimal = defclass(AssignAnimal, widgets.Window) +AssignAnimal.ATTRS { + frame_title='Animal and prisoner assignment', frame={w=6+SLIDER_WIDTH*2, h=47}, resizable=true, resize_min={h=27}, + target_name=DEFAULT_NIL, + status=DEFAULT_NIL, + status_revmap=DEFAULT_NIL, + get_status=DEFAULT_NIL, + get_allow_vermin=DEFAULT_NIL, + get_multi_select=DEFAULT_NIL, + attach=DEFAULT_NIL, + initial_min_disposition=DISPOSITION.PET.value, } local function sort_noop(a, b) @@ -123,7 +119,19 @@ local function sort_by_status_asc(a, b) return a.data.status > b.data.status end -function Pasture:init() +function AssignAnimal:init() + local status_options = {} + for k, v in ipairs(self.status_revmap) do + status_options[k] = self.status[v] + end + + local disposition_options = {} + for k, v in ipairs(DISPOSITION_REVMAP) do + disposition_options[k] = DISPOSITION[v] + end + + local can_assign_pets = self.initial_min_disposition == DISPOSITION.PET.value + self:addviews{ widgets.CycleHotkeyLabel{ view_id='sort', @@ -159,15 +167,8 @@ function Pasture:init() label_below=true, key_back='CUSTOM_SHIFT_Z', key='CUSTOM_SHIFT_X', - options={ - {label=STATUS.PASTURED_HERE.label, value=STATUS.PASTURED_HERE.value}, - {label=STATUS.PASTURED_ELSEWHERE.label, value=STATUS.PASTURED_ELSEWHERE.value}, - {label=STATUS.RESTRAINT.label, value=STATUS.RESTRAINT.value}, - {label=STATUS.BUILT_CAGE.label, value=STATUS.BUILT_CAGE.value}, - {label=STATUS.ITEM_CAGE.label, value=STATUS.ITEM_CAGE.value}, - {label=STATUS.ROAMING.label, value=STATUS.ROAMING.value}, - }, - initial_option=STATUS.PASTURED_HERE.value, + options=status_options, + initial_option=1, on_change=function(val) if self.subviews.max_status:getOptionValue() < val then self.subviews.max_status:setOption(val) @@ -182,15 +183,8 @@ function Pasture:init() label_below=true, key_back='CUSTOM_SHIFT_Q', key='CUSTOM_SHIFT_W', - options={ - {label=STATUS.PASTURED_HERE.label, value=STATUS.PASTURED_HERE.value}, - {label=STATUS.PASTURED_ELSEWHERE.label, value=STATUS.PASTURED_ELSEWHERE.value}, - {label=STATUS.RESTRAINT.label, value=STATUS.RESTRAINT.value}, - {label=STATUS.BUILT_CAGE.label, value=STATUS.BUILT_CAGE.value}, - {label=STATUS.ITEM_CAGE.label, value=STATUS.ITEM_CAGE.value}, - {label=STATUS.ROAMING.label, value=STATUS.ROAMING.value}, - }, - initial_option=STATUS.ROAMING.value, + options=status_options, + initial_option=#self.status_revmap, on_change=function(val) if self.subviews.min_status:getOptionValue() > val then self.subviews.min_status:setOption(val) @@ -200,7 +194,7 @@ function Pasture:init() }, widgets.RangeSlider{ frame={l=0, t=3}, - num_stops=6, + num_stops=#self.status_revmap, get_left_idx_fn=function() return self.subviews.min_status:getOptionValue() end, @@ -222,15 +216,8 @@ function Pasture:init() label_below=true, key_back='CUSTOM_SHIFT_C', key='CUSTOM_SHIFT_V', - options={ - {label=DISPOSITION.PET.label, value=DISPOSITION.PET.value}, - {label=DISPOSITION.TAME.label, value=DISPOSITION.TAME.value}, - {label=DISPOSITION.TRAINED.label, value=DISPOSITION.TRAINED.value}, - {label=DISPOSITION.WILD_TRAINABLE.label, value=DISPOSITION.WILD_TRAINABLE.value}, - {label=DISPOSITION.WILD_UNTRAINABLE.label, value=DISPOSITION.WILD_UNTRAINABLE.value}, - {label=DISPOSITION.HOSTILE.label, value=DISPOSITION.HOSTILE.value}, - }, - initial_option=DISPOSITION.PET.value, + options=disposition_options, + initial_option=self.initial_min_disposition, on_change=function(val) if self.subviews.max_disposition:getOptionValue() < val then self.subviews.max_disposition:setOption(val) @@ -245,14 +232,7 @@ function Pasture:init() label_below=true, key_back='CUSTOM_SHIFT_E', key='CUSTOM_SHIFT_R', - options={ - {label=DISPOSITION.PET.label, value=DISPOSITION.PET.value}, - {label=DISPOSITION.TAME.label, value=DISPOSITION.TAME.value}, - {label=DISPOSITION.TRAINED.label, value=DISPOSITION.TRAINED.value}, - {label=DISPOSITION.WILD_TRAINABLE.label, value=DISPOSITION.WILD_TRAINABLE.value}, - {label=DISPOSITION.WILD_UNTRAINABLE.label, value=DISPOSITION.WILD_UNTRAINABLE.value}, - {label=DISPOSITION.HOSTILE.label, value=DISPOSITION.HOSTILE.value}, - }, + options=disposition_options, initial_option=DISPOSITION.HOSTILE.value, on_change=function(val) if self.subviews.min_disposition:getOptionValue() > val then @@ -310,7 +290,7 @@ function Pasture:init() }, widgets.Panel{ view_id='list_panel', - frame={t=12, l=0, r=0, b=4}, + frame={t=12, l=0, r=0, b=4+(can_assign_pets and 0 or 1)}, subviews={ widgets.CycleHotkeyLabel{ view_id='sort_status', @@ -367,15 +347,20 @@ function Pasture:init() } }, widgets.HotkeyLabel{ - frame={l=0, b=2}, + frame={l=0, b=2+(can_assign_pets and 0 or 1)}, label='Assign all/none', key='CUSTOM_CTRL_A', on_activate=self:callback('toggle_visible'), + visible=self.get_multi_select, auto_width=true, }, widgets.WrappedLabel{ frame={b=0, l=0, r=0}, - text_to_wrap='Click to assign/unassign to current pasture. Shift click to assign/unassign a range.', + text_to_wrap=function() + return 'Click to assign/unassign to ' .. self.target_name .. '.' .. + (self.get_multi_select() and ' Shift click to assign/unassign a range.' or '') .. + (not can_assign_pets and '\nNote that pets cannot be assigned to cages or restraints.' or '') + end, }, } @@ -388,7 +373,7 @@ function Pasture:init() self.subviews.list:setChoices(self:get_choices()) end -function Pasture:refresh_list(sort_widget, sort_fn) +function AssignAnimal:refresh_list(sort_widget, sort_fn) sort_widget = sort_widget or 'sort' sort_fn = sort_fn or self.subviews.sort:getOptionValue() if sort_fn == sort_noop then @@ -405,25 +390,36 @@ function Pasture:refresh_list(sort_widget, sort_fn) list:setFilter(saved_filter) end -local function make_search_key(data) +local function make_search_key(desc) local out = '' - for c in data.desc:gmatch("[%w%s]") do + for c in desc:gmatch("[%w%s]") do out = out .. c:lower() end return out end -local function make_choice_text(data) +function AssignAnimal:make_choice_text(data) + local gender_ch = CH_NEUTER + if data.gender == df.pronoun_type.she then + gender_ch = CH_FEMALE + elseif data.gender == df.pronoun_type.he then + gender_ch = CH_MALE + end return { - {width=STATUS_COL_WIDTH, text=function() return STATUS[STATUS_REVMAP[data.status]].label end}, + {width=STATUS_COL_WIDTH, text=function() return self.status[self.status_revmap[data.status]].label end}, {gap=2, width=DISPOSITION_COL_WIDTH, text=function() return DISPOSITION[DISPOSITION_REVMAP[data.disposition]].label end}, - {gap=2, width=GENDER_COL_WIDTH, text=data.gender == 0 and CH_FEMALE or CH_MALE}, + {gap=2, width=GENDER_COL_WIDTH, text=gender_ch}, {gap=2, text=data.desc}, } end -local function get_cage_ref(unit) - return dfhack.units.getGeneralRef(unit, df.general_ref_type.CONTAINED_IN_ITEM) +local function get_general_ref(unit_or_vermin, ref_type) + local is_unit = df.unit:is_instance(unit_or_vermin) + return dfhack[is_unit and 'units' or 'items'].getGeneralRef(unit_or_vermin, ref_type) +end + +local function get_cage_ref(unit_or_vermin) + return get_general_ref(unit_or_vermin, df.general_ref_type.CONTAINED_IN_ITEM) end local function get_built_cage(item_cage) @@ -437,30 +433,22 @@ local function get_built_cage(item_cage) end end -local function get_status(unit) - local assigned_pasture_ref = dfhack.units.getGeneralRef(unit, df.general_ref_type.BUILDING_CIVZONE_ASSIGNED) - if assigned_pasture_ref then - if df.global.game.main_interface.civzone.cur_bld.id == assigned_pasture_ref.building_id then - return STATUS.PASTURED_HERE.value - else - return STATUS.PASTURED_ELSEWHERE.value +local function get_bld_assignments() + local assignments = {} + for _,cage in ipairs(df.global.world.buildings.other.CAGE) do + for _,unit_id in ipairs(cage.assigned_units) do + assignments[unit_id] = cage end end - if dfhack.units.getGeneralRef(unit, df.general_ref_type.BUILDING_CHAIN) then - return STATUS.RESTRAINT.value - end - local cage_ref = get_cage_ref(unit) - if cage_ref then - if get_built_cage(df.item.find(cage_ref.item_id)) then - return STATUS.BUILT_CAGE.value - else - return STATUS.ITEM_CAGE.value + for _,chain in ipairs(df.global.world.buildings.other.CHAIN) do + if chain.assigned then + assignments[chain.assigned.id] = chain end end - return STATUS.ROAMING.value + return assignments end -local function get_disposition(unit) +local function get_unit_disposition(unit) local disposition = DISPOSITION.NONE if dfhack.units.isPet(unit) then disposition = DISPOSITION.PET @@ -478,7 +466,12 @@ local function get_disposition(unit) return disposition.value end -local function is_pasturable_unit(unit) +local function get_vermin_disposition(vermin) + -- TODO + return DISPOSITION.TAME.value +end + +local function is_assignable_unit(unit) return dfhack.units.isActive(unit) and ((dfhack.units.isAnimal(unit) and dfhack.units.isOwnCiv(unit)) or get_cage_ref(unit)) and not dfhack.units.isDead(unit) and @@ -486,27 +479,57 @@ local function is_pasturable_unit(unit) not dfhack.units.isForest(unit) end -function Pasture:cache_choices() +local function is_assignable_vermin(vermin) + -- TODO are there unassignable vermin? + return true +end + +local function get_vermin_desc(vermin, raw) + if not raw then return 'Unknown vermin' end + return ('%s [%d]'):format(raw.name[1], vermin.stack_size) +end + +function AssignAnimal:cache_choices() if self.choices then return self.choices end + local bld_assignments = get_bld_assignments() local choices = {} for _, unit in ipairs(df.global.world.units.active) do - if not is_pasturable_unit(unit) then goto continue end + if not is_assignable_unit(unit) then goto continue end local raw = df.creature_raw.find(unit.race) local data = { unit=unit, desc=dfhack.units.getReadableName(unit), gender=unit.sex, race=raw and raw.creature_id or -1, - status=get_status(unit), - disposition=get_disposition(unit), + status=self.get_status(unit, bld_assignments), + disposition=get_unit_disposition(unit), egg=dfhack.units.isEggLayerRace(unit), graze=dfhack.units.isGrazer(unit), } local choice = { - search_key=make_search_key(data), + search_key=make_search_key(data.desc), + data=data, + text=self:make_choice_text(data), + } + table.insert(choices, choice) + ::continue:: + end + for _, vermin in ipairs(df.global.world.items.other.VERMIN) do + if not is_assignable_vermin(vermin) then goto continue end + local raw = df.creature_raw.find(vermin.race) + local data = { + vermin=vermin, + desc=get_vermin_desc(vermin, raw), + gender=df.pronoun_type.it, + race=raw and raw.creature_id or -1, + status=self.get_status(vermin, bld_assignments), + disposition=get_vermin_disposition(vermin), + } + local choice = { + search_key=make_search_key(data.desc), data=data, - text=make_choice_text(data), + text=self:make_choice_text(data), } table.insert(choices, choice) ::continue:: @@ -516,8 +539,9 @@ function Pasture:cache_choices() return choices end -function Pasture:get_choices() +function AssignAnimal:get_choices() local raw_choices = self:cache_choices() + local show_vermin = self.get_allow_vermin() local min_status = self.subviews.min_status:getOptionValue() local max_status = self.subviews.max_status:getOptionValue() local min_disposition = self.subviews.min_disposition:getOptionValue() @@ -527,6 +551,7 @@ function Pasture:get_choices() local choices = {} for _,choice in ipairs(raw_choices) do local data = choice.data + if not show_vermin and data.vermin then goto continue end if min_status > data.status then goto continue end if max_status < data.status then goto continue end if min_disposition > data.disposition then goto continue end @@ -542,122 +567,180 @@ function Pasture:get_choices() return choices end -local function unassign_unit(bld, unit) +local function get_bld_assigned_vec(bld, unit_or_vermin) if not bld then return end - for au_idx, au_id in ipairs(bld.assigned_units) do - if au_id == unit.id then - bld.assigned_units:erase(au_idx) - return + return df.unit:is_instance(unit_or_vermin) and bld.assigned_units or bld.assigned_items +end + +local function get_assigned_unit_or_vermin_idx(bld, unit_or_vermin, vec) + vec = vec or get_bld_assigned_vec(bld, unit_or_vermin) + if not vec then return end + for assigned_idx, assigned_id in ipairs(vec) do + if assigned_id == unit_or_vermin.id then + return assigned_idx end end end -local function detach_unit(unit) - for idx = #unit.general_refs-1, 0, -1 do - local ref = unit.general_refs[idx] +local function unassign_unit_or_vermin(bld, unit_or_vermin) + if not bld then return end + if df.building_chainst:is_instance(bld) then + if bld.assigned == unit_or_vermin then + bld.assigned = nil + end + return + end + local vec = get_bld_assigned_vec(bld, unit_or_vermin) + local idx = get_assigned_unit_or_vermin_idx(bld, unit_or_vermin, vec) + if vec and idx then + vec:erase(idx) + end +end + +local function detach_unit_or_vermin(unit_or_vermin, bld_assignments) + for idx = #unit_or_vermin.general_refs-1, 0, -1 do + local ref = unit_or_vermin.general_refs[idx] if df.general_ref_building_civzone_assignedst:is_instance(ref) then - unassign_unit(df.building.find(ref.building_id), unit) - unit.general_refs:erase(idx) + unassign_unit_or_vermin(df.building.find(ref.building_id), unit_or_vermin) + unit_or_vermin.general_refs:erase(idx) ref:delete() elseif df.general_ref_contained_in_itemst:is_instance(ref) then local built_cage = get_built_cage(df.item.find(ref.item_id)) if built_cage and built_cage:getType() == df.building_type.Cage then - unassign_unit(built_cage, unit) + unassign_unit_or_vermin(built_cage, unit_or_vermin) -- unit's general ref will be removed when the unit is released from the cage end - elseif df.general_ref_building_chainst:is_instance(ref) then - local chain = df.building.find(ref.building_id) - if chain then - chain.assigned = nil - end end end + bld_assignments = bld_assignments or get_bld_assignments() + if bld_assignments[unit_or_vermin.id] then + unassign_unit_or_vermin(bld_assignments[unit_or_vermin.id], unit_or_vermin) + end end -local function attach_unit(unit) - local pasture = df.global.game.main_interface.civzone.cur_bld - local ref = df.new(df.general_ref_building_civzone_assignedst) - ref.building_id = pasture.id; - unit.general_refs:insert('#', ref) - pasture.assigned_units:insert('#', unit.id) -end +function AssignAnimal:toggle_item_base(choice, target_value, bld_assignments) + local true_value = self.status[self.status_revmap[1]].value -local function toggle_item_base(choice, target_value) if target_value == nil then - target_value = choice.data.status ~= STATUS.PASTURED_HERE.value + target_value = choice.data.status ~= true_value end - if target_value and choice.data.status == STATUS.PASTURED_HERE.value then - return + if target_value and choice.data.status == true_value then + return target_value end - if not target_value and choice.data.status ~= STATUS.PASTURED_HERE.value then - return + if not target_value and choice.data.status ~= true_value then + return target_value end - local unit = choice.data.unit - detach_unit(unit) + if self.initial_min_disposition ~= DISPOSITION.PET.value and choice.data.disposition == DISPOSITION.PET.value then + return target_value + end + + local unit_or_vermin = choice.data.unit or choice.data.vermin + detach_unit_or_vermin(unit_or_vermin, bld_assignments) if target_value then - attach_unit(unit) + local displaced_unit = self.attach(unit_or_vermin) + if displaced_unit then + -- assigning a unit to a restraint can unassign a different unit + for _, c in ipairs(self.subviews.list:getChoices()) do + if c.data.unit == displaced_unit then + c.data.status = self.get_status(displaced_unit) + end + end + end end - choice.data.status = get_status(unit) + -- don't pass bld_assignments since it may no longer be valid + choice.data.status = self.get_status(unit_or_vermin) + + return target_value end -function Pasture:select_item(idx, choice) +function AssignAnimal:select_item(idx, choice) if not dfhack.internal.getModifiers().shift then self.prev_list_idx = self.subviews.list.list:getSelected() end end -function Pasture:toggle_item(idx, choice) - toggle_item_base(choice) +function AssignAnimal:toggle_item(idx, choice) + self:toggle_item_base(choice) end -function Pasture:toggle_range(idx, choice) +function AssignAnimal:toggle_range(idx, choice) + if not self.get_multi_select() then + self:toggle_item(idx, choice) + return + end if not self.prev_list_idx then self:toggle_item(idx, choice) return end local choices = self.subviews.list:getVisibleChoices() local list_idx = self.subviews.list.list:getSelected() + local bld_assignments = get_bld_assignments() local target_value for i = list_idx, self.prev_list_idx, list_idx < self.prev_list_idx and 1 or -1 do - target_value = toggle_item_base(choices[i], target_value) + target_value = self:toggle_item_base(choices[i], target_value, bld_assignments) end self.prev_list_idx = list_idx end -function Pasture:toggle_visible() +function AssignAnimal:toggle_visible() + local bld_assignments = get_bld_assignments() local target_value for _, choice in ipairs(self.subviews.list:getVisibleChoices()) do - target_value = toggle_item_base(choice, target_value) + target_value = self:toggle_item_base(choice, target_value, bld_assignments) end end -- ------------------- --- PastureScreen +-- AssignAnimalScreen -- view = view or nil -PastureScreen = defclass(PastureScreen, gui.ZScreen) -PastureScreen.ATTRS { - focus_path='zone/pasture', +AssignAnimalScreen = defclass(AssignAnimalScreen, gui.ZScreen) +AssignAnimalScreen.ATTRS { + focus_path='zone/assign', + is_valid_ui_state=DEFAULT_NIL, + status=DEFAULT_NIL, + status_revmap=DEFAULT_NIL, + get_status=DEFAULT_NIL, + get_allow_vermin=DEFAULT_NIL, + get_multi_select=DEFAULT_NIL, + attach=DEFAULT_NIL, + initial_min_disposition=DEFAULT_NIL, + target_name=DEFAULT_NIL, } -function PastureScreen:init() - self:addviews{Pasture{}} +function AssignAnimalScreen:init() + self:addviews{ + AssignAnimal{ + status=self.status, + status_revmap=self.status_revmap, + get_status=self.get_status, + get_allow_vermin=self.get_allow_vermin, + get_multi_select=self.get_multi_select, + attach=self.attach, + initial_min_disposition=self.initial_min_disposition, + target_name=self.target_name, + } + } end -function PastureScreen:onInput(keys) - local handled = PastureScreen.super.onInput(self, keys) +function AssignAnimalScreen:onInput(keys) + local handled = AssignAnimalScreen.super.onInput(self, keys) + if not self.is_valid_ui_state() then + view:dismiss() + return + end if keys._MOUSE_L_DOWN then - -- if any click is made outside of our window, we need to recheck unit properites + -- if any click is made outside of our window, we need to recheck unit properties local window = self.subviews[1] if not window:getMouseFramePos() then for _, choice in ipairs(self.subviews.list:getChoices()) do - choice.data.status = get_status(choice.data.unit) + choice.data.status = self.get_status(choice.data.unit or choice.data.vermin) end window:refresh_list() end @@ -665,42 +748,126 @@ function PastureScreen:onInput(keys) return handled end -function PastureScreen:onRenderFrame() - if df.global.game.main_interface.bottom_mode_selected ~= df.main_bottom_mode_type.ZONE or - not df.global.game.main_interface.civzone.cur_bld or - df.global.game.main_interface.civzone.cur_bld.type ~= df.civzone_type.Pen - then +function AssignAnimalScreen:onRenderFrame() + if not self.is_valid_ui_state() then view:dismiss() end end -function PastureScreen:onDismiss() +function AssignAnimalScreen:onDismiss() view = nil end -- ------------------- --- PastureOverlay +-- PasturePondOverlay -- -PastureOverlay = defclass(PastureOverlay, overlay.OverlayWidget) -PastureOverlay.ATTRS{ +PasturePondOverlay = defclass(PasturePondOverlay, overlay.OverlayWidget) +PasturePondOverlay.ATTRS{ default_pos={x=7,y=13}, default_enabled=true, - viewscreens='dwarfmode/Zone/Some/Pen', - frame={w=31, h=3}, - frame_background=gui.CLEAR_PEN, + viewscreens={'dwarfmode/Zone/Some/Pen', 'dwarfmode/Zone/Some/Pond'}, + frame={w=31, h=4}, } -function PastureOverlay:init() +local function is_valid_zone() + return df.global.game.main_interface.bottom_mode_selected == df.main_bottom_mode_type.ZONE and + df.global.game.main_interface.civzone.cur_bld and + (df.global.game.main_interface.civzone.cur_bld.type == df.civzone_type.Pen or + df.global.game.main_interface.civzone.cur_bld.type == df.civzone_type.Pond) +end + +local function is_pit_selected() + return df.global.game.main_interface.bottom_mode_selected == df.main_bottom_mode_type.ZONE and + df.global.game.main_interface.civzone.cur_bld and + df.global.game.main_interface.civzone.cur_bld.type == df.civzone_type.Pond +end + +local function attach_to_zone(unit_or_vermin) + local zone = df.global.game.main_interface.civzone.cur_bld + local ref = df.new(df.general_ref_building_civzone_assignedst) + ref.building_id = zone.id; + unit_or_vermin.general_refs:insert('#', ref) + local is_unit = df.unit:is_instance(unit_or_vermin) + local vec = is_unit and zone.assigned_units or zone.assigned_items + utils.insert_sorted(vec, unit_or_vermin.id) +end + +local PASTURE_STATUS = { + NONE={label='Unknown', value=0}, + ASSIGNED_HERE={label='Assigned here', value=1}, + PASTURED={label='In other pasture', value=2}, + PITTED={label='In other pit/pond', value=3}, + RESTRAINED={label='On restraint', value=4}, + BUILT_CAGE={label='In built cage', value=5}, + ITEM_CAGE={label='In stockpiled cage', value=6}, + ROAMING={label='Roaming', value=7}, +} +local PASTURE_STATUS_REVMAP = {} +for k, v in pairs(PASTURE_STATUS) do + PASTURE_STATUS_REVMAP[v.value] = k +end + +local function get_zone_status(unit_or_vermin, bld_assignments) + local assigned_zone_ref = get_general_ref(unit_or_vermin, df.general_ref_type.BUILDING_CIVZONE_ASSIGNED) + if assigned_zone_ref then + if df.global.game.main_interface.civzone.cur_bld.id == assigned_zone_ref.building_id then + return PASTURE_STATUS.ASSIGNED_HERE.value + else + local civzone = df.building.find(assigned_zone_ref.building_id) + if civzone.type == df.civzone_type.Pen then + return PASTURE_STATUS.PASTURED.value + elseif civzone.type == df.civzone_type.Pond then + return PASTURE_STATUS.PITTED.value + else + return PASTURE_STATUS.NONE.value + end + end + end + if get_general_ref(unit_or_vermin, df.general_ref_type.BUILDING_CHAIN) then + return PASTURE_STATUS.RESTRAINED.value + end + local cage_ref = get_cage_ref(unit_or_vermin) + if cage_ref then + if get_built_cage(df.item.find(cage_ref.item_id)) then + return PASTURE_STATUS.BUILT_CAGE.value + else + return PASTURE_STATUS.ITEM_CAGE.value + end + end + bld_assignments = bld_assignments or get_bld_assignments() + if bld_assignments and bld_assignments[unit_or_vermin.id] then + if df.building_chainst:is_instance(bld_assignments[unit_or_vermin.id]) then + return PASTURE_STATUS.RESTRAINED.value + end + return PASTURE_STATUS.BUILT_CAGE.value + end + return PASTURE_STATUS.ROAMING.value +end + +local function show_pasture_pond_screen() + return AssignAnimalScreen{ + is_valid_ui_state=is_valid_zone, + status=PASTURE_STATUS, + status_revmap=PASTURE_STATUS_REVMAP, + get_status=get_zone_status, + get_allow_vermin=is_pit_selected, + get_multi_select=function() return true end, + attach=attach_to_zone, + target_name='pasture/pond/pit', + }:show() +end + +function PasturePondOverlay:init() self:addviews{ widgets.TextButton{ - frame={t=0, l=0, r=0, h=1}, - label='DFHack manage pasture', + frame={t=0, l=0, w=23, h=1}, + label='DFHack assign', key='CUSTOM_CTRL_T', - on_activate=function() view = view and view:raise() or PastureScreen{}:show() end, + on_activate=function() view = view and view:raise() or show_pasture_pond_screen() end, }, widgets.TextButton{ - frame={t=2, l=0, r=0, h=1}, + frame={b=0, l=0, w=28, h=1}, label='DFHack autobutcher', key='CUSTOM_CTRL_B', on_activate=function() dfhack.run_script('gui/autobutcher') end, @@ -708,8 +875,142 @@ function PastureOverlay:init() } end +-- ------------------- +-- CageChainOverlay +-- + +CageChainOverlay = defclass(CageChainOverlay, overlay.OverlayWidget) +CageChainOverlay.ATTRS{ + default_pos={x=-40,y=34}, + default_enabled=true, + viewscreens={'dwarfmode/ViewSheets/BUILDING/Cage', 'dwarfmode/ViewSheets/BUILDING/Chain'}, + frame={w=23, h=1}, + frame_background=gui.CLEAR_PEN, +} + +local function is_valid_building() + local bld = dfhack.gui.getSelectedBuilding(true) + return bld and bld:getBuildStage() == bld:getMaxBuildStage() and + (bld:getType() == df.building_type.Cage or + bld:getType() == df.building_type.Chain) +end + +local function is_cage_selected() + local bld = dfhack.gui.getSelectedBuilding(true) + return bld and bld:getType() == df.building_type.Cage +end + +local function attach_to_building(unit_or_vermin) + local bld = dfhack.gui.getSelectedBuilding(true) + if not bld then return end + local is_unit = df.unit:is_instance(unit_or_vermin) + if is_unit and unit_or_vermin.relationship_ids[df.unit_relationship_type.Pet] ~= -1 then + -- pet owners would just release them + return + end + if bld:getType() == df.building_type.Cage then + local vec = is_unit and bld.assigned_units or bld.assigned_items + vec:insert('#', unit_or_vermin.id) + elseif is_unit and bld:getType() == df.building_type.Chain then + local prev_unit = bld.assigned + bld.assigned = unit_or_vermin + return prev_unit + end +end + +local function get_built_chain(unit_or_vermin) + local built_chain_ref = get_general_ref(unit_or_vermin, df.general_ref_type.BUILDING_CHAIN) + if not built_chain_ref then return end + return df.building.find(built_chain_ref.building_id) +end + +local CAGE_STATUS = { + NONE={label='Unknown', value=0}, + ASSIGNED_HERE={label='Assigned here', value=1}, + PASTURED={label='In pasture', value=2}, + PITTED={label='In pit/pond', value=3}, + RESTRAINED={label='On other chain', value=4}, + BUILT_CAGE={label='In built cage', value=5}, + ITEM_CAGE={label='In stockpiled cage', value=6}, + ROAMING={label='Roaming', value=7}, +} +local CAGE_STATUS_REVMAP = {} +for k, v in pairs(CAGE_STATUS) do + CAGE_STATUS_REVMAP[v.value] = k +end + +local function get_cage_status(unit_or_vermin, bld_assignments) + local bld = dfhack.gui.getSelectedBuilding(true) + local is_chain = bld and df.building_chainst:is_instance(bld) + + if is_chain and bld.assigned == unit_or_vermin then + return CAGE_STATUS.ASSIGNED_HERE.value + elseif not is_chain and get_assigned_unit_or_vermin_idx(bld, unit_or_vermin) then + return CAGE_STATUS.ASSIGNED_HERE.value + end + local cage_ref = get_cage_ref(unit_or_vermin) + if cage_ref then + if get_built_cage(df.item.find(cage_ref.item_id)) then + return CAGE_STATUS.BUILT_CAGE.value + end + return CAGE_STATUS.ITEM_CAGE.value + end + local built_chain = get_built_chain(unit_or_vermin) + if built_chain then + if bld and bld == built_chain then + return CAGE_STATUS.ASSIGNED_HERE.value + end + return CAGE_STATUS.RESTRAINED.value + end + local assigned_zone_ref = get_general_ref(unit_or_vermin, df.general_ref_type.BUILDING_CIVZONE_ASSIGNED) + if assigned_zone_ref then + local civzone = df.building.find(assigned_zone_ref.building_id) + if civzone.type == df.civzone_type.Pen then + return CAGE_STATUS.PASTURED.value + elseif civzone.type == df.civzone_type.Pond then + return CAGE_STATUS.PITTED.value + else + return CAGE_STATUS.NONE.value + end + end + bld_assignments = bld_assignments or get_bld_assignments() + if bld_assignments and bld_assignments[unit_or_vermin.id] then + if df.building_chainst:is_instance(bld_assignments[unit_or_vermin.id]) then + return CAGE_STATUS.RESTRAINED.value + end + return CAGE_STATUS.BUILT_CAGE.value + end + return CAGE_STATUS.ROAMING.value +end + +local function show_cage_chain_screen() + return AssignAnimalScreen{ + is_valid_ui_state=is_valid_building, + status=CAGE_STATUS, + status_revmap=CAGE_STATUS_REVMAP, + get_status=get_cage_status, + get_allow_vermin=is_cage_selected, + get_multi_select=is_cage_selected, + attach=attach_to_building, + initial_min_disposition=DISPOSITION.TAME.value, + target_name='cage/restraint', + }:show() +end + +function CageChainOverlay:init() + self:addviews{ + widgets.TextButton{ + frame={t=0, l=0, r=0, h=1}, + label='DFHack assign', + key='CUSTOM_CTRL_T', + on_activate=function() view = view and view:raise() or show_cage_chain_screen() end, + }, + } +end + OVERLAY_WIDGETS = { - pasture=PastureOverlay, + pasturepond=PasturePondOverlay, + cagechain=CageChainOverlay, } return _ENV From ab9ef7a1f167af70adaa7135460e16b9e6bfdf0a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 11 Aug 2023 18:33:50 -0700 Subject: [PATCH 307/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index ec42e30b6..749b00c93 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -56,6 +56,7 @@ Template for new versions: ## New Tools ## New Features +- `caravan`: advanced unit assignment screens for cages, restraints, and pits/ponds ## Fixes - Core: properly reload scripts in mods when a world is unloaded and immediately loaded again From 4aaf625f4d07cf20b92f4f586fd64bd2890ed192 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 12 Aug 2023 01:49:06 +0000 Subject: [PATCH 308/851] 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 ec4baa972..4d68eb01f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ec4baa9722233c6d2ec494318586f994bf215b42 +Subproject commit 4d68eb01fa10da89b6bd9f4de692a7f20cc3f911 diff --git a/scripts b/scripts index e5b30497c..ed3a8baf0 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit e5b30497c384cc72b91484bfc94ba2321690459c +Subproject commit ed3a8baf0be87a7a93731dcea62ff9e6a5a77ad8 From e61c4e8f8669935b2d595f8f035e57ea0bd2e5bf Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 11 Aug 2023 20:18:07 -0700 Subject: [PATCH 309/851] update zone docs ref: #3667 --- docs/plugins/zone.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/plugins/zone.rst b/docs/plugins/zone.rst index 2e1bbc613..f1e333126 100644 --- a/docs/plugins/zone.rst +++ b/docs/plugins/zone.rst @@ -162,12 +162,12 @@ Overlay ------- Advanced unit selection is available via an `overlay` widget that appears when -you select a pasture zone. +you select a cage, restraint, pasture zone, or pit/pond zone. In the window that pops up when you click the hotkey hint or hit the hotkey on your keyboard, you can: - search for units by name -- sort or filter by status (Pastured here, Pastured elsewhere, On restraint, On +- sort or filter by status (Assigned here, Pastured elsewhere, On restraint, On display in cage, In movable cage, or Roaming) - sort or filter by disposition (Pet, Domesticated, Partially trained, Wild (trainable), Wild (untrainable), or Hostile) @@ -177,11 +177,12 @@ In the window that pops up when you click the hotkey hint or hit the hotkey on y - filter by whether the unit needs a grazing area The window is fully navigatable via keyboard or mouse. Hit Enter or click on a -unit to assign/unassign it to the currently selected pasture. Shift click to -assign/unassign a range of units. +unit to assign/unassign it to the currently selected zone or building. Shift +click to assign/unassign a range of units. -You can also keep the window open and click around on different pastures, so -you can manage multiple pastures without having to close and reopen the window. +You can also keep the window open and click around on different cages, +restraints, pastures, or pit/ponds, so you can manage multiple buildings/zones +without having to close and reopen the window. -As for all other overlays, you can disable this one in `gui/control-panel` on +Just like all other overlays, you can disable this one in `gui/control-panel` on the Overlays tab if you don't want the option of using it. From 351dfa84c2806e92c8feba1bc9638b5e156aeaf8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 12 Aug 2023 01:17:44 -0400 Subject: [PATCH 310/851] Remove obsolete STATIC_FIELDS_GROUP check --- library/DataIdentity.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/DataIdentity.cpp b/library/DataIdentity.cpp index ba7c7f4a6..8e9467c5b 100644 --- a/library/DataIdentity.cpp +++ b/library/DataIdentity.cpp @@ -21,7 +21,6 @@ namespace df { opaque_identity identity_traits::identity(sizeof(type), allocator_noassign_fn, name) #define STL_OPAQUE_IDENTITY_TRAITS(type) OPAQUE_IDENTITY_TRAITS_NAME(std::type, #type) -#ifndef STATIC_FIELDS_GROUP INTEGER_IDENTITY_TRAITS(char, "char"); INTEGER_IDENTITY_TRAITS(signed char, "int8_t"); INTEGER_IDENTITY_TRAITS(unsigned char, "uint8_t"); @@ -51,5 +50,4 @@ namespace df { STL_OPAQUE_IDENTITY_TRAITS(future); buffer_container_identity buffer_container_identity::base_instance; -#endif } From 0a5e914a65e0145e4d568fa71027c09ce16c6940 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 12 Aug 2023 01:19:18 -0400 Subject: [PATCH 311/851] Add struct_field_info_extra::original_name field for globals --- library/include/DataDefs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index e03e9a0a8..c440c1eb7 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -265,6 +265,7 @@ namespace DFHack type_identity *ref_target; const char *union_tag_field; const char *union_tag_attr; + const char *original_name; }; struct struct_field_info { From 9cb764b847f0dd0129e47d80b28e3c2c750b8738 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 12 Aug 2023 07:11:31 +0000 Subject: [PATCH 312/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index ed3a8baf0..5b59f60c3 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ed3a8baf0be87a7a93731dcea62ff9e6a5a77ad8 +Subproject commit 5b59f60c30557ab24d6bc869c4976fdb70c322a5 From fe8bd4fa786369f7a95ae7925fc992095cc1fb2d Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sat, 12 Aug 2023 16:11:42 +0300 Subject: [PATCH 313/851] assets use dynamic texture loading --- library/Core.cpp | 2 - library/LuaApi.cpp | 13 +- library/include/modules/Textures.h | 67 ++----- library/lua/gui.lua | 38 +++- library/modules/Textures.cpp | 279 +++++++---------------------- plugins/lua/buildingplan/pens.lua | 31 ++-- plugins/lua/hotkeys.lua | 40 +++-- plugins/pathable.cpp | 6 +- 8 files changed, 150 insertions(+), 326 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index d2ef1174b..4950e848d 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1692,7 +1692,6 @@ bool Core::InitSimulationThread() } std::cerr << "Initializing textures.\n"; Textures::init(con); - Textures::initDynamic(con); // create mutex for syncing with interactive tasks std::cerr << "Initializing plugins.\n"; // create plugin manager @@ -2219,7 +2218,6 @@ void Core::onStateChange(color_ostream &out, state_change_event event) } break; case SC_VIEWSCREEN_CHANGED: - Textures::init(out); break; default: break; diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 578bb4746..61a7eb83d 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1710,18 +1710,7 @@ static const luaL_Reg dfhack_job_funcs[] = { /***** Textures module *****/ static const LuaWrapper::FunctionReg dfhack_textures_module[] = { - WRAPM(Textures, getDfhackLogoTexposStart), - WRAPM(Textures, getGreenPinTexposStart), - WRAPM(Textures, getRedPinTexposStart), - WRAPM(Textures, getIconsTexposStart), - WRAPM(Textures, getOnOffTexposStart), - WRAPM(Textures, getMapUnsuspendTexposStart), - WRAPM(Textures, getControlPanelTexposStart), - WRAPM(Textures, getThinBordersTexposStart), - WRAPM(Textures, getMediumBordersTexposStart), - WRAPM(Textures, getBoldBordersTexposStart), - WRAPM(Textures, getPanelBordersTexposStart), - WRAPM(Textures, getWindowBordersTexposStart), + WRAPM(Textures, getAsset), { NULL, NULL } }; diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index ff1007dad..9569a257a 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -1,10 +1,10 @@ #pragma once -#include #include +#include -#include "Export.h" #include "ColorText.h" +#include "Export.h" #include @@ -29,7 +29,8 @@ DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); * Load tileset from image file. * Return vector of handles to obtain valid texposes. */ -DFHACK_EXPORT std::vector loadTileset(const std::string& file, int tile_px_w, int tile_px_h); +DFHACK_EXPORT std::vector loadTileset(const std::string& file, int tile_px_w, + int tile_px_h); /** * Get texpos by handle. @@ -39,15 +40,15 @@ DFHACK_EXPORT std::vector loadTileset(const std::string& file, int DFHACK_EXPORT long getTexposByHandle(TexposHandle handle); /** - * Call this on DFHack init and on every viewscreen change so we can reload - * and reindex textures as needed. + * Get texpos for static asset with index in tileset. */ -void init(DFHack::color_ostream& out); +DFHACK_EXPORT long getAsset(const std::string asset, size_t index = 0); /** - * Call this on DFHack init just once to setup interposed handlers. + * Call this on DFHack init just once to setup interposed handlers and + * init static assets. */ -void initDynamic(DFHack::color_ostream& out); +void init(DFHack::color_ostream& out); /** * Call this when DFHack is being unloaded. @@ -55,51 +56,5 @@ void initDynamic(DFHack::color_ostream& out); */ void cleanup(); -/** - * Get first texpos for the DFHack logo. This texpos and the next 11 make up the - * 4x3 grid of logo textures that can be displayed on the UI layer. - */ -DFHACK_EXPORT long getDfhackLogoTexposStart(); - -/** - * Get the first texpos for the UI pin tiles. Each are 2x2 grids. - */ -DFHACK_EXPORT long getGreenPinTexposStart(); -DFHACK_EXPORT long getRedPinTexposStart(); - -/** - * Get the first texpos for the DFHack icons. It's a 5x2 grid. - */ -DFHACK_EXPORT long getIconsTexposStart(); - -/** - * Get the first texpos for the on and off icons. It's a 2x1 grid. - */ -DFHACK_EXPORT long getOnOffTexposStart(); - -/** - * Get the first texpos for the pathable 32x32 sprites. It's a 2x1 grid. - */ -DFHACK_EXPORT long getMapPathableTexposStart(); - -/** - * Get the first texpos for the unsuspend 32x32 sprites. It's a 5x1 grid. - */ -DFHACK_EXPORT long getMapUnsuspendTexposStart(); - -/** - * Get the first texpos for the control panel icons. 10x2 grid. - */ -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(); - -} -} +} // namespace Textures +} // namespace DFHack diff --git a/library/lua/gui.lua b/library/lua/gui.lua index ca3b212f0..c511f1005 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -913,10 +913,10 @@ local BASE_FRAME = { } local function make_frame(name, double_line) - local texpos = dfhack.textures['get'..name..'BordersTexposStart']() local tp = function(offset) + local texpos = dfhack.textures.getAsset('hack/data/art/border-'..name:lower()..'.png', offset) if texpos == -1 then return nil end - return texpos + offset + return texpos end local frame = copyall(BASE_FRAME) @@ -951,8 +951,40 @@ BOLD_FRAME = FRAME_BOLD INTERIOR_FRAME = FRAME_INTERIOR INTERIOR_MEDIUM_FRAME = FRAME_INTERIOR_MEDIUM +-- for compatibility with dynamic textures +local function choose_frame_style(style) + if style == FRAME_WINDOW then return make_frame('Window', true) end + if style == FRAME_PANEL then return make_frame('Panel', true) end + if style == FRAME_MEDIUM then return make_frame('Medium', true) end + if style == FRAME_BOLD then return make_frame('Bold', true) end + if style == FRAME_INTERIOR then + local frame = make_frame('Thin', true) + frame.signature_pen = false + return frame + end + if style == FRAME_INTERIOR_MEDIUM then + local frame = make_frame('Medium', true) + frame.signature_pen = false + return frame + end + if style == GREY_LINE_FRAME then return make_frame('Panel', true) end + if style == WINDOW_FRAME then return make_frame('Window', true) end + if style == PANEL_FRAME then return make_frame('Panel', true) end + if style == MEDIUM_FRAME then return make_frame('Medium', true) end + if style == INTERIOR_FRAME then + local frame = make_frame('Thin', true) + frame.signature_pen = false + return frame + end + if style == INTERIOR_MEDIUM_FRAME then + local frame = make_frame('Medium', true) + frame.signature_pen = false + return frame + end +end -function paint_frame(dc,rect,style,title,inactive,pause_forced,resizable) +function paint_frame(dc, rect, style, title, inactive, pause_forced, resizable) + style = choose_frame_style(style) local pen = style.frame_pen local x1,y1,x2,y2 = dc.x1+rect.x1, dc.y1+rect.y1, dc.x1+rect.x2, dc.y1+rect.y2 dscreen.paintTile(style.lt_frame_pen or pen, x1, y1) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index ec9fa41f1..712375a70 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -13,8 +13,8 @@ #include "df/enabler.h" #include "df/viewscreen_adopt_regionst.h" #include "df/viewscreen_loadgamest.h" -#include "df/viewscreen_new_regionst.h" #include "df/viewscreen_new_arenast.h" +#include "df/viewscreen_new_regionst.h" using df::global::enabler; using namespace DFHack; @@ -24,22 +24,6 @@ namespace DFHack { DBG_DECLARE(core, textures, DebugCategory::LINFO); } -static bool g_loaded = false; -static long g_num_dfhack_textures = 0; -static long g_dfhack_logo_texpos_start = -1; -static long g_green_pin_texpos_start = -1; -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_pathable_texpos_start = -1; -static long g_unsuspend_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 std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_surface; static std::mutex g_adding_mutex; @@ -47,6 +31,16 @@ static std::mutex g_adding_mutex; const uint32_t TILE_WIDTH_PX = 8; const uint32_t TILE_HEIGHT_PX = 12; +static std::vector empty{}; +static std::unordered_map> g_static_assets{ + {"hack/data/art/dfhack.png", empty}, {"hack/data/art/green-pin.png", empty}, + {"hack/data/art/red-pin.png", empty}, {"hack/data/art/icons.png", empty}, + {"hack/data/art/on-off.png", empty}, {"hack/data/art/pathable.png", empty}, + {"hack/data/art/unsuspend.png", empty}, {"hack/data/art/control-panel.png", empty}, + {"hack/data/art/border-thin.png", empty}, {"hack/data/art/border-medium.png", empty}, + {"hack/data/art/border-bold.png", empty}, {"hack/data/art/border-panel.png", empty}, + {"hack/data/art/border-window.png", empty}}; + // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -55,34 +49,40 @@ const uint32_t TILE_HEIGHT_PX = 12; // It uses the same pixel format (RGBA, R at lowest address) regardless of // hardware. SDL_Surface* canonicalize_format(SDL_Surface* src) { - SDL_PixelFormat fmt; - fmt.palette = NULL; - fmt.BitsPerPixel = 32; - fmt.BytesPerPixel = 4; - fmt.Rloss = fmt.Gloss = fmt.Bloss = fmt.Aloss = 0; + SDL_PixelFormat fmt; + fmt.palette = NULL; + fmt.BitsPerPixel = 32; + fmt.BytesPerPixel = 4; + fmt.Rloss = fmt.Gloss = fmt.Bloss = fmt.Aloss = 0; #if SDL_BYTEORDER == SDL_BIG_ENDIAN - fmt.Rshift = 24; fmt.Gshift = 16; fmt.Bshift = 8; fmt.Ashift = 0; + fmt.Rshift = 24; + fmt.Gshift = 16; + fmt.Bshift = 8; + fmt.Ashift = 0; #else - fmt.Rshift = 0; fmt.Gshift = 8; fmt.Bshift = 16; fmt.Ashift = 24; + fmt.Rshift = 0; + fmt.Gshift = 8; + fmt.Bshift = 16; + fmt.Ashift = 24; #endif - fmt.Rmask = 255 << fmt.Rshift; - fmt.Gmask = 255 << fmt.Gshift; - fmt.Bmask = 255 << fmt.Bshift; - fmt.Amask = 255 << fmt.Ashift; - - SDL_Surface* tgt = DFSDL_ConvertSurface(src, &fmt, SDL_SWSURFACE); - DFSDL_FreeSurface(src); - for (int x = 0; x < tgt->w; ++x) { - for (int y = 0; y < tgt->h; ++y) { - Uint8* p = (Uint8*)tgt->pixels + y * tgt->pitch + x * 4; - if (p[3] == 0) { - for (int c = 0; c < 3; c++) { - p[c] = 0; - } - } - } - } - return tgt; + fmt.Rmask = 255 << fmt.Rshift; + fmt.Gmask = 255 << fmt.Gshift; + fmt.Bmask = 255 << fmt.Bshift; + fmt.Amask = 255 << fmt.Ashift; + + SDL_Surface* tgt = DFSDL_ConvertSurface(src, &fmt, SDL_SWSURFACE); + DFSDL_FreeSurface(src); + for (int x = 0; x < tgt->w; ++x) { + for (int y = 0; y < tgt->h; ++y) { + Uint8* p = (Uint8*)tgt->pixels + y * tgt->pitch + x * 4; + if (p[3] == 0) { + for (int c = 0; c < 3; c++) { + p[c] = 0; + } + } + } + } + return tgt; } // register surface in texture raws, get a texpos @@ -97,7 +97,7 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { if (!surface) return 0; // should be some error, i guess - auto handle = reinterpret_cast(surface); + auto handle = reinterpret_cast(surface); // not the best way? but cheap g_handle_to_surface.emplace(handle, surface); surface->refcount++; // prevent destruct on next FreeSurface by game auto texpos = add_texture(surface); @@ -121,10 +121,10 @@ std::vector Textures::loadTileset(const std::string& file, int dimy = surface->h / tile_px_h; for (int y = 0; y < dimy; y++) { for (int x = 0; x < dimx; x++) { - SDL_Surface* tile = DFSDL_CreateRGBSurface(0, tile_px_w, tile_px_h, 32, - surface->format->Rmask, surface->format->Gmask, - surface->format->Bmask, surface->format->Amask); - SDL_Rect vp{ tile_px_w * x, tile_px_h * y, tile_px_w, tile_px_h }; + SDL_Surface* tile = DFSDL_CreateRGBSurface( + 0, tile_px_w, tile_px_h, 32, surface->format->Rmask, surface->format->Gmask, + surface->format->Bmask, surface->format->Amask); + SDL_Rect vp{tile_px_w * x, tile_px_h * y, tile_px_w, tile_px_h}; DFSDL_UpperBlit(surface, &vp, tile, NULL); auto handle = Textures::loadTexture(tile); handles.push_back(handle); @@ -154,6 +154,14 @@ long Textures::getTexposByHandle(TexposHandle handle) { return -1; } +long Textures::getAsset(const std::string asset, size_t index) { + if (!g_static_assets.contains(asset)) + return -1; + if (g_static_assets[asset].size() <= index) + return -1; + return Textures::getTexposByHandle(g_static_assets[asset][index]); +} + static void reset_texpos() { g_handle_to_texpos.clear(); } @@ -190,7 +198,7 @@ struct tracking_stage_adopt_region : df::viewscreen_adopt_regionst { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { this->m_cur_step = this->cur_step; - if (this->m_cur_step == df::viewscreen_adopt_regionst::T_cur_step::ProcessingRawData) + if (this->m_cur_step == 2) reset_texpos(); } INTERPOSE_NEXT(logic)(); @@ -208,7 +216,7 @@ struct tracking_stage_load_region : df::viewscreen_loadgamest { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { this->m_cur_step = this->cur_step; - if (this->m_cur_step == df::viewscreen_loadgamest::T_cur_step::ProcessingRawData) + if (this->m_cur_step == 1) reset_texpos(); } INTERPOSE_NEXT(logic)(); @@ -251,180 +259,19 @@ static void uninstall_reset_point() { INTERPOSE_HOOK(tracking_stage_new_arena, logic).remove(); } -static size_t load_tiles_from_image(color_ostream& out, const char* fname, - long* texpos_start, - int tile_w = TILE_WIDTH_PX, - int tile_h = TILE_HEIGHT_PX) { - SDL_Surface* s = DFIMG_Load(fname); - if (!s) { - out.printerr("unable to load textures from '%s'\n", fname); - return 0; - } +void Textures::init(color_ostream& out) { + install_reset_point(); + DEBUG(textures, out).print("dynamic texture loading ready"); - s = canonicalize_format(s); - int dimx = s->w / tile_w; - int dimy = s->h / tile_h; - long count = 0; - for (int y = 0; y < dimy; y++) { - for (int x = 0; x < dimx; x++) { - SDL_Surface* tile = DFSDL_CreateRGBSurface(0, // SDL_SWSURFACE - tile_w, tile_h, 32, - s->format->Rmask, s->format->Gmask, s->format->Bmask, - s->format->Amask); - SDL_Rect vp; - vp.x = tile_w * x; - vp.y = tile_h * y; - vp.w = tile_w; - vp.h = tile_h; - DFSDL_UpperBlit(s, &vp, tile, NULL); - if (!count++) - *texpos_start = enabler->textures.raws.size(); - enabler->textures.raws.push_back(tile); - } + for (auto& [key, value] : g_static_assets) { + g_static_assets[key] = Textures::loadTileset(key); } - DFSDL_FreeSurface(s); - DEBUG(textures,out).print("loaded %ld textures from '%s'\n", count, fname); - return count; + DEBUG(textures, out).print("assets loaded"); } -void Textures::initDynamic(color_ostream& out) { - install_reset_point(); - DEBUG(textures, out).print("dynamic texture reset points installed"); -} - -// DFHack could conceivably be loaded at any time, so we need to be able to -// handle loading textures before or after a world is loaded. -// If a world is already loaded, then append our textures to the raws. they'll -// be freed when the world is unloaded and we'll reload when we get to the title -// screen. If it's pre-world, append our textures and then adjust the "init" -// texture count so our textures will no longer be freed when worlds are -// unloaded. -// -void Textures::init(color_ostream& out) { - if (!enabler) - return; - - auto& textures = enabler->textures; - long num_textures = textures.raws.size(); - if (num_textures <= g_dfhack_logo_texpos_start) - g_loaded = false; - - if (g_loaded) - return; - - bool is_pre_world = num_textures == textures.init_texture_size; - - g_num_dfhack_textures = load_tiles_from_image(out, "hack/data/art/dfhack.png", - &g_dfhack_logo_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/green-pin.png", - &g_green_pin_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/red-pin.png", - &g_red_pin_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/icons.png", - &g_icons_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/on-off.png", - &g_on_off_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/pathable.png", - &g_pathable_texpos_start, 32, 32); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/unsuspend.png", - &g_unsuspend_texpos_start, 32, 32); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/control-panel.png", - &g_control_panel_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-thin.png", - &g_thin_borders_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-medium.png", - &g_medium_borders_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-bold.png", - &g_bold_borders_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-panel.png", - &g_panel_borders_texpos_start); - g_num_dfhack_textures += load_tiles_from_image(out, "hack/data/art/border-window.png", - &g_window_borders_texpos_start); - - DEBUG(textures,out).print("loaded %ld textures\n", g_num_dfhack_textures); - - if (is_pre_world) - textures.init_texture_size += g_num_dfhack_textures; - - // NOTE: when GL modes are supported, we'll have to re-upload textures here - - g_loaded = true; -} - -// It's ok to leave NULLs in the raws list (according to usage in g_src) void Textures::cleanup() { reset_texpos(); reset_surface(); uninstall_reset_point(); - - if (!g_loaded) - return; - - auto& textures = enabler->textures; - auto& raws = textures.raws; - size_t texpos_end = g_dfhack_logo_texpos_start + g_num_dfhack_textures - 1; - for (size_t idx = g_dfhack_logo_texpos_start; idx <= texpos_end; ++idx) { - DFSDL_FreeSurface((SDL_Surface *)raws[idx]); - raws[idx] = NULL; - } - - if (g_dfhack_logo_texpos_start == textures.init_texture_size - g_num_dfhack_textures) - textures.init_texture_size -= g_num_dfhack_textures; - - g_loaded = false; - g_num_dfhack_textures = 0; - g_dfhack_logo_texpos_start = -1; -} - -long Textures::getDfhackLogoTexposStart() { - return g_dfhack_logo_texpos_start; -} - -long Textures::getGreenPinTexposStart() { - return g_green_pin_texpos_start; -} - -long Textures::getRedPinTexposStart() { - return g_red_pin_texpos_start; -} - -long Textures::getIconsTexposStart() { - return g_icons_texpos_start; -} - -long Textures::getOnOffTexposStart() { - return g_on_off_texpos_start; -} - -long Textures::getMapPathableTexposStart() { - return g_pathable_texpos_start; -} - -long Textures::getMapUnsuspendTexposStart() { - return g_unsuspend_texpos_start; -} - -long Textures::getControlPanelTexposStart() { - return g_control_panel_texpos_start; -} - -long Textures::getThinBordersTexposStart() { - return g_thin_borders_texpos_start; -} - -long Textures::getMediumBordersTexposStart() { - return g_medium_borders_texpos_start; -} - -long Textures::getBoldBordersTexposStart() { - return g_bold_borders_texpos_start; -} - -long Textures::getPanelBordersTexposStart() { - return g_panel_borders_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 e69a4c210..52db6c893 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -9,29 +9,30 @@ MINI_TEXT_PEN, MINI_TEXT_HPEN, MINI_BUTT_PEN, MINI_BUTT_HPEN = nil, nil, nil, ni local to_pen = dfhack.pen.parse -local tp = function(base, offset) - if base == -1 then return nil end - return base + offset +local tp = function(asset, offset) + local texpos = dfhack.textures.getAsset(asset, offset) + if texpos == -1 then return nil end + return texpos end 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() - 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 tb = "hack/data/art/border-thin.png" + VERT_TOP_PEN = to_pen { tile = tp(tb, 10), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_MID_PEN = to_pen { tile = tp(tb, 4), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_BOT_PEN = to_pen { tile = tp(tb, 11), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } - 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} + local mb = "hack/data/art/border-medium.png" + HORI_LEFT_PEN = to_pen { tile = tp(mb, 12), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_MID_PEN = to_pen { tile = tp(mb, 5), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_RIGHT_PEN = to_pen { tile = tp(mb, 13), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } - local cp_texpos = dfhack.textures.getControlPanelTexposStart() - BUTTON_START_PEN = to_pen{tile=tp(cp_texpos, 13), ch='[', fg=COLOR_YELLOW} - BUTTON_END_PEN = to_pen{tile=tp(cp_texpos, 15), ch=']', fg=COLOR_YELLOW} - SELECTED_ITEM_PEN = to_pen{tile=tp(cp_texpos, 9), ch=string.char(251), fg=COLOR_YELLOW} + local cp = "hack/data/art/control-panel.png" + BUTTON_START_PEN = to_pen { tile = tp(cp, 13), ch = '[', fg = COLOR_YELLOW } + BUTTON_END_PEN = to_pen { tile = tp(cp, 15), ch = ']', fg = COLOR_YELLOW } + SELECTED_ITEM_PEN = to_pen { tile = tp(cp, 9), ch = string.char(251), fg = COLOR_YELLOW } MINI_TEXT_PEN = to_pen{fg=COLOR_BLACK, bg=COLOR_GREY} MINI_TEXT_HPEN = to_pen{fg=COLOR_BLACK, bg=COLOR_WHITE} diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 373b2945f..f58d8322a 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -68,28 +68,30 @@ end local dscreen = dfhack.screen function HotspotMenuWidget:onRenderBody(dc) - local tpos = dfhack.textures.getDfhackLogoTexposStart() local x, y = dc.x, dc.y + local tp = function(offset) + return dfhack.textures.getAsset("hack/data/art/dfhack.png", offset) + end - if tpos == -1 then - dscreen.paintString(COLOR_WHITE, x, y+0, '!DF!') - dscreen.paintString(COLOR_WHITE, x, y+1, '!Ha!') - dscreen.paintString(COLOR_WHITE, x, y+2, '!ck!') + if tp(0) == -1 then + dscreen.paintString(COLOR_WHITE, x, y + 0, '!DF!') + dscreen.paintString(COLOR_WHITE, x, y + 1, '!Ha!') + dscreen.paintString(COLOR_WHITE, x, y + 2, '!ck!') else - dscreen.paintTile(COLOR_WHITE, x+0, y+0, '!', tpos+0) - dscreen.paintTile(COLOR_WHITE, x+1, y+0, 'D', tpos+1) - dscreen.paintTile(COLOR_WHITE, x+2, y+0, 'F', tpos+2) - dscreen.paintTile(COLOR_WHITE, x+3, y+0, '!', tpos+3) - - dscreen.paintTile(COLOR_WHITE, x+0, y+1, '!', tpos+4) - dscreen.paintTile(COLOR_WHITE, x+1, y+1, 'H', tpos+5) - dscreen.paintTile(COLOR_WHITE, x+2, y+1, 'a', tpos+6) - dscreen.paintTile(COLOR_WHITE, x+3, y+1, '!', tpos+7) - - dscreen.paintTile(COLOR_WHITE, x+0, y+2, '!', tpos+8) - dscreen.paintTile(COLOR_WHITE, x+1, y+2, 'c', tpos+9) - dscreen.paintTile(COLOR_WHITE, x+2, y+2, 'k', tpos+10) - dscreen.paintTile(COLOR_WHITE, x+3, y+2, '!', tpos+11) + dscreen.paintTile(COLOR_WHITE, x + 0, y + 0, '!', tp(0)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 0, 'D', tp(1)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 0, 'F', tp(2)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 0, '!', tp(3)) + + dscreen.paintTile(COLOR_WHITE, x + 0, y + 1, '!', tp(4)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 1, 'H', tp(5)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 1, 'a', tp(6)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 1, '!', tp(7)) + + dscreen.paintTile(COLOR_WHITE, x + 0, y + 2, '!', tp(8)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 2, 'c', tp(9)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 2, 'k', tp(10)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 2, '!', tp(11)) end end diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index f60469489..c0c49c470 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -44,10 +44,10 @@ static void paintScreenPathable(df::coord target, bool show_hidden = false) { long pathable_tile_texpos = init->load_bar_texpos[1]; long unpathable_tile_texpos = init->load_bar_texpos[4]; - long on_off_texpos = Textures::getMapPathableTexposStart(); + long on_off_texpos = Textures::getAsset("hack/data/art/pathable.png", 0); if (on_off_texpos > 0) { - pathable_tile_texpos = on_off_texpos + 0; - unpathable_tile_texpos = on_off_texpos + 1; + pathable_tile_texpos = on_off_texpos; + unpathable_tile_texpos = Textures::getAsset("hack/data/art/pathable.png", 1); } auto dims = Gui::getDwarfmodeViewDims().map(); From b20889e694612a1dc374fee9ed99c05211c1bbd3 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sat, 12 Aug 2023 16:34:33 +0300 Subject: [PATCH 314/851] minor refactor for lua switch --- library/lua/gui.lua | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index c511f1005..aaca5b849 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -953,30 +953,18 @@ INTERIOR_MEDIUM_FRAME = FRAME_INTERIOR_MEDIUM -- for compatibility with dynamic textures local function choose_frame_style(style) - if style == FRAME_WINDOW then return make_frame('Window', true) end - if style == FRAME_PANEL then return make_frame('Panel', true) end - if style == FRAME_MEDIUM then return make_frame('Medium', true) end - if style == FRAME_BOLD then return make_frame('Bold', true) end - if style == FRAME_INTERIOR then - local frame = make_frame('Thin', true) - frame.signature_pen = false - return frame + if style == FRAME_WINDOW or style == WINDOW_FRAME then return make_frame('Window', true) end + if style == FRAME_PANEL or style == GREY_LINE_FRAME or style == PANEL_FRAME then + return make_frame('Panel', true) end - if style == FRAME_INTERIOR_MEDIUM then - local frame = make_frame('Medium', true) - frame.signature_pen = false - return frame - end - if style == GREY_LINE_FRAME then return make_frame('Panel', true) end - if style == WINDOW_FRAME then return make_frame('Window', true) end - if style == PANEL_FRAME then return make_frame('Panel', true) end - if style == MEDIUM_FRAME then return make_frame('Medium', true) end - if style == INTERIOR_FRAME then + if style == FRAME_MEDIUM or style == MEDIUM_FRAME then return make_frame('Medium', true) end + if style == FRAME_BOLD then return make_frame('Bold', true) end + if style == FRAME_INTERIOR or style == INTERIOR_FRAME then local frame = make_frame('Thin', true) frame.signature_pen = false return frame end - if style == INTERIOR_MEDIUM_FRAME then + if style == FRAME_INTERIOR_MEDIUM or style == INTERIOR_MEDIUM_FRAME then local frame = make_frame('Medium', true) frame.signature_pen = false return frame From 46a3454fee59f27676b43d559c2ce62a59a9d0b7 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sat, 12 Aug 2023 17:00:07 +0300 Subject: [PATCH 315/851] type alias for gcc --- library/include/modules/Textures.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 9569a257a..4d20302cc 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -8,7 +8,7 @@ #include -typedef typename void* TexposHandle; +typedef void* TexposHandle; namespace DFHack { From 687bd82542e32c111fb582e06bc8c68fa6ffc45b Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sat, 12 Aug 2023 20:05:15 +0300 Subject: [PATCH 316/851] pathable & unsuspend specific tile size --- library/modules/Textures.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 712375a70..4df928684 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -264,7 +264,13 @@ void Textures::init(color_ostream& out) { DEBUG(textures, out).print("dynamic texture loading ready"); for (auto& [key, value] : g_static_assets) { - g_static_assets[key] = Textures::loadTileset(key); + auto tile_w = TILE_WIDTH_PX; + auto tile_h = TILE_HEIGHT_PX; + if (key == "hack/data/art/pathable.png" || key == "hack/data/art/unsuspend.png") { + tile_w = 32; + tile_h = 32; + } + g_static_assets[key] = Textures::loadTileset(key, tile_w, tile_h); } DEBUG(textures, out).print("assets loaded"); From c37dce7c330132ce19bd5aa425a636542b4f39e6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 12 Aug 2023 15:53:22 -0700 Subject: [PATCH 317/851] detect extended tile properties and communicate them back to lua --- docs/changelog.txt | 1 + library/LuaApi.cpp | 17 +++++++++++++++++ library/modules/Screen.cpp | 30 +++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 749b00c93..bac0d2848 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -79,6 +79,7 @@ Template for new versions: - ``dfhack.items.getValue()``: remove ``caravan_buying`` param as per C++ API change - ``widgets.BannerPanel``: panel with distinctive border for marking DFHack UI elements on otherwise vanilla screens - ``widgets.Panel``: new functions to override instead of setting corresponding properties (useful when subclassing instead of just setting attributes): ``onDragBegin``, ``onDragEnd``, ``onResizeBegin``, ``onResizeEnd`` +- ``dfhack.screen.readTile()``: now populates extended tile property fields (like top_of_text) in the returned Pen object ## Removed diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 578bb4746..9dc86b526 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -844,6 +844,23 @@ static void make_pen_table(lua_State *L, Pen &pen) lua_pushboolean(L, false); lua_setfield(L, -2, "tile_color"); break; } + + if (pen.keep_lower) { + lua_pushboolean(L, true); + lua_setfield(L, -2, "keep_lower"); + } + if (pen.write_to_lower) { + lua_pushboolean(L, true); + lua_setfield(L, -2, "write_to_lower"); + } + if (pen.top_of_text) { + lua_pushboolean(L, true); + lua_setfield(L, -2, "top_of_text"); + } + if (pen.bottom_of_text) { + lua_pushboolean(L, true); + lua_setfield(L, -2, "bottom_of_text"); + } } } diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 9cc7104d8..93f4773ec 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -294,6 +294,7 @@ static Pen doGetTile_default(int x, int y, bool map) { return Pen(0, 0, 0, -1); long *texpos = &gps->screentexpos[index]; + long *texpos_lower = &gps->screentexpos_lower[index]; uint32_t *flag = &gps->screentexpos_flag[index]; if (gps->top_in_use && @@ -301,6 +302,7 @@ static Pen doGetTile_default(int x, int y, bool map) { (use_graphics && gps->screentexpos_top[index]))) { screen = &gps->screen_top[index * 8]; texpos = &gps->screentexpos_top[index]; + texpos_lower = &gps->screentexpos_top_lower[index]; flag = &gps->screentexpos_top_flag[index]; } @@ -308,19 +310,37 @@ static Pen doGetTile_default(int x, int y, bool map) { uint8_t fg = to_16_bit_color(&screen[1]); uint8_t bg = to_16_bit_color(&screen[4]); int tile = 0; - if (use_graphics) + bool write_to_lower = false; + bool top_of_text = false; + bool bottom_of_text = false; + if (use_graphics) { tile = *texpos; + if (!tile && *texpos_lower) { + tile = *texpos_lower; + write_to_lower = true; + } + if (*flag & 0x8) + top_of_text = true; + else if (*flag &0x10) + bottom_of_text = true; + } + Pen ret; if (*flag & 1) { // TileColor - return Pen(ch, fg&7, bg, !!(fg&8), tile, fg, bg); + ret = Pen(ch, fg&7, bg, !!(fg&8), tile, fg, bg); } else if (*flag & 2) { // CharColor - return Pen(ch, fg, bg, tile, true); + ret = Pen(ch, fg, bg, tile, true); + } else { + // AsIs + ret = Pen(ch, fg, bg, tile, false); } - // AsIs - return Pen(ch, fg, bg, tile, false); + ret.write_to_lower = write_to_lower; + ret.top_of_text = top_of_text; + ret.bottom_of_text = bottom_of_text; + return ret; } GUI_HOOK_DEFINE(Screen::Hooks::get_tile, doGetTile_default); From 92549f3c561e6c8f3678dac424b942eae94653c7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 12 Aug 2023 03:09:18 -0400 Subject: [PATCH 318/851] Add _fields table to struct types --- library/LuaTypes.cpp | 106 ++++++++++++++++++++++++++++++++++++++--- library/LuaWrapper.cpp | 1 + 2 files changed, 100 insertions(+), 7 deletions(-) diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index ddc166abc..7e1ab67cb 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -1291,11 +1291,27 @@ void LuaWrapper::SetFunctionWrappers(lua_State *state, const FunctionReg *reg) /** * Add fields in the array to the UPVAL_FIELDTABLE candidates on the stack. + * + * flags: + * GLOBALS: if true, pstruct is a global_identity and fields with addresses of 0 are skipped + * RAW: if true, no fields are skipped (supersedes `GLOBALS` flag) and + * special-case fields like OBJ_METHODs are not added to the metatable + * + * Stack in & out: + * base+1: metatable + * base+2: fields table (to be populated, map of name -> struct_field_info*) + * base+3: field iter table (to be populated, bimap of name <-> integer index) */ -static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bool globals) +namespace IndexFieldsFlags { + enum IndexFieldsFlags { + GLOBALS = 1 << 0, + RAW = 1 << 1, + }; +} +static void IndexFields(lua_State *state, int base, struct_identity *pstruct, int flags) { if (pstruct->getParent()) - IndexFields(state, base, pstruct->getParent(), globals); + IndexFields(state, base, pstruct->getParent(), flags); auto fields = pstruct->getFields(); if (!fields) @@ -1315,6 +1331,7 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bo bool add_to_enum = true; + if (!(flags & IndexFieldsFlags::RAW)) // Handle the field switch (fields[i].mode) { @@ -1337,10 +1354,10 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bo } // Do not add invalid globals to the enumeration order - if (globals && !*(void**)fields[i].offset) + if ((flags & IndexFieldsFlags::GLOBALS) && !*(void**)fields[i].offset) add_to_enum = false; - if (add_to_enum) + if (add_to_enum || (flags & IndexFieldsFlags::RAW)) AssociateId(state, base+3, ++cnt, name.c_str()); lua_pushlightuserdata(state, (void*)&fields[i]); @@ -1348,10 +1365,86 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, bo } } +static void AddFieldInfoTable(lua_State *state, int ftable_idx, struct_identity *pstruct) +{ + Lua::StackUnwinder base{state}; + + // metatable + lua_newtable(state); + int ix_meta = lua_gettop(state); + + // field info table (name -> struct_field_info*) + lua_newtable(state); + int ix_fieldinfo = lua_gettop(state); + + // field iter table (int <-> name) + lua_newtable(state); + int ix_fielditer = lua_gettop(state); + IndexFields(state, base, pstruct, IndexFieldsFlags::RAW); + + PushStructMethod(state, ix_meta, ix_fielditer, meta_struct_next); + SetPairsMethod(state, ix_meta, "__pairs"); + + // field table (name -> table representation of struct_field_info) + lua_newtable(state); + int ix_fields = lua_gettop(state); + + // wrapper table (empty, indexes into field table with metamethods) + lua_newtable(state); + int ix_wrapper = lua_gettop(state); + + // set up metatable for the wrapper + // use field table for __index + lua_pushstring(state, "__index"); + lua_pushvalue(state, ix_fields); + lua_settable(state, ix_meta); + + // use change_error() for __newindex + lua_pushstring(state, "__newindex"); + lua_getfield(state, LUA_REGISTRYINDEX, DFHACK_CHANGEERROR_NAME); + lua_settable(state, ix_meta); + + lua_pushvalue(state, ix_meta); + lua_setmetatable(state, ix_wrapper); + + // convert field info table (struct_field_info) to field table (lua tables) + lua_pushnil(state); // initial key for next() + while (lua_next(state, ix_fieldinfo)) { + auto field = static_cast(lua_touserdata(state, -1)); + lua_pushvalue(state, -2); // field name + lua_newtable(state); // new field info + Lua::TableInsert(state, "name", field->name); + Lua::TableInsert(state, "offset", field->offset); + + if (field->type) { + Lua::TableInsert(state, "type_name", field->type->getFullName()); + + lua_pushstring(state, "type"); + lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPEID_TABLE_TOKEN); + lua_rawgetp(state, -1, field->type); + lua_remove(state, -2); // TYPEID_TABLE + lua_settable(state, -3); + } + + lua_settable(state, ix_fields); + + lua_pop(state, 1); // field name + } + + lua_pushvalue(state, ix_wrapper); + lua_setfield(state, ftable_idx, "_fields"); + lua_pushvalue(state, ix_fieldinfo); + lua_setfield(state, ftable_idx, "_fieldsinfo"); + lua_pushvalue(state, ix_meta); + lua_setfield(state, ftable_idx, "_fieldsmeta"); + lua_pushvalue(state, ix_fielditer); + lua_setfield(state, ftable_idx, "_fieldsiter"); +} + void LuaWrapper::IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct) { // stack: metatable fieldtable - + AddFieldInfoTable(state, ftable_idx, pstruct); for (struct_identity *p = pstruct; p; p = p->getParent()) { auto fields = p->getFields(); @@ -1387,8 +1480,7 @@ static void MakeFieldMetatable(lua_State *state, struct_identity *pstruct, // Index the fields lua_newtable(state); - - IndexFields(state, base, pstruct, globals); + IndexFields(state, base, pstruct, globals ? IndexFieldsFlags::GLOBALS : 0); // Add the iteration metamethods PushStructMethod(state, base+1, base+3, iterator); diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 1ea4865bd..9d2357c70 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -1670,6 +1670,7 @@ static void RenderType(lua_State *state, compound_identity *node) { RenderTypeChildren(state, node->getScopeChildren()); + IndexStatics(state, ix_meta, ftable, (struct_identity*)node); lua_pushlightuserdata(state, node); lua_setfield(state, ftable, "_identity"); From 29f99733fe67b12facd4f10997c0b08f8b8cef16 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 12 Aug 2023 19:00:24 -0400 Subject: [PATCH 319/851] Add tests --- library/LuaTypes.cpp | 9 ++---- test/structures/struct_fields.lua | 54 +++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 test/structures/struct_fields.lua diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index 7e1ab67cb..1cc83be31 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -1426,19 +1426,16 @@ static void AddFieldInfoTable(lua_State *state, int ftable_idx, struct_identity lua_settable(state, -3); } + // freeze_table(state); // TODO: make pairs() work lua_settable(state, ix_fields); lua_pop(state, 1); // field name } + // lua_pushvalue(state, ix_fields); + // freeze_table(state); // TODO: figure out why this creates an __index cycle for nonexistent fields lua_pushvalue(state, ix_wrapper); lua_setfield(state, ftable_idx, "_fields"); - lua_pushvalue(state, ix_fieldinfo); - lua_setfield(state, ftable_idx, "_fieldsinfo"); - lua_pushvalue(state, ix_meta); - lua_setfield(state, ftable_idx, "_fieldsmeta"); - lua_pushvalue(state, ix_fielditer); - lua_setfield(state, ftable_idx, "_fieldsiter"); } void LuaWrapper::IndexStatics(lua_State *state, int meta_idx, int ftable_idx, struct_identity *pstruct) diff --git a/test/structures/struct_fields.lua b/test/structures/struct_fields.lua new file mode 100644 index 000000000..e94c9fbc5 --- /dev/null +++ b/test/structures/struct_fields.lua @@ -0,0 +1,54 @@ +config.target = 'core' + +local COORD_FIELD_NAMES = {'x', 'y', 'z', 'isValid', 'clear'} +local COORD_FIELD_EXPECTED_DATA = { + x = {type_name='int16_t'}, + y = {type_name='int16_t'}, + z = {type_name='int16_t'}, + isValid = {type_name='function'}, + clear = {type_name='function'}, +} + +local READONLY_MSG = 'Attempt to change a read%-only table.' + +function test.access() + local fields = df.coord._fields + expect.true_(fields) + expect.eq(fields, df.coord._fields) + + for name, expected in pairs(COORD_FIELD_EXPECTED_DATA) do + expect.true_(fields[name], name) + expect.eq(fields[name].name, name, name) + expect.eq(fields[name].type_name, expected.type_name, name) + expect.eq(type(fields[name].offset), 'number', name) + end +end + +function test.order() + local i = 0 + for name in pairs(df.coord._fields) do + i = i + 1 + expect.eq(name, COORD_FIELD_NAMES[i], i) + end + expect.eq(i, #COORD_FIELD_NAMES) +end + +function test.nonexistent() + expect.nil_(df.coord._fields.nonexistent) +end + +function test.readonly() + expect.error_match(READONLY_MSG, function() + df.coord._fields.x = 'foo' + end) + expect.error_match(READONLY_MSG, function() + df.coord._fields.nonexistent = 'foo' + end) + -- see TODOs in LuaTypes.cpp + -- expect.error_match(READONLY_MSG, function() + -- df.coord._fields.x.name = 'foo' + -- end) + + expect.eq(df.coord._fields.x.name, 'x') + expect.nil_(df.coord._fields.nonexistent) +end From 4a9a83daa5e40cf8f1cd493ffcdc699434fe90f6 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 12 Aug 2023 19:28:02 -0400 Subject: [PATCH 320/851] Expose more fields, refactor --- library/LuaTypes.cpp | 55 +++++++++++++++++++++---------- test/structures/struct_fields.lua | 8 +++++ 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index 1cc83be31..0d81886db 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -1365,6 +1365,42 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, in } } +static void PushFieldInfoSubTable(lua_State *state, const struct_field_info *field) +{ + lua_newtable(state); // new field info + Lua::TableInsert(state, "mode", field->mode); + Lua::TableInsert(state, "name", field->name); + Lua::TableInsert(state, "offset", field->offset); + Lua::TableInsert(state, "count", field->count); + + if (field->type) { + Lua::TableInsert(state, "type_name", field->type->getFullName()); + + lua_pushlightuserdata(state, field->type); + lua_setfield(state, -2, "type_identity"); + + lua_pushstring(state, "type"); + lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPEID_TABLE_TOKEN); + lua_rawgetp(state, -1, field->type); + lua_remove(state, -2); // TYPEID_TABLE + lua_settable(state, -3); + } + + if (field->extra) { + // TODO: index_enum, ref_target + if (field->extra->union_tag_field) { + Lua::TableInsert(state, "union_tag_field", field->extra->union_tag_field); + } + if (field->extra->union_tag_attr) { + Lua::TableInsert(state, "union_tag_attr", field->extra->union_tag_attr); + } + if (field->extra->original_name) { + Lua::TableInsert(state, "original_name", field->extra->original_name); + } + } + // freeze_table(state); // TODO: make pairs() work +} + static void AddFieldInfoTable(lua_State *state, int ftable_idx, struct_identity *pstruct) { Lua::StackUnwinder base{state}; @@ -1412,24 +1448,9 @@ static void AddFieldInfoTable(lua_State *state, int ftable_idx, struct_identity while (lua_next(state, ix_fieldinfo)) { auto field = static_cast(lua_touserdata(state, -1)); lua_pushvalue(state, -2); // field name - lua_newtable(state); // new field info - Lua::TableInsert(state, "name", field->name); - Lua::TableInsert(state, "offset", field->offset); - - if (field->type) { - Lua::TableInsert(state, "type_name", field->type->getFullName()); - - lua_pushstring(state, "type"); - lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPEID_TABLE_TOKEN); - lua_rawgetp(state, -1, field->type); - lua_remove(state, -2); // TYPEID_TABLE - lua_settable(state, -3); - } - - // freeze_table(state); // TODO: make pairs() work + PushFieldInfoSubTable(state, field); lua_settable(state, ix_fields); - - lua_pop(state, 1); // field name + lua_pop(state, 1); // struct_field_info } // lua_pushvalue(state, ix_fields); diff --git a/test/structures/struct_fields.lua b/test/structures/struct_fields.lua index e94c9fbc5..5ad513dcc 100644 --- a/test/structures/struct_fields.lua +++ b/test/structures/struct_fields.lua @@ -21,6 +21,14 @@ function test.access() expect.eq(fields[name].name, name, name) expect.eq(fields[name].type_name, expected.type_name, name) expect.eq(type(fields[name].offset), 'number', name) + expect.eq(type(fields[name].mode), 'number', name) + expect.eq(type(fields[name].count), 'number', name) + end +end + +function test.globals_original_name() + for name, info in pairs(df.global._fields) do + expect.eq(type(info.original_name), 'string', name) end end From fc6d4caa8ea3c28579e28cf2a2e86fa446a32f21 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 12 Aug 2023 20:18:22 -0400 Subject: [PATCH 321/851] Dynamically generate field info in __index Constructing the complete tables when the types were initialized made it impossible to populate the "type" field, because not all types had been added to the global type tables yet. --- library/LuaTypes.cpp | 58 +++++++++++++++++++++++++++++-- test/structures/struct_fields.lua | 12 +++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index 0d81886db..4507cb718 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -1367,6 +1367,11 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, in static void PushFieldInfoSubTable(lua_State *state, const struct_field_info *field) { + if (!field) { + lua_pushnil(state); + return; + } + lua_newtable(state); // new field info Lua::TableInsert(state, "mode", field->mode); Lua::TableInsert(state, "name", field->name); @@ -1401,6 +1406,51 @@ static void PushFieldInfoSubTable(lua_State *state, const struct_field_info *fie // freeze_table(state); // TODO: make pairs() work } +/** + * Metamethod: __index for struct._fields + * + * upvalue 1: name -> struct_field_info* table + */ +static int meta_fieldinfo_index(lua_State *state) +{ + luaL_checktype(state, -1, LUA_TSTRING); + + lua_gettable(state, lua_upvalueindex(1)); + auto field = static_cast(lua_touserdata(state, -1)); + lua_pop(state, 1); + PushFieldInfoSubTable(state, field); + + return 1; +} + +/** + * Metamethod: iterator for struct._fields + * + * upvalue 1: name -> struct_field_info* table + * upvalue 3: field table (int <-> name) + */ +static int meta_fieldinfo_next(lua_State *state) +{ + if (lua_gettop(state) < 2) lua_pushnil(state); + + int len = lua_rawlen(state, UPVAL_FIELDTABLE); + int idx = cur_iter_index(state, len+1, 2, 0); + if (idx == len) + return 0; + + lua_rawgeti(state, UPVAL_FIELDTABLE, idx+1); + + // modified from meta_struct_next: + // retrieve the struct_field_info* from the table and convert it + lua_dup(state); + lua_gettable(state, lua_upvalueindex(1)); + auto field = static_cast(lua_touserdata(state, -1)); + lua_pop(state, 1); + PushFieldInfoSubTable(state, field); + + return 2; +} + static void AddFieldInfoTable(lua_State *state, int ftable_idx, struct_identity *pstruct) { Lua::StackUnwinder base{state}; @@ -1418,7 +1468,10 @@ static void AddFieldInfoTable(lua_State *state, int ftable_idx, struct_identity int ix_fielditer = lua_gettop(state); IndexFields(state, base, pstruct, IndexFieldsFlags::RAW); - PushStructMethod(state, ix_meta, ix_fielditer, meta_struct_next); + PushStructMethod(state, ix_meta, ix_fielditer, meta_fieldinfo_next); + // change upvalue 1 to the field info table since we don't need the original + lua_pushvalue(state, ix_fieldinfo); + lua_setupvalue(state, -2, 1); SetPairsMethod(state, ix_meta, "__pairs"); // field table (name -> table representation of struct_field_info) @@ -1432,7 +1485,8 @@ static void AddFieldInfoTable(lua_State *state, int ftable_idx, struct_identity // set up metatable for the wrapper // use field table for __index lua_pushstring(state, "__index"); - lua_pushvalue(state, ix_fields); + lua_pushvalue(state, ix_fieldinfo); + lua_pushcclosure(state, meta_fieldinfo_index, 1); lua_settable(state, ix_meta); // use change_error() for __newindex diff --git a/test/structures/struct_fields.lua b/test/structures/struct_fields.lua index 5ad513dcc..f9b3c41fc 100644 --- a/test/structures/struct_fields.lua +++ b/test/structures/struct_fields.lua @@ -60,3 +60,15 @@ function test.readonly() expect.eq(df.coord._fields.x.name, 'x') expect.nil_(df.coord._fields.nonexistent) end + +function test.circular_refs_init() + expect.eq(df.job._fields.list_link.type, df.job_list_link) + expect.eq(df.job_list_link._fields.item.type, df.job) +end + +function test.subclass_match() + for f, parent in pairs(df.viewscreen._fields) do + local child = df.viewscreen_titlest._fields[f] + expect.table_eq(parent, child, f) + end +end From 1a630eab3438ba90fadf789c0f783eab1798b76f Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 13 Aug 2023 00:45:42 +0000 Subject: [PATCH 322/851] 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 4d68eb01f..179e7406d 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 4d68eb01fa10da89b6bd9f4de692a7f20cc3f911 +Subproject commit 179e7406d567623ac875024002c620234a64e5aa From 396b2d7832746bc8a1ae6ba6d34164e25f4fe27f Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 12 Aug 2023 21:59:14 -0400 Subject: [PATCH 323/851] Adapt tests to dynamically-generated field info No need to freeze the field info tables anymore --- library/LuaTypes.cpp | 1 - test/structures/struct_fields.lua | 15 ++++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index 4507cb718..ac99600a1 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -1403,7 +1403,6 @@ static void PushFieldInfoSubTable(lua_State *state, const struct_field_info *fie Lua::TableInsert(state, "original_name", field->extra->original_name); } } - // freeze_table(state); // TODO: make pairs() work } /** diff --git a/test/structures/struct_fields.lua b/test/structures/struct_fields.lua index f9b3c41fc..53c9ebcc1 100644 --- a/test/structures/struct_fields.lua +++ b/test/structures/struct_fields.lua @@ -43,6 +43,13 @@ end function test.nonexistent() expect.nil_(df.coord._fields.nonexistent) + + expect.error_match('string expected', function() + expect.nil_(df.coord._fields[2]) + end) + expect.error_match('string expected', function() + expect.nil_(df.coord._fields[nil]) + end) end function test.readonly() @@ -52,13 +59,11 @@ function test.readonly() expect.error_match(READONLY_MSG, function() df.coord._fields.nonexistent = 'foo' end) - -- see TODOs in LuaTypes.cpp - -- expect.error_match(READONLY_MSG, function() - -- df.coord._fields.x.name = 'foo' - -- end) + expect.nil_(df.coord._fields.nonexistent) + -- should have no effect + df.coord._fields.x.name = 'foo' expect.eq(df.coord._fields.x.name, 'x') - expect.nil_(df.coord._fields.nonexistent) end function test.circular_refs_init() From 574fa08747a2809fe41d74f56e999b8684470e98 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 12 Aug 2023 22:12:45 -0400 Subject: [PATCH 324/851] Add index_enum, ref_target --- library/LuaTypes.cpp | 23 +++++++++++++++++------ test/structures/struct_fields.lua | 12 ++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index ac99600a1..407dea265 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -1365,6 +1365,13 @@ static void IndexFields(lua_State *state, int base, struct_identity *pstruct, in } } +static void PushTypeIdentity(lua_State *state, const type_identity *id) +{ + lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPEID_TABLE_TOKEN); + lua_rawgetp(state, -1, id); + lua_remove(state, -2); // TYPEID_TABLE +} + static void PushFieldInfoSubTable(lua_State *state, const struct_field_info *field) { if (!field) { @@ -1384,15 +1391,19 @@ static void PushFieldInfoSubTable(lua_State *state, const struct_field_info *fie lua_pushlightuserdata(state, field->type); lua_setfield(state, -2, "type_identity"); - lua_pushstring(state, "type"); - lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_TYPEID_TABLE_TOKEN); - lua_rawgetp(state, -1, field->type); - lua_remove(state, -2); // TYPEID_TABLE - lua_settable(state, -3); + PushTypeIdentity(state, field->type); + lua_setfield(state, -2, "type"); } if (field->extra) { - // TODO: index_enum, ref_target + if (field->extra->index_enum) { + PushTypeIdentity(state, field->extra->index_enum); + lua_setfield(state, -2, "index_enum"); + } + if (field->extra->ref_target) { + PushTypeIdentity(state, field->extra->ref_target); + lua_setfield(state, -2, "ref_target"); + } if (field->extra->union_tag_field) { Lua::TableInsert(state, "union_tag_field", field->extra->union_tag_field); } diff --git a/test/structures/struct_fields.lua b/test/structures/struct_fields.lua index 53c9ebcc1..d61c71846 100644 --- a/test/structures/struct_fields.lua +++ b/test/structures/struct_fields.lua @@ -52,6 +52,18 @@ function test.nonexistent() end) end +function test.count() + expect.eq(df.unit._fields.relationship_ids.count, 10) +end + +function test.index_enum() + expect.eq(df.unit._fields.relationship_ids.index_enum, df.unit_relationship_type) +end + +function test.ref_target() + expect.eq(df.unit._fields.hist_figure_id.ref_target, df.historical_figure) +end + function test.readonly() expect.error_match(READONLY_MSG, function() df.coord._fields.x = 'foo' From 2a82add030f74c80dc3c45a1703e58c2a06b236c Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 12 Aug 2023 22:39:20 -0400 Subject: [PATCH 325/851] Test for order of subclass fields --- test/structures/struct_fields.lua | 33 +++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/test/structures/struct_fields.lua b/test/structures/struct_fields.lua index d61c71846..01e4175d4 100644 --- a/test/structures/struct_fields.lua +++ b/test/structures/struct_fields.lua @@ -11,6 +11,14 @@ local COORD_FIELD_EXPECTED_DATA = { local READONLY_MSG = 'Attempt to change a read%-only table.' +local function listFieldNames(t) + local names = {} + for name in pairs(t._fields) do + table.insert(names, name) + end + return names +end + function test.access() local fields = df.coord._fields expect.true_(fields) @@ -33,12 +41,7 @@ function test.globals_original_name() end function test.order() - local i = 0 - for name in pairs(df.coord._fields) do - i = i + 1 - expect.eq(name, COORD_FIELD_NAMES[i], i) - end - expect.eq(i, #COORD_FIELD_NAMES) + expect.table_eq(listFieldNames(df.coord), COORD_FIELD_NAMES) end function test.nonexistent() @@ -89,3 +92,21 @@ function test.subclass_match() expect.table_eq(parent, child, f) end end + +function test.subclass_order() + -- ensure that parent class fields come before subclass fields + local hierarchy = {df.item, df.item_actual, df.item_crafted, df.item_constructed, df.item_bedst} + local field_names = {} + for _, t in pairs(hierarchy) do + field_names[t] = listFieldNames(t) + end + for ic = 1, #hierarchy do + for ip = 1, ic - 1 do + local parent_fields = listFieldNames(hierarchy[ip]) + local child_fields = listFieldNames(hierarchy[ic]) + child_fields = table.pack(table.unpack(child_fields, 1, #parent_fields)) + child_fields.n = nil + expect.table_eq(child_fields, parent_fields, ('compare %s to %s'):format(hierarchy[ip], hierarchy[ic])) + end + end +end From 4bc3a9b552614109f88cc80cfd8a241a1d53be55 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 13 Aug 2023 07:36:39 +0300 Subject: [PATCH 326/851] single quotes --- plugins/lua/buildingplan/pens.lua | 6 +++--- plugins/lua/hotkeys.lua | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index 52db6c893..30ce478d8 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -19,17 +19,17 @@ 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 = "hack/data/art/border-thin.png" + local tb = 'hack/data/art/border-thin.png' VERT_TOP_PEN = to_pen { tile = tp(tb, 10), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } VERT_MID_PEN = to_pen { tile = tp(tb, 4), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } VERT_BOT_PEN = to_pen { tile = tp(tb, 11), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } - local mb = "hack/data/art/border-medium.png" + local mb = 'hack/data/art/border-medium.png' HORI_LEFT_PEN = to_pen { tile = tp(mb, 12), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } HORI_MID_PEN = to_pen { tile = tp(mb, 5), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } HORI_RIGHT_PEN = to_pen { tile = tp(mb, 13), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } - local cp = "hack/data/art/control-panel.png" + local cp = 'hack/data/art/control-panel.png' BUTTON_START_PEN = to_pen { tile = tp(cp, 13), ch = '[', fg = COLOR_YELLOW } BUTTON_END_PEN = to_pen { tile = tp(cp, 15), ch = ']', fg = COLOR_YELLOW } SELECTED_ITEM_PEN = to_pen { tile = tp(cp, 9), ch = string.char(251), fg = COLOR_YELLOW } diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index f58d8322a..e2bef331b 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -70,7 +70,7 @@ local dscreen = dfhack.screen function HotspotMenuWidget:onRenderBody(dc) local x, y = dc.x, dc.y local tp = function(offset) - return dfhack.textures.getAsset("hack/data/art/dfhack.png", offset) + return dfhack.textures.getAsset('hack/data/art/dfhack.png', offset) end if tp(0) == -1 then From 20460feccad16c365b5901ed2823e158e4e1467f Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 13 Aug 2023 07:40:35 +0300 Subject: [PATCH 327/851] tiny refactor texpos methods --- library/lua/gui.lua | 3 +-- plugins/lua/buildingplan/pens.lua | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index aaca5b849..d9f826cd1 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -915,8 +915,7 @@ local BASE_FRAME = { local function make_frame(name, double_line) local tp = function(offset) local texpos = dfhack.textures.getAsset('hack/data/art/border-'..name:lower()..'.png', offset) - if texpos == -1 then return nil end - return texpos + return texpos >= 0 and texpos or nil end local frame = copyall(BASE_FRAME) diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index 30ce478d8..7e9b24300 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -11,8 +11,7 @@ local to_pen = dfhack.pen.parse local tp = function(asset, offset) local texpos = dfhack.textures.getAsset(asset, offset) - if texpos == -1 then return nil end - return texpos + return texpos >= 0 and texpos or nil end function reload_pens() From b787c2bb1e857727a98af1edad6aada26bb48fc1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 12 Aug 2023 22:02:17 -0700 Subject: [PATCH 328/851] make creating a workorder a subscreen instead of a top-level --- library/modules/Gui.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index a8941fee7..acd8d0107 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -215,6 +215,8 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) case df::enums::info_interface_mode_type::WORK_ORDERS: if (game->main_interface.info.work_orders.conditions.open) newFocusString += "/Conditions"; + else if (game->main_interface.create_work_order.open) + newFocusString += "/Create"; else newFocusString += "/Default"; break; @@ -481,11 +483,6 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) newFocusString += "/AssignUniform"; focusStrings.push_back(newFocusString); } - if (game->main_interface.create_work_order.open) { - newFocusString = baseFocus; - newFocusString += "/CreateWorkOrder"; - focusStrings.push_back(newFocusString); - } if (game->main_interface.hotkey.open) { newFocusString = baseFocus; newFocusString += "/Hotkey"; From 1c2efcd8cea263c04fd0a1fa5e80e445a0f560c6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 12 Aug 2023 22:04:15 -0700 Subject: [PATCH 329/851] fix test --- test/library/gui.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/test/library/gui.lua b/test/library/gui.lua index 80c91198c..3fc8b889d 100644 --- a/test/library/gui.lua +++ b/test/library/gui.lua @@ -18,6 +18,7 @@ function test.clear_pen() bg = COLOR_BLACK, bold = false, tile_color = false, + write_to_lower = true, }) end From 35b0765f58e83051a3e39e1735ecc38ec692054a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 12 Aug 2023 22:06:52 -0700 Subject: [PATCH 330/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 749b00c93..6db94a14c 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -61,6 +61,7 @@ Template for new versions: ## Fixes - Core: properly reload scripts in mods when a world is unloaded and immediately loaded again - Core: fix text getting added to DFHack text entry widgets when Alt- or Ctrl- keys are hit +- `orders`: prevent import/export overlay from appearing on the create workorder screen ## Misc Improvements - Surround DFHack-specific UI elements with square brackets instead of red-yellow blocks for better readability From b039f227c336b8fee9295a3f2eb5e599e99cca7e Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 13 Aug 2023 01:16:25 -0400 Subject: [PATCH 331/851] Document type._fields --- docs/dev/Lua API.rst | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index be0062696..08b20e1b3 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -306,7 +306,32 @@ All types and the global object have the following features: * ``type._identity`` Contains a lightuserdata pointing to the underlying - ``DFHack::type_instance`` object. + ``DFHack::type_identity`` object. + +All compound types (structs, classes, unions, and the global object) support: + +* ``type._fields`` + + Contains a table mapping field names to descriptions of the type's fields, + including data members and functions. Iterating with ``pairs()`` returns data + fields in the order they are defined in the type. Functions and globals may + appear in an arbitrary order. + + Each entry contains the following fields: + + * ``name``: the name of the field (matches the ``_fields`` table key) + * ``offset``: for data members, the position of the field relative to the start of the type, in bytes + * ``count``: for arrays, the number of elements + * ``mode``: implementation detail. See ``struct_field_info::Mode`` in ``DataDefs.h``. + + Each entry may also contain the following fields, depending on its type: + + * ``type_name``: present for most fields; a string representation of the field's type + * ``type``: the type object matching the field's type; present if such an object exists + (e.g. present for DF types, absent for primitive types) + * ``type_identity``: present for most fields; a lightuserdata pointing to the field's underlying ``DFHack::type_identity`` object + * ``index_enum``, ``ref_target``: the type object corresponding to the field's similarly-named XML attribute, if present + * ``union_tag_field``, ``union_tag_attr``, ``original_name``: the string value of the field's similarly-named XML attribute, if present Types excluding the global object also support: From 22b0671038e60b1180649aadceb1e4a4b70868f5 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 13 Aug 2023 08:33:31 +0300 Subject: [PATCH 332/851] review 2 --- library/Core.cpp | 2 -- library/include/modules/Textures.h | 12 ++++--- library/modules/Textures.cpp | 55 ++++++++++++++++-------------- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 4950e848d..7576f892b 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -2217,8 +2217,6 @@ void Core::onStateChange(color_ostream &out, state_change_event event) } } break; - case SC_VIEWSCREEN_CHANGED: - break; default: break; } diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 4d20302cc..9166e7607 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -6,9 +6,9 @@ #include "ColorText.h" #include "Export.h" -#include +struct SDL_Surface; -typedef void* TexposHandle; +typedef SDL_Surface* TexposHandle; namespace DFHack { @@ -19,6 +19,9 @@ namespace DFHack { */ namespace Textures { +const uint32_t TILE_WIDTH_PX = 8; +const uint32_t TILE_HEIGHT_PX = 12; + /** * Load texture and get handle. * Keep it to obtain valid texpos. @@ -29,8 +32,9 @@ DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); * Load tileset from image file. * Return vector of handles to obtain valid texposes. */ -DFHACK_EXPORT std::vector loadTileset(const std::string& file, int tile_px_w, - int tile_px_h); +DFHACK_EXPORT std::vector loadTileset(const std::string& file, + int tile_px_w = TILE_WIDTH_PX, + int tile_px_h = TILE_HEIGHT_PX); /** * Get texpos by handle. diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 4df928684..0eb4e442d 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -16,30 +16,38 @@ #include "df/viewscreen_new_arenast.h" #include "df/viewscreen_new_regionst.h" +#include + using df::global::enabler; using namespace DFHack; using namespace DFHack::DFSDL; namespace DFHack { - DBG_DECLARE(core, textures, DebugCategory::LINFO); +DBG_DECLARE(core, textures, DebugCategory::LINFO); } static std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_surface; static std::mutex g_adding_mutex; -const uint32_t TILE_WIDTH_PX = 8; -const uint32_t TILE_HEIGHT_PX = 12; - static std::vector empty{}; -static std::unordered_map> g_static_assets{ - {"hack/data/art/dfhack.png", empty}, {"hack/data/art/green-pin.png", empty}, - {"hack/data/art/red-pin.png", empty}, {"hack/data/art/icons.png", empty}, - {"hack/data/art/on-off.png", empty}, {"hack/data/art/pathable.png", empty}, - {"hack/data/art/unsuspend.png", empty}, {"hack/data/art/control-panel.png", empty}, - {"hack/data/art/border-thin.png", empty}, {"hack/data/art/border-medium.png", empty}, - {"hack/data/art/border-bold.png", empty}, {"hack/data/art/border-panel.png", empty}, - {"hack/data/art/border-window.png", empty}}; +// handle, tile width px, tile height px +static std::tuple, int, int> basic{empty, Textures::TILE_WIDTH_PX, + Textures::TILE_HEIGHT_PX}; +static std::unordered_map, int, int>> + g_static_assets{{"hack/data/art/dfhack.png", basic}, + {"hack/data/art/green-pin.png", basic}, + {"hack/data/art/red-pin.png", basic}, + {"hack/data/art/icons.png", basic}, + {"hack/data/art/on-off.png", basic}, + {"hack/data/art/pathable.png", std::make_tuple(empty, 32, 32)}, + {"hack/data/art/unsuspend.png", std::make_tuple(empty, 32, 32)}, + {"hack/data/art/control-panel.png", basic}, + {"hack/data/art/border-thin.png", basic}, + {"hack/data/art/border-medium.png", basic}, + {"hack/data/art/border-bold.png", basic}, + {"hack/data/art/border-panel.png", basic}, + {"hack/data/art/border-window.png", basic}}; // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set @@ -97,7 +105,7 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { if (!surface) return 0; // should be some error, i guess - auto handle = reinterpret_cast(surface); // not the best way? but cheap + auto handle = surface; g_handle_to_surface.emplace(handle, surface); surface->refcount++; // prevent destruct on next FreeSurface by game auto texpos = add_texture(surface); @@ -105,9 +113,8 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { return handle; } -std::vector Textures::loadTileset(const std::string& file, - int tile_px_w = TILE_WIDTH_PX, - int tile_px_h = TILE_HEIGHT_PX) { +std::vector Textures::loadTileset(const std::string& file, int tile_px_w, + int tile_px_h) { std::vector handles{}; SDL_Surface* surface = DFIMG_Load(file.c_str()); @@ -157,9 +164,10 @@ long Textures::getTexposByHandle(TexposHandle handle) { long Textures::getAsset(const std::string asset, size_t index) { if (!g_static_assets.contains(asset)) return -1; - if (g_static_assets[asset].size() <= index) + auto handles = std::get<0>(g_static_assets[asset]); + if (handles.size() <= index) return -1; - return Textures::getTexposByHandle(g_static_assets[asset][index]); + return Textures::getTexposByHandle(handles[index]); } static void reset_texpos() { @@ -264,13 +272,10 @@ void Textures::init(color_ostream& out) { DEBUG(textures, out).print("dynamic texture loading ready"); for (auto& [key, value] : g_static_assets) { - auto tile_w = TILE_WIDTH_PX; - auto tile_h = TILE_HEIGHT_PX; - if (key == "hack/data/art/pathable.png" || key == "hack/data/art/unsuspend.png") { - tile_w = 32; - tile_h = 32; - } - g_static_assets[key] = Textures::loadTileset(key, tile_w, tile_h); + auto tile_w = std::get<1>(value); + auto tile_h = std::get<2>(value); + g_static_assets[key] = + std::make_tuple(Textures::loadTileset(key, tile_w, tile_h), tile_w, tile_h); } DEBUG(textures, out).print("assets loaded"); From 93ed45d6e73efd5fa83a803ba868c8f80fc77231 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 12 Aug 2023 23:29:45 -0700 Subject: [PATCH 333/851] handle small pets, similar to vermin --- plugins/lua/zone.lua | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 4637f1b3f..b30ba3a5c 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -466,7 +466,7 @@ local function get_unit_disposition(unit) return disposition.value end -local function get_vermin_disposition(vermin) +local function get_item_disposition(item) -- TODO return DISPOSITION.TAME.value end @@ -479,8 +479,8 @@ local function is_assignable_unit(unit) not dfhack.units.isForest(unit) end -local function is_assignable_vermin(vermin) - -- TODO are there unassignable vermin? +local function is_assignable_item(item) + -- TODO are there unassignable vermin/small pets? return true end @@ -489,6 +489,11 @@ local function get_vermin_desc(vermin, raw) return ('%s [%d]'):format(raw.name[1], vermin.stack_size) end +local function get_small_pet_desc(raw) + if not raw then return 'Unknown small pet' end + return ('tame %s'):format(raw.name[0]) +end + function AssignAnimal:cache_choices() if self.choices then return self.choices end @@ -516,7 +521,7 @@ function AssignAnimal:cache_choices() ::continue:: end for _, vermin in ipairs(df.global.world.items.other.VERMIN) do - if not is_assignable_vermin(vermin) then goto continue end + if not is_assignable_item(vermin) then goto continue end local raw = df.creature_raw.find(vermin.race) local data = { vermin=vermin, @@ -524,7 +529,26 @@ function AssignAnimal:cache_choices() gender=df.pronoun_type.it, race=raw and raw.creature_id or -1, status=self.get_status(vermin, bld_assignments), - disposition=get_vermin_disposition(vermin), + disposition=get_item_disposition(vermin), + } + local choice = { + search_key=make_search_key(data.desc), + data=data, + text=self:make_choice_text(data), + } + table.insert(choices, choice) + ::continue:: + end + for _, small_pet in ipairs(df.global.world.items.other.PET) do + if not is_assignable_item(small_pet) then goto continue end + local raw = df.creature_raw.find(small_pet.race) + local data = { + vermin=small_pet, + desc=get_small_pet_desc(raw), + gender=df.pronoun_type.it, + race=raw and raw.creature_id or -1, + status=self.get_status(small_pet, bld_assignments), + disposition=get_item_disposition(small_pet), } local choice = { search_key=make_search_key(data.desc), From 296a34834c986290ff9ba435e9bf48f15821de82 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 13 Aug 2023 00:20:08 -0700 Subject: [PATCH 334/851] expose and use casteFlagSet --- docs/dev/Lua API.rst | 5 +++++ library/LuaApi.cpp | 1 + plugins/lua/zone.lua | 23 ++++++++++++++++++----- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 08b20e1b3..f29df78c6 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1525,6 +1525,11 @@ Units module Computes the effective attribute value, including curse effect. +* ``dfhack.units.casteFlagSet(race, caste, flag)`` + + Returns whether the given ``df.caste_raw_flags`` flag is set for the given + race and caste. + * ``dfhack.units.getMiscTrait(unit, type[, create])`` Finds (or creates if requested) a misc trait object with the given id. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 9dc86b526..beaf50579 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1816,6 +1816,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, getNemesis), WRAPM(Units, getPhysicalAttrValue), WRAPM(Units, getMentalAttrValue), + WRAPM(Units, casteFlagSet), WRAPM(Units, getMiscTrait), WRAPM(Units, getAge), WRAPM(Units, getKillCount), diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index b30ba3a5c..29859e419 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -450,7 +450,9 @@ end local function get_unit_disposition(unit) local disposition = DISPOSITION.NONE - if dfhack.units.isPet(unit) then + if dfhack.units.isInvader(unit) or dfhack.units.isOpposedToLife(unit) then + disposition = DISPOSITION.HOSTILE + elseif dfhack.units.isPet(unit) then disposition = DISPOSITION.PET elseif dfhack.units.isDomesticated(unit) then disposition = DISPOSITION.TAME @@ -458,8 +460,6 @@ local function get_unit_disposition(unit) disposition = DISPOSITION.TRAINED elseif dfhack.units.isTamable(unit) then disposition = DISPOSITION.WILD_TRAINABLE - elseif dfhack.units.isInvader(unit) or dfhack.units.isOpposedToLife(unit) then - disposition = DISPOSITION.HOSTILE else disposition = DISPOSITION.WILD_UNTRAINABLE end @@ -467,8 +467,21 @@ local function get_unit_disposition(unit) end local function get_item_disposition(item) - -- TODO - return DISPOSITION.TAME.value + local disposition = DISPOSITION.NONE + if dfhack.units.casteFlagSet(item.race, item.caste, df.caste_raw_flags.OPPOSED_TO_LIFE) then + disposition = DISPOSITION.HOSTILE + -- elseif dfhack.units.isPet(unit) then + -- disposition = DISPOSITION.PET + -- elseif dfhack.units.isDomesticated(unit) then + -- disposition = DISPOSITION.TAME + elseif dfhack.units.casteFlagSet(item.race, item.caste, df.caste_raw_flags.PET) or + dfhack.units.casteFlagSet(item.race, item.caste, df.caste_raw_flags.PET_EXOTIC) + then + disposition = DISPOSITION.WILD_TRAINABLE + else + disposition = DISPOSITION.WILD_UNTRAINABLE + end + return disposition.value end local function is_assignable_unit(unit) From 463a8647e6c5fcf7d13f9dd39e1a9b252a249205 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 13 Aug 2023 02:45:04 -0700 Subject: [PATCH 335/851] complete vermin and small animal support --- plugins/lua/zone.lua | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 29859e419..ef28a91b3 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -467,21 +467,23 @@ local function get_unit_disposition(unit) end local function get_item_disposition(item) - local disposition = DISPOSITION.NONE if dfhack.units.casteFlagSet(item.race, item.caste, df.caste_raw_flags.OPPOSED_TO_LIFE) then - disposition = DISPOSITION.HOSTILE - -- elseif dfhack.units.isPet(unit) then - -- disposition = DISPOSITION.PET - -- elseif dfhack.units.isDomesticated(unit) then - -- disposition = DISPOSITION.TAME - elseif dfhack.units.casteFlagSet(item.race, item.caste, df.caste_raw_flags.PET) or + return DISPOSITION.HOSTILE.value + end + + if df.item_petst:is_instance(item) then + if item.owner_id > -1 then + return DISPOSITION.PET.value + end + return DISPOSITION.TAME.value + end + + if dfhack.units.casteFlagSet(item.race, item.caste, df.caste_raw_flags.PET) or dfhack.units.casteFlagSet(item.race, item.caste, df.caste_raw_flags.PET_EXOTIC) then - disposition = DISPOSITION.WILD_TRAINABLE - else - disposition = DISPOSITION.WILD_UNTRAINABLE + return DISPOSITION.WILD_TRAINABLE.value end - return disposition.value + return DISPOSITION.WILD_UNTRAINABLE.value end local function is_assignable_unit(unit) @@ -493,13 +495,16 @@ local function is_assignable_unit(unit) end local function is_assignable_item(item) - -- TODO are there unassignable vermin/small pets? + -- all vermin/small pets are assignable return true end local function get_vermin_desc(vermin, raw) if not raw then return 'Unknown vermin' end - return ('%s [%d]'):format(raw.name[1], vermin.stack_size) + if vermin.stack_size > 1 then + return ('%s [%d]'):format(raw.name[1], vermin.stack_size) + end + return ('%s'):format(raw.name[0]) end local function get_small_pet_desc(raw) @@ -519,7 +524,7 @@ function AssignAnimal:cache_choices() unit=unit, desc=dfhack.units.getReadableName(unit), gender=unit.sex, - race=raw and raw.creature_id or -1, + race=raw and raw.creature_id or '', status=self.get_status(unit, bld_assignments), disposition=get_unit_disposition(unit), egg=dfhack.units.isEggLayerRace(unit), @@ -540,7 +545,7 @@ function AssignAnimal:cache_choices() vermin=vermin, desc=get_vermin_desc(vermin, raw), gender=df.pronoun_type.it, - race=raw and raw.creature_id or -1, + race=raw and raw.creature_id or '', status=self.get_status(vermin, bld_assignments), disposition=get_item_disposition(vermin), } @@ -559,7 +564,7 @@ function AssignAnimal:cache_choices() vermin=small_pet, desc=get_small_pet_desc(raw), gender=df.pronoun_type.it, - race=raw and raw.creature_id or -1, + race=raw and raw.creature_id or '', status=self.get_status(small_pet, bld_assignments), disposition=get_item_disposition(small_pet), } From 1409af67de7cc818ae3c29def1c3d813f3c7ce1a Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 13 Aug 2023 20:09:12 +0300 Subject: [PATCH 336/851] expose api to lua --- library/LuaApi.cpp | 18 +++++++++++++++- library/include/modules/Textures.h | 2 +- library/modules/Textures.cpp | 7 +++---- plugins/lua/hotkeys.lua | 33 +++++++++++++++--------------- 4 files changed, 38 insertions(+), 22 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 61a7eb83d..095d432ee 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1709,8 +1709,24 @@ static const luaL_Reg dfhack_job_funcs[] = { /***** Textures module *****/ +static int textures_loadTileset(lua_State *state) +{ + std::string file = luaL_checkstring(state, 1); + auto tile_w = luaL_checkint(state, 2); + auto tile_h = luaL_checkint(state, 3); + auto handles = Textures::loadTileset(file, tile_w, tile_h); + Lua::PushVector(state, handles); + return 1; +} + static const LuaWrapper::FunctionReg dfhack_textures_module[] = { WRAPM(Textures, getAsset), + WRAPM(Textures, getTexposByHandle), + { NULL, NULL } +}; + +static const luaL_Reg dfhack_textures_funcs[] = { + { "loadTileset", textures_loadTileset }, { NULL, NULL } }; @@ -3680,7 +3696,7 @@ void OpenDFHackApi(lua_State *state) luaL_setfuncs(state, dfhack_funcs, 0); OpenModule(state, "gui", dfhack_gui_module, dfhack_gui_funcs); OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs); - OpenModule(state, "textures", dfhack_textures_module); + OpenModule(state, "textures", dfhack_textures_module, dfhack_textures_funcs); OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs); OpenModule(state, "military", dfhack_military_module); OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs); diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 9166e7607..d8a256b2b 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -8,7 +8,7 @@ struct SDL_Surface; -typedef SDL_Surface* TexposHandle; +typedef uintptr_t TexposHandle; namespace DFHack { diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 0eb4e442d..10ccbf59d 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -35,8 +35,7 @@ static std::vector empty{}; static std::tuple, int, int> basic{empty, Textures::TILE_WIDTH_PX, Textures::TILE_HEIGHT_PX}; static std::unordered_map, int, int>> - g_static_assets{{"hack/data/art/dfhack.png", basic}, - {"hack/data/art/green-pin.png", basic}, + g_static_assets{{"hack/data/art/green-pin.png", basic}, {"hack/data/art/red-pin.png", basic}, {"hack/data/art/icons.png", basic}, {"hack/data/art/on-off.png", basic}, @@ -105,7 +104,7 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { if (!surface) return 0; // should be some error, i guess - auto handle = surface; + auto handle = reinterpret_cast(surface); g_handle_to_surface.emplace(handle, surface); surface->refcount++; // prevent destruct on next FreeSurface by game auto texpos = add_texture(surface); @@ -139,7 +138,7 @@ std::vector Textures::loadTileset(const std::string& file, int til } DFSDL_FreeSurface(surface); - DEBUG(textures).print("loaded %ld textures from '%s'\n", handles.size(), file.c_str()); + DEBUG(textures).print("loaded %i textures from '%s'\n", handles.size(), file.c_str()); return handles; } diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index e2bef331b..ce4342ea0 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -50,6 +50,7 @@ HotspotMenuWidget.ATTRS{ function HotspotMenuWidget:init() self.mouseover = false + self.textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) end function HotspotMenuWidget:overlay_onupdate() @@ -70,28 +71,28 @@ local dscreen = dfhack.screen function HotspotMenuWidget:onRenderBody(dc) local x, y = dc.x, dc.y local tp = function(offset) - return dfhack.textures.getAsset('hack/data/art/dfhack.png', offset) + return dfhack.textures.getTexposByHandle(self.textures[offset]) end - if tp(0) == -1 then + if tp(1) == -1 then dscreen.paintString(COLOR_WHITE, x, y + 0, '!DF!') dscreen.paintString(COLOR_WHITE, x, y + 1, '!Ha!') dscreen.paintString(COLOR_WHITE, x, y + 2, '!ck!') else - dscreen.paintTile(COLOR_WHITE, x + 0, y + 0, '!', tp(0)) - dscreen.paintTile(COLOR_WHITE, x + 1, y + 0, 'D', tp(1)) - dscreen.paintTile(COLOR_WHITE, x + 2, y + 0, 'F', tp(2)) - dscreen.paintTile(COLOR_WHITE, x + 3, y + 0, '!', tp(3)) - - dscreen.paintTile(COLOR_WHITE, x + 0, y + 1, '!', tp(4)) - dscreen.paintTile(COLOR_WHITE, x + 1, y + 1, 'H', tp(5)) - dscreen.paintTile(COLOR_WHITE, x + 2, y + 1, 'a', tp(6)) - dscreen.paintTile(COLOR_WHITE, x + 3, y + 1, '!', tp(7)) - - dscreen.paintTile(COLOR_WHITE, x + 0, y + 2, '!', tp(8)) - dscreen.paintTile(COLOR_WHITE, x + 1, y + 2, 'c', tp(9)) - dscreen.paintTile(COLOR_WHITE, x + 2, y + 2, 'k', tp(10)) - dscreen.paintTile(COLOR_WHITE, x + 3, y + 2, '!', tp(11)) + dscreen.paintTile(COLOR_WHITE, x + 0, y + 0, '!', tp(1)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 0, 'D', tp(2)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 0, 'F', tp(3)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 0, '!', tp(4)) + + dscreen.paintTile(COLOR_WHITE, x + 0, y + 1, '!', tp(5)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 1, 'H', tp(6)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 1, 'a', tp(7)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 1, '!', tp(8)) + + dscreen.paintTile(COLOR_WHITE, x + 0, y + 2, '!', tp(9)) + dscreen.paintTile(COLOR_WHITE, x + 1, y + 2, 'c', tp(10)) + dscreen.paintTile(COLOR_WHITE, x + 2, y + 2, 'k', tp(11)) + dscreen.paintTile(COLOR_WHITE, x + 3, y + 2, '!', tp(12)) end end From 91f4c3d561593f72839a7c63898929c06ded4f12 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 14 Aug 2023 08:17:57 +0300 Subject: [PATCH 337/851] mirgate preloaded assets to lua --- library/LuaApi.cpp | 1 - library/include/modules/Textures.h | 5 -- library/lua/gui.lua | 117 +++++++++++++++++------------ library/modules/Textures.cpp | 36 --------- plugins/lua/buildingplan/pens.lua | 28 +++---- plugins/lua/hotkeys.lua | 5 +- plugins/pathable.cpp | 7 +- 7 files changed, 89 insertions(+), 110 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 095d432ee..d61786feb 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1720,7 +1720,6 @@ static int textures_loadTileset(lua_State *state) } static const LuaWrapper::FunctionReg dfhack_textures_module[] = { - WRAPM(Textures, getAsset), WRAPM(Textures, getTexposByHandle), { NULL, NULL } }; diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index d8a256b2b..17cd6e2fc 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -43,11 +43,6 @@ DFHACK_EXPORT std::vector loadTileset(const std::string& file, */ DFHACK_EXPORT long getTexposByHandle(TexposHandle handle); -/** - * Get texpos for static asset with index in tileset. - */ -DFHACK_EXPORT long getAsset(const std::string asset, size_t index = 0); - /** * Call this on DFHack init just once to setup interposed handlers and * init static assets. diff --git a/library/lua/gui.lua b/library/lua/gui.lua index d9f826cd1..0176c998e 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -912,32 +912,77 @@ local BASE_FRAME = { paused_pen = to_pen{fg=COLOR_RED, bg=COLOR_BLACK}, } -local function make_frame(name, double_line) - local tp = function(offset) - local texpos = dfhack.textures.getAsset('hack/data/art/border-'..name:lower()..'.png', offset) - return texpos >= 0 and texpos or nil - end +local texpos_handles = { + green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), + red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12), + icons = dfhack.textures.loadTileset('hack/data/art/icons.png', 8, 12), + on_off = dfhack.textures.loadTileset('hack/data/art/on-off.png', 8, 12), + control_panel = dfhack.textures.loadTileset('hack/data/art/control-panel.png', 8, 12), + border_thin = dfhack.textures.loadTileset('hack/data/art/border-thin.png', 8, 12), + border_medium = dfhack.textures.loadTileset('hack/data/art/border-medium.png', 8, 12), + border_bold = dfhack.textures.loadTileset('hack/data/art/border-bold.png', 8, 12), + border_panel = dfhack.textures.loadTileset('hack/data/art/border-panel.png', 8, 12), + border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), +} +function tp_border_thin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_thin[offset]) +end +function tp_border_medium(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_medium[offset]) +end +function tp_border_bold(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_bold[offset]) +end +function tp_border_panel(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_panel[offset]) +end +function tp_border_window(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_window[offset]) +end +function tp_control_panel(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.control_panel[offset]) +end + +local function make_frame(tp, double_line) local frame = copyall(BASE_FRAME) - frame.t_frame_pen = to_pen{ tile=tp(1), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.l_frame_pen = to_pen{ tile=tp(7), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.b_frame_pen = to_pen{ tile=tp(15), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.r_frame_pen = to_pen{ tile=tp(9), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.lt_frame_pen = to_pen{ tile=tp(0), ch=double_line and 201 or 218, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.lb_frame_pen = to_pen{ tile=tp(14), ch=double_line and 200 or 192, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.rt_frame_pen = to_pen{ tile=tp(2), ch=double_line and 187 or 191, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.rb_frame_pen = to_pen{ tile=tp(16), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.t_frame_pen = to_pen{ tile=tp(2), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.l_frame_pen = to_pen{ tile=tp(8), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.b_frame_pen = to_pen{ tile=tp(16), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.r_frame_pen = to_pen{ tile=tp(10), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.lt_frame_pen = to_pen{ tile=tp(1), ch=double_line and 201 or 218, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.lb_frame_pen = to_pen{ tile=tp(15), ch=double_line and 200 or 192, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rt_frame_pen = to_pen{ tile=tp(3), ch=double_line and 187 or 191, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rb_frame_pen = to_pen{ tile=tp(17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } return frame end -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 +function FRAME_WINDOW(resizable) + local frame = make_frame(tp_border_window, true) + if not resizable then + frame.rb_frame_pen = to_pen{ tile=tp_border_panel(17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } + end + return frame +end +function FRAME_PANEL(resizable) + return make_frame(tp_border_panel, false) +end +function FRAME_MEDIUM(resizable) + return make_frame(tp_border_medium, false) +end +function FRAME_BOLD(resizable) + return make_frame(tp_border_bold, true) +end +function FRAME_INTERIOR(resizable) + local frame = make_frame(tp_border_thin, false) + frame.signature_pen = false + return frame +end +function FRAME_INTERIOR_MEDIUM(resizable) + local frame = make_frame(tp_border_medium, false) + frame.signature_pen = false + return frame +end -- for compatibility with pre-steam code GREY_LINE_FRAME = FRAME_PANEL @@ -950,38 +995,16 @@ BOLD_FRAME = FRAME_BOLD INTERIOR_FRAME = FRAME_INTERIOR INTERIOR_MEDIUM_FRAME = FRAME_INTERIOR_MEDIUM --- for compatibility with dynamic textures -local function choose_frame_style(style) - if style == FRAME_WINDOW or style == WINDOW_FRAME then return make_frame('Window', true) end - if style == FRAME_PANEL or style == GREY_LINE_FRAME or style == PANEL_FRAME then - return make_frame('Panel', true) - end - if style == FRAME_MEDIUM or style == MEDIUM_FRAME then return make_frame('Medium', true) end - if style == FRAME_BOLD then return make_frame('Bold', true) end - if style == FRAME_INTERIOR or style == INTERIOR_FRAME then - local frame = make_frame('Thin', true) - frame.signature_pen = false - return frame - end - if style == FRAME_INTERIOR_MEDIUM or style == INTERIOR_MEDIUM_FRAME then - local frame = make_frame('Medium', true) - frame.signature_pen = false - return frame - end -end - function paint_frame(dc, rect, style, title, inactive, pause_forced, resizable) - style = choose_frame_style(style) + if type(style) == 'function' then + style = style(resizable) + end local pen = style.frame_pen local x1,y1,x2,y2 = dc.x1+rect.x1, dc.y1+rect.y1, dc.x1+rect.x2, dc.y1+rect.y2 dscreen.paintTile(style.lt_frame_pen or pen, x1, y1) 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 == 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.paintTile(style.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) dscreen.fillRect(style.b_frame_pen or style.h_frame_pen or pen,x1+1,y2,x2-1,y2) dscreen.fillRect(style.l_frame_pen or style.v_frame_pen or pen,x1,y1+1,x1,y2-1) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 10ccbf59d..729bf0cae 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -30,24 +30,6 @@ static std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_surface; static std::mutex g_adding_mutex; -static std::vector empty{}; -// handle, tile width px, tile height px -static std::tuple, int, int> basic{empty, Textures::TILE_WIDTH_PX, - Textures::TILE_HEIGHT_PX}; -static std::unordered_map, int, int>> - g_static_assets{{"hack/data/art/green-pin.png", basic}, - {"hack/data/art/red-pin.png", basic}, - {"hack/data/art/icons.png", basic}, - {"hack/data/art/on-off.png", basic}, - {"hack/data/art/pathable.png", std::make_tuple(empty, 32, 32)}, - {"hack/data/art/unsuspend.png", std::make_tuple(empty, 32, 32)}, - {"hack/data/art/control-panel.png", basic}, - {"hack/data/art/border-thin.png", basic}, - {"hack/data/art/border-medium.png", basic}, - {"hack/data/art/border-bold.png", basic}, - {"hack/data/art/border-panel.png", basic}, - {"hack/data/art/border-window.png", basic}}; - // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -160,15 +142,6 @@ long Textures::getTexposByHandle(TexposHandle handle) { return -1; } -long Textures::getAsset(const std::string asset, size_t index) { - if (!g_static_assets.contains(asset)) - return -1; - auto handles = std::get<0>(g_static_assets[asset]); - if (handles.size() <= index) - return -1; - return Textures::getTexposByHandle(handles[index]); -} - static void reset_texpos() { g_handle_to_texpos.clear(); } @@ -269,15 +242,6 @@ static void uninstall_reset_point() { void Textures::init(color_ostream& out) { install_reset_point(); DEBUG(textures, out).print("dynamic texture loading ready"); - - for (auto& [key, value] : g_static_assets) { - auto tile_w = std::get<1>(value); - auto tile_h = std::get<2>(value); - g_static_assets[key] = - std::make_tuple(Textures::loadTileset(key, tile_w, tile_h), tile_w, tile_h); - } - - DEBUG(textures, out).print("assets loaded"); } void Textures::cleanup() { diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index 7e9b24300..d50ee4c75 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -1,5 +1,7 @@ local _ENV = mkmodule('plugins.buildingplan.pens') +local gui = require('gui') + GOOD_TILE_PEN, BAD_TILE_PEN = nil, nil VERT_TOP_PEN, VERT_MID_PEN, VERT_BOT_PEN = nil, nil, nil HORI_LEFT_PEN, HORI_MID_PEN, HORI_RIGHT_PEN = nil, nil, nil @@ -9,29 +11,21 @@ MINI_TEXT_PEN, MINI_TEXT_HPEN, MINI_BUTT_PEN, MINI_BUTT_HPEN = nil, nil, nil, ni local to_pen = dfhack.pen.parse -local tp = function(asset, offset) - local texpos = dfhack.textures.getAsset(asset, offset) - return texpos >= 0 and texpos or nil -end - 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 = 'hack/data/art/border-thin.png' - VERT_TOP_PEN = to_pen { tile = tp(tb, 10), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_MID_PEN = to_pen { tile = tp(tb, 4), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_BOT_PEN = to_pen { tile = tp(tb, 11), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_TOP_PEN = to_pen { tile = gui.tp_border_thin(11), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_MID_PEN = to_pen { tile = gui.tp_border_thin(5), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_BOT_PEN = to_pen { tile = gui.tp_border_thin(12), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } - local mb = 'hack/data/art/border-medium.png' - HORI_LEFT_PEN = to_pen { tile = tp(mb, 12), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_MID_PEN = to_pen { tile = tp(mb, 5), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_RIGHT_PEN = to_pen { tile = tp(mb, 13), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_LEFT_PEN = to_pen { tile = gui.tp_border_medium(13), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_MID_PEN = to_pen { tile = gui.tp_border_medium(6), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_RIGHT_PEN = to_pen { tile = gui.tp_border_medium(14), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } - local cp = 'hack/data/art/control-panel.png' - BUTTON_START_PEN = to_pen { tile = tp(cp, 13), ch = '[', fg = COLOR_YELLOW } - BUTTON_END_PEN = to_pen { tile = tp(cp, 15), ch = ']', fg = COLOR_YELLOW } - SELECTED_ITEM_PEN = to_pen { tile = tp(cp, 9), ch = string.char(251), fg = COLOR_YELLOW } + BUTTON_START_PEN = to_pen { tile = gui.tp_control_panel(14), ch = '[', fg = COLOR_YELLOW } + BUTTON_END_PEN = to_pen { tile = gui.tp_control_panel(16), ch = ']', fg = COLOR_YELLOW } + SELECTED_ITEM_PEN = to_pen { tile = gui.tp_control_panel(10), ch = string.char(251), fg = COLOR_YELLOW } MINI_TEXT_PEN = to_pen{fg=COLOR_BLACK, bg=COLOR_GREY} MINI_TEXT_HPEN = to_pen{fg=COLOR_BLACK, bg=COLOR_WHITE} diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index ce4342ea0..728b8e9df 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -5,6 +5,8 @@ local helpdb = require('helpdb') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') +local textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) + local function get_command(cmdline) local first_word = cmdline:trim():split(' +')[1] if first_word:startswith(':') then first_word = first_word:sub(2) end @@ -50,7 +52,6 @@ HotspotMenuWidget.ATTRS{ function HotspotMenuWidget:init() self.mouseover = false - self.textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) end function HotspotMenuWidget:overlay_onupdate() @@ -71,7 +72,7 @@ local dscreen = dfhack.screen function HotspotMenuWidget:onRenderBody(dc) local x, y = dc.x, dc.y local tp = function(offset) - return dfhack.textures.getTexposByHandle(self.textures[offset]) + return dfhack.textures.getTexposByHandle(textures[offset]) end if tp(1) == -1 then diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index c0c49c470..12a69dd31 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -26,7 +26,10 @@ namespace DFHack { DBG_DECLARE(pathable, log, DebugCategory::LINFO); } +static std::vector textures; + DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { + textures = Textures::loadTileset("hack/data/art/pathable.png", 32, 32); return CR_OK; } @@ -44,10 +47,10 @@ static void paintScreenPathable(df::coord target, bool show_hidden = false) { long pathable_tile_texpos = init->load_bar_texpos[1]; long unpathable_tile_texpos = init->load_bar_texpos[4]; - long on_off_texpos = Textures::getAsset("hack/data/art/pathable.png", 0); + long on_off_texpos = Textures::getTexposByHandle(textures[0]); if (on_off_texpos > 0) { pathable_tile_texpos = on_off_texpos; - unpathable_tile_texpos = Textures::getAsset("hack/data/art/pathable.png", 1); + unpathable_tile_texpos = Textures::getTexposByHandle(textures[1]); } auto dims = Gui::getDwarfmodeViewDims().map(); From 900a2c65ba12a06c9b479748fd8b5d89bbf45a76 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 14 Aug 2023 09:02:37 +0300 Subject: [PATCH 338/851] invalid texpos is nil for lua --- library/LuaApi.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index d61786feb..174bedb56 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1719,13 +1719,25 @@ static int textures_loadTileset(lua_State *state) return 1; } +static int textures_getTexposByHandle(lua_State *state) +{ + auto handle = luaL_checkunsigned(state, 1); + auto texpos = Textures::getTexposByHandle(handle); + if (texpos == -1) { + lua_pushnil(state); + } else { + Lua::Push(state, texpos); + } + return 1; +} + static const LuaWrapper::FunctionReg dfhack_textures_module[] = { - WRAPM(Textures, getTexposByHandle), { NULL, NULL } }; static const luaL_Reg dfhack_textures_funcs[] = { { "loadTileset", textures_loadTileset }, + { "getTexposByHandle", textures_getTexposByHandle }, { NULL, NULL } }; From fa3c2222e610c2711613e8c8fb39b884cf63f89c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 13 Aug 2023 23:54:18 -0700 Subject: [PATCH 339/851] higher granularity for unit viewsheet focus strings --- library/modules/Gui.cpp | 85 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 3 deletions(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index acd8d0107..23e0f5585 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -230,10 +230,89 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) newFocusString = baseFocus; newFocusString += "/ViewSheets"; newFocusString += '/' + enum_item_key(game->main_interface.view_sheets.active_sheet); - if (game->main_interface.view_sheets.active_sheet == df::view_sheet_type::BUILDING) { - auto bld = df::building::find(game->main_interface.view_sheets.viewing_bldid); - if (bld) + switch (game->main_interface.view_sheets.active_sheet) { + case df::view_sheet_type::UNIT: + switch (game->main_interface.view_sheets.active_sub_tab) { + case 0: newFocusString += "/Overview"; break; + case 1: newFocusString += "/Items"; break; + case 2: + newFocusString += "/Health"; + switch (game->main_interface.view_sheets.unit_health_active_tab) { + case 0: newFocusString += "/Status"; break; + case 1: newFocusString += "/Wounds"; break; + case 2: newFocusString += "/Treatment"; break; + case 3: newFocusString += "/History"; break; + case 4: newFocusString += "/Description"; break; + default: break; + } + break; + case 3: + newFocusString += "/Skills"; + switch (game->main_interface.view_sheets.unit_skill_active_tab) { + case 0: newFocusString += "/Labor"; break; + case 1: newFocusString += "/Combat"; break; + case 2: newFocusString += "/Social"; break; + case 3: newFocusString += "/Other"; break; + case 4: + newFocusString += "/Knowledge"; + if (game->main_interface.view_sheets.skill_description_raw_str.size()) + newFocusString += "/Details"; + else + newFocusString += "/Default"; + break; + default: break; + } + break; + case 4: newFocusString += "/Rooms"; break; + case 5: + newFocusString += "/Labor"; + switch (game->main_interface.view_sheets.unit_labor_active_tab) { + case 0: newFocusString += "/WorkDetails"; break; + case 1: newFocusString += "/Workshops"; break; + case 2: newFocusString += "/Locations"; break; + case 3: newFocusString += "/WorkAnimals"; break; + default: break; + } + break; + case 6: newFocusString += "/Relations"; break; + case 7: newFocusString += "/Groups"; break; + case 8: + newFocusString += "/Military"; + switch (game->main_interface.view_sheets.unit_military_active_tab) { + case 0: newFocusString += "/Squad"; break; + case 1: newFocusString += "/Uniform"; break; + case 2: newFocusString += "/Kills"; break; + default: break; + } + break; + case 9: + newFocusString += "/Thoughts"; + switch (game->main_interface.view_sheets.thoughts_active_tab) { + case 0: newFocusString += "/Recent"; break; + case 1: newFocusString += "/Memories"; break; + default: break; + } + break; + case 10: + newFocusString += "/Personality"; + switch (game->main_interface.view_sheets.personality_active_tab) { + case 0: newFocusString += "/Traits"; break; + case 1: newFocusString += "/Values"; break; + case 2: newFocusString += "/Preferences"; break; + case 3: newFocusString += "/Needs"; break; + default: break; + } + break; + default: + break; + } + break; + case df::view_sheet_type::BUILDING: + if (auto bld = df::building::find(game->main_interface.view_sheets.viewing_bldid)) newFocusString += '/' + enum_item_key(bld->getType()); + break; + default: + break; } focusStrings.push_back(newFocusString); } From 5c06e9f99eb4789b545891d6ecc5e000576410d3 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 14 Aug 2023 07:12:55 +0000 Subject: [PATCH 340/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 5b59f60c3..b291421e1 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 5b59f60c30557ab24d6bc869c4976fdb70c322a5 +Subproject commit b291421e1c9ea0d777ace41c64e5db133c813bdf From 0e725be04639db4f63c6e532fc70403d81f9b7da Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 14 Aug 2023 12:07:27 +0300 Subject: [PATCH 341/851] support closure as tile arg to get texpos --- library/LuaApi.cpp | 22 +++++++++++++++- library/lua/gui.lua | 43 ++++++++++++++++++++++--------- plugins/lua/buildingplan/pens.lua | 18 ++++++------- 3 files changed, 61 insertions(+), 22 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 174bedb56..29d343c17 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -161,6 +161,26 @@ static bool get_int_field(lua_State *L, T *pf, int idx, const char *name, int de return !nil; } +template +static bool get_int_or_closure_field(lua_State *L, T *pf, int idx, const char *name, int defval) +{ + lua_getfield(L, idx, name); + bool nil = lua_isnil(L, -1); + if (nil) { + *pf = T(defval); + } else if (lua_isnumber(L, -1)) { + *pf = T(lua_tointeger(L, -1)); + } else if (lua_isfunction(L, -1)) { + lua_call(L, 0, 1); + *pf = T(lua_tointeger(L, -1)); + lua_pop(L, 1); + } else { + luaL_error(L, "Field %s is not a number or closure function.", name); + } + lua_pop(L, 1); + return !nil; +} + static bool get_char_field(lua_State *L, char *pf, int idx, const char *name, char defval) { lua_getfield(L, idx, name); @@ -207,7 +227,7 @@ static void decode_pen(lua_State *L, Pen &pen, int idx) else pen.bold = lua_toboolean(L, -1); lua_pop(L, 1); - get_int_field(L, &pen.tile, idx, "tile", 0); + get_int_or_closure_field(L, &pen.tile, idx, "tile", 0); bool tcolor = get_int_field(L, &pen.tile_fg, idx, "tile_fg", 7); tcolor = get_int_field(L, &pen.tile_bg, idx, "tile_bg", 0) || tcolor; diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 0176c998e..8c61da6fd 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -912,6 +912,11 @@ local BASE_FRAME = { paused_pen = to_pen{fg=COLOR_RED, bg=COLOR_BLACK}, } +-- DFHack textures +-------------------------- + +-- Preloaded DFHack Asset +-- Use this handles if you need to get dfhack standard textures local texpos_handles = { green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12), @@ -925,6 +930,22 @@ local texpos_handles = { border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), } +-- Mathods to obtain valid texposes by handles +function tp_green_pin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.green_pin[offset]) +end +function tp_red_pin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.red_pin[offset]) +end +function tp_icons(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.icons[offset]) +end +function tp_on_off(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.on_off[offset]) +end +function tp_control_panel(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.control_panel[offset]) +end function tp_border_thin(offset) return dfhack.textures.getTexposByHandle(texpos_handles.border_thin[offset]) end @@ -940,27 +961,25 @@ end function tp_border_window(offset) return dfhack.textures.getTexposByHandle(texpos_handles.border_window[offset]) end -function tp_control_panel(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.control_panel[offset]) -end + local function make_frame(tp, double_line) local frame = copyall(BASE_FRAME) - frame.t_frame_pen = to_pen{ tile=tp(2), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.l_frame_pen = to_pen{ tile=tp(8), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.b_frame_pen = to_pen{ tile=tp(16), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.r_frame_pen = to_pen{ tile=tp(10), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.lt_frame_pen = to_pen{ tile=tp(1), ch=double_line and 201 or 218, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.lb_frame_pen = to_pen{ tile=tp(15), ch=double_line and 200 or 192, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.rt_frame_pen = to_pen{ tile=tp(3), ch=double_line and 187 or 191, fg=COLOR_GREY, bg=COLOR_BLACK } - frame.rb_frame_pen = to_pen{ tile=tp(17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.t_frame_pen = to_pen{ tile=curry(tp, 2), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.l_frame_pen = to_pen{ tile=curry(tp, 8), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.b_frame_pen = to_pen{ tile=curry(tp, 16), ch=double_line and 205 or 196, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.r_frame_pen = to_pen{ tile=curry(tp, 10), ch=double_line and 186 or 179, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.lt_frame_pen = to_pen{ tile=curry(tp, 1), ch=double_line and 201 or 218, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.lb_frame_pen = to_pen{ tile=curry(tp, 15), ch=double_line and 200 or 192, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rt_frame_pen = to_pen{ tile=curry(tp, 3), ch=double_line and 187 or 191, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rb_frame_pen = to_pen{ tile=curry(tp, 17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } return frame end function FRAME_WINDOW(resizable) local frame = make_frame(tp_border_window, true) if not resizable then - frame.rb_frame_pen = to_pen{ tile=tp_border_panel(17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rb_frame_pen = to_pen{ tile=curry(tp_border_panel, 17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } end return frame end diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index d50ee4c75..817070b76 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -15,17 +15,17 @@ 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)} - VERT_TOP_PEN = to_pen { tile = gui.tp_border_thin(11), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_MID_PEN = to_pen { tile = gui.tp_border_thin(5), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_BOT_PEN = to_pen { tile = gui.tp_border_thin(12), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_TOP_PEN = to_pen { tile = curry(gui.tp_border_thin, 11), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_MID_PEN = to_pen { tile = curry(gui.tp_border_thin, 5), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_BOT_PEN = to_pen { tile = curry(gui.tp_border_thin, 12), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_LEFT_PEN = to_pen { tile = gui.tp_border_medium(13), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_MID_PEN = to_pen { tile = gui.tp_border_medium(6), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_RIGHT_PEN = to_pen { tile = gui.tp_border_medium(14), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_LEFT_PEN = to_pen { tile = curry(gui.tp_border_medium, 13), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_MID_PEN = to_pen { tile = curry(gui.tp_border_medium, 6), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_RIGHT_PEN = to_pen { tile = curry(gui.tp_border_medium, 14), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } - BUTTON_START_PEN = to_pen { tile = gui.tp_control_panel(14), ch = '[', fg = COLOR_YELLOW } - BUTTON_END_PEN = to_pen { tile = gui.tp_control_panel(16), ch = ']', fg = COLOR_YELLOW } - SELECTED_ITEM_PEN = to_pen { tile = gui.tp_control_panel(10), ch = string.char(251), fg = COLOR_YELLOW } + BUTTON_START_PEN = to_pen { tile = curry(gui.tp_control_panel, 14), ch = '[', fg = COLOR_YELLOW } + BUTTON_END_PEN = to_pen { tile = curry(gui.tp_control_panel, 16), ch = ']', fg = COLOR_YELLOW } + SELECTED_ITEM_PEN = to_pen { tile = curry(gui.tp_control_panel, 10), ch = string.char(251), fg = COLOR_YELLOW } MINI_TEXT_PEN = to_pen{fg=COLOR_BLACK, bg=COLOR_GREY} MINI_TEXT_HPEN = to_pen{fg=COLOR_BLACK, bg=COLOR_WHITE} From 5cafffaaf6a0d73605bb3501bc7b9d4204d0870d Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 14 Aug 2023 13:04:38 +0300 Subject: [PATCH 342/851] typos --- library/lua/gui.lua | 58 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 8c61da6fd..d94c1373b 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -885,37 +885,10 @@ ZScreenModal.ATTRS{ pass_mouse_clicks = false, } --- Framed screen object --------------------------- - --- Plain grey-colored frame. --- deprecated -GREY_FRAME = { - frame_pen = to_pen{ ch = ' ', fg = COLOR_BLACK, bg = COLOR_GREY }, - title_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_WHITE }, - signature_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, -} - --- The boundary used by the pre-steam DF screens. --- deprecated -BOUNDARY_FRAME = { - frame_pen = to_pen{ ch = 0xDB, fg = COLOR_GREY, bg = COLOR_BLACK }, - title_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, - signature_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, -} - -local BASE_FRAME = { - frame_pen = to_pen{ ch=206, fg=COLOR_GREY, bg=COLOR_BLACK }, - title_pen = to_pen{ fg=COLOR_BLACK, bg=COLOR_GREY }, - inactive_title_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK }, - signature_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK }, - paused_pen = to_pen{fg=COLOR_RED, bg=COLOR_BLACK}, -} - -- DFHack textures -------------------------- --- Preloaded DFHack Asset +-- Preloaded DFHack Assets -- Use this handles if you need to get dfhack standard textures local texpos_handles = { green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), @@ -930,7 +903,7 @@ local texpos_handles = { border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), } --- Mathods to obtain valid texposes by handles +-- Methods to obtain valid texposes by handles function tp_green_pin(offset) return dfhack.textures.getTexposByHandle(texpos_handles.green_pin[offset]) end @@ -962,6 +935,33 @@ function tp_border_window(offset) return dfhack.textures.getTexposByHandle(texpos_handles.border_window[offset]) end +-- Framed screen object +-------------------------- + +-- Plain grey-colored frame. +-- deprecated +GREY_FRAME = { + frame_pen = to_pen{ ch = ' ', fg = COLOR_BLACK, bg = COLOR_GREY }, + title_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_WHITE }, + signature_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, +} + +-- The boundary used by the pre-steam DF screens. +-- deprecated +BOUNDARY_FRAME = { + frame_pen = to_pen{ ch = 0xDB, fg = COLOR_GREY, bg = COLOR_BLACK }, + title_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, + signature_pen = to_pen{ fg = COLOR_BLACK, bg = COLOR_GREY }, +} + +local BASE_FRAME = { + frame_pen = to_pen{ ch=206, fg=COLOR_GREY, bg=COLOR_BLACK }, + title_pen = to_pen{ fg=COLOR_BLACK, bg=COLOR_GREY }, + inactive_title_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK }, + signature_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK }, + paused_pen = to_pen{fg=COLOR_RED, bg=COLOR_BLACK}, +} + local function make_frame(tp, double_line) local frame = copyall(BASE_FRAME) From a521b54da1d0a6bc98063bd17a249218d079442a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 14 Aug 2023 16:38:43 -0700 Subject: [PATCH 343/851] normalize input for animal assignment search --- plugins/lua/zone.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index ef28a91b3..81d1e5cb7 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -392,7 +392,7 @@ end local function make_search_key(desc) local out = '' - for c in desc:gmatch("[%w%s]") do + for c in dfhack.toSearchNormalized(desc):gmatch("[%w%s]") do out = out .. c:lower() end return out From 7a4aaf8bc94ded52a43885a0a6423b07b84f5e06 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 14 Aug 2023 16:39:28 -0700 Subject: [PATCH 344/851] normalize characters in search text and match keys for FilteredLists --- library/lua/gui/widgets.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 36ae358bc..6a0a0091b 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -2191,6 +2191,8 @@ function FilteredList:setFilter(filter, pos) for _,key in ipairs(tokens) do key = key:escape_pattern() if key ~= '' then + search_key = dfhack.toSearchNormalized(search_key) + key = dfhack.toSearchNormalized(key) if not self.case_sensitive then search_key = string.lower(search_key) key = string.lower(key) From c6c7331b1bddc7232942e562686cf33d4ac9671b Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 15 Aug 2023 01:36:20 -0400 Subject: [PATCH 345/851] test.lua: disallow overwriting existing tests i.e. if a function name is accidentally reused - previously, later test functions would silently overwrite earlier ones --- ci/test.lua | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/ci/test.lua b/ci/test.lua index 01168800b..543334e72 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -247,6 +247,25 @@ local function load_test_config(config_file) return config end +local function TestTable() + local inner = utils.OrderedTable() + local meta = copyall(getmetatable(inner)) + + function meta:__newindex(k, v) + if inner[k] then + error('Attempt to overwrite existing test: ' .. k) + elseif type(v) ~= 'function' then + error('Attempt to define test as non-function: ' .. k .. ' = ' .. tostring(v)) + else + inner[k] = v + end + end + + local self = {} + setmetatable(self, meta) + return self +end + -- we have to save and use the original dfhack.printerr here so our test harness -- output doesn't trigger its own dfhack.printerr usage detection (see -- detect_printerr below) @@ -291,7 +310,7 @@ end local function build_test_env(path) local env = { - test = utils.OrderedTable(), + test = TestTable(), -- config values can be overridden in the test file to define -- requirements for the tests in that file config = { From 25038648c0356c6e052adc78f1eb623937adbac6 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Tue, 15 Aug 2023 21:11:06 +0300 Subject: [PATCH 346/851] remove unused variable --- library/LuaApi.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 29d343c17..56052bbd3 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1380,6 +1380,13 @@ static void OpenModule(lua_State *state, const char *mname, lua_pop(state, 1); } +static void OpenModule(lua_State *state, const char *mname, const luaL_Reg *reg2) +{ + luaL_getsubtable(state, lua_gettop(state), mname); + luaL_setfuncs(state, reg2, 0); + lua_pop(state, 1); +} + #define WRAPM(module, function) { #function, df::wrap_function(module::function,true) } #define WRAP(function) { #function, df::wrap_function(function,true) } #define WRAPN(name, function) { #name, df::wrap_function(function,true) } @@ -1751,10 +1758,6 @@ static int textures_getTexposByHandle(lua_State *state) return 1; } -static const LuaWrapper::FunctionReg dfhack_textures_module[] = { - { NULL, NULL } -}; - static const luaL_Reg dfhack_textures_funcs[] = { { "loadTileset", textures_loadTileset }, { "getTexposByHandle", textures_getTexposByHandle }, @@ -3727,7 +3730,7 @@ void OpenDFHackApi(lua_State *state) luaL_setfuncs(state, dfhack_funcs, 0); OpenModule(state, "gui", dfhack_gui_module, dfhack_gui_funcs); OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs); - OpenModule(state, "textures", dfhack_textures_module, dfhack_textures_funcs); + OpenModule(state, "textures", dfhack_textures_funcs); OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs); OpenModule(state, "military", dfhack_military_module); OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs); From bbbb8fbb9c99ef2f22af38bf57e64dd43acca6fc Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Tue, 15 Aug 2023 21:18:52 +0300 Subject: [PATCH 347/851] invalid texpos is nil now --- 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 728b8e9df..422306be0 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -75,7 +75,7 @@ function HotspotMenuWidget:onRenderBody(dc) return dfhack.textures.getTexposByHandle(textures[offset]) end - if tp(1) == -1 then + if tp(1) == nil then dscreen.paintString(COLOR_WHITE, x, y + 0, '!DF!') dscreen.paintString(COLOR_WHITE, x, y + 1, '!Ha!') dscreen.paintString(COLOR_WHITE, x, y + 2, '!ck!') From 8401d5c72a55d38a88fddac3e9f944a4c2120fd3 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 16 Aug 2023 07:12:45 +0000 Subject: [PATCH 348/851] 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 179e7406d..ce5ae6407 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 179e7406d567623ac875024002c620234a64e5aa +Subproject commit ce5ae6407870b35aaec15dfb3f391dbd447eb7f5 From a843364262ed9ad02170f49a14eee0a41a70b138 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 16 Aug 2023 13:06:28 +0000 Subject: [PATCH 349/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index b291421e1..3e1389d29 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit b291421e1c9ea0d777ace41c64e5db133c813bdf +Subproject commit 3e1389d2965af61db53eacd1f292a301484434be From 754464137736627328ba77901f9258bc2561f683 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 14 Aug 2023 16:40:53 -0700 Subject: [PATCH 350/851] first draft of squad assignment search and sort --- plugins/CMakeLists.txt | 2 +- plugins/lua/sort.lua | 502 +++++++++++++++++++++++++++++++++++++++++ plugins/sort.cpp | 100 ++------ 3 files changed, 524 insertions(+), 80 deletions(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index b3b69fb12..b96606284 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -156,7 +156,7 @@ if(BUILD_SUPPORTED) dfhack_plugin(seedwatch seedwatch.cpp LINK_LIBRARIES lua) dfhack_plugin(showmood showmood.cpp) #dfhack_plugin(siege-engine siege-engine.cpp LINK_LIBRARIES lua) - #dfhack_plugin(sort sort.cpp LINK_LIBRARIES lua) + dfhack_plugin(sort sort.cpp LINK_LIBRARIES lua) #dfhack_plugin(steam-engine steam-engine.cpp) #add_subdirectory(spectate) #dfhack_plugin(stockflow stockflow.cpp LINK_LIBRARIES lua) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index acd2eef6a..0500cd3e0 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1,5 +1,506 @@ local _ENV = mkmodule('plugins.sort') +local gui = require('gui') +local overlay = require('plugins.overlay') +local utils = require('utils') +local widgets = require('gui.widgets') + +local CH_UP = string.char(30) +local CH_DN = string.char(31) + +local MELEE_WEAPON_SKILLS = { + df.job_skill.AXE, + df.job_skill.SWORD, + df.job_skill.MACE, + df.job_skill.HAMMER, + df.job_skill.SPEAR, + df.job_skill.MELEE_COMBAT, --Fighter +} + +local RANGED_WEAPON_SKILLS = { + df.job_skill.CROSSBOW, + df.job_skill.RANGED_COMBAT, +} + +local LEADERSHIP_SKILLS = { + df.job_skill.MILITARY_TACTICS, + df.job_skill.LEADERSHIP, + df.job_skill.TEACHING, +} + +local function sort_noop(a, b) + -- this function is used as a marker and never actually gets called + error('sort_noop should not be called') +end + +local function sort_by_name_desc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local name1 = dfhack.TranslateName(dfhack.units.getVisibleName(unit1)) + local name2 = dfhack.TranslateName(dfhack.units.getVisibleName(unit2)) + return utils.compare_name(name1, name2) +end + +local function sort_by_name_asc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local name1 = dfhack.TranslateName(dfhack.units.getVisibleName(unit1)) + local name2 = dfhack.TranslateName(dfhack.units.getVisibleName(unit2)) + return utils.compare_name(name2, name1) +end + +local function sort_by_migrant_wave_desc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + return utils.compare(unit2.id, unit1.id) +end + +local function sort_by_migrant_wave_asc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + return utils.compare(unit1.id, unit2.id) +end + +local function get_skill(unit_id, skill, unit) + unit = unit or df.unit.find(unit_id) + return unit and + unit.status.current_soul and + utils.binsearch(unit.status.current_soul.skills, skill, 'id') +end + +local function get_max_skill(unit_id, list) + local unit = df.unit.find(unit_id) + if not unit or not unit.status.current_soul then return end + local max + for _,skill in ipairs(list) do + local s = get_skill(unit_id, skill, unit) + if s then + if not max then + max = s + else + if max.rating == s.rating and max.experience < s.experience then + max = s + elseif max.rating < s.rating then + max = s + end + end + end + end + return max +end + +local function make_sort_by_skill_list_desc(list) + return function(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + if unit_id_1 == -1 then return -1 end + if unit_id_2 == -1 then return 1 end + local s1 = get_max_skill(unit_id_1, list) + local s2 = get_max_skill(unit_id_2, list) + if s1 == s2 then return sort_by_name_desc(unit_id_1, unit_id_2) end + if not s2 then return -1 end + if not s1 then return 1 end + if s1.rating ~= s2.rating then + return utils.compare(s2.rating, s1.rating) + end + if s1.experience ~= s2.experience then + return utils.compare(s2.experience, s1.experience) + end + return sort_by_name_desc(unit_id_1, unit_id_2) + end +end + +local function make_sort_by_skill_list_asc(list) + return function(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + if unit_id_1 == -1 then return -1 end + if unit_id_2 == -1 then return 1 end + local s1 = get_max_skill(unit_id_1, list) + local s2 = get_max_skill(unit_id_2, list) + if s1 == s2 then return sort_by_name_desc(unit_id_1, unit_id_2) end + if not s2 then return 1 end + if not s1 then return -1 end + if s1.rating ~= s2.rating then + return utils.compare(s1.rating, s2.rating) + end + if s1.experience ~= s2.experience then + return utils.compare(s1.experience, s2.experience) + end + return sort_by_name_desc(unit_id_1, unit_id_2) + end +end + +local function make_sort_by_skill_desc(sort_skill) + return function(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + if unit_id_1 == -1 then return -1 end + if unit_id_2 == -1 then return 1 end + local s1 = get_skill(unit_id_1, sort_skill) + local s2 = get_skill(unit_id_2, sort_skill) + if s1 == s2 then return sort_by_name_desc(unit_id_1, unit_id_2) end + if not s2 then return -1 end + if not s1 then return 1 end + if s1.rating ~= s2.rating then + return utils.compare(s2.rating, s1.rating) + end + if s1.experience ~= s2.experience then + return utils.compare(s2.experience, s1.experience) + end + return sort_by_name_desc(unit_id_1, unit_id_2) + end +end + +local function make_sort_by_skill_asc(sort_skill) + return function(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + if unit_id_1 == -1 then return -1 end + if unit_id_2 == -1 then return 1 end + local s1 = get_skill(unit_id_1, sort_skill) + local s2 = get_skill(unit_id_2, sort_skill) + if s1 == s2 then return sort_by_name_desc(unit_id_1, unit_id_2) end + if not s2 then return 1 end + if not s1 then return -1 end + if s1.rating ~= s2.rating then + return utils.compare(s1.rating, s2.rating) + end + if s1.experience ~= s2.experience then + return utils.compare(s1.experience, s2.experience) + end + return sort_by_name_desc(unit_id_1, unit_id_2) + end +end + +local SORT_FNS = { + sort_by_any_melee_desc=make_sort_by_skill_list_desc(MELEE_WEAPON_SKILLS), + sort_by_any_melee_asc=make_sort_by_skill_list_asc(MELEE_WEAPON_SKILLS), + sort_by_any_ranged_desc=make_sort_by_skill_list_desc(RANGED_WEAPON_SKILLS), + sort_by_any_ranged_asc=make_sort_by_skill_list_asc(RANGED_WEAPON_SKILLS), + sort_by_leadership_desc=make_sort_by_skill_list_desc(LEADERSHIP_SKILLS), + sort_by_leadership_asc=make_sort_by_skill_list_asc(LEADERSHIP_SKILLS), + sort_by_axe_desc=make_sort_by_skill_desc(df.job_skill.AXE), + sort_by_axe_asc=make_sort_by_skill_asc(df.job_skill.AXE), + sort_by_sword_desc=make_sort_by_skill_desc(df.job_skill.SWORD), + sort_by_sword_asc=make_sort_by_skill_asc(df.job_skill.SWORD), + sort_by_mace_desc=make_sort_by_skill_desc(df.job_skill.MACE), + sort_by_mace_asc=make_sort_by_skill_asc(df.job_skill.MACE), + sort_by_hammer_desc=make_sort_by_skill_desc(df.job_skill.HAMMER), + sort_by_hammer_asc=make_sort_by_skill_asc(df.job_skill.HAMMER), + sort_by_spear_desc=make_sort_by_skill_desc(df.job_skill.SPEAR), + sort_by_spear_asc=make_sort_by_skill_asc(df.job_skill.SPEAR), + sort_by_crossbow_desc=make_sort_by_skill_desc(df.job_skill.CROSSBOW), + sort_by_crossbow_asc=make_sort_by_skill_asc(df.job_skill.CROSSBOW), +} + +-- ---------------------- +-- SquadAssignmentOverlay +-- + +SquadAssignmentOverlay = defclass(SquadAssignmentOverlay, overlay.OverlayWidget) +SquadAssignmentOverlay.ATTRS{ + default_pos={x=-33, y=40}, + default_enabled=true, + viewscreens='dwarfmode/UnitSelector/SQUAD_FILL_POSITION', + frame={w=63, h=7}, + frame_style=gui.FRAME_PANEL, + frame_background=gui.CLEAR_PEN, +} + +function SquadAssignmentOverlay:init() + self.dirty = true + + self:addviews{ + widgets.CycleHotkeyLabel{ + view_id='sort', + frame={l=0, t=0, w=29}, + label='Sort by:', + key='CUSTOM_SHIFT_S', + options={ + {label='any melee skill'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc}, + {label='any melee skill'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc}, + {label='any ranged skill'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc}, + {label='any ranged skill'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc}, + {label='any leader skill'..CH_DN, value=SORT_FNS.sort_by_leadership_desc}, + {label='any leader skill'..CH_UP, value=SORT_FNS.sort_by_leadership_asc}, + {label='name'..CH_DN, value=sort_by_name_desc}, + {label='name'..CH_UP, value=sort_by_name_asc}, + {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc}, + {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc}, + {label='axe skill'..CH_DN, value=SORT_FNS.sort_by_axe_desc}, + {label='axe skill'..CH_UP, value=SORT_FNS.sort_by_axe_asc}, + {label='sword skill'..CH_DN, value=SORT_FNS.sort_by_sword_desc}, + {label='sword skill'..CH_UP, value=SORT_FNS.sort_by_sword_asc}, + {label='mace skill'..CH_DN, value=SORT_FNS.sort_by_mace_desc}, + {label='mace skill'..CH_UP, value=SORT_FNS.sort_by_mace_asc}, + {label='hammer skill'..CH_DN, value=SORT_FNS.sort_by_hammer_desc}, + {label='hammer skill'..CH_UP, value=SORT_FNS.sort_by_hammer_asc}, + {label='spear skill'..CH_DN, value=SORT_FNS.sort_by_spear_desc}, + {label='spear skill'..CH_UP, value=SORT_FNS.sort_by_spear_asc}, + {label='crossbow skill'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc}, + {label='crossbow skill'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc}, + }, + initial_option=SORT_FNS.sort_by_any_melee_desc, + on_change=self:callback('refresh_list', 'sort'), + }, + widgets.EditField{ + view_id='search', + frame={l=32, t=0}, + label_text='Search: ', + on_char=function(ch) return ch:match('[%l _-]') end, + on_change=function() self:refresh_list() end, + }, + widgets.Panel{ + frame={t=2, l=0, r=0, b=0}, + subviews={ + widgets.CycleHotkeyLabel{ + view_id='sort_any_melee', + frame={t=0, l=0, w=10}, + options={ + {label='any melee', value=sort_noop}, + {label='any melee'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc}, + {label='any melee'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc}, + }, + initial_option=SORT_FNS.sort_by_any_melee_desc, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_any_melee'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_any_ranged', + frame={t=0, l=13, w=11}, + options={ + {label='any ranged', value=sort_noop}, + {label='any ranged'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc}, + {label='any ranged'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_any_ranged'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_leadership', + frame={t=0, l=27, w=11}, + options={ + {label='leadership', value=sort_noop}, + {label='leadership'..CH_DN, value=SORT_FNS.sort_by_leadership_desc}, + {label='leadership'..CH_UP, value=SORT_FNS.sort_by_leadership_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_leadership'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_name', + frame={t=0, l=41, w=5}, + options={ + {label='name', value=sort_noop}, + {label='name'..CH_DN, value=sort_by_name_desc}, + {label='name'..CH_UP, value=sort_by_name_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_name'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_migrant_wave', + frame={t=0, l=48, w=13}, + options={ + {label='migrant wave', value=sort_noop}, + {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc}, + {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_migrant_wave'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_axe', + frame={t=2, l=0, w=4}, + options={ + {label='axe', value=sort_noop}, + {label='axe'..CH_DN, value=SORT_FNS.sort_by_axe_desc}, + {label='axe'..CH_UP, value=SORT_FNS.sort_by_axe_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_axe'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_sword', + frame={t=2, l=7, w=6}, + options={ + {label='sword', value=sort_noop}, + {label='sword'..CH_DN, value=SORT_FNS.sort_by_sword_desc}, + {label='sword'..CH_UP, value=SORT_FNS.sort_by_sword_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_sword'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_mace', + frame={t=2, l=16, w=5}, + options={ + {label='mace', value=sort_noop}, + {label='mace'..CH_DN, value=SORT_FNS.sort_by_mace_desc}, + {label='mace'..CH_UP, value=SORT_FNS.sort_by_mace_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_mace'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_hammer', + frame={t=2, l=23, w=7}, + options={ + {label='hammer', value=sort_noop}, + {label='hammer'..CH_DN, value=SORT_FNS.sort_by_hammer_desc}, + {label='hammer'..CH_UP, value=SORT_FNS.sort_by_hammer_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_hammer'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_spear', + frame={t=2, l=34, w=6}, + options={ + {label='spear', value=sort_noop}, + {label='spear'..CH_DN, value=SORT_FNS.sort_by_spear_desc}, + {label='spear'..CH_UP, value=SORT_FNS.sort_by_spear_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_spear'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_crossbow', + frame={t=2, l=43, w=9}, + options={ + {label='crossbow', value=sort_noop}, + {label='crossbow'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc}, + {label='crossbow'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_crossbow'), + }, + } + }, + } +end + +local function normalize_search_key(search_key) + local out = '' + for c in dfhack.toSearchNormalized(search_key):gmatch("[%w%s]") do + out = out .. c:lower() + end + return out +end + +local function filter_matches(unit_id, search) + if unit_id == -1 then return true end + local unit = df.unit.find(unit_id) + if not unit then return true end + local search_key = dfhack.TranslateName(dfhack.units.getVisibleName(unit)) + if unit.status.current_soul then + for _,skill in ipairs(unit.status.current_soul.skills) do + search_key = (search_key or '') .. ' ' .. (df.job_skill[skill.id] or '') + end + end + return normalize_search_key(search_key):find(dfhack.toSearchNormalized(search)) +end + +local unit_selector = df.global.game.main_interface.unit_selector + +-- this function uses the unused itemid and selected vectors to keep state, +-- taking advantage of the fact that they are reset by DF when the list of units changes +local function filter_vector(search, prev_search) + local unid_is_filtered = #unit_selector.selected >= 0 and unit_selector.selected[0] ~= 0 + if #search == 0 or #unit_selector.selected == 0 then + if not unid_is_filtered then + -- we haven't modified the unid vector; nothing to do here + return + end + -- restore the unid vector + unit_selector.unid:assign(unit_selector.itemid) + -- clear our "we meddled" flag + unit_selector.selected[0] = 0 + return + end + if unid_is_filtered and search == prev_search then + -- prev filter still stands + return + end + if unid_is_filtered then + -- restore the unid vector + unit_selector.unid:assign(unit_selector.itemid) + else + -- save the unid vector and set our meddle flag + unit_selector.itemid:assign(unit_selector.unid) + unit_selector.selected[0] = 1 + end + -- do the actual filtering + for idx=#unit_selector.unid-1,0,-1 do + if not filter_matches(unit_selector.unid[idx], search) then + unit_selector.unid:erase(idx) + end + end +end + +local SORT_WIDGET_NAMES = { + 'sort', + 'sort_any_melee', + 'sort_any_ranged', + 'sort_leadership', + 'sort_name', + 'sort_migrant_wave', + 'sort_axe', + 'sort_sword', + 'sort_mace', + 'sort_hammer', + 'sort_spear', + 'sort_crossbow', +} + +function SquadAssignmentOverlay:refresh_list(sort_widget, sort_fn) + sort_widget = sort_widget or 'sort' + sort_fn = sort_fn or self.subviews.sort:getOptionValue() + if sort_fn == sort_noop then + self.subviews[sort_widget]:cycle() + return + end + for _,widget_name in ipairs(SORT_WIDGET_NAMES) do + self.subviews[widget_name]:setOption(sort_fn) + end + local search = self.subviews.search.text + filter_vector(search, self.prev_search) + self.prev_search = search + utils.sort_vector(unit_selector.unid, nil, sort_fn) +end + +function SquadAssignmentOverlay:onInput(keys) + if keys._MOUSE_R_DOWN or + keys._MOUSE_L_DOWN and not self:getMouseFramePos() + then + -- if any click is made outside of our window, we may need to refresh our list + self.dirty = true + end + return SquadAssignmentOverlay.super.onInput(self, keys) +end + +function SquadAssignmentOverlay:onRenderFrame(dc, frame_rect) + SquadAssignmentOverlay.super.onRenderFrame(self, dc, frame_rect) + if self.dirty then + self:refresh_list() + self.dirty = false + end +end + +OVERLAY_WIDGETS = { + squad_assignment=SquadAssignmentOverlay, +} + +--[[ local utils = require('utils') local units = require('plugins.sort.units') local items = require('plugins.sort.items') @@ -51,5 +552,6 @@ function parse_ordering_spec(type,...) end make_sort_order = utils.make_sort_order +]] return _ENV diff --git a/plugins/sort.cpp b/plugins/sort.cpp index 62af2c416..453914f5a 100644 --- a/plugins/sort.cpp +++ b/plugins/sort.cpp @@ -1,43 +1,13 @@ -#include "Core.h" -#include "Console.h" -#include "Export.h" #include "PluginManager.h" -#include "modules/Gui.h" -#include "modules/Translation.h" -#include "modules/Units.h" -#include "modules/Job.h" - -#include "LuaTools.h" - -#include "DataDefs.h" -#include "df/plotinfost.h" -#include "df/world.h" -#include "df/viewscreen_joblistst.h" -#include "df/viewscreen_unitlistst.h" -#include "df/viewscreen_layer_militaryst.h" -#include "df/viewscreen_layer_noblelistst.h" -#include "df/viewscreen_layer_overall_healthst.h" -#include "df/viewscreen_layer_assigntradest.h" -#include "df/viewscreen_tradegoodsst.h" -#include "df/viewscreen_dwarfmodest.h" -#include "df/viewscreen_petst.h" -#include "df/viewscreen_storesst.h" -#include "df/viewscreen_workshop_profilest.h" -#include "df/layer_object_listst.h" -#include "df/assign_trade_status.h" - -#include "MiscUtils.h" - -#include - using std::vector; using std::string; -using std::endl; + using namespace DFHack; -using namespace df::enums; DFHACK_PLUGIN("sort"); + +/* REQUIRE_GLOBAL(plotinfo); REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(ui_building_in_assign); @@ -52,16 +22,18 @@ static bool item_list_hotkey(df::viewscreen *top); static command_result sort_units(color_ostream &out, vector & parameters); static command_result sort_items(color_ostream &out, vector & parameters); +*/ -DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) +DFhackCExport command_result plugin_init (color_ostream &out, vector &commands) { - commands.push_back(PluginCommand( - "sort-units", "Sort the visible unit list.", sort_units, unit_list_hotkey)); - commands.push_back(PluginCommand( - "sort-items", "Sort the visible item list.", sort_items, item_list_hotkey)); + // commands.push_back(PluginCommand( + // "sort-units", "Sort the visible unit list.", sort_units, unit_list_hotkey)); + // commands.push_back(PluginCommand( + // "sort-items", "Sort the visible item list.", sort_items, item_list_hotkey)); return CR_OK; } +/* DFhackCExport command_result plugin_shutdown ( color_ostream &out ) { return CR_OK; @@ -232,10 +204,7 @@ typedef void (*SortHandler)(color_ostream *pout, lua_State *L, int top, static std::map unit_sorters; -/* - * Sort units in the 'u'nit list screen. - */ - +// Sort units in the 'u'nit list screen. DEFINE_SORT_HANDLER(unit_sorters, unitlist, "", units) { PARSE_SPEC("units", parameters); @@ -250,10 +219,7 @@ DEFINE_SORT_HANDLER(unit_sorters, unitlist, "", units) } } -/* - * Sort units in the 'j'ob list screen. - */ - +//Sort units in the 'j'ob list screen. DEFINE_SORT_HANDLER(unit_sorters, joblist, "", jobs) { PARSE_SPEC("units", parameters); @@ -275,10 +241,7 @@ DEFINE_SORT_HANDLER(unit_sorters, joblist, "", jobs) } } -/* - * Sort candidate units in the 'p'osition page of the 'm'ilitary screen. - */ - +// Sort candidate units in the 'p'osition page of the 'm'ilitary screen. DEFINE_SORT_HANDLER(unit_sorters, layer_military, "/Positions/Candidates", military) { auto &candidates = military->positions.candidates; @@ -293,7 +256,6 @@ DEFINE_SORT_HANDLER(unit_sorters, layer_military, "/Positions/Candidates", milit } } - DEFINE_SORT_HANDLER(unit_sorters, layer_noblelist, "/Appoint", nobles) { auto list2 = getLayerList(nobles, 1); @@ -312,10 +274,7 @@ DEFINE_SORT_HANDLER(unit_sorters, layer_noblelist, "/Appoint", nobles) } } -/* - * Sort animal units in the Animal page of the 'z' status screen. - */ - +//Sort animal units in the Animal page of the 'z' status screen. DEFINE_SORT_HANDLER(unit_sorters, pet, "/List", animals) { PARSE_SPEC("units", parameters); @@ -334,10 +293,7 @@ DEFINE_SORT_HANDLER(unit_sorters, pet, "/List", animals) } } -/* - * Sort candidate trainers in the Animal page of the 'z' status screen. - */ - +// Sort candidate trainers in the Animal page of the 'z' status screen. DEFINE_SORT_HANDLER(unit_sorters, pet, "/SelectTrainer", animals) { sort_null_first(parameters); @@ -351,10 +307,7 @@ DEFINE_SORT_HANDLER(unit_sorters, pet, "/SelectTrainer", animals) } } -/* - * Sort units in the Health page of the 'z' status screen. - */ - +// Sort units in the Health page of the 'z' status screen. DEFINE_SORT_HANDLER(unit_sorters, layer_overall_health, "/Units", health) { auto list1 = getLayerList(health, 0); @@ -371,10 +324,7 @@ DEFINE_SORT_HANDLER(unit_sorters, layer_overall_health, "/Units", health) } } -/* - * Sort burrow member candidate units in the 'w' sidebar mode. - */ - +// Sort burrow member candidate units in the 'w' sidebar mode. DEFINE_SORT_HANDLER(unit_sorters, dwarfmode, "/Burrows/AddUnits", screen) { PARSE_SPEC("units", parameters); @@ -387,10 +337,7 @@ DEFINE_SORT_HANDLER(unit_sorters, dwarfmode, "/Burrows/AddUnits", screen) } } -/* - * Sort building owner candidate units in the 'q' sidebar mode, or cage assignment. - */ - +// Sort building owner candidate units in the 'q' sidebar mode, or cage assignment. DEFINE_SORT_HANDLER(unit_sorters, dwarfmode, "/QueryBuilding/Some/Assign", screen) { sort_null_first(parameters); @@ -410,10 +357,7 @@ DEFINE_SORT_HANDLER(unit_sorters, dwarfmode, "/QueryBuilding/Some/Assign", scree } } -/* - * Sort units in the workshop 'q'uery 'P'rofile modification screen. - */ - +// Sort units in the workshop 'q'uery 'P'rofile modification screen. DEFINE_SORT_HANDLER(unit_sorters, workshop_profile, "/Unit", profile) { PARSE_SPEC("units", parameters); @@ -425,10 +369,7 @@ DEFINE_SORT_HANDLER(unit_sorters, workshop_profile, "/Unit", profile) } } -/* - * Sort pen assignment candidate units in 'z'->'N'. - */ - +// Sort pen assignment candidate units in 'z'->'N'. DEFINE_SORT_HANDLER(unit_sorters, dwarfmode, "/ZonesPenInfo/Assign", screen) { PARSE_SPEC("units", parameters); @@ -562,3 +503,4 @@ static command_result sort_items(color_ostream &out, vector ¶meters return CR_OK; } +*/ From 614bc546a869b0a342cdf704a9e79c7bb96689b2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 14 Aug 2023 16:56:01 -0700 Subject: [PATCH 351/851] clear text buffer when input is handled by the overlay --- plugins/overlay.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/overlay.cpp b/plugins/overlay.cpp index 5dc9ed327..9c75e6951 100644 --- a/plugins/overlay.cpp +++ b/plugins/overlay.cpp @@ -1,3 +1,4 @@ +#include "df/enabler.h" #include "df/viewscreen_adopt_regionst.h" #include "df/viewscreen_choose_game_typest.h" #include "df/viewscreen_choose_start_sitest.h" @@ -29,6 +30,7 @@ DFHACK_PLUGIN("overlay"); DFHACK_PLUGIN_IS_ENABLED(is_enabled); REQUIRE_GLOBAL(world); +REQUIRE_GLOBAL(enabler); namespace DFHack { DBG_DECLARE(overlay, control, DebugCategory::LINFO); @@ -82,6 +84,8 @@ struct viewscreen_overlay : T { }); if (!input_is_handled) INTERPOSE_NEXT(feed)(input); + else + enabler->last_text_input[0] = '\0'; } DEFINE_VMETHOD_INTERPOSE(void, render, ()) { INTERPOSE_NEXT(render)(); From d9fd090e522c360590bc91165df047299d5bfc76 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 14 Aug 2023 17:28:32 -0700 Subject: [PATCH 352/851] update docs for sort --- docs/plugins/sort.rst | 66 +++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 067e188fd..4ddef85cd 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -2,59 +2,37 @@ sort ==== .. dfhack-tool:: - :summary: Sort lists shown in the DF interface. - :tags: unavailable fort productivity interface + :summary: Search and sort lists shown in the DF interface. + :tags: fort productivity interface :no-command: -.. dfhack-command:: sort-items - :summary: Sort the visible item list. +The ``sort`` tool provides overlays that sorting and searching options for +lists displayed in the DF interface. -.. dfhack-command:: sort-units - :summary: Sort the visible unit list. +Searching and sorting functionality is provided by `overlay` widgets, and widgets for individual lists can be moved via `gui/overlay` or turned on or off via `gui/control-panel`. -Usage ------ +Squad assignment overlay +------------------------ -:: +The squad assignment screen can be sorted by name, by migrant wave, or by various military-related skills. - sort-items [ ...] - sort-units [ ...] +If sorted by "any melee", then the citizen is sorted according to the highest +skill they have in axes, short swords, maces, warhammers, spears, or general +fighting. -Both commands sort the visible list using the given sequence of comparisons. -Each property can be prefixed with a ``<`` or ``>`` character to indicate -whether elements that don't have the given property defined go first or last -(respectively) in the sorted list. +If sorted by "any ranged", then the citizen is sorted according to the highest +skill they have in crossbows or general ranged combat. -Examples --------- +If sorted by "leadership", then the citizen is sorted according to the highest +skill they have in leader, teacher, or military tactics. -``sort-items material type quality`` - Sort a list of items by material, then by type, then by quality -``sort-units profession name`` - Sort a list of units by profession, then by name +You can search for a dwarf by name by typing in the Search field. You can also +type in the name of any job skill (military-related or not) and dwarves with +any experience in that skill will be shown. For example, to only see citizens +with military tactics skill, type in "tactics". -Properties ----------- +You can see all the job skill names that you can search for by running:: -Items can be sorted by the following properties: + :lua @df.job_skill -- ``type`` -- ``description`` -- ``base_quality`` -- ``quality`` -- ``improvement`` -- ``wear`` -- ``material`` - -Units can be sorted by the following properties: - -- ``name`` -- ``age`` -- ``arrival`` -- ``noble`` -- ``profession`` -- ``profession_class`` -- ``race`` -- ``squad`` -- ``squad_position`` -- ``happiness`` +in `gui/launcher`. From 2620bfbb43aa0c698c53d88e3cf9ef9455897181 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 14 Aug 2023 17:56:48 -0700 Subject: [PATCH 353/851] tweak color and layout --- plugins/lua/sort.lua | 100 +++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 0500cd3e0..743820103 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -226,28 +226,28 @@ function SquadAssignmentOverlay:init() label='Sort by:', key='CUSTOM_SHIFT_S', options={ - {label='any melee skill'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc}, - {label='any melee skill'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc}, - {label='any ranged skill'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc}, - {label='any ranged skill'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc}, - {label='any leader skill'..CH_DN, value=SORT_FNS.sort_by_leadership_desc}, - {label='any leader skill'..CH_UP, value=SORT_FNS.sort_by_leadership_asc}, - {label='name'..CH_DN, value=sort_by_name_desc}, - {label='name'..CH_UP, value=sort_by_name_asc}, - {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc}, - {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc}, - {label='axe skill'..CH_DN, value=SORT_FNS.sort_by_axe_desc}, - {label='axe skill'..CH_UP, value=SORT_FNS.sort_by_axe_asc}, - {label='sword skill'..CH_DN, value=SORT_FNS.sort_by_sword_desc}, - {label='sword skill'..CH_UP, value=SORT_FNS.sort_by_sword_asc}, - {label='mace skill'..CH_DN, value=SORT_FNS.sort_by_mace_desc}, - {label='mace skill'..CH_UP, value=SORT_FNS.sort_by_mace_asc}, - {label='hammer skill'..CH_DN, value=SORT_FNS.sort_by_hammer_desc}, - {label='hammer skill'..CH_UP, value=SORT_FNS.sort_by_hammer_asc}, - {label='spear skill'..CH_DN, value=SORT_FNS.sort_by_spear_desc}, - {label='spear skill'..CH_UP, value=SORT_FNS.sort_by_spear_asc}, - {label='crossbow skill'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc}, - {label='crossbow skill'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc}, + {label='any melee skill'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc, pen=COLOR_GREEN}, + {label='any melee skill'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc, pen=COLOR_YELLOW}, + {label='any ranged skill'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc, pen=COLOR_GREEN}, + {label='any ranged skill'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc, pen=COLOR_YELLOW}, + {label='any leader skill'..CH_DN, value=SORT_FNS.sort_by_leadership_desc, pen=COLOR_GREEN}, + {label='any leader skill'..CH_UP, value=SORT_FNS.sort_by_leadership_asc, pen=COLOR_YELLOW}, + {label='name'..CH_DN, value=sort_by_name_desc, pen=COLOR_GREEN}, + {label='name'..CH_UP, value=sort_by_name_asc, pen=COLOR_YELLOW}, + {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc, pen=COLOR_GREEN}, + {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc, pen=COLOR_YELLOW}, + {label='axe skill'..CH_DN, value=SORT_FNS.sort_by_axe_desc, pen=COLOR_GREEN}, + {label='axe skill'..CH_UP, value=SORT_FNS.sort_by_axe_asc, pen=COLOR_YELLOW}, + {label='sword skill'..CH_DN, value=SORT_FNS.sort_by_sword_desc, pen=COLOR_GREEN}, + {label='sword skill'..CH_UP, value=SORT_FNS.sort_by_sword_asc, pen=COLOR_YELLOW}, + {label='mace skill'..CH_DN, value=SORT_FNS.sort_by_mace_desc, pen=COLOR_GREEN}, + {label='mace skill'..CH_UP, value=SORT_FNS.sort_by_mace_asc, pen=COLOR_YELLOW}, + {label='hammer skill'..CH_DN, value=SORT_FNS.sort_by_hammer_desc, pen=COLOR_GREEN}, + {label='hammer skill'..CH_UP, value=SORT_FNS.sort_by_hammer_asc, pen=COLOR_YELLOW}, + {label='spear skill'..CH_DN, value=SORT_FNS.sort_by_spear_desc, pen=COLOR_GREEN}, + {label='spear skill'..CH_UP, value=SORT_FNS.sort_by_spear_asc, pen=COLOR_YELLOW}, + {label='crossbow skill'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc, pen=COLOR_GREEN}, + {label='crossbow skill'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc, pen=COLOR_YELLOW}, }, initial_option=SORT_FNS.sort_by_any_melee_desc, on_change=self:callback('refresh_list', 'sort'), @@ -267,8 +267,8 @@ function SquadAssignmentOverlay:init() frame={t=0, l=0, w=10}, options={ {label='any melee', value=sort_noop}, - {label='any melee'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc}, - {label='any melee'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc}, + {label='any melee'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc, pen=COLOR_GREEN}, + {label='any melee'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc, pen=COLOR_YELLOW}, }, initial_option=SORT_FNS.sort_by_any_melee_desc, option_gap=0, @@ -279,8 +279,8 @@ function SquadAssignmentOverlay:init() frame={t=0, l=13, w=11}, options={ {label='any ranged', value=sort_noop}, - {label='any ranged'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc}, - {label='any ranged'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc}, + {label='any ranged'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc, pen=COLOR_GREEN}, + {label='any ranged'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_any_ranged'), @@ -290,8 +290,8 @@ function SquadAssignmentOverlay:init() frame={t=0, l=27, w=11}, options={ {label='leadership', value=sort_noop}, - {label='leadership'..CH_DN, value=SORT_FNS.sort_by_leadership_desc}, - {label='leadership'..CH_UP, value=SORT_FNS.sort_by_leadership_asc}, + {label='leadership'..CH_DN, value=SORT_FNS.sort_by_leadership_desc, pen=COLOR_GREEN}, + {label='leadership'..CH_UP, value=SORT_FNS.sort_by_leadership_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_leadership'), @@ -301,8 +301,8 @@ function SquadAssignmentOverlay:init() frame={t=0, l=41, w=5}, options={ {label='name', value=sort_noop}, - {label='name'..CH_DN, value=sort_by_name_desc}, - {label='name'..CH_UP, value=sort_by_name_asc}, + {label='name'..CH_DN, value=sort_by_name_desc, pen=COLOR_GREEN}, + {label='name'..CH_UP, value=sort_by_name_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_name'), @@ -312,74 +312,74 @@ function SquadAssignmentOverlay:init() frame={t=0, l=48, w=13}, options={ {label='migrant wave', value=sort_noop}, - {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc}, - {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc}, + {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc, pen=COLOR_GREEN}, + {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_migrant_wave'), }, widgets.CycleHotkeyLabel{ view_id='sort_axe', - frame={t=2, l=0, w=4}, + frame={t=2, l=2, w=4}, options={ {label='axe', value=sort_noop}, - {label='axe'..CH_DN, value=SORT_FNS.sort_by_axe_desc}, - {label='axe'..CH_UP, value=SORT_FNS.sort_by_axe_asc}, + {label='axe'..CH_DN, value=SORT_FNS.sort_by_axe_desc, pen=COLOR_GREEN}, + {label='axe'..CH_UP, value=SORT_FNS.sort_by_axe_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_axe'), }, widgets.CycleHotkeyLabel{ view_id='sort_sword', - frame={t=2, l=7, w=6}, + frame={t=2, l=9, w=6}, options={ {label='sword', value=sort_noop}, - {label='sword'..CH_DN, value=SORT_FNS.sort_by_sword_desc}, - {label='sword'..CH_UP, value=SORT_FNS.sort_by_sword_asc}, + {label='sword'..CH_DN, value=SORT_FNS.sort_by_sword_desc, pen=COLOR_GREEN}, + {label='sword'..CH_UP, value=SORT_FNS.sort_by_sword_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_sword'), }, widgets.CycleHotkeyLabel{ view_id='sort_mace', - frame={t=2, l=16, w=5}, + frame={t=2, l=18, w=5}, options={ {label='mace', value=sort_noop}, - {label='mace'..CH_DN, value=SORT_FNS.sort_by_mace_desc}, - {label='mace'..CH_UP, value=SORT_FNS.sort_by_mace_asc}, + {label='mace'..CH_DN, value=SORT_FNS.sort_by_mace_desc, pen=COLOR_GREEN}, + {label='mace'..CH_UP, value=SORT_FNS.sort_by_mace_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_mace'), }, widgets.CycleHotkeyLabel{ view_id='sort_hammer', - frame={t=2, l=23, w=7}, + frame={t=2, l=25, w=7}, options={ {label='hammer', value=sort_noop}, - {label='hammer'..CH_DN, value=SORT_FNS.sort_by_hammer_desc}, - {label='hammer'..CH_UP, value=SORT_FNS.sort_by_hammer_asc}, + {label='hammer'..CH_DN, value=SORT_FNS.sort_by_hammer_desc, pen=COLOR_GREEN}, + {label='hammer'..CH_UP, value=SORT_FNS.sort_by_hammer_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_hammer'), }, widgets.CycleHotkeyLabel{ view_id='sort_spear', - frame={t=2, l=34, w=6}, + frame={t=2, l=36, w=6}, options={ {label='spear', value=sort_noop}, - {label='spear'..CH_DN, value=SORT_FNS.sort_by_spear_desc}, - {label='spear'..CH_UP, value=SORT_FNS.sort_by_spear_asc}, + {label='spear'..CH_DN, value=SORT_FNS.sort_by_spear_desc, pen=COLOR_GREEN}, + {label='spear'..CH_UP, value=SORT_FNS.sort_by_spear_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_spear'), }, widgets.CycleHotkeyLabel{ view_id='sort_crossbow', - frame={t=2, l=43, w=9}, + frame={t=2, l=45, w=9}, options={ {label='crossbow', value=sort_noop}, - {label='crossbow'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc}, - {label='crossbow'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc}, + {label='crossbow'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc, pen=COLOR_GREEN}, + {label='crossbow'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_crossbow'), From 4f04d551af594a67b9f41939ed7f601a49eda5c9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 16 Aug 2023 05:32:01 -0700 Subject: [PATCH 354/851] update changelog --- docs/changelog.txt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 99a7b0fc2..6d24fbc28 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -36,8 +36,6 @@ Template for new versions: ## API -## Internals - ## Lua ## Removed @@ -56,10 +54,11 @@ Template for new versions: ## New Tools ## New Features -- `caravan`: advanced unit assignment screens for cages, restraints, and pits/ponds +- `sort`: search and sort for squad assignment screen +- `zone`: advanced unit assignment screens for cages, restraints, and pits/ponds ## Fixes -- Core: properly reload scripts in mods when a world is unloaded and immediately loaded again +- Core: reload scripts in mods when a world is unloaded and immediately loaded again - Core: fix text getting added to DFHack text entry widgets when Alt- or Ctrl- keys are hit - `orders`: prevent import/export overlay from appearing on the create workorder screen @@ -73,14 +72,12 @@ Template for new versions: - ``Items::getValue()``: remove ``caravan_buying`` parameter since the identity of the selling party doesn't actually affect the item value - `RemoteFortressReader`: add a ``force_reload`` option to the GetBlockList RPC API to return blocks regardless of whether they have changed since the last request -## Internals - ## Lua - ``new()``: improved error handling so that certain errors that were previously uncatchable (creating objects with members with unknown vtables) are now catchable with ``pcall()`` - ``dfhack.items.getValue()``: remove ``caravan_buying`` param as per C++ API change - ``widgets.BannerPanel``: panel with distinctive border for marking DFHack UI elements on otherwise vanilla screens - ``widgets.Panel``: new functions to override instead of setting corresponding properties (useful when subclassing instead of just setting attributes): ``onDragBegin``, ``onDragEnd``, ``onResizeBegin``, ``onResizeEnd`` -- ``dfhack.screen.readTile()``: now populates extended tile property fields (like top_of_text) in the returned Pen object +- ``dfhack.screen.readTile()``: now populates extended tile property fields (like ``top_of_text``) in the returned ``Pen`` object ## Removed From caae21ae5d30736c1135951f82b4cd1bfc443736 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 16 Aug 2023 07:13:25 -0700 Subject: [PATCH 355/851] instruct ci to install xmldump when it is built --- .github/workflows/build-linux.yml | 1 + .github/workflows/build-windows.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 2f052b53e..9e377a3c7 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -124,6 +124,7 @@ jobs: -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} \ -DBUILD_TESTS:BOOL=${{ inputs.tests }} \ -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }} \ + -DINSTALL_XMLDUMP:BOOL=1 \ -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} \ -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} - name: Build DFHack diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 6469d5be7..e1039b6ff 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -94,7 +94,7 @@ jobs: win-msvc - name: Cross-compile env: - CMAKE_EXTRA_ARGS: '-DBUILD_LIBRARY=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} -DBUILD_TESTS:BOOL=${{ inputs.tests }} -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }}' + CMAKE_EXTRA_ARGS: '-DBUILD_LIBRARY=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} -DBUILD_TESTS:BOOL=${{ inputs.tests }} -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }} -DINSTALL_XMLDUMP:BOOL=1' run: | cd build bash -x build-win64-from-linux.sh From c1945f7b54f139a90a31a5227e695e82aa868df2 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Thu, 17 Aug 2023 06:32:26 +0300 Subject: [PATCH 356/851] fix build err in gcc --- library/include/modules/Textures.h | 2 +- library/modules/Textures.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 17cd6e2fc..fa1f743be 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -38,7 +38,7 @@ DFHACK_EXPORT std::vector loadTileset(const std::string& file, /** * Get texpos by handle. - * Always use this function, if you need to get valid texpos for your texure. + * Always use this function, if you need to get valid texpos for your texture. * Texpos can change on game textures reset, but handle will be the same. */ DFHACK_EXPORT long getTexposByHandle(TexposHandle handle); diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 729bf0cae..31575dca0 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -120,7 +120,7 @@ std::vector Textures::loadTileset(const std::string& file, int til } DFSDL_FreeSurface(surface); - DEBUG(textures).print("loaded %i textures from '%s'\n", handles.size(), file.c_str()); + DEBUG(textures).print("loaded %zd textures from '%s'\n", handles.size(), file.c_str()); return handles; } From 9511d4ba067535d47f3bc812f5fee24a5cdc3828 Mon Sep 17 00:00:00 2001 From: Myk Date: Wed, 16 Aug 2023 21:51:26 -0700 Subject: [PATCH 357/851] Temporarily override structures ref for Linux build Until the windows and Linux structures align again --- .github/workflows/steam-deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index 2df81d45d..07e7cafa5 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -53,6 +53,7 @@ jobs: with: artifact-name: linux64-depot dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} + structures_ref: linux cache-id: release cache-readonly: true common-files: false From 57e324b8f43cce6eb52928ef1c03adea6e9ac631 Mon Sep 17 00:00:00 2001 From: Myk Date: Wed, 16 Aug 2023 22:05:00 -0700 Subject: [PATCH 358/851] Allow forced structures ref to find the branch name --- .github/workflows/build-linux.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 9e377a3c7..37247c395 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -91,6 +91,7 @@ jobs: with: repository: ${{ inputs.structures_ref && github.repository || 'DFHack/df-structures' }} ref: ${{ inputs.structures_ref }} + fetch_depth: 0 path: library/xml - name: Fetch ccache if: inputs.platform-files From 1b5bee53bcdb45303e52e5084034993a73e30327 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 16 Aug 2023 22:17:33 -0700 Subject: [PATCH 359/851] prepend origin on ref --- .github/workflows/build-linux.yml | 1 - .github/workflows/steam-deploy.yml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 37247c395..9e377a3c7 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -91,7 +91,6 @@ jobs: with: repository: ${{ inputs.structures_ref && github.repository || 'DFHack/df-structures' }} ref: ${{ inputs.structures_ref }} - fetch_depth: 0 path: library/xml - name: Fetch ccache if: inputs.platform-files diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index 07e7cafa5..00f755254 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -53,7 +53,7 @@ jobs: with: artifact-name: linux64-depot dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} - structures_ref: linux + structures_ref: origin/linux cache-id: release cache-readonly: true common-files: false From 2287ebe99a4f793ea8260e7cf3a89a22981db78d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 16 Aug 2023 22:22:34 -0700 Subject: [PATCH 360/851] another try at the ref format --- .github/workflows/steam-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index 00f755254..f01655798 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -53,7 +53,7 @@ jobs: with: artifact-name: linux64-depot dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} - structures_ref: origin/linux + structures_ref: refs/heads/linux cache-id: release cache-readonly: true common-files: false From 1a6aec1de8854929ec869e4dec5a8081087167a6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 16 Aug 2023 22:24:45 -0700 Subject: [PATCH 361/851] fetch full history to get other branches --- .github/workflows/build-linux.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 9e377a3c7..00b13e23e 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -92,6 +92,7 @@ jobs: repository: ${{ inputs.structures_ref && github.repository || 'DFHack/df-structures' }} ref: ${{ inputs.structures_ref }} path: library/xml + fetch-depth: 0 - name: Fetch ccache if: inputs.platform-files uses: actions/cache/restore@v3 From 6a94dd4f253a6252cb77f35d8349fae8ec75100b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 16 Aug 2023 22:32:05 -0700 Subject: [PATCH 362/851] ensure we check out the correct repo --- .github/workflows/build-linux.yml | 8 +++++++- .github/workflows/steam-deploy.yml | 1 - 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 00b13e23e..f7e5cdaa4 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -92,7 +92,13 @@ jobs: repository: ${{ inputs.structures_ref && github.repository || 'DFHack/df-structures' }} ref: ${{ inputs.structures_ref }} path: library/xml - fetch-depth: 0 + - name: Clone structures (temporary override) + if: '!inputs.structures_ref' + uses: actions/checkout@v3 + with: + repository: DFHack/df-structures + ref: refs/heads/linux + path: library/xml - name: Fetch ccache if: inputs.platform-files uses: actions/cache/restore@v3 diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index f01655798..2df81d45d 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -53,7 +53,6 @@ jobs: with: artifact-name: linux64-depot dfhack_ref: ${{ github.event.inputs && github.event.inputs.ref || github.event.ref }} - structures_ref: refs/heads/linux cache-id: release cache-readonly: true common-files: false From 89ddc4b798421bcfdc986516028135bc93f59162 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 17 Aug 2023 06:06:58 +0000 Subject: [PATCH 363/851] 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 ce5ae6407..161bf3991 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ce5ae6407870b35aaec15dfb3f391dbd447eb7f5 +Subproject commit 161bf3991f45f5d24e48df1996adff0bb06d98c7 From 790f0ff628a1cd26d0af67e03e9eccb5eb9fe392 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 16 Aug 2023 23:58:00 -0700 Subject: [PATCH 364/851] fix stonesense --- package/linux/dfhack | 2 +- plugins/stonesense | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package/linux/dfhack b/package/linux/dfhack index 2e371c8e5..46ff59fc7 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -36,7 +36,7 @@ fi old_tty_settings=$(stty -g) # Now run -export LD_LIBRARY_PATH="./hack/libs:./hack:$LD_LIBRARY_PATH" +export LD_LIBRARY_PATH="./hack:$LD_LIBRARY_PATH" LIB="./hack/libdfhack.so" LIBSAN="" diff --git a/plugins/stonesense b/plugins/stonesense index 9080becf8..17106d68f 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 9080becf81ee93a069dff48f13aa0f0f7df8c51d +Subproject commit 17106d68f19a8944a6dfe74c57f1d4c0d20e777b From e7ebaf6a7af83a36fe8d561c1ecd359106fe2b92 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 17 Aug 2023 02:33:13 -0700 Subject: [PATCH 365/851] supercede LD_LIBRARY_PATH for dfhack libs --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d39943a3..13e915384 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -227,7 +227,7 @@ if(UNIX) # default to hidden symbols # ensure compatibility with older CPUs add_definitions(-DLINUX_BUILD) - set(GCC_COMMON_FLAGS "-fvisibility=hidden -mtune=generic -Wall -Werror") + set(GCC_COMMON_FLAGS "-fvisibility=hidden -mtune=generic -Wall -Werror -Wl,--disable-new-dtags") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COMMON_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_COMMON_FLAGS}") From 43f265fb6fbaa9d19e32d349eaa175c3e45afec1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 17 Aug 2023 02:33:30 -0700 Subject: [PATCH 366/851] update stonesense ref --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index 17106d68f..2f87534ce 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 17106d68f19a8944a6dfe74c57f1d4c0d20e777b +Subproject commit 2f87534cebdeee4ce7281333c8f71ae5b93790b9 From 96eb6a6de3b5dc7afaaf2f993c16805af6a0d744 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 17 Aug 2023 02:35:41 -0700 Subject: [PATCH 367/851] we no longer need to set LD_LIBRARY_PATH --- package/linux/dfhack | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/package/linux/dfhack b/package/linux/dfhack index 46ff59fc7..cd2766a80 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -36,8 +36,6 @@ fi old_tty_settings=$(stty -g) # Now run -export LD_LIBRARY_PATH="./hack:$LD_LIBRARY_PATH" - LIB="./hack/libdfhack.so" LIBSAN="" if which objdump > /dev/null; then @@ -60,7 +58,7 @@ fi case "$1" in -g | --gdb) shift - echo "set exec-wrapper env LD_LIBRARY_PATH='$LD_LIBRARY_PATH' LD_PRELOAD='$PRELOAD_LIB' MALLOC_PERTURB_=45" > gdbcmd.tmp + echo "set exec-wrapper env LD_PRELOAD='$PRELOAD_LIB' MALLOC_PERTURB_=45" > gdbcmd.tmp gdb $DF_GDB_OPTS -x gdbcmd.tmp --args ./dwarfort "$@" rm gdbcmd.tmp ret=$? @@ -73,8 +71,7 @@ case "$1" in echo "If your world gen name has spaces you need to remove spaces from the name in data/init/world_gen.txt" echo "****" fi - echo "set environment LD_LIBRARY_PATH $LD_LIBRARY_PATH" > gdbcmd.tmp - echo "set environment LD_PRELOAD $PRELOAD_LIB" >> gdbcmd.tmp + echo "set environment LD_PRELOAD $PRELOAD_LIB" > gdbcmd.tmp echo "set environment MALLOC_PERTURB_ 45" >> gdbcmd.tmp echo "set startup-with-shell off" >> gdbcmd.tmp echo "target extended-remote localhost:12345" >> gdbcmd.tmp From 56bc9a18ba67929473727d36c104365573f1ac1c Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 18 Aug 2023 16:34:15 +0000 Subject: [PATCH 368/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 3e1389d29..734ed2c2d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 3e1389d2965af61db53eacd1f292a301484434be +Subproject commit 734ed2c2d8556fc440c7913ac63610c981b40d5e From 833a54da053bd2dba4fe3fc708993ae177a8ccbb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 18 Aug 2023 09:35:07 -0700 Subject: [PATCH 369/851] bump version string to 50.09-r3rc1 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 13e915384..d7388d720 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.09") -set(DFHACK_RELEASE "r2") -set(DFHACK_PRERELEASE FALSE) +set(DFHACK_RELEASE "r3rc1") +set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_ABI_VERSION 1) From d9fa827b20d0a47c2abb748af147165e62f5b39c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 18 Aug 2023 19:27:12 -0700 Subject: [PATCH 370/851] support overlays on the load arena screen --- plugins/lua/hotkeys.lua | 1 + plugins/overlay.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 373b2945f..629f743cc 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -37,6 +37,7 @@ HotspotMenuWidget.ATTRS{ 'initial_prep', --'legends', -- conflicts with vanilla export button and info text 'loadgame', + -- 'new_arena', -- conflicts with vanilla panel layouts -- 'new_region', -- conflicts with vanilla panel layouts 'savegame', 'setupdwarfgame', diff --git a/plugins/overlay.cpp b/plugins/overlay.cpp index 9c75e6951..3fec6091b 100644 --- a/plugins/overlay.cpp +++ b/plugins/overlay.cpp @@ -8,6 +8,7 @@ #include "df/viewscreen_initial_prepst.h" #include "df/viewscreen_legendsst.h" #include "df/viewscreen_loadgamest.h" +#include "df/viewscreen_new_arenast.h" #include "df/viewscreen_new_regionst.h" #include "df/viewscreen_savegamest.h" #include "df/viewscreen_setupdwarfgamest.h" @@ -112,6 +113,7 @@ IMPLEMENT_HOOKS(game_cleaner) IMPLEMENT_HOOKS(initial_prep) IMPLEMENT_HOOKS(legends) IMPLEMENT_HOOKS(loadgame) +IMPLEMENT_HOOKS(new_arena) IMPLEMENT_HOOKS(new_region) IMPLEMENT_HOOKS(savegame) IMPLEMENT_HOOKS(setupdwarfgame) @@ -146,6 +148,7 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { INTERPOSE_HOOKS_FAILED(initial_prep) || INTERPOSE_HOOKS_FAILED(legends) || INTERPOSE_HOOKS_FAILED(loadgame) || + INTERPOSE_HOOKS_FAILED(new_arena) || INTERPOSE_HOOKS_FAILED(new_region) || INTERPOSE_HOOKS_FAILED(savegame) || INTERPOSE_HOOKS_FAILED(setupdwarfgame) || From 8b91e8494481fa6f7d8c20455f73caaae045d9ec Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 18 Aug 2023 19:28:24 -0700 Subject: [PATCH 371/851] offer sort by race on animal assignment screen --- docs/changelog.txt | 1 + plugins/lua/zone.lua | 42 +++++++++++++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 6d24fbc28..8e4ee5d8c 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -65,6 +65,7 @@ Template for new versions: ## Misc Improvements - Surround DFHack-specific UI elements with square brackets instead of red-yellow blocks for better readability - `hotkeys`: don't display DFHack logo in legends mode since it covers up important interface elements. the Ctrl-Shift-C hotkey to bring up the menu and the mouseover hotspot still function, though. +- `sort`: animals are now sortable by race on the assignment screens ## Documentation diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 81d1e5cb7..b98ba8f08 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -56,65 +56,72 @@ local function sort_noop(a, b) error('sort_noop should not be called') end -local function sort_base(a, b) +local function sort_by_race_desc(a, b) if a.data.race == b.data.race then return a.data.gender < b.data.gender end return a.data.race < b.data.race end +local function sort_by_race_asc(a, b) + if a.data.race == b.data.race then + return a.data.gender < b.data.gender + end + return a.data.race > b.data.race +end + local function sort_by_name_desc(a, b) if a.search_key == b.search_key then - return sort_base(a, b) + return sort_by_race_desc(a, b) end return a.search_key < b.search_key end local function sort_by_name_asc(a, b) if a.search_key == b.search_key then - return sort_base(a, b) + return sort_by_race_desc(a, b) end return a.search_key > b.search_key end local function sort_by_gender_desc(a, b) if a.data.gender == b.data.gender then - return sort_base(a, b) + return sort_by_race_desc(a, b) end return a.data.gender < b.data.gender end local function sort_by_gender_asc(a, b) if a.data.gender == b.data.gender then - return sort_base(a, b) + return sort_by_race_desc(a, b) end return a.data.gender > b.data.gender end local function sort_by_disposition_desc(a, b) if a.data.disposition == b.data.disposition then - return sort_base(a, b) + return sort_by_race_desc(a, b) end return a.data.disposition < b.data.disposition end local function sort_by_disposition_asc(a, b) if a.data.disposition == b.data.disposition then - return sort_base(a, b) + return sort_by_race_desc(a, b) end return a.data.disposition > b.data.disposition end local function sort_by_status_desc(a, b) if a.data.status == b.data.status then - return sort_base(a, b) + return sort_by_race_desc(a, b) end return a.data.status < b.data.status end local function sort_by_status_asc(a, b) if a.data.status == b.data.status then - return sort_base(a, b) + return sort_by_race_desc(a, b) end return a.data.status > b.data.status end @@ -145,6 +152,8 @@ function AssignAnimal:init() {label='disposition'..CH_UP, value=sort_by_disposition_asc}, {label='gender'..CH_DN, value=sort_by_gender_desc}, {label='gender'..CH_UP, value=sort_by_gender_asc}, + {label='race'..CH_DN, value=sort_by_race_desc}, + {label='race'..CH_UP, value=sort_by_race_asc}, {label='name'..CH_DN, value=sort_by_name_desc}, {label='name'..CH_UP, value=sort_by_name_asc}, }, @@ -327,8 +336,19 @@ function AssignAnimal:init() on_change=self:callback('refresh_list', 'sort_gender'), }, widgets.CycleHotkeyLabel{ - view_id='sort_name', + view_id='sort_race', frame={t=0, l=STATUS_COL_WIDTH+2+DISPOSITION_COL_WIDTH+2+GENDER_COL_WIDTH+2, w=5}, + options={ + {label='race', value=sort_noop}, + {label='race'..CH_DN, value=sort_by_race_desc}, + {label='race'..CH_UP, value=sort_by_race_asc}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_race'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_name', + frame={t=0, l=STATUS_COL_WIDTH+2+DISPOSITION_COL_WIDTH+2+GENDER_COL_WIDTH+2+7, w=5}, options={ {label='name', value=sort_noop}, {label='name'..CH_DN, value=sort_by_name_desc}, @@ -380,7 +400,7 @@ function AssignAnimal:refresh_list(sort_widget, sort_fn) self.subviews[sort_widget]:cycle() return end - for _,widget_name in ipairs{'sort', 'sort_status', 'sort_disposition', 'sort_gender', 'sort_name'} do + for _,widget_name in ipairs{'sort', 'sort_status', 'sort_disposition', 'sort_gender', 'sort_race', 'sort_name'} do self.subviews[widget_name]:setOption(sort_fn) end local list = self.subviews.list From 592990f1d314b6dcad308fad27a07756bc66932a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 18 Aug 2023 23:34:37 -0700 Subject: [PATCH 372/851] make deploy to github action work for non-releases --- .github/workflows/github-release.yml | 8 +++++--- .github/workflows/steam-deploy.yml | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 2d8e55335..15791d699 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -3,7 +3,7 @@ name: Deploy to GitHub on: push: tags: - - '*-r[0-9]+' + - '*-r*' workflow_dispatch: inputs: @@ -39,10 +39,12 @@ jobs: - name: Generate release text run: | python docs/gen_changelog.py -a + CHANGELOG_FILE=docs/changelogs/${{ steps.gettag.outputs.name }}-github.txt + if ! test -f $CHANGELOG_FILE; then CHANGELOG_FILE=docs/changelogs/future-github.txt; fi TOKEN_LINE=$(grep -Fhne '%RELEASE_NOTES%' .github/release_template.md | sed 's/:.*//') head -n $((TOKEN_LINE - 1)) .github/release_template.md > release_body.md - CHANGELOG_LINES=$(wc -l > release_body.md + CHANGELOG_LINES=$(wc -l <$CHANGELOG_FILE) + tail -n $((CHANGELOG_LINES - 3)) $CHANGELOG_FILE >> release_body.md tail -n 2 .github/release_template.md >> release_body.md cat release_body.md - name: Stage release diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index 2df81d45d..20160e52f 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -3,7 +3,7 @@ name: Deploy to Steam on: push: tags: - - '*' + - '*-r*' workflow_dispatch: inputs: From 1e4594f8d5a4873f16077ef41de9ff2846c63838 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 18 Aug 2023 23:46:12 -0700 Subject: [PATCH 373/851] need sphinx to generate changelogs --- .github/workflows/github-release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 15791d699..2d1cc4f45 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -28,6 +28,8 @@ jobs: permissions: contents: write steps: + - name: Install doc dependencies + run: pip install 'sphinx<4.4.0' - name: Clone DFHack uses: actions/checkout@v3 with: From 4e090d8fe0bc2ac163d06538f7fed23dbba3764b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 19 Aug 2023 00:09:16 -0700 Subject: [PATCH 374/851] put artifacts in their own dir so unrelated files don't get uploaded --- .github/workflows/github-release.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 2d1cc4f45..12f5cf4e4 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -51,18 +51,20 @@ jobs: cat release_body.md - name: Stage release uses: actions/download-artifact@v3 + - name: Prep artifact directory + run: mkdir artifacts - name: Create win64 release archive run: | cd dfhack-windows64-build - zip -r ../dfhack-${{ steps.gettag.outputs.name }}-Windows-64bit.zip . + zip -qr ../artifacts/dfhack-${{ steps.gettag.outputs.name }}-Windows-64bit.zip . - name: Create linux64 release archive run: | cd dfhack-linux64-build - tar cjf ../dfhack-${{ steps.gettag.outputs.name }}-Linux-64bit.tar.bz2 . + tar cjf ../artifacts/dfhack-${{ steps.gettag.outputs.name }}-Linux-64bit.tar.bz2 . - name: Create or update GitHub release uses: ncipollo/release-action@v1 with: - artifacts: "dfhack-*" + artifacts: "artifacts/dfhack-*" bodyFile: "release_body.md" allowUpdates: true artifactErrorsFailBuild: true From c05ac0c94436eead21030a10b88919fc1c28c939 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 19 Aug 2023 00:32:36 -0700 Subject: [PATCH 375/851] pre-archive build output so artifact upload/download takes seconds instead of minutes we can potentially revert this commit if/when the v4 release of the upload-artifact and download-artifact actions comes out --- .github/workflows/build-linux.yml | 18 ++++++++++++++---- .github/workflows/build-windows.yml | 18 ++++++++++++++---- .github/workflows/github-release.yml | 13 ++++++------- .github/workflows/steam-deploy.yml | 10 +++++++++- .github/workflows/test.yml | 6 ++++-- 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index f7e5cdaa4..55761f18b 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -152,12 +152,22 @@ jobs: path: ~/.cache/ccache key: linux-gcc-${{ inputs.gcc-ver }}-${{ inputs.cache-id }}-${{ github.sha }} - name: Format artifact name - if: inputs.append-date-and-hash + if: inputs.artifact-name id: artifactname - run: echo name=${{ inputs.artifact-name }}-$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT + run: | + if test "false" = "${{ inputs.append-date-and-hash }}"; then + echo name=${{ inputs.artifact-name }} >> $GITHUB_OUTPUT + else + echo name=${{ inputs.artifact-name }}-$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT + fi + - name: Prep artifact + if: inputs.artifact-name + run: | + cd build/image + tar cjf ../../${{ steps.artifactname.outputs.name }}.tar.bz2 . - name: Upload artifact if: inputs.artifact-name uses: actions/upload-artifact@v3 with: - name: ${{ inputs.append-date-and-hash && steps.artifactname.outputs.name || inputs.artifact-name }} - path: build/image/* + name: ${{ steps.artifactname.outputs.name }} + path: ${{ steps.artifactname.outputs.name }}.tar.bz2 diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index e1039b6ff..67bcf08a5 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -111,12 +111,22 @@ jobs: path: build/win64-cross/ccache key: win-msvc-${{ inputs.cache-id }}-${{ github.sha }} - name: Format artifact name - if: inputs.append-date-and-hash + if: inputs.artifact-name id: artifactname - run: echo "name=${{ inputs.artifact-name }}-$(date +%Y%m%d)-$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" + run: | + if test "false" = "${{ inputs.append-date-and-hash }}"; then + echo name=${{ inputs.artifact-name }} >> $GITHUB_OUTPUT + else + echo name=${{ inputs.artifact-name }}-$(date +%Y%m%d)-$(git rev-parse --short HEAD) >> $GITHUB_OUTPUT + fi + - name: Prep artifact + if: inputs.artifact-name + run: | + cd build/win64-cross/output + tar cjf ../../../${{ steps.artifactname.outputs.name }}.tar.bz2 . - name: Upload artifact if: inputs.artifact-name uses: actions/upload-artifact@v3 with: - name: ${{ inputs.append-date-and-hash && steps.artifactname.outputs.name || inputs.artifact-name }} - path: build/win64-cross/output/* + name: ${{ steps.artifactname.outputs.name }} + path: ${{ steps.artifactname.outputs.name }}.tar.bz2 diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 12f5cf4e4..5b4565511 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -51,16 +51,15 @@ jobs: cat release_body.md - name: Stage release uses: actions/download-artifact@v3 - - name: Prep artifact directory - run: mkdir artifacts - - name: Create win64 release archive + - name: Prep artifacts run: | + mkdir artifacts cd dfhack-windows64-build + tar xjf dfhack-windows64-build.tar.bz2 + rm dfhack-windows64-build.tar.bz2 zip -qr ../artifacts/dfhack-${{ steps.gettag.outputs.name }}-Windows-64bit.zip . - - name: Create linux64 release archive - run: | - cd dfhack-linux64-build - tar cjf ../artifacts/dfhack-${{ steps.gettag.outputs.name }}-Linux-64bit.tar.bz2 . + cd ../dfhack-linux64-build + mv dfhack-linux64-build.tar.bz2 ../artifacts/dfhack-${{ steps.gettag.outputs.name }}-Linux-64bit.tar.bz2 - name: Create or update GitHub release uses: ncipollo/release-action@v1 with: diff --git a/.github/workflows/steam-deploy.yml b/.github/workflows/steam-deploy.yml index 20160e52f..d4c4d9e8a 100644 --- a/.github/workflows/steam-deploy.yml +++ b/.github/workflows/steam-deploy.yml @@ -68,8 +68,16 @@ jobs: runs-on: ubuntu-latest concurrency: steam steps: - - name: Stage depot files + - name: Download depot files uses: actions/download-artifact@v3 + - name: Stage depot files + run: | + for name in common win64 linux64; do + cd ${name}-depot + tar xjf ${name}-depot.tar.bz2 + rm ${name}-depot.tar.bz2 + cd .. + done - name: Steam deploy uses: game-ci/steam-deploy@v3 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 131229adc..40b30cd13 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -110,11 +110,13 @@ jobs: mkdir -p ${{ env.DF_FOLDER }}/dfhack-config/init cd data/dfhack-config/init for fname in *.init; do touch ../../../${{ env.DF_FOLDER }}/dfhack-config/init/$fname; done - - name: Install DFHack + - name: Download DFHack uses: actions/download-artifact@v3 with: name: test-${{ matrix.compiler }} - path: ${{ env.DF_FOLDER }} + - name: Install DFHack + shell: bash + run: tar xjf test-${{ matrix.compiler }}.tar.bz2 -C ${{ env.DF_FOLDER }} - name: Run lua tests timeout-minutes: 10 run: python ci/run-tests.py --keep-status "${{ env.DF_FOLDER }}" From a1d60984461de4a992871e6085c9205760b81d23 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 19 Aug 2023 09:21:39 +0000 Subject: [PATCH 376/851] 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 161bf3991..1177a172b 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 161bf3991f45f5d24e48df1996adff0bb06d98c7 +Subproject commit 1177a172b28f6152233368dc58e6589e010ff817 From 6db338bf256de75193c237345be7b65676888bb6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 19 Aug 2023 02:32:13 -0700 Subject: [PATCH 377/851] set prerelease flag appropriately for github releases --- .github/workflows/github-release.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 5b4565511..e455ea34d 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -37,7 +37,10 @@ jobs: submodules: true - name: Get tag id: gettag - run: echo name=$(git describe --tags --abbrev=0 --exact-match) >> $GITHUB_OUTPUT + run: | + TAG=$(git describe --tags --abbrev=0 --exact-match) + echo name="$TAG" >> $GITHUB_OUTPUT + echo type=$(echo "$TAG" | egrep '-r[0-9]+$' && echo "release" || echo "prerelease") >> $GITHUB_OUTPUT - name: Generate release text run: | python docs/gen_changelog.py -a @@ -73,5 +76,6 @@ jobs: omitDraftDuringUpdate: true omitNameDuringUpdate: true omitPrereleaseDuringUpdate: true + prerelease: ${{ steps.gettag.outputs.type == 'prerelease' }} replacesArtifacts: true tag: ${{ steps.gettag.outputs.name }} From a06ba694465e11282c45bb80de84d7d51b6810f6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 19 Aug 2023 02:45:18 -0700 Subject: [PATCH 378/851] pass launchdf param through to windows build workflow --- .github/workflows/package.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index eba2f4f71..733f567cf 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -33,6 +33,7 @@ jobs: cache-readonly: ${{ inputs.cache-readonly }} stonesense: true docs: true + launchdf: ${{ inputs.launchdf }} secrets: inherit package-linux: From 8725fd26f609596ff2006e88627a852b715320db Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 19 Aug 2023 10:23:13 -0700 Subject: [PATCH 379/851] Revert "we no longer need to set LD_LIBRARY_PATH" This reverts commit 96eb6a6de3b5dc7afaaf2f993c16805af6a0d744. --- package/linux/dfhack | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/package/linux/dfhack b/package/linux/dfhack index cd2766a80..46ff59fc7 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -36,6 +36,8 @@ fi old_tty_settings=$(stty -g) # Now run +export LD_LIBRARY_PATH="./hack:$LD_LIBRARY_PATH" + LIB="./hack/libdfhack.so" LIBSAN="" if which objdump > /dev/null; then @@ -58,7 +60,7 @@ fi case "$1" in -g | --gdb) shift - echo "set exec-wrapper env LD_PRELOAD='$PRELOAD_LIB' MALLOC_PERTURB_=45" > gdbcmd.tmp + echo "set exec-wrapper env LD_LIBRARY_PATH='$LD_LIBRARY_PATH' LD_PRELOAD='$PRELOAD_LIB' MALLOC_PERTURB_=45" > gdbcmd.tmp gdb $DF_GDB_OPTS -x gdbcmd.tmp --args ./dwarfort "$@" rm gdbcmd.tmp ret=$? @@ -71,7 +73,8 @@ case "$1" in echo "If your world gen name has spaces you need to remove spaces from the name in data/init/world_gen.txt" echo "****" fi - echo "set environment LD_PRELOAD $PRELOAD_LIB" > gdbcmd.tmp + echo "set environment LD_LIBRARY_PATH $LD_LIBRARY_PATH" > gdbcmd.tmp + echo "set environment LD_PRELOAD $PRELOAD_LIB" >> gdbcmd.tmp echo "set environment MALLOC_PERTURB_ 45" >> gdbcmd.tmp echo "set startup-with-shell off" >> gdbcmd.tmp echo "target extended-remote localhost:12345" >> gdbcmd.tmp From 053ae023b2a36ee5ce5f90cf4f04eea47cf2830d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 19 Aug 2023 10:23:58 -0700 Subject: [PATCH 380/851] put df root in LD_LIBRARY_PATH so DF can find SDL2.so --- package/linux/dfhack | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/linux/dfhack b/package/linux/dfhack index 46ff59fc7..a83da71b4 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -36,7 +36,7 @@ fi old_tty_settings=$(stty -g) # Now run -export LD_LIBRARY_PATH="./hack:$LD_LIBRARY_PATH" +export LD_LIBRARY_PATH=".:$LD_LIBRARY_PATH" LIB="./hack/libdfhack.so" LIBSAN="" From 1763a16831e85051f277afb7c56e390b2c324bd0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 20 Aug 2023 10:08:25 -0700 Subject: [PATCH 381/851] add training check functions to Units --- docs/dev/Lua API.rst | 4 ++++ library/LuaApi.cpp | 4 ++++ library/include/modules/Units.h | 4 ++++ library/modules/Units.cpp | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index f29df78c6..d14e56640 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1380,6 +1380,10 @@ Units module * ``dfhack.units.isTame(unit)`` * ``dfhack.units.isTamable(unit)`` * ``dfhack.units.isDomesticated(unit)`` +* ``dfhack.units.isMarkedForTraining(unit)`` +* ``dfhack.units.isMarkedForTaming(unit)`` +* ``dfhack.units.isMarkedForWarTraining(unit)`` +* ``dfhack.units.isMarkedForHuntTraining(unit)`` * ``dfhack.units.isMarkedForSlaughter(unit)`` * ``dfhack.units.isMarkedForGelding(unit)`` * ``dfhack.units.isGeldable(unit)`` diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index beaf50579..f470e69c0 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1777,6 +1777,10 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, isTame), WRAPM(Units, isTamable), WRAPM(Units, isDomesticated), + WRAPM(Units, isMarkedForTraining), + WRAPM(Units, isMarkedForTaming), + WRAPM(Units, isMarkedForWarTraining), + WRAPM(Units, isMarkedForHuntTraining), WRAPM(Units, isMarkedForSlaughter), WRAPM(Units, isMarkedForGelding), WRAPM(Units, isGeldable), diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 19af4ec9a..11a6c120a 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -109,6 +109,10 @@ DFHACK_EXPORT bool isWar(df::unit* unit); DFHACK_EXPORT bool isTame(df::unit* unit); DFHACK_EXPORT bool isTamable(df::unit* unit); DFHACK_EXPORT bool isDomesticated(df::unit* unit); +DFHACK_EXPORT bool isMarkedForTraining(df::unit* unit); +DFHACK_EXPORT bool isMarkedForTaming(df::unit* unit); +DFHACK_EXPORT bool isMarkedForWarTraining(df::unit* unit); +DFHACK_EXPORT bool isMarkedForHuntTraining(df::unit* unit); DFHACK_EXPORT bool isMarkedForSlaughter(df::unit* unit); DFHACK_EXPORT bool isMarkedForGelding(df::unit* unit); DFHACK_EXPORT bool isGeldable(df::unit* unit); diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 1605a3d06..ebfd13b5e 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -76,6 +76,7 @@ using namespace std; #include "df/tile_occupancy.h" #include "df/plotinfost.h" #include "df/syndrome.h" +#include "df/training_assignment.h" #include "df/unit_inventory_item.h" #include "df/unit_misc_trait.h" #include "df/unit_relationship_type.h" @@ -510,6 +511,38 @@ bool Units::isDomesticated(df::unit* unit) return tame; } +static df::training_assignment * get_training_assignment(df::unit* unit) { + return binsearch_in_vector(df::global::plotinfo->equipment.training_assignments, + &df::training_assignment::animal_id, unit->id); +} + +bool Units::isMarkedForTraining(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + return !!get_training_assignment(unit); +} + +bool Units::isMarkedForTaming(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + auto assignment = get_training_assignment(unit); + return assignment && !assignment->flags.bits.train_war && !assignment->flags.bits.train_hunt; +} + +bool Units::isMarkedForWarTraining(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + auto assignment = get_training_assignment(unit); + return assignment && assignment->flags.bits.train_war; +} + +bool Units::isMarkedForHuntTraining(df::unit* unit) +{ + CHECK_NULL_POINTER(unit); + auto assignment = get_training_assignment(unit); + return assignment && assignment->flags.bits.train_hunt; +} + bool Units::isMarkedForSlaughter(df::unit* unit) { CHECK_NULL_POINTER(unit); From 8e9c6c708ae20b097a8174f09e16d2bcc02a8db2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 20 Aug 2023 10:08:42 -0700 Subject: [PATCH 382/851] don't butcher animals who have some kind of training also use new units functions in logistics --- plugins/autobutcher.cpp | 1 + plugins/logistics.cpp | 9 ++------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/plugins/autobutcher.cpp b/plugins/autobutcher.cpp index 536c74f0f..483e29759 100644 --- a/plugins/autobutcher.cpp +++ b/plugins/autobutcher.cpp @@ -746,6 +746,7 @@ static bool isInappropriateUnit(df::unit *unit) { static bool isProtectedUnit(df::unit *unit) { return Units::isWar(unit) // ignore war dogs etc || Units::isHunter(unit) // ignore hunting dogs etc + || Units::isMarkedForTraining(unit) // ignore units marked for any kind of training // ignore creatures in built cages which are defined as rooms to leave zoos alone // (TODO: better solution would be to allow some kind of slaughter cages which you can place near the butcher) || (isContainedInItem(unit) && isInBuiltCageRoom(unit)) // !!! see comments in isBuiltCageRoom() diff --git a/plugins/logistics.cpp b/plugins/logistics.cpp index 69b864c5c..86f65d351 100644 --- a/plugins/logistics.cpp +++ b/plugins/logistics.cpp @@ -392,14 +392,14 @@ public: bool is_designated(color_ostream& out, df::item* item) override { auto unit = get_caged_unit(item); - return unit && has_training_assignment(unit); + return unit && Units::isMarkedForTraining(unit); } bool can_designate(color_ostream& out, df::item* item) override { auto unit = get_caged_unit(item); return unit && !Units::isInvader(unit) && Units::isTamable(unit) && !Units::isTame(unit) && - !has_training_assignment(unit); + !Units::isMarkedForTraining(unit); } bool designate(color_ostream& out, df::item* item) override { @@ -424,11 +424,6 @@ private: return NULL; return gref->getUnit(); } - - static bool has_training_assignment(df::unit* unit) { - return binsearch_index(df::global::plotinfo->equipment.training_assignments, - &df::training_assignment::animal_id, unit->id) > -1; - } }; static const struct BadFlags { From 6caed7debe7c66d0982c5dafce1bcec9c57187b4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 20 Aug 2023 10:09:08 -0700 Subject: [PATCH 383/851] update changelog --- docs/changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 8e4ee5d8c..b8db746af 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -64,6 +64,7 @@ Template for new versions: ## Misc Improvements - Surround DFHack-specific UI elements with square brackets instead of red-yellow blocks for better readability +- `autobutcher`: don't mark animals for butchering if they are already marked for some kind of training (war, hunt) - `hotkeys`: don't display DFHack logo in legends mode since it covers up important interface elements. the Ctrl-Shift-C hotkey to bring up the menu and the mouseover hotspot still function, though. - `sort`: animals are now sortable by race on the assignment screens @@ -72,6 +73,7 @@ Template for new versions: ## API - ``Items::getValue()``: remove ``caravan_buying`` parameter since the identity of the selling party doesn't actually affect the item value - `RemoteFortressReader`: add a ``force_reload`` option to the GetBlockList RPC API to return blocks regardless of whether they have changed since the last request +- ``Units``: new animal propery check functions ``isMarkedForTraining(unit)``, ``isMarkedForTaming(unit)``, ``isMarkedForWarTraining(unit)``, and ``isMarkedForHuntTraining(unit)`` ## Lua - ``new()``: improved error handling so that certain errors that were previously uncatchable (creating objects with members with unknown vtables) are now catchable with ``pcall()`` @@ -79,6 +81,7 @@ Template for new versions: - ``widgets.BannerPanel``: panel with distinctive border for marking DFHack UI elements on otherwise vanilla screens - ``widgets.Panel``: new functions to override instead of setting corresponding properties (useful when subclassing instead of just setting attributes): ``onDragBegin``, ``onDragEnd``, ``onResizeBegin``, ``onResizeEnd`` - ``dfhack.screen.readTile()``: now populates extended tile property fields (like ``top_of_text``) in the returned ``Pen`` object +- ``dfhack.units``: new animal propery check functions ``isMarkedForTraining(unit)``, ``isMarkedForTaming(unit)``, ``isMarkedForWarTraining(unit)``, and ``isMarkedForHuntTraining(unit)`` ## Removed From 432e415a137f58c3b1869d27424d5c573ecbd4ab Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 21 Aug 2023 07:47:25 +0000 Subject: [PATCH 384/851] 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 1177a172b..dfa86bba5 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 1177a172b28f6152233368dc58e6589e010ff817 +Subproject commit dfa86bba5c653b6650b8e8c27467d87c28c878fa From 2d71a6b009174ef43642ffdd3f3c76eece571980 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 21 Aug 2023 00:49:31 -0700 Subject: [PATCH 385/851] bump version to r3rc2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7388d720..4b8c29b91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.09") -set(DFHACK_RELEASE "r3rc1") +set(DFHACK_RELEASE "r3rc2") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From a7a57427104f9921a753e3882a9f668e41a43706 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 21 Aug 2023 01:48:42 -0700 Subject: [PATCH 386/851] fix tests sometimes timing out in ci --- ci/test.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index 543334e72..ee08d5285 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -162,16 +162,19 @@ end local function ensure_title_screen() for i = 1, 100 do local scr = dfhack.gui.getCurViewscreen() - if is_title_screen(scr) then + if df.viewscreen_initial_prepst:is_instance(scr) then + delay(10000) + elseif is_title_screen(scr) then print('Found title screen') return + else + scr:feed_key(df.interface_key.LEAVESCREEN) + delay(10) end - scr:feed_key(df.interface_key.LEAVESCREEN) - delay(10) if i % 10 == 0 then print('Looking for title screen...') end end qerror(string.format('Could not find title screen (timed out at %s)', - dfhack.gui.getCurFocus(true))) + dfhack.gui.getCurFocus(true)[1])) end local function is_fortress(focus_string) From b76333ae877ca91106a5b61b0debae347e60c0e1 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 21 Aug 2023 12:46:24 -0500 Subject: [PATCH 387/851] `tailor`: remove crash clothing items may have an invalid maker race; this should not happen but it does so we have to deal with it --- docs/changelog.txt | 1 + plugins/tailor.cpp | 3 +++ 2 files changed, 4 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index b8db746af..0ef3d5cf5 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -29,6 +29,7 @@ Template for new versions: ## New Features ## Fixes +- `tailor`: remove crash caused by clothing items with an invalid ``maker_race`` ## Misc Improvements diff --git a/plugins/tailor.cpp b/plugins/tailor.cpp index df8781caa..af2a61e4a 100644 --- a/plugins/tailor.cpp +++ b/plugins/tailor.cpp @@ -186,6 +186,9 @@ public: } if (i->getWear() >= 1) continue; + if (i->getMakerRace() < 0) // sometimes we get borked items with no valid maker race + continue; + df::item_type t = i->getType(); int size = world->raws.creatures.all[i->getMakerRace()]->adultsize; From 03cfd6071b9bc96bd0ea65b1838822922f994a20 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 23 Aug 2023 00:48:22 -0700 Subject: [PATCH 388/851] limit wait for title screen in wall clock time --- ci/test.lua | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index ee08d5285..ac0e5718d 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -160,17 +160,29 @@ end -- has already loaded a fortress or is in any screen that can't get to the title -- screen by sending ESC keys. local function ensure_title_screen() + local start_ms = dfhack.getTickCount() + local prev_ms = start_ms + while df.viewscreen_initial_prepst:is_instance(dfhack.gui.getCurViewscreen()) do + delay(10) + -- wait up to 1 minute for the game to load and show the title screen + local now_ms = dfhack.getTickCount() + if now_ms - start_ms > 60000 then + qerror(('Could not find title screen (timed out at %s)'):format( + dfhack.gui.getCurFocus(true)[1])) + end + if now_ms - prev_ms > 1000 then + print('Waiting for game to load and show title screen...') + prev_ms = now_ms + end + end for i = 1, 100 do local scr = dfhack.gui.getCurViewscreen() - if df.viewscreen_initial_prepst:is_instance(scr) then - delay(10000) - elseif is_title_screen(scr) then + if is_title_screen(scr) then print('Found title screen') return - else - scr:feed_key(df.interface_key.LEAVESCREEN) - delay(10) end + scr:feed_key(df.interface_key.LEAVESCREEN) + delay(10) if i % 10 == 0 then print('Looking for title screen...') end end qerror(string.format('Could not find title screen (timed out at %s)', From a1d68286cd351896c48dc0588d9c07ae05b1fdea Mon Sep 17 00:00:00 2001 From: Mikhail Date: Thu, 24 Aug 2023 16:26:09 +0300 Subject: [PATCH 389/851] Added melee rating, ranged rating, mental stability rating and stress to sorting options on military screen in sort.lua. Added info about new sorting methods to sort.rst. Added name to Authors.rst. --- docs/about/Authors.rst | 1 + docs/plugins/sort.rst | 20 +++- plugins/lua/sort.lua | 260 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 278 insertions(+), 3 deletions(-) diff --git a/docs/about/Authors.rst b/docs/about/Authors.rst index cf74c6412..e6d24f6e5 100644 --- a/docs/about/Authors.rst +++ b/docs/about/Authors.rst @@ -129,6 +129,7 @@ Michael Crouch creidieki Michon van Dooren MaienM miffedmap miffedmap Mike Stewart thewonderidiot +Mikhail Panov Halifay Mikko Juola Noeda Adeon Milo Christiansen milochristiansen MithrilTuxedo MithrilTuxedo diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 4ddef85cd..e8e280f61 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -14,7 +14,7 @@ Searching and sorting functionality is provided by `overlay` widgets, and widget Squad assignment overlay ------------------------ -The squad assignment screen can be sorted by name, by migrant wave, or by various military-related skills. +The squad assignment screen can be sorted by name, by migrant wave, by stress, by various military-related skills or by specific potential ratings. If sorted by "any melee", then the citizen is sorted according to the highest skill they have in axes, short swords, maces, warhammers, spears, or general @@ -26,6 +26,24 @@ skill they have in crossbows or general ranged combat. If sorted by "leadership", then the citizen is sorted according to the highest skill they have in leader, teacher, or military tactics. +If sorting is done by "melee potential" citizens are arranged based on their +melee potential rating. This rating is a heuristic measure that takes into +account genetic predispositions in physical and mental attributes, as +well as body size. The goal is to assign a higher value to dwarves (and other +humanoid creatures) that are expected to be more effective in melee combat +against opponents of similar skill levels. + +If sorting is done by "ranged potential" citizens are arranged based on their +ranged potential rating. This rating is a heuristic measure that takes into +account genetic predispositions in physical and mental attributes. +The goal is to assign a higher value to dwarves (and other humanoid creatures) +that are expected to be more effective in ranged combat. + +If sorting is done by "mental stability" citizens are arranged based on their +mental stability rating. This rating is a measure that takes into account +facets and values of an individual and correlates to better stress values. +It is designed to be higher for more stress-resistant citizens. + You can search for a dwarf by name by typing in the Search field. You can also type in the name of any job skill (military-related or not) and dwarves with any experience in that skill will be shown. For example, to only see citizens diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 743820103..8cb1e7127 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -5,6 +5,8 @@ local overlay = require('plugins.overlay') local utils = require('utils') local widgets = require('gui.widgets') +local setbelief = reqscript("modtools/set-belief") + local CH_UP = string.char(30) local CH_DN = string.char(31) @@ -73,6 +75,28 @@ local function sort_by_migrant_wave_asc(unit_id_1, unit_id_2) return utils.compare(unit1.id, unit2.id) end +local function sort_by_stress_desc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local happiness1 = unit1.status.current_soul.personality.stress + local happiness2 = unit2.status.current_soul.personality.stress + return utils.compare(happiness2, happiness1) +end + +local function sort_by_stress_asc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local happiness1 = unit1.status.current_soul.personality.stress + local happiness2 = unit2.status.current_soul.personality.stress + return utils.compare(happiness1, happiness2) +end + local function get_skill(unit_id, skill, unit) unit = unit or df.unit.find(unit_id) return unit and @@ -181,6 +205,181 @@ local function make_sort_by_skill_asc(sort_skill) end end +-- Heuristic rating that is bigger for more potent dwarves in long run melee military training +-- Wounds are not considered! +local function melee_potential(unit) + -- Physical attributes + local strength = unit.body.physical_attrs.STRENGTH.max_value + local agility = unit.body.physical_attrs.AGILITY.max_value + local toughness = unit.body.physical_attrs.TOUGHNESS.max_value + local endurance = unit.body.physical_attrs.ENDURANCE.max_value + local recuperation = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.RECUPERATION) + local diseaseResistance = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.DISEASE_RESISTANCE) + local bodySize = unit.body.size_info.size_base + + -- Mental attributes + local focus = unit.status.current_soul.mental_attrs.FOCUS.max_value + local willpower = unit.status.current_soul.mental_attrs.WILLPOWER.max_value + local spatialSense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value + local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value + + -- strength/bodysize is a dirty approximation of momentum formula + local rating = 10000*strength/bodySize + strength*4 + agility*3 + toughness + + endurance + recuperation/3 + diseaseResistance/3 + + kinestheticSense*3 + willpower/2 + spatialSense/2 + focus/4 + return rating +end + +local function sort_by_melee_potential_desc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = melee_potential(unit1) + local rating2 = melee_potential(unit2) + if rating1 == rating2 then + return sort_by_name_desc(unit_id_1, unit_id_2) + end + return utils.compare(rating2, rating1) +end + +local function sort_by_melee_potential_asc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = melee_potential(unit1) + local rating2 = melee_potential(unit2) + if rating1 == rating2 then + return sort_by_name_asc(unit_id_1, unit_id_2) + end + return utils.compare(rating1, rating2) +end + +-- Heuristic rating that is bigger for more potent dwarves in long run ranged military training +-- Wounds are not considered! +local function ranged_potential(unit) + -- Physical attributes + local strength = unit.body.physical_attrs.STRENGTH.max_value + local agility = unit.body.physical_attrs.AGILITY.max_value + local toughness = unit.body.physical_attrs.TOUGHNESS.max_value + local endurance = unit.body.physical_attrs.ENDURANCE.max_value + local recuperation = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.RECUPERATION) + local diseaseResistance = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.DISEASE_RESISTANCE) + local bodySize = unit.body.size_info.size_base + + -- Mental attributes + local focus = unit.status.current_soul.mental_attrs.FOCUS.max_value + local willpower = unit.status.current_soul.mental_attrs.WILLPOWER.max_value + local spatialSense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value + local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value + + local rating = strength + agility*4 + toughness + endurance + recuperation/2 + + diseaseResistance/2 - bodySize/2 + + kinestheticSense + willpower + spatialSense*3 + focus + return rating +end + +local function sort_by_ranged_potential_desc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = ranged_potential(unit1) + local rating2 = ranged_potential(unit2) + if rating1 == rating2 then + return sort_by_name_desc(unit_id_1, unit_id_2) + end + return utils.compare(rating2, rating1) +end + +local function sort_by_ranged_potential_asc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = ranged_potential(unit1) + local rating2 = ranged_potential(unit2) + if rating1 == rating2 then + return sort_by_name_asc(unit_id_1, unit_id_2) + end + return utils.compare(rating1, rating2) +end + +-- Statistical rating that is bigger for dwarves that are mentally stable +local function mental_stability(unit) + local ALTRUISM = unit.status.current_soul.personality.traits.ALTRUISM + local ANXIETY_PROPENSITY = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY + local BRAVERY = unit.status.current_soul.personality.traits.BRAVERY + local CHEER_PROPENSITY = unit.status.current_soul.personality.traits.CHEER_PROPENSITY + local CURIOUS = unit.status.current_soul.personality.traits.CURIOUS + local DISCORD = unit.status.current_soul.personality.traits.DISCORD + local DUTIFULNESS = unit.status.current_soul.personality.traits.DUTIFULNESS + local EMOTIONALLY_OBSESSIVE = unit.status.current_soul.personality.traits.EMOTIONALLY_OBSESSIVE + local HUMOR = unit.status.current_soul.personality.traits.HUMOR + local LOVE_PROPENSITY = unit.status.current_soul.personality.traits.LOVE_PROPENSITY + local PERSEVERENCE = unit.status.current_soul.personality.traits.PERSEVERENCE + local POLITENESS = unit.status.current_soul.personality.traits.POLITENESS + local PRIVACY = unit.status.current_soul.personality.traits.PRIVACY + local STRESS_VULNERABILITY = unit.status.current_soul.personality.traits.STRESS_VULNERABILITY + local TOLERANT = unit.status.current_soul.personality.traits.TOLERANT + + local CRAFTSMANSHIP = setbelief.getUnitBelief(unit, df.value_type['CRAFTSMANSHIP']) + local FAMILY = setbelief.getUnitBelief(unit, df.value_type['FAMILY']) + local HARMONY = setbelief.getUnitBelief(unit, df.value_type['HARMONY']) + local INDEPENDENCE = setbelief.getUnitBelief(unit, df.value_type['INDEPENDENCE']) + local KNOWLEDGE = setbelief.getUnitBelief(unit, df.value_type['KNOWLEDGE']) + local LEISURE_TIME = setbelief.getUnitBelief(unit, df.value_type['LEISURE_TIME']) + local NATURE = setbelief.getUnitBelief(unit, df.value_type['NATURE']) + local SKILL = setbelief.getUnitBelief(unit, df.value_type['SKILL']) + + -- Calculate the rating using the defined variables + local rating = (CRAFTSMANSHIP * -0.01) + (FAMILY * -0.09) + (HARMONY * 0.05) + + (INDEPENDENCE * 0.06) + (KNOWLEDGE * -0.30) + (LEISURE_TIME * 0.24) + + (NATURE * 0.27) + (SKILL * -0.21) + (ALTRUISM * 0.13) + + (ANXIETY_PROPENSITY * -0.06) + (BRAVERY * 0.06) + + (CHEER_PROPENSITY * 0.41) + (CURIOUS * -0.06) + (DISCORD * 0.14) + + (DUTIFULNESS * -0.03) + (EMOTIONALLY_OBSESSIVE * -0.13) + + (HUMOR * -0.05) + (LOVE_PROPENSITY * 0.15) + (PERSEVERENCE * -0.07) + + (POLITENESS * -0.14) + (PRIVACY * 0.03) + (STRESS_VULNERABILITY * -0.20) + + (TOLERANT * -0.11) + + return rating +end + + +local function sort_by_mental_stability_desc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = mental_stability(unit1) + local rating2 = mental_stability(unit2) + if rating1 == rating2 then + return sort_by_name_desc(unit_id_1, unit_id_2) + end + return utils.compare(rating2, rating1) +end + +local function sort_by_mental_stability_asc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = mental_stability(unit1) + local rating2 = mental_stability(unit2) + if rating1 == rating2 then + return sort_by_name_asc(unit_id_1, unit_id_2) + end + return utils.compare(rating1, rating2) +end + local SORT_FNS = { sort_by_any_melee_desc=make_sort_by_skill_list_desc(MELEE_WEAPON_SKILLS), sort_by_any_melee_asc=make_sort_by_skill_list_asc(MELEE_WEAPON_SKILLS), @@ -211,7 +410,7 @@ SquadAssignmentOverlay.ATTRS{ default_pos={x=-33, y=40}, default_enabled=true, viewscreens='dwarfmode/UnitSelector/SQUAD_FILL_POSITION', - frame={w=63, h=7}, + frame={w=74, h=9}, frame_style=gui.FRAME_PANEL, frame_background=gui.CLEAR_PEN, } @@ -236,6 +435,8 @@ function SquadAssignmentOverlay:init() {label='name'..CH_UP, value=sort_by_name_asc, pen=COLOR_YELLOW}, {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc, pen=COLOR_GREEN}, {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc, pen=COLOR_YELLOW}, + {label='stress'..CH_DN, value=sort_by_stress_desc, pen=COLOR_GREEN}, + {label='stress'..CH_UP, value=sort_by_stress_asc, pen=COLOR_YELLOW}, {label='axe skill'..CH_DN, value=SORT_FNS.sort_by_axe_desc, pen=COLOR_GREEN}, {label='axe skill'..CH_UP, value=SORT_FNS.sort_by_axe_asc, pen=COLOR_YELLOW}, {label='sword skill'..CH_DN, value=SORT_FNS.sort_by_sword_desc, pen=COLOR_GREEN}, @@ -248,6 +449,12 @@ function SquadAssignmentOverlay:init() {label='spear skill'..CH_UP, value=SORT_FNS.sort_by_spear_asc, pen=COLOR_YELLOW}, {label='crossbow skill'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc, pen=COLOR_GREEN}, {label='crossbow skill'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc, pen=COLOR_YELLOW}, + {label='melee potential'..CH_DN, value=sort_by_melee_potential_desc, pen=COLOR_GREEN}, + {label='melee potential'..CH_UP, value=sort_by_melee_potential_asc, pen=COLOR_YELLOW}, + {label='ranged potential'..CH_DN, value=sort_by_ranged_potential_desc, pen=COLOR_GREEN}, + {label='ranged potential'..CH_UP, value=sort_by_ranged_potential_asc, pen=COLOR_YELLOW}, + {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, + {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, }, initial_option=SORT_FNS.sort_by_any_melee_desc, on_change=self:callback('refresh_list', 'sort'), @@ -309,7 +516,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_migrant_wave', - frame={t=0, l=48, w=13}, + frame={t=0, l=49, w=13}, options={ {label='migrant wave', value=sort_noop}, {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc, pen=COLOR_GREEN}, @@ -318,6 +525,17 @@ function SquadAssignmentOverlay:init() option_gap=0, on_change=self:callback('refresh_list', 'sort_migrant_wave'), }, + widgets.CycleHotkeyLabel{ + view_id='sort_stress', + frame={t=0, l=65, w=7}, + options={ + {label='stress', value=sort_noop}, + {label='stress'..CH_DN, value=sort_by_stress_desc, pen=COLOR_GREEN}, + {label='stress'..CH_UP, value=sort_by_stress_asc, pen=COLOR_YELLOW}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_stress'), + }, widgets.CycleHotkeyLabel{ view_id='sort_axe', frame={t=2, l=2, w=4}, @@ -384,6 +602,39 @@ function SquadAssignmentOverlay:init() option_gap=0, on_change=self:callback('refresh_list', 'sort_crossbow'), }, + widgets.CycleHotkeyLabel{ + view_id='sort_melee_potential', + frame={t=4, l=2, w=16}, + options={ + {label='melee potential', value=sort_noop}, + {label='melee potential'..CH_DN, value=sort_by_melee_potential_desc, pen=COLOR_GREEN}, + {label='melee potential'..CH_UP, value=sort_by_melee_potential_asc, pen=COLOR_YELLOW}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_melee_potential'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_ranged_potential', + frame={t=4, l=21, w=17}, + options={ + {label='ranged potential', value=sort_noop}, + {label='ranged potential'..CH_DN, value=sort_by_ranged_potential_desc, pen=COLOR_GREEN}, + {label='ranged potential'..CH_UP, value=sort_by_ranged_potential_asc, pen=COLOR_YELLOW}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_ranged_potential'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_mental_stability', + frame={t=4, l=41, w=17}, + options={ + {label='mental stability', value=sort_noop}, + {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, + {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_mental_stability'), + }, } }, } @@ -454,12 +705,16 @@ local SORT_WIDGET_NAMES = { 'sort_leadership', 'sort_name', 'sort_migrant_wave', + 'sort_stress', 'sort_axe', 'sort_sword', 'sort_mace', 'sort_hammer', 'sort_spear', 'sort_crossbow', + 'sort_melee_potential', + 'sort_ranged_potential', + 'sort_mental_stability', } function SquadAssignmentOverlay:refresh_list(sort_widget, sort_fn) @@ -555,3 +810,4 @@ make_sort_order = utils.make_sort_order ]] return _ENV + From aef60649fe130961ed4b6446ce539f165c277bf9 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Thu, 24 Aug 2023 17:18:46 +0300 Subject: [PATCH 390/851] Trim trailing whitespace. --- plugins/lua/sort.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 8cb1e7127..94f4098ce 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -810,4 +810,3 @@ make_sort_order = utils.make_sort_order ]] return _ENV - From 30488dc3104240cb56f22223cd14efba31bdf8f6 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Thu, 24 Aug 2023 18:47:42 +0300 Subject: [PATCH 391/851] Trailing space again. My bad. --- plugins/lua/sort.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 94f4098ce..ae6ea4eeb 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -809,4 +809,4 @@ end make_sort_order = utils.make_sort_order ]] -return _ENV +return _ENV \ No newline at end of file From 771d7f6c6c9d1e76cb153fc3579ab387b5c5ec8a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 24 Aug 2023 15:49:53 +0000 Subject: [PATCH 392/851] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/plugins/sort.rst | 24 ++++++++++++------------ plugins/lua/sort.lua | 26 +++++++++++++------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index e8e280f61..84f7359e4 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -26,22 +26,22 @@ skill they have in crossbows or general ranged combat. If sorted by "leadership", then the citizen is sorted according to the highest skill they have in leader, teacher, or military tactics. -If sorting is done by "melee potential" citizens are arranged based on their -melee potential rating. This rating is a heuristic measure that takes into -account genetic predispositions in physical and mental attributes, as -well as body size. The goal is to assign a higher value to dwarves (and other -humanoid creatures) that are expected to be more effective in melee combat +If sorting is done by "melee potential" citizens are arranged based on their +melee potential rating. This rating is a heuristic measure that takes into +account genetic predispositions in physical and mental attributes, as +well as body size. The goal is to assign a higher value to dwarves (and other +humanoid creatures) that are expected to be more effective in melee combat against opponents of similar skill levels. -If sorting is done by "ranged potential" citizens are arranged based on their -ranged potential rating. This rating is a heuristic measure that takes into -account genetic predispositions in physical and mental attributes. -The goal is to assign a higher value to dwarves (and other humanoid creatures) +If sorting is done by "ranged potential" citizens are arranged based on their +ranged potential rating. This rating is a heuristic measure that takes into +account genetic predispositions in physical and mental attributes. +The goal is to assign a higher value to dwarves (and other humanoid creatures) that are expected to be more effective in ranged combat. -If sorting is done by "mental stability" citizens are arranged based on their -mental stability rating. This rating is a measure that takes into account -facets and values of an individual and correlates to better stress values. +If sorting is done by "mental stability" citizens are arranged based on their +mental stability rating. This rating is a measure that takes into account +facets and values of an individual and correlates to better stress values. It is designed to be higher for more stress-resistant citizens. You can search for a dwarf by name by typing in the Search field. You can also diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index ae6ea4eeb..db132b855 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -224,8 +224,8 @@ local function melee_potential(unit) local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value -- strength/bodysize is a dirty approximation of momentum formula - local rating = 10000*strength/bodySize + strength*4 + agility*3 + toughness - + endurance + recuperation/3 + diseaseResistance/3 + local rating = 10000*strength/bodySize + strength*4 + agility*3 + toughness + + endurance + recuperation/3 + diseaseResistance/3 + kinestheticSense*3 + willpower/2 + spatialSense/2 + focus/4 return rating end @@ -277,7 +277,7 @@ local function ranged_potential(unit) local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value local rating = strength + agility*4 + toughness + endurance + recuperation/2 - + diseaseResistance/2 - bodySize/2 + + diseaseResistance/2 - bodySize/2 + kinestheticSense + willpower + spatialSense*3 + focus return rating end @@ -338,16 +338,16 @@ local function mental_stability(unit) local SKILL = setbelief.getUnitBelief(unit, df.value_type['SKILL']) -- Calculate the rating using the defined variables - local rating = (CRAFTSMANSHIP * -0.01) + (FAMILY * -0.09) + (HARMONY * 0.05) - + (INDEPENDENCE * 0.06) + (KNOWLEDGE * -0.30) + (LEISURE_TIME * 0.24) - + (NATURE * 0.27) + (SKILL * -0.21) + (ALTRUISM * 0.13) - + (ANXIETY_PROPENSITY * -0.06) + (BRAVERY * 0.06) - + (CHEER_PROPENSITY * 0.41) + (CURIOUS * -0.06) + (DISCORD * 0.14) - + (DUTIFULNESS * -0.03) + (EMOTIONALLY_OBSESSIVE * -0.13) - + (HUMOR * -0.05) + (LOVE_PROPENSITY * 0.15) + (PERSEVERENCE * -0.07) - + (POLITENESS * -0.14) + (PRIVACY * 0.03) + (STRESS_VULNERABILITY * -0.20) + local rating = (CRAFTSMANSHIP * -0.01) + (FAMILY * -0.09) + (HARMONY * 0.05) + + (INDEPENDENCE * 0.06) + (KNOWLEDGE * -0.30) + (LEISURE_TIME * 0.24) + + (NATURE * 0.27) + (SKILL * -0.21) + (ALTRUISM * 0.13) + + (ANXIETY_PROPENSITY * -0.06) + (BRAVERY * 0.06) + + (CHEER_PROPENSITY * 0.41) + (CURIOUS * -0.06) + (DISCORD * 0.14) + + (DUTIFULNESS * -0.03) + (EMOTIONALLY_OBSESSIVE * -0.13) + + (HUMOR * -0.05) + (LOVE_PROPENSITY * 0.15) + (PERSEVERENCE * -0.07) + + (POLITENESS * -0.14) + (PRIVACY * 0.03) + (STRESS_VULNERABILITY * -0.20) + (TOLERANT * -0.11) - + return rating end @@ -809,4 +809,4 @@ end make_sort_order = utils.make_sort_order ]] -return _ENV \ No newline at end of file +return _ENV From 25f2c1746a8169fb8f1d0f13e1007f41f9ea84c2 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Fri, 25 Aug 2023 16:18:20 +0300 Subject: [PATCH 393/851] Changed melee and ranged ratings to statistically proven linear formulas. --- docs/plugins/sort.rst | 32 ++++++++++++++++---------------- plugins/lua/sort.lua | 24 ++++++++---------------- 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index e8e280f61..8ec9fefcc 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -26,22 +26,22 @@ skill they have in crossbows or general ranged combat. If sorted by "leadership", then the citizen is sorted according to the highest skill they have in leader, teacher, or military tactics. -If sorting is done by "melee potential" citizens are arranged based on their -melee potential rating. This rating is a heuristic measure that takes into -account genetic predispositions in physical and mental attributes, as -well as body size. The goal is to assign a higher value to dwarves (and other -humanoid creatures) that are expected to be more effective in melee combat -against opponents of similar skill levels. - -If sorting is done by "ranged potential" citizens are arranged based on their -ranged potential rating. This rating is a heuristic measure that takes into -account genetic predispositions in physical and mental attributes. -The goal is to assign a higher value to dwarves (and other humanoid creatures) -that are expected to be more effective in ranged combat. - -If sorting is done by "mental stability" citizens are arranged based on their -mental stability rating. This rating is a measure that takes into account -facets and values of an individual and correlates to better stress values. +If sorting is done by "melee potential" citizens are arranged based on their +melee potential rating. This rating is a heuristic measure that takes into +account genetic predispositions in physical and mental attributes, as +well as body size. Dwarves (and other humanoid creatures) with bigger rating +are expected to be more effective in melee combat against opponents of +similar skill levels. + +If sorting is done by "ranged potential" citizens are arranged based on their +ranged potential rating. This rating is a statistical measure that takes into +account genetic predispositions in physical and mental attributes. +Dwarves (and other humanoid creatures) with bigger rating are expected to be +more effective in ranged combat. + +If sorting is done by "mental stability" citizens are arranged based on their +mental stability rating. This rating is a measure that takes into account +facets and values of an individual and correlates to better stress values. It is designed to be higher for more stress-resistant citizens. You can search for a dwarf by name by typing in the Search field. You can also diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index ae6ea4eeb..ee2f38c34 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -205,7 +205,7 @@ local function make_sort_by_skill_asc(sort_skill) end end --- Heuristic rating that is bigger for more potent dwarves in long run melee military training +-- Statistical rating that is bigger for more potent dwarves in long run melee military training -- Wounds are not considered! local function melee_potential(unit) -- Physical attributes @@ -213,20 +213,16 @@ local function melee_potential(unit) local agility = unit.body.physical_attrs.AGILITY.max_value local toughness = unit.body.physical_attrs.TOUGHNESS.max_value local endurance = unit.body.physical_attrs.ENDURANCE.max_value - local recuperation = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.RECUPERATION) - local diseaseResistance = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.DISEASE_RESISTANCE) local bodySize = unit.body.size_info.size_base -- Mental attributes - local focus = unit.status.current_soul.mental_attrs.FOCUS.max_value local willpower = unit.status.current_soul.mental_attrs.WILLPOWER.max_value local spatialSense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value - -- strength/bodysize is a dirty approximation of momentum formula - local rating = 10000*strength/bodySize + strength*4 + agility*3 + toughness - + endurance + recuperation/3 + diseaseResistance/3 - + kinestheticSense*3 + willpower/2 + spatialSense/2 + focus/4 + -- Melee potential rating + local rating = strength*5.8 + kinestheticSense*3.7 + bodySize*2 + agility*2 + endurance*1.8 + + willpower*1.5 * spatialSense*1.5 + toughness*1.5 return rating end @@ -258,17 +254,13 @@ local function sort_by_melee_potential_asc(unit_id_1, unit_id_2) return utils.compare(rating1, rating2) end --- Heuristic rating that is bigger for more potent dwarves in long run ranged military training +-- Statistical rating that is bigger for more potent dwarves in long run ranged military training -- Wounds are not considered! local function ranged_potential(unit) -- Physical attributes - local strength = unit.body.physical_attrs.STRENGTH.max_value local agility = unit.body.physical_attrs.AGILITY.max_value local toughness = unit.body.physical_attrs.TOUGHNESS.max_value local endurance = unit.body.physical_attrs.ENDURANCE.max_value - local recuperation = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.RECUPERATION) - local diseaseResistance = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.DISEASE_RESISTANCE) - local bodySize = unit.body.size_info.size_base -- Mental attributes local focus = unit.status.current_soul.mental_attrs.FOCUS.max_value @@ -276,9 +268,9 @@ local function ranged_potential(unit) local spatialSense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value - local rating = strength + agility*4 + toughness + endurance + recuperation/2 - + diseaseResistance/2 - bodySize/2 - + kinestheticSense + willpower + spatialSense*3 + focus + -- Ranged potential formula + local rating = agility*3.9 + kinestheticSense*3 + spatialSense*2.9 + toughness*0.9 + + focus*0.7 + endurance*0.7 + willpower*0.6 return rating end From 6fcbf48c8412bbdfdee51e713e70f23930bf11b0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 25 Aug 2023 13:28:36 +0000 Subject: [PATCH 394/851] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- plugins/lua/sort.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 57992b6dd..c4610ecc6 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -269,7 +269,7 @@ local function ranged_potential(unit) local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value -- Ranged potential formula - local rating = agility*3.9 + kinestheticSense*3 + spatialSense*2.9 + toughness*0.9 + local rating = agility*3.9 + kinestheticSense*3 + spatialSense*2.9 + toughness*0.9 + focus*0.7 + endurance*0.7 + willpower*0.6 return rating end From c91a02ca6a9498b24a9644ecf4afd63800455be2 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sun, 27 Aug 2023 17:52:09 +0300 Subject: [PATCH 395/851] Reworked fallback from rating sortings. Renamed melee potential to solo combat potential. Added group combat potential. --- docs/plugins/sort.rst | 23 ++-- plugins/lua/sort.lua | 269 ++++++++++++++++++++++++++---------------- 2 files changed, 180 insertions(+), 112 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 8ec9fefcc..dd8b206ce 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -26,12 +26,22 @@ skill they have in crossbows or general ranged combat. If sorted by "leadership", then the citizen is sorted according to the highest skill they have in leader, teacher, or military tactics. -If sorting is done by "melee potential" citizens are arranged based on their -melee potential rating. This rating is a heuristic measure that takes into +If sorting is done by "mental stability" citizens are arranged based on their +mental stability rating. This rating is a measure that takes into account +facets and values of an individual and correlates to better stress values. +It is designed to be higher for more stress-resistant citizens. + +If sorting is done by "solo combat potential" citizens are arranged based on their +solo combat potential rating. This rating is a measure that takes into account genetic predispositions in physical and mental attributes, as well as body size. Dwarves (and other humanoid creatures) with bigger rating -are expected to be more effective in melee combat against opponents of -similar skill levels. +are expected to be more effective in melee combat against strong opponents. + +If sorting is done by "group combat potential" citizens are arranged based on their +group combat potential rating. Similar with solo combat rating except this rating +taking into account efficiency in a fight against multiple opponents. This rating +is valid only for dwarves because it considers martial trance which only dwarves +are capable of. If sorting is done by "ranged potential" citizens are arranged based on their ranged potential rating. This rating is a statistical measure that takes into @@ -39,11 +49,6 @@ account genetic predispositions in physical and mental attributes. Dwarves (and other humanoid creatures) with bigger rating are expected to be more effective in ranged combat. -If sorting is done by "mental stability" citizens are arranged based on their -mental stability rating. This rating is a measure that takes into account -facets and values of an individual and correlates to better stress values. -It is designed to be higher for more stress-resistant citizens. - You can search for a dwarf by name by typing in the Search field. You can also type in the name of any job skill (military-related or not) and dwarves with any experience in that skill will be shown. For example, to only see citizens diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index c4610ecc6..c418b1f5a 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -205,9 +205,82 @@ local function make_sort_by_skill_asc(sort_skill) end end +-- Statistical rating that is bigger for dwarves that are mentally stable +local function mental_stability(unit) + local ALTRUISM = unit.status.current_soul.personality.traits.ALTRUISM + local ANXIETY_PROPENSITY = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY + local BRAVERY = unit.status.current_soul.personality.traits.BRAVERY + local CHEER_PROPENSITY = unit.status.current_soul.personality.traits.CHEER_PROPENSITY + local CURIOUS = unit.status.current_soul.personality.traits.CURIOUS + local DISCORD = unit.status.current_soul.personality.traits.DISCORD + local DUTIFULNESS = unit.status.current_soul.personality.traits.DUTIFULNESS + local EMOTIONALLY_OBSESSIVE = unit.status.current_soul.personality.traits.EMOTIONALLY_OBSESSIVE + local HUMOR = unit.status.current_soul.personality.traits.HUMOR + local LOVE_PROPENSITY = unit.status.current_soul.personality.traits.LOVE_PROPENSITY + local PERSEVERENCE = unit.status.current_soul.personality.traits.PERSEVERENCE + local POLITENESS = unit.status.current_soul.personality.traits.POLITENESS + local PRIVACY = unit.status.current_soul.personality.traits.PRIVACY + local STRESS_VULNERABILITY = unit.status.current_soul.personality.traits.STRESS_VULNERABILITY + local TOLERANT = unit.status.current_soul.personality.traits.TOLERANT + + local CRAFTSMANSHIP = setbelief.getUnitBelief(unit, df.value_type['CRAFTSMANSHIP']) + local FAMILY = setbelief.getUnitBelief(unit, df.value_type['FAMILY']) + local HARMONY = setbelief.getUnitBelief(unit, df.value_type['HARMONY']) + local INDEPENDENCE = setbelief.getUnitBelief(unit, df.value_type['INDEPENDENCE']) + local KNOWLEDGE = setbelief.getUnitBelief(unit, df.value_type['KNOWLEDGE']) + local LEISURE_TIME = setbelief.getUnitBelief(unit, df.value_type['LEISURE_TIME']) + local NATURE = setbelief.getUnitBelief(unit, df.value_type['NATURE']) + local SKILL = setbelief.getUnitBelief(unit, df.value_type['SKILL']) + + -- Calculate the rating using the defined variables + local rating = (CRAFTSMANSHIP * -0.01) + (FAMILY * -0.09) + (HARMONY * 0.05) + + (INDEPENDENCE * 0.06) + (KNOWLEDGE * -0.30) + (LEISURE_TIME * 0.24) + + (NATURE * 0.27) + (SKILL * -0.21) + (ALTRUISM * 0.13) + + (ANXIETY_PROPENSITY * -0.06) + (BRAVERY * 0.06) + + (CHEER_PROPENSITY * 0.41) + (CURIOUS * -0.06) + (DISCORD * 0.14) + + (DUTIFULNESS * -0.03) + (EMOTIONALLY_OBSESSIVE * -0.13) + + (HUMOR * -0.05) + (LOVE_PROPENSITY * 0.15) + (PERSEVERENCE * -0.07) + + (POLITENESS * -0.14) + (PRIVACY * 0.03) + (STRESS_VULNERABILITY * -0.20) + + (TOLERANT * -0.11) + + return rating +end + + +local function sort_by_mental_stability_desc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = mental_stability(unit1) + local rating2 = mental_stability(unit2) + if rating1 == rating2 then + -- sorting by stress is opposite + -- more mental stable dwarves should have less stress + return sort_by_stress_asc(unit_id_1, unit_id_2) + end + return utils.compare(rating2, rating1) +end + +local function sort_by_mental_stability_asc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = mental_stability(unit1) + local rating2 = mental_stability(unit2) + if rating1 == rating2 then + return sort_by_stress_desc(unit_id_1, unit_id_2) + end + return utils.compare(rating1, rating2) +end + -- Statistical rating that is bigger for more potent dwarves in long run melee military training +-- Rating considers fighting solo opponents -- Wounds are not considered! -local function melee_potential(unit) +local function solo_combat_potential(unit) -- Physical attributes local strength = unit.body.physical_attrs.STRENGTH.max_value local agility = unit.body.physical_attrs.AGILITY.max_value @@ -220,154 +293,130 @@ local function melee_potential(unit) local spatialSense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value - -- Melee potential rating + -- solo combat potential rating local rating = strength*5.8 + kinestheticSense*3.7 + bodySize*2 + agility*2 + endurance*1.8 + willpower*1.5 * spatialSense*1.5 + toughness*1.5 return rating end -local function sort_by_melee_potential_desc(unit_id_1, unit_id_2) +local function sort_by_solo_combat_potential_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = melee_potential(unit1) - local rating2 = melee_potential(unit2) + local rating1 = solo_combat_potential(unit1) + local rating2 = solo_combat_potential(unit2) if rating1 == rating2 then - return sort_by_name_desc(unit_id_1, unit_id_2) + return sort_by_mental_stability_desc(unit_id_1, unit_id_2) end return utils.compare(rating2, rating1) end -local function sort_by_melee_potential_asc(unit_id_1, unit_id_2) +local function sort_by_solo_combat_potential_asc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = melee_potential(unit1) - local rating2 = melee_potential(unit2) + local rating1 = solo_combat_potential(unit1) + local rating2 = solo_combat_potential(unit2) if rating1 == rating2 then - return sort_by_name_asc(unit_id_1, unit_id_2) + return sort_by_mental_stability_asc(unit_id_1, unit_id_2) end return utils.compare(rating1, rating2) end --- Statistical rating that is bigger for more potent dwarves in long run ranged military training +-- Statistical rating that is bigger for more potent dwarves in long run melee military training +-- Rating considers fighting group of opponents -- Wounds are not considered! -local function ranged_potential(unit) +local function group_combat_potential(unit) -- Physical attributes - local agility = unit.body.physical_attrs.AGILITY.max_value - local toughness = unit.body.physical_attrs.TOUGHNESS.max_value + local strength = unit.body.physical_attrs.STRENGTH.max_value local endurance = unit.body.physical_attrs.ENDURANCE.max_value + local bodySize = unit.body.size_info.size_base -- Mental attributes - local focus = unit.status.current_soul.mental_attrs.FOCUS.max_value - local willpower = unit.status.current_soul.mental_attrs.WILLPOWER.max_value local spatialSense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value - -- Ranged potential formula - local rating = agility*3.9 + kinestheticSense*3 + spatialSense*2.9 + toughness*0.9 - + focus*0.7 + endurance*0.7 + willpower*0.6 + -- group combat potential rating + local rating = strength*8.3 + endurance*3 + bodySize*2.8 + kinestheticSense*0.6 + spatialSense*0.4 return rating end -local function sort_by_ranged_potential_desc(unit_id_1, unit_id_2) +local function sort_by_group_combat_potential_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = ranged_potential(unit1) - local rating2 = ranged_potential(unit2) + local rating1 = group_combat_potential(unit1) + local rating2 = group_combat_potential(unit2) if rating1 == rating2 then - return sort_by_name_desc(unit_id_1, unit_id_2) + return sort_by_mental_stability_desc(unit_id_1, unit_id_2) end return utils.compare(rating2, rating1) end -local function sort_by_ranged_potential_asc(unit_id_1, unit_id_2) +local function sort_by_group_combat_potential_asc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = ranged_potential(unit1) - local rating2 = ranged_potential(unit2) + local rating1 = group_combat_potential(unit1) + local rating2 = group_combat_potential(unit2) if rating1 == rating2 then - return sort_by_name_asc(unit_id_1, unit_id_2) + return sort_by_mental_stability_asc(unit_id_1, unit_id_2) end return utils.compare(rating1, rating2) end --- Statistical rating that is bigger for dwarves that are mentally stable -local function mental_stability(unit) - local ALTRUISM = unit.status.current_soul.personality.traits.ALTRUISM - local ANXIETY_PROPENSITY = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY - local BRAVERY = unit.status.current_soul.personality.traits.BRAVERY - local CHEER_PROPENSITY = unit.status.current_soul.personality.traits.CHEER_PROPENSITY - local CURIOUS = unit.status.current_soul.personality.traits.CURIOUS - local DISCORD = unit.status.current_soul.personality.traits.DISCORD - local DUTIFULNESS = unit.status.current_soul.personality.traits.DUTIFULNESS - local EMOTIONALLY_OBSESSIVE = unit.status.current_soul.personality.traits.EMOTIONALLY_OBSESSIVE - local HUMOR = unit.status.current_soul.personality.traits.HUMOR - local LOVE_PROPENSITY = unit.status.current_soul.personality.traits.LOVE_PROPENSITY - local PERSEVERENCE = unit.status.current_soul.personality.traits.PERSEVERENCE - local POLITENESS = unit.status.current_soul.personality.traits.POLITENESS - local PRIVACY = unit.status.current_soul.personality.traits.PRIVACY - local STRESS_VULNERABILITY = unit.status.current_soul.personality.traits.STRESS_VULNERABILITY - local TOLERANT = unit.status.current_soul.personality.traits.TOLERANT - - local CRAFTSMANSHIP = setbelief.getUnitBelief(unit, df.value_type['CRAFTSMANSHIP']) - local FAMILY = setbelief.getUnitBelief(unit, df.value_type['FAMILY']) - local HARMONY = setbelief.getUnitBelief(unit, df.value_type['HARMONY']) - local INDEPENDENCE = setbelief.getUnitBelief(unit, df.value_type['INDEPENDENCE']) - local KNOWLEDGE = setbelief.getUnitBelief(unit, df.value_type['KNOWLEDGE']) - local LEISURE_TIME = setbelief.getUnitBelief(unit, df.value_type['LEISURE_TIME']) - local NATURE = setbelief.getUnitBelief(unit, df.value_type['NATURE']) - local SKILL = setbelief.getUnitBelief(unit, df.value_type['SKILL']) +-- Statistical rating that is bigger for more potent dwarves in long run ranged military training +-- Wounds are not considered! +local function ranged_potential(unit) + -- Physical attributes + local agility = unit.body.physical_attrs.AGILITY.max_value + local toughness = unit.body.physical_attrs.TOUGHNESS.max_value + local endurance = unit.body.physical_attrs.ENDURANCE.max_value - -- Calculate the rating using the defined variables - local rating = (CRAFTSMANSHIP * -0.01) + (FAMILY * -0.09) + (HARMONY * 0.05) - + (INDEPENDENCE * 0.06) + (KNOWLEDGE * -0.30) + (LEISURE_TIME * 0.24) - + (NATURE * 0.27) + (SKILL * -0.21) + (ALTRUISM * 0.13) - + (ANXIETY_PROPENSITY * -0.06) + (BRAVERY * 0.06) - + (CHEER_PROPENSITY * 0.41) + (CURIOUS * -0.06) + (DISCORD * 0.14) - + (DUTIFULNESS * -0.03) + (EMOTIONALLY_OBSESSIVE * -0.13) - + (HUMOR * -0.05) + (LOVE_PROPENSITY * 0.15) + (PERSEVERENCE * -0.07) - + (POLITENESS * -0.14) + (PRIVACY * 0.03) + (STRESS_VULNERABILITY * -0.20) - + (TOLERANT * -0.11) + -- Mental attributes + local focus = unit.status.current_soul.mental_attrs.FOCUS.max_value + local willpower = unit.status.current_soul.mental_attrs.WILLPOWER.max_value + local spatialSense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value + local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value + -- Ranged potential formula + local rating = agility*3.9 + kinestheticSense*3 + spatialSense*2.9 + toughness*0.9 + + focus*0.7 + endurance*0.7 + willpower*0.6 return rating end - -local function sort_by_mental_stability_desc(unit_id_1, unit_id_2) +local function sort_by_ranged_potential_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = mental_stability(unit1) - local rating2 = mental_stability(unit2) + local rating1 = ranged_potential(unit1) + local rating2 = ranged_potential(unit2) if rating1 == rating2 then - return sort_by_name_desc(unit_id_1, unit_id_2) + return sort_by_mental_stability_desc(unit_id_1, unit_id_2) end return utils.compare(rating2, rating1) end -local function sort_by_mental_stability_asc(unit_id_1, unit_id_2) +local function sort_by_ranged_potential_asc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = mental_stability(unit1) - local rating2 = mental_stability(unit2) + local rating1 = ranged_potential(unit1) + local rating2 = ranged_potential(unit2) if rating1 == rating2 then - return sort_by_name_asc(unit_id_1, unit_id_2) + return sort_by_mental_stability_asc(unit_id_1, unit_id_2) end return utils.compare(rating1, rating2) end @@ -402,7 +451,7 @@ SquadAssignmentOverlay.ATTRS{ default_pos={x=-33, y=40}, default_enabled=true, viewscreens='dwarfmode/UnitSelector/SQUAD_FILL_POSITION', - frame={w=74, h=9}, + frame={w=84, h=9}, frame_style=gui.FRAME_PANEL, frame_background=gui.CLEAR_PEN, } @@ -441,12 +490,14 @@ function SquadAssignmentOverlay:init() {label='spear skill'..CH_UP, value=SORT_FNS.sort_by_spear_asc, pen=COLOR_YELLOW}, {label='crossbow skill'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc, pen=COLOR_GREEN}, {label='crossbow skill'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc, pen=COLOR_YELLOW}, - {label='melee potential'..CH_DN, value=sort_by_melee_potential_desc, pen=COLOR_GREEN}, - {label='melee potential'..CH_UP, value=sort_by_melee_potential_asc, pen=COLOR_YELLOW}, - {label='ranged potential'..CH_DN, value=sort_by_ranged_potential_desc, pen=COLOR_GREEN}, - {label='ranged potential'..CH_UP, value=sort_by_ranged_potential_asc, pen=COLOR_YELLOW}, {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, + {label='solo combat potential'..CH_DN, value=sort_by_solo_combat_potential_desc, pen=COLOR_GREEN}, + {label='solo combat potential'..CH_UP, value=sort_by_solo_combat_potential_asc, pen=COLOR_YELLOW}, + {label='group combat potential'..CH_DN, value=sort_by_group_combat_potential_desc, pen=COLOR_GREEN}, + {label='group combat potential'..CH_UP, value=sort_by_group_combat_potential_asc, pen=COLOR_YELLOW}, + {label='ranged potential'..CH_DN, value=sort_by_ranged_potential_desc, pen=COLOR_GREEN}, + {label='ranged potential'..CH_UP, value=sort_by_ranged_potential_asc, pen=COLOR_YELLOW}, }, initial_option=SORT_FNS.sort_by_any_melee_desc, on_change=self:callback('refresh_list', 'sort'), @@ -530,7 +581,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_axe', - frame={t=2, l=2, w=4}, + frame={t=2, l=0, w=4}, options={ {label='axe', value=sort_noop}, {label='axe'..CH_DN, value=SORT_FNS.sort_by_axe_desc, pen=COLOR_GREEN}, @@ -541,7 +592,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_sword', - frame={t=2, l=9, w=6}, + frame={t=2, l=7, w=6}, options={ {label='sword', value=sort_noop}, {label='sword'..CH_DN, value=SORT_FNS.sort_by_sword_desc, pen=COLOR_GREEN}, @@ -552,7 +603,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_mace', - frame={t=2, l=18, w=5}, + frame={t=2, l=16, w=5}, options={ {label='mace', value=sort_noop}, {label='mace'..CH_DN, value=SORT_FNS.sort_by_mace_desc, pen=COLOR_GREEN}, @@ -563,7 +614,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_hammer', - frame={t=2, l=25, w=7}, + frame={t=2, l=23, w=7}, options={ {label='hammer', value=sort_noop}, {label='hammer'..CH_DN, value=SORT_FNS.sort_by_hammer_desc, pen=COLOR_GREEN}, @@ -574,7 +625,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_spear', - frame={t=2, l=36, w=6}, + frame={t=2, l=34, w=6}, options={ {label='spear', value=sort_noop}, {label='spear'..CH_DN, value=SORT_FNS.sort_by_spear_desc, pen=COLOR_GREEN}, @@ -585,7 +636,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_crossbow', - frame={t=2, l=45, w=9}, + frame={t=2, l=43, w=9}, options={ {label='crossbow', value=sort_noop}, {label='crossbow'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc, pen=COLOR_GREEN}, @@ -595,37 +646,48 @@ function SquadAssignmentOverlay:init() on_change=self:callback('refresh_list', 'sort_crossbow'), }, widgets.CycleHotkeyLabel{ - view_id='sort_melee_potential', - frame={t=4, l=2, w=16}, + view_id='sort_mental_stability', + frame={t=4, l=0, w=17}, + options={ + {label='mental stability', value=sort_noop}, + {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, + {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_mental_stability'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_solo_combat_potential', + frame={t=4, l=18, w=22}, options={ - {label='melee potential', value=sort_noop}, - {label='melee potential'..CH_DN, value=sort_by_melee_potential_desc, pen=COLOR_GREEN}, - {label='melee potential'..CH_UP, value=sort_by_melee_potential_asc, pen=COLOR_YELLOW}, + {label='solo combat potential', value=sort_noop}, + {label='solo combat potential'..CH_DN, value=sort_by_solo_combat_potential_desc, pen=COLOR_GREEN}, + {label='solo combat potential'..CH_UP, value=sort_by_solo_combat_potential_asc, pen=COLOR_YELLOW}, }, option_gap=0, - on_change=self:callback('refresh_list', 'sort_melee_potential'), + on_change=self:callback('refresh_list', 'sort_solo_combat_potential'), }, widgets.CycleHotkeyLabel{ - view_id='sort_ranged_potential', - frame={t=4, l=21, w=17}, + view_id='sort_group_combat_potential', + frame={t=4, l=41, w=23}, options={ - {label='ranged potential', value=sort_noop}, - {label='ranged potential'..CH_DN, value=sort_by_ranged_potential_desc, pen=COLOR_GREEN}, - {label='ranged potential'..CH_UP, value=sort_by_ranged_potential_asc, pen=COLOR_YELLOW}, + {label='group combat potential', value=sort_noop}, + {label='group combat potential'..CH_DN, value=sort_by_group_combat_potential_desc, pen=COLOR_GREEN}, + {label='group combat potential'..CH_UP, value=sort_by_group_combat_potential_asc, pen=COLOR_YELLOW}, }, option_gap=0, - on_change=self:callback('refresh_list', 'sort_ranged_potential'), + on_change=self:callback('refresh_list', 'sort_group_combat_potential'), }, widgets.CycleHotkeyLabel{ - view_id='sort_mental_stability', - frame={t=4, l=41, w=17}, + view_id='sort_ranged_potential', + frame={t=4, l=65, w=17}, options={ - {label='mental stability', value=sort_noop}, - {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, - {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, + {label='ranged potential', value=sort_noop}, + {label='ranged potential'..CH_DN, value=sort_by_ranged_potential_desc, pen=COLOR_GREEN}, + {label='ranged potential'..CH_UP, value=sort_by_ranged_potential_asc, pen=COLOR_YELLOW}, }, option_gap=0, - on_change=self:callback('refresh_list', 'sort_mental_stability'), + on_change=self:callback('refresh_list', 'sort_ranged_potential'), }, } }, @@ -704,9 +766,10 @@ local SORT_WIDGET_NAMES = { 'sort_hammer', 'sort_spear', 'sort_crossbow', - 'sort_melee_potential', - 'sort_ranged_potential', 'sort_mental_stability', + 'sort_solo_combat_potential', + 'sort_group_combat_potential', + 'sort_ranged_potential', } function SquadAssignmentOverlay:refresh_list(sort_widget, sort_fn) From 6c5163af9ed458cbc5d69ec2d24aea89960b4ef7 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 27 Aug 2023 22:28:03 +0300 Subject: [PATCH 396/851] adjust adopt region reset step --- library/modules/Textures.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 31575dca0..48bc71e3c 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -178,7 +178,7 @@ struct tracking_stage_adopt_region : df::viewscreen_adopt_regionst { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { this->m_cur_step = this->cur_step; - if (this->m_cur_step == 2) + if (this->m_cur_step == 1) reset_texpos(); } INTERPOSE_NEXT(logic)(); From 4fb6b09b30abec70b742eaf9bcd90addde0185b8 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 28 Aug 2023 06:58:30 +0300 Subject: [PATCH 397/851] move textures to separate lua module --- library/lua/gui.lua | 65 +++------------------ library/lua/gui/textures.lua | 93 +++++++++++++++++++++++++++++++ plugins/lua/buildingplan/pens.lua | 19 ++++--- 3 files changed, 111 insertions(+), 66 deletions(-) create mode 100644 library/lua/gui/textures.lua diff --git a/library/lua/gui.lua b/library/lua/gui.lua index d94c1373b..ac25381ca 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -2,6 +2,7 @@ local _ENV = mkmodule('gui') +local textures = require('gui.textures') local utils = require('utils') local dscreen = dfhack.screen @@ -885,56 +886,6 @@ ZScreenModal.ATTRS{ pass_mouse_clicks = false, } --- DFHack textures --------------------------- - --- Preloaded DFHack Assets --- Use this handles if you need to get dfhack standard textures -local texpos_handles = { - green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), - red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12), - icons = dfhack.textures.loadTileset('hack/data/art/icons.png', 8, 12), - on_off = dfhack.textures.loadTileset('hack/data/art/on-off.png', 8, 12), - control_panel = dfhack.textures.loadTileset('hack/data/art/control-panel.png', 8, 12), - border_thin = dfhack.textures.loadTileset('hack/data/art/border-thin.png', 8, 12), - border_medium = dfhack.textures.loadTileset('hack/data/art/border-medium.png', 8, 12), - border_bold = dfhack.textures.loadTileset('hack/data/art/border-bold.png', 8, 12), - border_panel = dfhack.textures.loadTileset('hack/data/art/border-panel.png', 8, 12), - border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), -} - --- Methods to obtain valid texposes by handles -function tp_green_pin(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.green_pin[offset]) -end -function tp_red_pin(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.red_pin[offset]) -end -function tp_icons(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.icons[offset]) -end -function tp_on_off(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.on_off[offset]) -end -function tp_control_panel(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.control_panel[offset]) -end -function tp_border_thin(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.border_thin[offset]) -end -function tp_border_medium(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.border_medium[offset]) -end -function tp_border_bold(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.border_bold[offset]) -end -function tp_border_panel(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.border_panel[offset]) -end -function tp_border_window(offset) - return dfhack.textures.getTexposByHandle(texpos_handles.border_window[offset]) -end - -- Framed screen object -------------------------- @@ -977,28 +928,28 @@ local function make_frame(tp, double_line) end function FRAME_WINDOW(resizable) - local frame = make_frame(tp_border_window, true) + local frame = make_frame(textures.tp_border_window, true) if not resizable then - frame.rb_frame_pen = to_pen{ tile=curry(tp_border_panel, 17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } + frame.rb_frame_pen = to_pen{ tile=curry(textures.tp_border_panel, 17), ch=double_line and 188 or 217, fg=COLOR_GREY, bg=COLOR_BLACK } end return frame end function FRAME_PANEL(resizable) - return make_frame(tp_border_panel, false) + return make_frame(textures.tp_border_panel, false) end function FRAME_MEDIUM(resizable) - return make_frame(tp_border_medium, false) + return make_frame(textures.tp_border_medium, false) end function FRAME_BOLD(resizable) - return make_frame(tp_border_bold, true) + return make_frame(textures.tp_border_bold, true) end function FRAME_INTERIOR(resizable) - local frame = make_frame(tp_border_thin, false) + local frame = make_frame(textures.tp_border_thin, false) frame.signature_pen = false return frame end function FRAME_INTERIOR_MEDIUM(resizable) - local frame = make_frame(tp_border_medium, false) + local frame = make_frame(textures.tp_border_medium, false) frame.signature_pen = false return frame end diff --git a/library/lua/gui/textures.lua b/library/lua/gui/textures.lua new file mode 100644 index 000000000..6557b6e02 --- /dev/null +++ b/library/lua/gui/textures.lua @@ -0,0 +1,93 @@ +-- DFHack textures + +local _ENV = mkmodule('gui.textures') + +---@alias TexposHandle integer + +-- Preloaded DFHack Assets. +-- Use this handles if you need to get dfhack standard textures. +---@type table +local texpos_handles = { + green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), + red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12), + icons = dfhack.textures.loadTileset('hack/data/art/icons.png', 8, 12), + on_off = dfhack.textures.loadTileset('hack/data/art/on-off.png', 8, 12), + control_panel = dfhack.textures.loadTileset('hack/data/art/control-panel.png', 8, 12), + border_thin = dfhack.textures.loadTileset('hack/data/art/border-thin.png', 8, 12), + border_medium = dfhack.textures.loadTileset('hack/data/art/border-medium.png', 8, 12), + border_bold = dfhack.textures.loadTileset('hack/data/art/border-bold.png', 8, 12), + border_panel = dfhack.textures.loadTileset('hack/data/art/border-panel.png', 8, 12), + border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), +} + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_green_pin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.green_pin[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_red_pin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.red_pin[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_icons(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.icons[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_on_off(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.on_off[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_control_panel(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.control_panel[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_border_thin(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_thin[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_border_medium(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_medium[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return TexposHandle +function tp_border_bold(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_bold[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_border_panel(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_panel[offset]) +end + +-- Get valid texpos for preloaded texture in tileset +---@param offset integer +---@return integer +function tp_border_window(offset) + return dfhack.textures.getTexposByHandle(texpos_handles.border_window[offset]) +end + +return _ENV diff --git a/plugins/lua/buildingplan/pens.lua b/plugins/lua/buildingplan/pens.lua index 817070b76..2ab76da06 100644 --- a/plugins/lua/buildingplan/pens.lua +++ b/plugins/lua/buildingplan/pens.lua @@ -1,6 +1,7 @@ local _ENV = mkmodule('plugins.buildingplan.pens') local gui = require('gui') +local textures = require('gui.textures') GOOD_TILE_PEN, BAD_TILE_PEN = nil, nil VERT_TOP_PEN, VERT_MID_PEN, VERT_BOT_PEN = nil, nil, nil @@ -15,17 +16,17 @@ 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)} - VERT_TOP_PEN = to_pen { tile = curry(gui.tp_border_thin, 11), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_MID_PEN = to_pen { tile = curry(gui.tp_border_thin, 5), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } - VERT_BOT_PEN = to_pen { tile = curry(gui.tp_border_thin, 12), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_TOP_PEN = to_pen { tile = curry(textures.tp_border_thin, 11), ch = 194, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_MID_PEN = to_pen { tile = curry(textures.tp_border_thin, 5), ch = 179, fg = COLOR_GREY, bg = COLOR_BLACK } + VERT_BOT_PEN = to_pen { tile = curry(textures.tp_border_thin, 12), ch = 193, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_LEFT_PEN = to_pen { tile = curry(gui.tp_border_medium, 13), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_MID_PEN = to_pen { tile = curry(gui.tp_border_medium, 6), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } - HORI_RIGHT_PEN = to_pen { tile = curry(gui.tp_border_medium, 14), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_LEFT_PEN = to_pen { tile = curry(textures.tp_border_medium, 13), ch = 195, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_MID_PEN = to_pen { tile = curry(textures.tp_border_medium, 6), ch = 196, fg = COLOR_GREY, bg = COLOR_BLACK } + HORI_RIGHT_PEN = to_pen { tile = curry(textures.tp_border_medium, 14), ch = 180, fg = COLOR_GREY, bg = COLOR_BLACK } - BUTTON_START_PEN = to_pen { tile = curry(gui.tp_control_panel, 14), ch = '[', fg = COLOR_YELLOW } - BUTTON_END_PEN = to_pen { tile = curry(gui.tp_control_panel, 16), ch = ']', fg = COLOR_YELLOW } - SELECTED_ITEM_PEN = to_pen { tile = curry(gui.tp_control_panel, 10), ch = string.char(251), fg = COLOR_YELLOW } + BUTTON_START_PEN = to_pen { tile = curry(textures.tp_control_panel, 14), ch = '[', fg = COLOR_YELLOW } + BUTTON_END_PEN = to_pen { tile = curry(textures.tp_control_panel, 16), ch = ']', fg = COLOR_YELLOW } + SELECTED_ITEM_PEN = to_pen { tile = curry(textures.tp_control_panel, 10), ch = string.char(251), fg = COLOR_YELLOW } MINI_TEXT_PEN = to_pen{fg=COLOR_BLACK, bg=COLOR_GREY} MINI_TEXT_HPEN = to_pen{fg=COLOR_BLACK, bg=COLOR_WHITE} From 3ce2909309fdc335d8e791aff4d5e6261594affa Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 28 Aug 2023 06:20:58 +0000 Subject: [PATCH 398/851] 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 dfa86bba5..ae56641b1 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit dfa86bba5c653b6650b8e8c27467d87c28c878fa +Subproject commit ae56641b1ae986a01ebd64c701b7758d64a41d51 diff --git a/scripts b/scripts index 734ed2c2d..830034287 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 734ed2c2d8556fc440c7913ac63610c981b40d5e +Subproject commit 830034287f6d1c970666d00c80c815a9b331f2d2 From 6f11812729e42e720544e7157b29e728cf4fc667 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 28 Aug 2023 10:00:39 +0300 Subject: [PATCH 399/851] create and delete textures --- docs/about/Authors.rst | 1 + library/LuaApi.cpp | 42 ++++++++++ library/include/LuaTools.h | 11 +++ library/include/modules/DFSDL.h | 2 + library/include/modules/Textures.h | 21 +++++ library/modules/DFSDL.cpp | 15 +++- library/modules/Textures.cpp | 127 ++++++++++++++++++++--------- 7 files changed, 179 insertions(+), 40 deletions(-) diff --git a/docs/about/Authors.rst b/docs/about/Authors.rst index cf74c6412..ba556ab64 100644 --- a/docs/about/Authors.rst +++ b/docs/about/Authors.rst @@ -203,6 +203,7 @@ Sebastian Wolfertz Enkrod SeerSkye SeerSkye seishuuu seishuuu Seth Woodworth sethwoodworth +shevernitskiy shevernitskiy Shim Panze Shim-Panze Silver silverflyone simon diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index a1821d2fb..241d1888b 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1775,9 +1775,51 @@ static int textures_getTexposByHandle(lua_State *state) return 1; } +static int textures_deleteHandle(lua_State *state) +{ + if (lua_isinteger(state,1)) { + auto handle = luaL_checkunsigned(state, 1); + Textures::deleteHandle(handle); + } else if (lua_istable(state,1)) { + std::vector handles; + Lua::GetVector(state, handles); + for (auto& handle: handles) { + Textures::deleteHandle(handle); + } + } + return 0; +} + +static int textures_createTile(lua_State *state) +{ + std::vector pixels; + Lua::GetVector(state, pixels); + auto tile_w = luaL_checkint(state, 2); + auto tile_h = luaL_checkint(state, 3); + auto handle = Textures::createTile(pixels, tile_w, tile_h); + Lua::Push(state, handle); + return 1; +} + +static int textures_createTileset(lua_State *state) +{ + std::vector pixels; + Lua::GetVector(state, pixels); + auto texture_w = luaL_checkint(state, 2); + auto texture_h = luaL_checkint(state, 3); + auto tile_w = luaL_checkint(state, 4); + auto tile_h = luaL_checkint(state, 5); + auto handles = Textures::createTileset(pixels, texture_w, texture_h, tile_w, tile_h); + Lua::PushVector(state, handles); + return 1; +} + static const luaL_Reg dfhack_textures_funcs[] = { { "loadTileset", textures_loadTileset }, { "getTexposByHandle", textures_getTexposByHandle }, + { "deleteHandle", textures_deleteHandle }, + { "createTile", textures_createTile }, + { "createTileset", textures_createTileset }, { NULL, NULL } }; diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h index cab3ee9cc..188d63854 100644 --- a/library/include/LuaTools.h +++ b/library/include/LuaTools.h @@ -410,6 +410,17 @@ namespace DFHack {namespace Lua { } } + template + requires std::is_arithmetic_v + void GetVector(lua_State *state, std::vector &pvec, int idx = 1) { + lua_pushnil(state); // first key + while (lua_next(state, idx) != 0) + { + pvec.push_back(lua_tointeger(state, -1)); + lua_pop(state, 1); // remove value, leave key + } + } + 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); diff --git a/library/include/modules/DFSDL.h b/library/include/modules/DFSDL.h index 36dd641d5..b70255ec8 100644 --- a/library/include/modules/DFSDL.h +++ b/library/include/modules/DFSDL.h @@ -48,6 +48,8 @@ DFHACK_EXPORT void DFSDL_FreeSurface(SDL_Surface *surface); // DFHACK_EXPORT int DFSDL_SemPost(SDL_sem *sem); DFHACK_EXPORT int DFSDL_PushEvent(SDL_Event *event); DFHACK_EXPORT void DFSDL_free(void *ptr); +DFHACK_EXPORT SDL_PixelFormat* DFSDL_AllocFormat(uint32_t pixel_format); +DFHACK_EXPORT SDL_Surface* DFSDL_CreateRGBSurfaceWithFormat(uint32_t flags, int width, int height, int depth, uint32_t format); // submitted and returned text is UTF-8 // see wrapper functions below for cp-437 variants diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index fa1f743be..e371df90e 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -43,6 +43,27 @@ DFHACK_EXPORT std::vector loadTileset(const std::string& file, */ DFHACK_EXPORT long getTexposByHandle(TexposHandle handle); +/** + * Delete all info about texture by TexposHandle + */ +DFHACK_EXPORT void deleteHandle(TexposHandle handle); + +/** + * Create new texture with RGBA32 format and pixels as data. + * Register this texture and return TexposHandle. + */ +DFHACK_EXPORT TexposHandle createTile(std::vector& pixels, int tile_px_w = TILE_WIDTH_PX, + int tile_px_h = TILE_HEIGHT_PX); + +/** + * Create new textures as tileset with RGBA32 format and pixels as data. + * Register this textures and return vector of TexposHandle. + */ +DFHACK_EXPORT std::vector createTileset(std::vector& pixels, + int texture_px_w, int texture_px_h, + int tile_px_w = TILE_WIDTH_PX, + int tile_px_h = TILE_HEIGHT_PX); + /** * Call this on DFHack init just once to setup interposed handlers and * init static assets. diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp index 72105b2e6..398a9c8b2 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -41,6 +41,8 @@ SDL_bool (*g_SDL_HasClipboardText)(); int (*g_SDL_SetClipboardText)(const char *text); char * (*g_SDL_GetClipboardText)(); void (*g_SDL_free)(void *); +SDL_PixelFormat* (*g_SDL_AllocFormat)(uint32_t pixel_format) = nullptr; +SDL_Surface* (*g_SDL_CreateRGBSurfaceWithFormat)(uint32_t flags, int width, int height, int depth, uint32_t format) = nullptr; bool DFSDL::init(color_ostream &out) { for (auto &lib_str : SDL_LIBS) { @@ -81,7 +83,9 @@ bool DFSDL::init(color_ostream &out) { bind(g_sdl_handle, SDL_SetClipboardText); bind(g_sdl_handle, SDL_GetClipboardText); bind(g_sdl_handle, SDL_free); - #undef bind + bind(g_sdl_handle, SDL_AllocFormat); + bind(g_sdl_handle, SDL_CreateRGBSurfaceWithFormat); +#undef bind DEBUG(dfsdl,out).print("sdl successfully loaded\n"); return true; @@ -147,6 +151,15 @@ int DFSDL::DFSDL_SetClipboardText(const char *text) { return g_SDL_SetClipboardText(text); } +SDL_PixelFormat* DFSDL::DFSDL_AllocFormat(uint32_t pixel_format) { + return g_SDL_AllocFormat(pixel_format); +} + +SDL_Surface* DFSDL::DFSDL_CreateRGBSurfaceWithFormat(uint32_t flags, int width, int height, int depth, uint32_t format) { + return g_SDL_CreateRGBSurfaceWithFormat(flags, width, height, depth, format); +} + + DFHACK_EXPORT std::string DFHack::getClipboardTextCp437() { if (!g_sdl_handle || g_SDL_HasClipboardText() != SDL_TRUE) return ""; diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 48bc71e3c..26a769e48 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -1,4 +1,5 @@ #include +#include #include #include "Internal.h" @@ -30,6 +31,10 @@ static std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_surface; static std::mutex g_adding_mutex; +// it is SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32 +// initialized inplace to avoid including SDL_pixels.h +static const uint32_t RGBA32 = 376840196; + // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -38,28 +43,14 @@ static std::mutex g_adding_mutex; // It uses the same pixel format (RGBA, R at lowest address) regardless of // hardware. SDL_Surface* canonicalize_format(SDL_Surface* src) { - SDL_PixelFormat fmt; - fmt.palette = NULL; - fmt.BitsPerPixel = 32; - fmt.BytesPerPixel = 4; - fmt.Rloss = fmt.Gloss = fmt.Bloss = fmt.Aloss = 0; -#if SDL_BYTEORDER == SDL_BIG_ENDIAN - fmt.Rshift = 24; - fmt.Gshift = 16; - fmt.Bshift = 8; - fmt.Ashift = 0; -#else - fmt.Rshift = 0; - fmt.Gshift = 8; - fmt.Bshift = 16; - fmt.Ashift = 24; -#endif - fmt.Rmask = 255 << fmt.Rshift; - fmt.Gmask = 255 << fmt.Gshift; - fmt.Bmask = 255 << fmt.Bshift; - fmt.Amask = 255 << fmt.Ashift; - - SDL_Surface* tgt = DFSDL_ConvertSurface(src, &fmt, SDL_SWSURFACE); + // however we have null check after DFIMG_Load + // in loadTileset() (the only consumer of this method) + // it's better put nullcheck here as well + if (!src) + return src; + + auto fmt = DFSDL_AllocFormat(RGBA32); + SDL_Surface* tgt = DFSDL_ConvertSurface(src, fmt, SDL_SWSURFACE); DFSDL_FreeSurface(src); for (int x = 0; x < tgt->w; ++x) { for (int y = 0; y < tgt->h; ++y) { @@ -71,6 +62,7 @@ SDL_Surface* canonicalize_format(SDL_Surface* src) { } } } + return tgt; } @@ -82,31 +74,34 @@ static long add_texture(SDL_Surface* surface) { return texpos; } -TexposHandle Textures::loadTexture(SDL_Surface* surface) { - if (!surface) - return 0; // should be some error, i guess +// delete surface from texture raws +static void delete_texture(long texpos) { + std::lock_guard lg_add_texture(g_adding_mutex); + if (texpos >= enabler->textures.raws.size()) + return; + enabler->textures.raws[texpos] = NULL; +} - auto handle = reinterpret_cast(surface); - g_handle_to_surface.emplace(handle, surface); - surface->refcount++; // prevent destruct on next FreeSurface by game - auto texpos = add_texture(surface); - g_handle_to_texpos.emplace(handle, texpos); - return handle; +// create new surface with RGBA32 format and pixels as data +SDL_Surface* create_texture(std::vector& pixels, int texture_px_w, int texture_px_h) { + auto surface = DFSDL_CreateRGBSurfaceWithFormat(0, texture_px_w, texture_px_h, 32, RGBA32); + for (auto i = 0; i < pixels.size() && i < texture_px_w * texture_px_h; i++) { + uint32_t* p = (uint32_t*)surface->pixels + i; + *p = pixels[i]; + } + return surface; } -std::vector Textures::loadTileset(const std::string& file, int tile_px_w, - int tile_px_h) { +// convert single surface into tiles according w/h +// register tiles in texture raws and return handles +std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int tile_px_h) { std::vector handles{}; - - SDL_Surface* surface = DFIMG_Load(file.c_str()); - if (!surface) { - ERR(textures).printerr("unable to load textures from '%s'\n", file.c_str()); + if (!surface) return handles; - } - surface = canonicalize_format(surface); int dimx = surface->w / tile_px_w; int dimy = surface->h / tile_px_h; + for (int y = 0; y < dimy; y++) { for (int x = 0; x < dimx; x++) { SDL_Surface* tile = DFSDL_CreateRGBSurface( @@ -120,6 +115,32 @@ std::vector Textures::loadTileset(const std::string& file, int til } DFSDL_FreeSurface(surface); + return handles; +} + +TexposHandle Textures::loadTexture(SDL_Surface* surface) { + if (!surface) + return 0; // should be some error, i guess + + auto handle = reinterpret_cast(surface); + g_handle_to_surface.emplace(handle, surface); + surface->refcount++; // prevent destruct on next FreeSurface by game + auto texpos = add_texture(surface); + g_handle_to_texpos.emplace(handle, texpos); + return handle; +} + +std::vector Textures::loadTileset(const std::string& file, int tile_px_w, + int tile_px_h) { + SDL_Surface* surface = DFIMG_Load(file.c_str()); + if (!surface) { + ERR(textures).printerr("unable to load textures from '%s'\n", file.c_str()); + return std::vector{}; + } + + surface = canonicalize_format(surface); + auto handles = slice_tileset(surface, tile_px_w, tile_px_h); + DEBUG(textures).print("loaded %zd textures from '%s'\n", handles.size(), file.c_str()); return handles; @@ -142,6 +163,34 @@ long Textures::getTexposByHandle(TexposHandle handle) { return -1; } +TexposHandle Textures::createTile(std::vector& pixels, int tile_px_w, int tile_px_h) { + auto texture = create_texture(pixels, tile_px_w, tile_px_h); + auto handle = Textures::loadTexture(texture); + return handle; +} + +std::vector Textures::createTileset(std::vector& pixels, int texture_px_w, + int texture_px_h, int tile_px_w, int tile_px_h) { + auto texture = create_texture(pixels, texture_px_w, texture_px_h); + auto handles = slice_tileset(texture, tile_px_w, tile_px_h); + return handles; +} + +void Textures::deleteHandle(TexposHandle handle) { + auto texpos = Textures::getTexposByHandle(handle); + if (texpos > 0) + delete_texture(texpos); + if (g_handle_to_texpos.contains(handle)) + g_handle_to_texpos.erase(handle); + if (g_handle_to_surface.contains(handle)) { + auto surface = g_handle_to_surface[handle]; + for (auto i = 0; i < surface->refcount; i++) { + DFSDL_FreeSurface(surface); + } + g_handle_to_surface.erase(handle); + } +} + static void reset_texpos() { g_handle_to_texpos.clear(); } From 51baa0d674999fe786dbfaf4d089940cfefca3cc Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 28 Aug 2023 10:46:59 +0300 Subject: [PATCH 400/851] fix linux build --- library/modules/Textures.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 26a769e48..85ce5d2b6 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -77,7 +77,8 @@ static long add_texture(SDL_Surface* surface) { // delete surface from texture raws static void delete_texture(long texpos) { std::lock_guard lg_add_texture(g_adding_mutex); - if (texpos >= enabler->textures.raws.size()) + auto pos = static_cast(texpos); + if (pos >= enabler->textures.raws.size()) return; enabler->textures.raws[texpos] = NULL; } @@ -85,7 +86,7 @@ static void delete_texture(long texpos) { // create new surface with RGBA32 format and pixels as data SDL_Surface* create_texture(std::vector& pixels, int texture_px_w, int texture_px_h) { auto surface = DFSDL_CreateRGBSurfaceWithFormat(0, texture_px_w, texture_px_h, 32, RGBA32); - for (auto i = 0; i < pixels.size() && i < texture_px_w * texture_px_h; i++) { + for (size_t i = 0; i < pixels.size() && i < texture_px_w * texture_px_h; i++) { uint32_t* p = (uint32_t*)surface->pixels + i; *p = pixels[i]; } From 4b0219e2254f347850cf24450b62a304a0bf62d0 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 28 Aug 2023 10:56:08 +0300 Subject: [PATCH 401/851] fix stupid linux build again --- library/modules/Textures.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 85ce5d2b6..e6f6d5aaa 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -86,7 +86,8 @@ static void delete_texture(long texpos) { // create new surface with RGBA32 format and pixels as data SDL_Surface* create_texture(std::vector& pixels, int texture_px_w, int texture_px_h) { auto surface = DFSDL_CreateRGBSurfaceWithFormat(0, texture_px_w, texture_px_h, 32, RGBA32); - for (size_t i = 0; i < pixels.size() && i < texture_px_w * texture_px_h; i++) { + auto canvas_length = static_cast(texture_px_w * texture_px_h); + for (size_t i = 0; i < pixels.size() && i < canvas_length; i++) { uint32_t* p = (uint32_t*)surface->pixels + i; *p = pixels[i]; } From 423bba2c2491760be15ef3fd817fcef026236c95 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 28 Aug 2023 13:27:46 -0700 Subject: [PATCH 402/851] pass getAnyStockpile and getAnyCivZone through ZScreens --- docs/changelog.txt | 2 ++ docs/dev/Lua API.rst | 33 +++++++++----------------------- library/LuaApi.cpp | 2 ++ library/include/modules/Screen.h | 6 ++++++ library/lua/gui.lua | 6 ++++++ library/modules/Gui.cpp | 15 +++++++++------ library/modules/Screen.cpp | 16 ++++++++++++++++ 7 files changed, 50 insertions(+), 30 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0ef3d5cf5..2eb4c39fa 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -75,6 +75,7 @@ Template for new versions: - ``Items::getValue()``: remove ``caravan_buying`` parameter since the identity of the selling party doesn't actually affect the item value - `RemoteFortressReader`: add a ``force_reload`` option to the GetBlockList RPC API to return blocks regardless of whether they have changed since the last request - ``Units``: new animal propery check functions ``isMarkedForTraining(unit)``, ``isMarkedForTaming(unit)``, ``isMarkedForWarTraining(unit)``, and ``isMarkedForHuntTraining(unit)`` +- ``Gui``: ``getAnyStockpile`` and ``getAnyCivzone`` (along with their ``getSelected`` variants) now work through layers of ZScreens. This means that they will still return valid results even if a DFHack tool window is in the foereground. ## Lua - ``new()``: improved error handling so that certain errors that were previously uncatchable (creating objects with members with unknown vtables) are now catchable with ``pcall()`` @@ -83,6 +84,7 @@ Template for new versions: - ``widgets.Panel``: new functions to override instead of setting corresponding properties (useful when subclassing instead of just setting attributes): ``onDragBegin``, ``onDragEnd``, ``onResizeBegin``, ``onResizeEnd`` - ``dfhack.screen.readTile()``: now populates extended tile property fields (like ``top_of_text``) in the returned ``Pen`` object - ``dfhack.units``: new animal propery check functions ``isMarkedForTraining(unit)``, ``isMarkedForTaming(unit)``, ``isMarkedForWarTraining(unit)``, and ``isMarkedForHuntTraining(unit)`` +- ``dfhack.gui``: new ``getAnyCivZone`` and ``getAnyStockpile`` functions; also behavior of ``getSelectedCivZone`` and ``getSelectedStockpile`` functions has changes as per the related API notes ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index d14e56640..4fe623e85 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1010,41 +1010,26 @@ General-purpose selections ~~~~~~~~~~~~~~~~~~~~~~~~~~ * ``dfhack.gui.getSelectedWorkshopJob([silent])`` - - When a job is selected in :kbd:`q` mode, returns the job, else - prints error unless silent and returns *nil*. - * ``dfhack.gui.getSelectedJob([silent])`` - - Returns the job selected in a workshop or unit/jobs screen. - * ``dfhack.gui.getSelectedUnit([silent])`` - - Returns the unit selected via :kbd:`v`, :kbd:`k`, unit/jobs, or - a full-screen item view of a cage or suchlike. - * ``dfhack.gui.getSelectedItem([silent])`` - - Returns the item selected via :kbd:`v` ->inventory, :kbd:`k`, :kbd:`t`, or - a full-screen item view of a container. Note that in the - last case, the highlighted *contained item* is returned, not - the container itself. - * ``dfhack.gui.getSelectedBuilding([silent])`` - - Returns the building selected via :kbd:`q`, :kbd:`t`, :kbd:`k` or :kbd:`i`. - * ``dfhack.gui.getSelectedCivZone([silent])`` - - Returns the zone currently selected via :kbd:`z` - +* ``dfhack.gui.getSelectedStockpile([silent])`` * ``dfhack.gui.getSelectedPlant([silent])`` - Returns the plant selected via :kbd:`k`. + Returns the currently selected in-game object or the indicated thing + associated with the selected in-game object. For example, Calling + ``getSelectedJob`` when a building is selected will return the job associated + with the building (e.g. the ``ConstructBuilding`` job). If ``silent`` is + ommitted or set to ``false`` and a selected object cannot be found, then an + error is printed to the console. * ``dfhack.gui.getAnyUnit(screen)`` * ``dfhack.gui.getAnyItem(screen)`` * ``dfhack.gui.getAnyBuilding(screen)`` +* ``dfhack.gui.getAnyCivZone(screen)`` +* ``dfhack.gui.getAnyStockpile(screen)`` * ``dfhack.gui.getAnyPlant(screen)`` Similar to the corresponding ``getSelected`` functions, but operate on the diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index a1821d2fb..e98853377 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1527,6 +1527,8 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = { WRAPM(Gui, getAnyUnit), WRAPM(Gui, getAnyItem), WRAPM(Gui, getAnyBuilding), + WRAPM(Gui, getAnyCivZone), + WRAPM(Gui, getAnyStockpile), WRAPM(Gui, getAnyPlant), WRAPM(Gui, writeToGamelog), WRAPM(Gui, makeAnnouncement), diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index b918ab6c2..681398f89 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -36,6 +36,8 @@ distribution. #include "DataDefs.h" #include "df/graphic.h" #include "df/viewscreen.h" +#include "df/building_civzonest.h" +#include "df/building_stockpilest.h" #include "df/zoom_commands.h" #include "modules/GuiHooks.h" @@ -362,6 +364,8 @@ namespace DFHack virtual df::item *getSelectedItem() { return nullptr; } virtual df::job *getSelectedJob() { return nullptr; } virtual df::building *getSelectedBuilding() { return nullptr; } + virtual df::building_stockpilest *getSelectedStockpile() { return nullptr; } + virtual df::building_civzonest *getSelectedCivZone() { return nullptr; } virtual df::plant *getSelectedPlant() { return nullptr; } static virtual_identity _identity; @@ -406,6 +410,8 @@ namespace DFHack virtual df::item *getSelectedItem(); virtual df::job *getSelectedJob(); virtual df::building *getSelectedBuilding(); + virtual df::building_civzonest *getSelectedCivZone(); + virtual df::building_stockpilest *getSelectedStockpile(); virtual df::plant *getSelectedPlant(); static virtual_identity _identity; diff --git a/library/lua/gui.lua b/library/lua/gui.lua index ac25381ca..1a4a7f197 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -872,6 +872,12 @@ end function ZScreen:onGetSelectedBuilding() return zscreen_get_any(self, 'Building') end +function ZScreen:onGetSelectedStockpile() + return zscreen_get_any(self, 'Stockpile') +end +function ZScreen:onGetSelectedCivZone() + return zscreen_get_any(self, 'CivZone') +end function ZScreen:onGetSelectedPlant() return zscreen_get_any(self, 'Plant') end diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 23e0f5585..b7cffc72f 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -1235,9 +1235,11 @@ bool Gui::any_stockpile_hotkey(df::viewscreen* top) } df::building_stockpilest* Gui::getAnyStockpile(df::viewscreen* top) { - if (matchFocusString("dwarfmode/Some/Stockpile")) { + if (auto dfscreen = dfhack_viewscreen::try_cast(top)) + return dfscreen->getSelectedStockpile(); + + if (game->main_interface.bottom_mode_selected == main_bottom_mode_type::STOCKPILE) return game->main_interface.stockpile.cur_bld; - } return NULL; } @@ -1256,9 +1258,12 @@ bool Gui::any_civzone_hotkey(df::viewscreen* top) { } df::building_civzonest *Gui::getAnyCivZone(df::viewscreen* top) { - if (matchFocusString("dwarfmode/Zone")) { + if (auto dfscreen = dfhack_viewscreen::try_cast(top)) + return dfscreen->getSelectedCivZone(); + + if (game->main_interface.bottom_mode_selected == main_bottom_mode_type::ZONE) return game->main_interface.civzone.cur_bld; - } + return NULL; } @@ -1273,8 +1278,6 @@ df::building_civzonest *Gui::getSelectedCivZone(color_ostream &out, bool quiet) df::building *Gui::getAnyBuilding(df::viewscreen *top) { - using df::global::game; - if (auto dfscreen = dfhack_viewscreen::try_cast(top)) return dfscreen->getSelectedBuilding(); diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 93f4773ec..cce06d284 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -1104,6 +1104,22 @@ df::building *dfhack_lua_viewscreen::getSelectedBuilding() return Lua::GetDFObject(Lua::Core::State, -1); } +df::building_stockpilest *dfhack_lua_viewscreen::getSelectedStockpile() +{ + Lua::StackUnwinder frame(Lua::Core::State); + lua_pushstring(Lua::Core::State, "onGetSelectedStockpile"); + safe_call_lua(do_notify, 1, 1); + return Lua::GetDFObject(Lua::Core::State, -1); +} + +df::building_civzonest *dfhack_lua_viewscreen::getSelectedCivZone() +{ + Lua::StackUnwinder frame(Lua::Core::State); + lua_pushstring(Lua::Core::State, "onGetSelectedCivZone"); + safe_call_lua(do_notify, 1, 1); + return Lua::GetDFObject(Lua::Core::State, -1); +} + df::plant *dfhack_lua_viewscreen::getSelectedPlant() { Lua::StackUnwinder frame(Lua::Core::State); From a8bf8a04ae700eec1d513da204cf6410b07e7fb5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 28 Aug 2023 15:42:56 -0700 Subject: [PATCH 403/851] add in value for units contained in cages --- docs/changelog.txt | 1 + library/modules/Items.cpp | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 2eb4c39fa..2d78ef76e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,6 +62,7 @@ Template for new versions: - Core: reload scripts in mods when a world is unloaded and immediately loaded again - Core: fix text getting added to DFHack text entry widgets when Alt- or Ctrl- keys are hit - `orders`: prevent import/export overlay from appearing on the create workorder screen +- `caravan`: corrected prices for cages that have units inside of them ## Misc Improvements - Surround DFHack-specific UI elements with square brackets instead of red-yellow blocks for better readability diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 0b91bdd47..bf4437ef7 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -1910,6 +1910,21 @@ static int32_t get_sell_request_multiplier(df::item *item, const df::caravan_sta return get_sell_request_multiplier(item, caravan_he->resources, &sell_prices->price[0]); } +static int32_t get_sell_request_multiplier(df::unit *unit, const df::caravan_state *caravan) { + const df::entity_sell_prices *sell_prices = caravan->sell_prices; + if (!sell_prices) + return DEFAULT_AGREEMENT_MULTIPLIER; + + auto caravan_he = df::historical_entity::find(caravan->entity); + if (!caravan_he) + return DEFAULT_AGREEMENT_MULTIPLIER; + + auto & resources = caravan_he->resources; + int32_t price = get_price(resources.animals.pet_races, unit->race, resources.animals.pet_castes, unit->caste, + sell_prices->price[df::entity_sell_category::Pets]); + return (price != -1) ? price : DEFAULT_AGREEMENT_MULTIPLIER; +} + static bool is_requested_trade_good(df::item *item, df::caravan_state *caravan) { auto trade_state = caravan->trade_state; if (caravan->time_remaining <= 0 || @@ -2031,6 +2046,28 @@ int Items::getValue(df::item *item, df::caravan_state *caravan) if (divisor > 1) value /= divisor; } + + // Add in value from units contained in cages + if (item_type == item_type::CAGE) { + for (auto gref : item->general_refs) { + if (gref->getType() != df::general_ref_type::CONTAINS_UNIT) + continue; + auto unit = gref->getUnit(); + if (!unit) + continue; + df::creature_raw *raw = world->raws.creatures.all[unit->race]; + df::caste_raw *caste = raw->caste.at(unit->caste); + int unit_value = caste->misc.petvalue; + if (Units::isWar(unit) || Units::isHunter(unit)) + unit_value *= 2; + if (caravan) { + unit_value *= get_sell_request_multiplier(unit, caravan); + unit_value >>= 7; + } + value += unit_value; + } + } + return value; } From 6185df25d6f6f9ad72b298a6a655270a7321c074 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 28 Aug 2023 17:59:52 -0700 Subject: [PATCH 404/851] update quickfort user guide for new take_from semantics --- docs/guides/quickfort-user-guide.rst | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/guides/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst index 9dda52454..c12df3eee 100644 --- a/docs/guides/quickfort-user-guide.rst +++ b/docs/guides/quickfort-user-guide.rst @@ -1992,10 +1992,10 @@ All stockpiles support the following properties: Property Description ================ =========== ``name`` the name of the stockpile -``take_from`` comma-separated list of names of stockpiles or workshops that - the stockpile takes from -``give_to`` comma-separated list of names of stockpiles or workshops that - the stockpile gives to +``take_from`` comma-separated list of names or building ids of stockpiles + or workshops that the stockpile takes from +``give_to`` comma-separated list of names or building ids of stockpiles + or workshops that the stockpile gives to ``links_only`` if set to ``true`` then the stockpile will only take from links ``barrels`` the number of desired barrels @@ -2014,6 +2014,12 @@ Property Description feature ================ =========== +Note that specifying building IDs in ``take_from`` or ``give_to`` lists is +primarily useful when dynamically generating `quickfort` blueprints and +applying them via the API. You will not generally know the ID of a stockpile or +building when writing a blueprint by hand or when preparing a blueprint to +apply in a different fort. + #build mode reference ~~~~~~~~~~~~~~~~~~~~~ @@ -2023,8 +2029,8 @@ accept the ``name`` property. Moreover, all workshops and furnaces accept the ``max_general_orders`` property, which sets the maximum number of general workorders that the building can accept, and the ``take_from`` and ``give_to`` properties, which are -comma-separated lists of names (the same as the correponding stockpile -properties above). +comma-separated lists of names or building ids (the same as the correponding +stockpile properties above). ================= ============================= ========== Symbol Type Properties @@ -2141,7 +2147,8 @@ Symbol Type Properties route stop on this track stop and make it take from the given comma-separated list of - stockpile names. ``route``: add + stockpile names or stockpile + building ids. ``route``: add this route stop to the named route. if no route of this name exists, it will be created. If From f2a5d82b90c3097e469187b9755f92e5c047ede6 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 29 Aug 2023 01:23:03 +0000 Subject: [PATCH 405/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 830034287..0d5b6e691 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 830034287f6d1c970666d00c80c815a9b331f2d2 +Subproject commit 0d5b6e6918e39454bf24855198598866c13a3568 From 73af533a906c3b3d6ec4e75f3fcf4d6ed9e6b821 Mon Sep 17 00:00:00 2001 From: Mikhail Panov Date: Tue, 29 Aug 2023 10:59:28 +0300 Subject: [PATCH 406/851] Update docs/plugins/sort.rst Co-authored-by: Myk --- docs/plugins/sort.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index dd8b206ce..c4e7654ef 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -14,7 +14,8 @@ Searching and sorting functionality is provided by `overlay` widgets, and widget Squad assignment overlay ------------------------ -The squad assignment screen can be sorted by name, by migrant wave, by stress, by various military-related skills or by specific potential ratings. +The squad assignment screen can be sorted by name, by migrant wave, by stress, +by various military-related skills or by long-term military potential. If sorted by "any melee", then the citizen is sorted according to the highest skill they have in axes, short swords, maces, warhammers, spears, or general From fa9d2e21752fd32a8dba5f3eb6e1171150a55338 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 29 Aug 2023 22:23:13 -0500 Subject: [PATCH 407/851] seedwatch: ignore tree seeds --- docs/changelog.txt | 1 + plugins/seedwatch.cpp | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 2d78ef76e..23159c012 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -30,6 +30,7 @@ Template for new versions: ## Fixes - `tailor`: remove crash caused by clothing items with an invalid ``maker_race`` +- `seedwatch`: seedwatch will now ignore tree seeds entirely ## Misc Improvements diff --git a/plugins/seedwatch.cpp b/plugins/seedwatch.cpp index 4a2a03f3a..ee2f95466 100644 --- a/plugins/seedwatch.cpp +++ b/plugins/seedwatch.cpp @@ -171,7 +171,8 @@ DFhackCExport command_result plugin_load_data (color_ostream &out) { world_plant_ids.clear(); for (size_t i = 0; i < world->raws.plants.all.size(); ++i) { auto & plant = world->raws.plants.all[i]; - if (plant->material_defs.type[plant_material_def::seed] != -1) + if (plant->material_defs.type[plant_material_def::seed] != -1 && + !plant->flags.is_set(df::enums::plant_raw_flags::TREE)) world_plant_ids[plant->id] = i; } @@ -180,8 +181,13 @@ DFhackCExport command_result plugin_load_data (color_ostream &out) { World::GetPersistentData(&seed_configs, SEED_CONFIG_KEY_PREFIX, true); const size_t num_seed_configs = seed_configs.size(); for (size_t idx = 0; idx < num_seed_configs; ++idx) { - auto &c = seed_configs[idx]; - watched_seeds.emplace(get_config_val(c, SEED_CONFIG_ID), c); + auto& c = seed_configs[idx]; + int seed_id = get_config_val(c, SEED_CONFIG_ID); + auto plant = binsearch_in_vector(world->raws.plants.all, &df::plant_raw::index, seed_id); + if (!plant->flags.is_set(df::enums::plant_raw_flags::TREE)) + watched_seeds.emplace(get_config_val(c, SEED_CONFIG_ID), c); + else + DEBUG(config, out).print("reference to tree seed in saved config discarded\n"); } config = World::GetPersistentData(CONFIG_KEY); From 8a015f7f87ead789bc7cb79fdea35a167ad79b38 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 07:38:21 +0300 Subject: [PATCH 408/851] review --- docs/dev/Lua API.rst | 45 ++++++++++++++++++++++++++++++ library/include/modules/Textures.h | 4 +-- library/modules/Textures.cpp | 15 ++++------ 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index d14e56640..110834c34 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3864,6 +3864,9 @@ These modules make extensive use of the ``class`` module, and define things ranging from the basic ``Painter``, ``View`` and ``Screen`` classes, to fully functional predefined dialogs. +In addition to the ``gui`` module, there is a ``textures`` module that allows +you to perform actions on textures to use them as tiles during rendering. + gui === @@ -5342,6 +5345,48 @@ The parent widget owns the range values, and can control them independently (e.g :on_left_change: Callback executed when moving the left handle. :on_right_change: Callback executed when moving the right handle. +textures +======== + +In order for the game to render a particular tile (graphic), it needs to know ``texpos`` - the position in the vector of the registered game textures. +Add your own texture to it and get ``texpos`` is not difficult. But the game periodically deletes textures that are in the vector, and that's the problem. +Because the ``texpos`` we got earlier no longer points to our added texture. +The ``texture`` module solves this problem. Instead of ``texpos`` directly, it operates on the ``TexposHandle`` entity, which is essentially a reference to ``texpos``. +Thanks to this handle, it is possible to get a valid ``texpos`` at any time. + +* ``loadTileset(file, tile_px_w, tile_px_h)`` + + Loads tileset from the image ``file`` with give tile dimension in pixels (image will be sliced in row major order). + + Returns an array of ``TexposHandle`` + +* ``getTexposByHandle(handle)`` + + Get ``texpos`` by ``TexposHandle``. + Always use this method if you need to get valid texpos for your texture. + ``texpos`` can change on game textures reset, but the handle will be the same. + +* ``createTile(pixels, tile_px_w, tile_px_h)`` + + Create and register new a texture with the given tile dimension and array of ``pixels`` as data in row major order. + Each pixel is an integer representing color in packed RBGA format (for example, #0022FF11). + + Returns ``TexposHandle``. + +* ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h)`` + + Create and register a new texture with the given texture dimension and array of ``pixels`` as data in row major order. + Then slice it on tiles with the given dimension in row major order. + Each pixel is an integer representing color in packed RBGA format (for example #0022FF11). + + Returns an array of ``TexposHandle``. + +* ``deleteHandle(handle)`` + + ``handle`` here can be signle ``TexposHandle``, or array of ``TexposHandle``. + Deletes all metadata and texture(s) itself by given handle(s). + You must be sure that the game does not use this texture in rendering process. + .. _lua-plugins: ======= diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index e371df90e..5b238a4fd 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -49,14 +49,14 @@ DFHACK_EXPORT long getTexposByHandle(TexposHandle handle); DFHACK_EXPORT void deleteHandle(TexposHandle handle); /** - * Create new texture with RGBA32 format and pixels as data. + * Create new texture with RGBA32 format and pixels as data in row major order. * Register this texture and return TexposHandle. */ DFHACK_EXPORT TexposHandle createTile(std::vector& pixels, int tile_px_w = TILE_WIDTH_PX, int tile_px_h = TILE_HEIGHT_PX); /** - * Create new textures as tileset with RGBA32 format and pixels as data. + * Create new textures as tileset with RGBA32 format and pixels as data in row major order. * Register this textures and return vector of TexposHandle. */ DFHACK_EXPORT std::vector createTileset(std::vector& pixels, diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index e6f6d5aaa..25af2135a 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -17,6 +17,7 @@ #include "df/viewscreen_new_arenast.h" #include "df/viewscreen_new_regionst.h" +#include #include using df::global::enabler; @@ -31,10 +32,6 @@ static std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_surface; static std::mutex g_adding_mutex; -// it is SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32 -// initialized inplace to avoid including SDL_pixels.h -static const uint32_t RGBA32 = 376840196; - // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -43,13 +40,13 @@ static const uint32_t RGBA32 = 376840196; // It uses the same pixel format (RGBA, R at lowest address) regardless of // hardware. SDL_Surface* canonicalize_format(SDL_Surface* src) { - // however we have null check after DFIMG_Load + // even though we have null check after DFIMG_Load // in loadTileset() (the only consumer of this method) // it's better put nullcheck here as well if (!src) return src; - auto fmt = DFSDL_AllocFormat(RGBA32); + auto fmt = DFSDL_AllocFormat(SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32); SDL_Surface* tgt = DFSDL_ConvertSurface(src, fmt, SDL_SWSURFACE); DFSDL_FreeSurface(src); for (int x = 0; x < tgt->w; ++x) { @@ -85,7 +82,8 @@ static void delete_texture(long texpos) { // create new surface with RGBA32 format and pixels as data SDL_Surface* create_texture(std::vector& pixels, int texture_px_w, int texture_px_h) { - auto surface = DFSDL_CreateRGBSurfaceWithFormat(0, texture_px_w, texture_px_h, 32, RGBA32); + auto surface = DFSDL_CreateRGBSurfaceWithFormat(0, texture_px_w, texture_px_h, 32, + SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32); auto canvas_length = static_cast(texture_px_w * texture_px_h); for (size_t i = 0; i < pixels.size() && i < canvas_length; i++) { uint32_t* p = (uint32_t*)surface->pixels + i; @@ -186,9 +184,8 @@ void Textures::deleteHandle(TexposHandle handle) { g_handle_to_texpos.erase(handle); if (g_handle_to_surface.contains(handle)) { auto surface = g_handle_to_surface[handle]; - for (auto i = 0; i < surface->refcount; i++) { + while (surface->refcount) DFSDL_FreeSurface(surface); - } g_handle_to_surface.erase(handle); } } From c5d30763b989753f67a8898b0c795fd42d7ce835 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Wed, 30 Aug 2023 00:07:30 -0500 Subject: [PATCH 409/851] seedwatch: rewrite configuration cleaning --- plugins/seedwatch.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/plugins/seedwatch.cpp b/plugins/seedwatch.cpp index ee2f95466..df49efec2 100644 --- a/plugins/seedwatch.cpp +++ b/plugins/seedwatch.cpp @@ -96,6 +96,20 @@ static void remove_seed_config(color_ostream &out, int id) { watched_seeds.erase(id); } +// this validation removes configuration data from versions prior to 50.09-r3 +// it can be removed once saves from 50.09 are no longer loadable + +static bool validate_seed_config(color_ostream& out, PersistentDataItem c) +{ + int seed_id = get_config_val(c, SEED_CONFIG_ID); + auto plant = binsearch_in_vector(world->raws.plants.all, &df::plant_raw::index, seed_id); + bool valid = (!plant->flags.is_set(df::enums::plant_raw_flags::TREE)); + if (!valid) { + DEBUG(config, out).print("invalid configuration for %s discarded\n", plant->id.c_str()); + } + return valid; +} + static const int32_t CYCLE_TICKS = 1200; static int32_t cycle_timestamp = 0; // world->frame_counter at last cycle @@ -182,12 +196,8 @@ DFhackCExport command_result plugin_load_data (color_ostream &out) { const size_t num_seed_configs = seed_configs.size(); for (size_t idx = 0; idx < num_seed_configs; ++idx) { auto& c = seed_configs[idx]; - int seed_id = get_config_val(c, SEED_CONFIG_ID); - auto plant = binsearch_in_vector(world->raws.plants.all, &df::plant_raw::index, seed_id); - if (!plant->flags.is_set(df::enums::plant_raw_flags::TREE)) + if (validate_seed_config(out, c)) watched_seeds.emplace(get_config_val(c, SEED_CONFIG_ID), c); - else - DEBUG(config, out).print("reference to tree seed in saved config discarded\n"); } config = World::GetPersistentData(CONFIG_KEY); From e87aefa7bf12d677a2a3a6c06fe663619fc843c3 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Wed, 30 Aug 2023 00:08:51 -0500 Subject: [PATCH 410/851] seedwatch: changelog --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 23159c012..f84526ebd 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -30,7 +30,7 @@ Template for new versions: ## Fixes - `tailor`: remove crash caused by clothing items with an invalid ``maker_race`` -- `seedwatch`: seedwatch will now ignore tree seeds entirely +- `seedwatch`: seedwatch will now ignore (unplantable) tree seeds entirely ## Misc Improvements From 26b81cfbbd8c9ac6625bb62ed821a94a834681a7 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Wed, 30 Aug 2023 09:39:13 +0300 Subject: [PATCH 411/851] Merged military rating back into one. Adjusted formulas for melee and ranged rating. Added skill effectiveness ratings for ranged and melee. Changed any melee and any ranged to skill effectiveness ratings. Added info about new ratings and research links to the docs. --- docs/plugins/sort.rst | 45 ++++---- plugins/lua/sort.lua | 263 ++++++++++++++++++++++++------------------ 2 files changed, 177 insertions(+), 131 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index c4e7654ef..f142534db 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -17,12 +17,16 @@ Squad assignment overlay The squad assignment screen can be sorted by name, by migrant wave, by stress, by various military-related skills or by long-term military potential. -If sorted by "any melee", then the citizen is sorted according to the highest -skill they have in axes, short swords, maces, warhammers, spears, or general -fighting. +If sorted by "any melee", then the citizen is sorted according to the "melee +skill effectiveness". This rating uses the highest skill they have in axes, short +swords, maces, warhammers or spears along with physical and mental attributes and +general fighting skill. Citizens with higher rating are expected to be more +effective in melee combat with their corresponding weapon. -If sorted by "any ranged", then the citizen is sorted according to the highest -skill they have in crossbows or general ranged combat. +If sorted by "any ranged", then the citizen is sorted according to the "ranged +skill effectiveness". This rating uses crossbow and general archery skills +along with mental and physical attributes. Citizens with higher rating are +expected to be more effective in ranged combat. If sorted by "leadership", then the citizen is sorted according to the highest skill they have in leader, teacher, or military tactics. @@ -32,29 +36,30 @@ mental stability rating. This rating is a measure that takes into account facets and values of an individual and correlates to better stress values. It is designed to be higher for more stress-resistant citizens. -If sorting is done by "solo combat potential" citizens are arranged based on their -solo combat potential rating. This rating is a measure that takes into -account genetic predispositions in physical and mental attributes, as -well as body size. Dwarves (and other humanoid creatures) with bigger rating -are expected to be more effective in melee combat against strong opponents. - -If sorting is done by "group combat potential" citizens are arranged based on their -group combat potential rating. Similar with solo combat rating except this rating -taking into account efficiency in a fight against multiple opponents. This rating -is valid only for dwarves because it considers martial trance which only dwarves -are capable of. +If sorting is done by "melee potential" citizens are arranged based on +their "melee combat potential" rating. This rating is a statistical measure +that takes into account genetic predispositions in physical and mental +attributes, as well as body size. Dwarves (and other humanoid creatures) with +higher rating are expected to be more effective in melee combat if they train +their attributes to their genetic maximum. If sorting is done by "ranged potential" citizens are arranged based on their -ranged potential rating. This rating is a statistical measure that takes into -account genetic predispositions in physical and mental attributes. -Dwarves (and other humanoid creatures) with bigger rating are expected to be -more effective in ranged combat. +ranged combat potential rating. This rating is a statistical measure that takes into +account genetic predispositions in physical and mental attributes. Dwarves +(and other humanoid creatures) with higher rating are expected to be more +effective in ranged combat if they train their attributes to the maximum. You can search for a dwarf by name by typing in the Search field. You can also type in the name of any job skill (military-related or not) and dwarves with any experience in that skill will be shown. For example, to only see citizens with military tactics skill, type in "tactics". +"Melee skill effectiveness", "ranged skill effectiveness", "melee combat potential" +and "ranged combat potential" are explained in detail here: +https://www.reddit.com/r/dwarffortress/comments/163kczo/enhancing_military_candidate_selection_part_3/ +"Mental stability" is explained here: +https://www.reddit.com/r/dwarffortress/comments/1617s11/enhancing_military_candidate_selection_part_2/ + You can see all the job skill names that you can search for by running:: :lua @df.job_skill diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index c418b1f5a..02431bd7f 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -16,12 +16,12 @@ local MELEE_WEAPON_SKILLS = { df.job_skill.MACE, df.job_skill.HAMMER, df.job_skill.SPEAR, - df.job_skill.MELEE_COMBAT, --Fighter + -- df.job_skill.MELEE_COMBAT, --Fighter } local RANGED_WEAPON_SKILLS = { df.job_skill.CROSSBOW, - df.job_skill.RANGED_COMBAT, + -- df.job_skill.RANGED_COMBAT, } local LEADERSHIP_SKILLS = { @@ -125,6 +125,109 @@ local function get_max_skill(unit_id, list) return max end +local function melee_skill_effectiveness(unit_id, skill_list) + local unit = df.unit.find(unit_id) + + -- Physical attributes + local strength = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.STRENGTH) + local agility = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.AGILITY) + local toughness = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.TOUGHNESS) + local endurance = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.ENDURANCE) + local body_size_base = unit.body.size_info.size_base + + -- Mental attributes + local willpower = dfhack.units.getMentalAttrValue(unit, df.mental_attribute_type.WILLPOWER) + local spatial_sense = dfhack.units.getMentalAttrValue(unit, df.mental_attribute_type.SPATIAL_SENSE) + local kinesthetic_sense = dfhack.units.getMentalAttrValue(unit, df.mental_attribute_type.KINESTHETIC_SENSE) + + -- Skills + local melee_skill = get_max_skill(unit_id, skill_list) + if melee_skill then + melee_skill = melee_skill.rating + else + melee_skill = 0 + end + local melee_combat = dfhack.units.getNominalSkill(unit, df.job_skill.MELEE_COMBAT, true) + + local rating = melee_skill * 27000 + melee_combat * 9000 + + strength * 180 + body_size_base * 100 + kinesthetic_sense * 50 + endurance * 50 + + agility * 30 + toughness * 20 + willpower * 20 + spatial_sense * 20 + return rating +end + +local function make_sort_by_melee_skill_effectiveness_desc(list) + return function(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + if unit_id_1 == -1 then return -1 end + if unit_id_2 == -1 then return 1 end + local rating1 = melee_skill_effectiveness(unit_id_1, list) + local rating2 = melee_skill_effectiveness(unit_id_2, list) + if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end + if rating1 ~= rating2 then return utils.compare(rating2, rating1) end + end +end + +local function make_sort_by_melee_skill_effectiveness_asc(list) + return function(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + if unit_id_1 == -1 then return -1 end + if unit_id_2 == -1 then return 1 end + local rating1 = melee_skill_effectiveness(unit_id_1, list) + local rating2 = melee_skill_effectiveness(unit_id_2, list) + if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end + if rating1 ~= rating2 then return utils.compare(rating1, rating2) end + end +end + +local function ranged_skill_effectiveness(unit_id, skill_list) + local unit = df.unit.find(unit_id) + + -- Physical attributes + local agility = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.AGILITY) + + -- Mental attributes + local spatial_sense = dfhack.units.getMentalAttrValue(unit, df.mental_attribute_type.SPATIAL_SENSE) + local kinesthetic_sense = dfhack.units.getMentalAttrValue(unit, df.mental_attribute_type.KINESTHETIC_SENSE) + local focus = dfhack.units.getMentalAttrValue(unit, df.mental_attribute_type.FOCUS) + + -- Skills + local ranged_skill = get_max_skill(unit_id, skill_list) + if ranged_skill then + ranged_skill = ranged_skill.rating + else + ranged_skill = 0 + end + local ranged_combat = dfhack.units.getNominalSkill(unit, df.job_skill.RANGED_COMBAT, true) + + local rating = ranged_skill * 24000 + ranged_combat * 8000 + + agility * 15 + spatial_sense * 15 + kinesthetic_sense * 6 + focus * 6 + return rating +end + +local function make_sort_by_ranged_skill_effectiveness_desc(list) + return function(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + if unit_id_1 == -1 then return -1 end + if unit_id_2 == -1 then return 1 end + local rating1 = ranged_skill_effectiveness(unit_id_1, list) + local rating2 = ranged_skill_effectiveness(unit_id_2, list) + if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end + if rating1 ~= rating2 then return utils.compare(rating2, rating1) end + end +end + +local function make_sort_by_ranged_skill_effectiveness_asc(list) + return function(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + if unit_id_1 == -1 then return -1 end + if unit_id_2 == -1 then return 1 end + local rating1 = ranged_skill_effectiveness(unit_id_1, list) + local rating2 = ranged_skill_effectiveness(unit_id_2, list) + if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end + if rating1 ~= rating2 then return utils.compare(rating1, rating2) end + end +end + local function make_sort_by_skill_list_desc(list) return function(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end @@ -246,7 +349,6 @@ local function mental_stability(unit) return rating end - local function sort_by_mental_stability_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) @@ -278,95 +380,49 @@ local function sort_by_mental_stability_asc(unit_id_1, unit_id_2) end -- Statistical rating that is bigger for more potent dwarves in long run melee military training --- Rating considers fighting solo opponents +-- Rating considers fighting melee opponents -- Wounds are not considered! -local function solo_combat_potential(unit) +local function melee_combat_potential(unit) -- Physical attributes local strength = unit.body.physical_attrs.STRENGTH.max_value local agility = unit.body.physical_attrs.AGILITY.max_value local toughness = unit.body.physical_attrs.TOUGHNESS.max_value local endurance = unit.body.physical_attrs.ENDURANCE.max_value - local bodySize = unit.body.size_info.size_base + local body_size_base = unit.body.size_info.size_base -- Mental attributes local willpower = unit.status.current_soul.mental_attrs.WILLPOWER.max_value - local spatialSense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value - local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value - - -- solo combat potential rating - local rating = strength*5.8 + kinestheticSense*3.7 + bodySize*2 + agility*2 + endurance*1.8 - + willpower*1.5 * spatialSense*1.5 + toughness*1.5 - return rating -end - -local function sort_by_solo_combat_potential_desc(unit_id_1, unit_id_2) - if unit_id_1 == unit_id_2 then return 0 end - local unit1 = df.unit.find(unit_id_1) - local unit2 = df.unit.find(unit_id_2) - if not unit1 then return -1 end - if not unit2 then return 1 end - local rating1 = solo_combat_potential(unit1) - local rating2 = solo_combat_potential(unit2) - if rating1 == rating2 then - return sort_by_mental_stability_desc(unit_id_1, unit_id_2) - end - return utils.compare(rating2, rating1) -end - -local function sort_by_solo_combat_potential_asc(unit_id_1, unit_id_2) - if unit_id_1 == unit_id_2 then return 0 end - local unit1 = df.unit.find(unit_id_1) - local unit2 = df.unit.find(unit_id_2) - if not unit1 then return -1 end - if not unit2 then return 1 end - local rating1 = solo_combat_potential(unit1) - local rating2 = solo_combat_potential(unit2) - if rating1 == rating2 then - return sort_by_mental_stability_asc(unit_id_1, unit_id_2) - end - return utils.compare(rating1, rating2) -end - --- Statistical rating that is bigger for more potent dwarves in long run melee military training --- Rating considers fighting group of opponents --- Wounds are not considered! -local function group_combat_potential(unit) - -- Physical attributes - local strength = unit.body.physical_attrs.STRENGTH.max_value - local endurance = unit.body.physical_attrs.ENDURANCE.max_value - local bodySize = unit.body.size_info.size_base - - -- Mental attributes - local spatialSense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value - local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value + local spatial_sense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value + local kinesthetic_sense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value - -- group combat potential rating - local rating = strength*8.3 + endurance*3 + bodySize*2.8 + kinestheticSense*0.6 + spatialSense*0.4 + -- melee combat potential rating + local rating = strength * 264 + endurance * 84 + body_size_base * 77 + kinesthetic_sense * 74 + + agility * 33 + willpower * 31 + spatial_sense * 27 + toughness * 25 return rating end -local function sort_by_group_combat_potential_desc(unit_id_1, unit_id_2) +local function sort_by_melee_combat_potential_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = group_combat_potential(unit1) - local rating2 = group_combat_potential(unit2) + local rating1 = melee_combat_potential(unit1) + local rating2 = melee_combat_potential(unit2) if rating1 == rating2 then return sort_by_mental_stability_desc(unit_id_1, unit_id_2) end return utils.compare(rating2, rating1) end -local function sort_by_group_combat_potential_asc(unit_id_1, unit_id_2) +local function sort_by_melee_combat_potential_asc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = group_combat_potential(unit1) - local rating2 = group_combat_potential(unit2) + local rating1 = melee_combat_potential(unit1) + local rating2 = melee_combat_potential(unit2) if rating1 == rating2 then return sort_by_mental_stability_asc(unit_id_1, unit_id_2) end @@ -375,7 +431,7 @@ end -- Statistical rating that is bigger for more potent dwarves in long run ranged military training -- Wounds are not considered! -local function ranged_potential(unit) +local function ranged_combat_potential(unit) -- Physical attributes local agility = unit.body.physical_attrs.AGILITY.max_value local toughness = unit.body.physical_attrs.TOUGHNESS.max_value @@ -384,37 +440,36 @@ local function ranged_potential(unit) -- Mental attributes local focus = unit.status.current_soul.mental_attrs.FOCUS.max_value local willpower = unit.status.current_soul.mental_attrs.WILLPOWER.max_value - local spatialSense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value - local kinestheticSense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value + local spatial_sense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value + local kinesthetic_sense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value - -- Ranged potential formula - local rating = agility*3.9 + kinestheticSense*3 + spatialSense*2.9 + toughness*0.9 - + focus*0.7 + endurance*0.7 + willpower*0.6 + -- ranged combat potential formula + local rating = agility * 5 + kinesthetic_sense * 5 + spatial_sense * 2 + focus * 2 return rating end -local function sort_by_ranged_potential_desc(unit_id_1, unit_id_2) +local function sort_by_ranged_combat_potential_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = ranged_potential(unit1) - local rating2 = ranged_potential(unit2) + local rating1 = ranged_combat_potential(unit1) + local rating2 = ranged_combat_potential(unit2) if rating1 == rating2 then return sort_by_mental_stability_desc(unit_id_1, unit_id_2) end return utils.compare(rating2, rating1) end -local function sort_by_ranged_potential_asc(unit_id_1, unit_id_2) +local function sort_by_ranged_combat_potential_asc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = ranged_potential(unit1) - local rating2 = ranged_potential(unit2) + local rating1 = ranged_combat_potential(unit1) + local rating2 = ranged_combat_potential(unit2) if rating1 == rating2 then return sort_by_mental_stability_asc(unit_id_1, unit_id_2) end @@ -422,10 +477,10 @@ local function sort_by_ranged_potential_asc(unit_id_1, unit_id_2) end local SORT_FNS = { - sort_by_any_melee_desc=make_sort_by_skill_list_desc(MELEE_WEAPON_SKILLS), - sort_by_any_melee_asc=make_sort_by_skill_list_asc(MELEE_WEAPON_SKILLS), - sort_by_any_ranged_desc=make_sort_by_skill_list_desc(RANGED_WEAPON_SKILLS), - sort_by_any_ranged_asc=make_sort_by_skill_list_asc(RANGED_WEAPON_SKILLS), + sort_by_any_melee_desc=make_sort_by_melee_skill_effectiveness_desc(MELEE_WEAPON_SKILLS), + sort_by_any_melee_asc=make_sort_by_melee_skill_effectiveness_asc(MELEE_WEAPON_SKILLS), + sort_by_any_ranged_desc=make_sort_by_ranged_skill_effectiveness_desc(RANGED_WEAPON_SKILLS), + sort_by_any_ranged_asc=make_sort_by_ranged_skill_effectiveness_asc(RANGED_WEAPON_SKILLS), sort_by_leadership_desc=make_sort_by_skill_list_desc(LEADERSHIP_SKILLS), sort_by_leadership_asc=make_sort_by_skill_list_asc(LEADERSHIP_SKILLS), sort_by_axe_desc=make_sort_by_skill_desc(df.job_skill.AXE), @@ -451,7 +506,7 @@ SquadAssignmentOverlay.ATTRS{ default_pos={x=-33, y=40}, default_enabled=true, viewscreens='dwarfmode/UnitSelector/SQUAD_FILL_POSITION', - frame={w=84, h=9}, + frame={w=65, h=9}, frame_style=gui.FRAME_PANEL, frame_background=gui.CLEAR_PEN, } @@ -492,12 +547,10 @@ function SquadAssignmentOverlay:init() {label='crossbow skill'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc, pen=COLOR_YELLOW}, {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, - {label='solo combat potential'..CH_DN, value=sort_by_solo_combat_potential_desc, pen=COLOR_GREEN}, - {label='solo combat potential'..CH_UP, value=sort_by_solo_combat_potential_asc, pen=COLOR_YELLOW}, - {label='group combat potential'..CH_DN, value=sort_by_group_combat_potential_desc, pen=COLOR_GREEN}, - {label='group combat potential'..CH_UP, value=sort_by_group_combat_potential_asc, pen=COLOR_YELLOW}, - {label='ranged potential'..CH_DN, value=sort_by_ranged_potential_desc, pen=COLOR_GREEN}, - {label='ranged potential'..CH_UP, value=sort_by_ranged_potential_asc, pen=COLOR_YELLOW}, + {label='melee potential'..CH_DN, value=sort_by_melee_combat_potential_desc, pen=COLOR_GREEN}, + {label='melee potential'..CH_UP, value=sort_by_melee_combat_potential_asc, pen=COLOR_YELLOW}, + {label='ranged potential'..CH_DN, value=sort_by_ranged_combat_potential_desc, pen=COLOR_GREEN}, + {label='ranged potential'..CH_UP, value=sort_by_ranged_combat_potential_asc, pen=COLOR_YELLOW}, }, initial_option=SORT_FNS.sort_by_any_melee_desc, on_change=self:callback('refresh_list', 'sort'), @@ -657,37 +710,26 @@ function SquadAssignmentOverlay:init() on_change=self:callback('refresh_list', 'sort_mental_stability'), }, widgets.CycleHotkeyLabel{ - view_id='sort_solo_combat_potential', - frame={t=4, l=18, w=22}, - options={ - {label='solo combat potential', value=sort_noop}, - {label='solo combat potential'..CH_DN, value=sort_by_solo_combat_potential_desc, pen=COLOR_GREEN}, - {label='solo combat potential'..CH_UP, value=sort_by_solo_combat_potential_asc, pen=COLOR_YELLOW}, - }, - option_gap=0, - on_change=self:callback('refresh_list', 'sort_solo_combat_potential'), - }, - widgets.CycleHotkeyLabel{ - view_id='sort_group_combat_potential', - frame={t=4, l=41, w=23}, + view_id='sort_melee_combat_potential', + frame={t=4, l=20, w=16}, options={ - {label='group combat potential', value=sort_noop}, - {label='group combat potential'..CH_DN, value=sort_by_group_combat_potential_desc, pen=COLOR_GREEN}, - {label='group combat potential'..CH_UP, value=sort_by_group_combat_potential_asc, pen=COLOR_YELLOW}, + {label='melee potential', value=sort_noop}, + {label='melee potential'..CH_DN, value=sort_by_melee_combat_potential_desc, pen=COLOR_GREEN}, + {label='melee potential'..CH_UP, value=sort_by_melee_combat_potential_asc, pen=COLOR_YELLOW}, }, option_gap=0, - on_change=self:callback('refresh_list', 'sort_group_combat_potential'), + on_change=self:callback('refresh_list', 'sort_melee_combat_potential'), }, widgets.CycleHotkeyLabel{ - view_id='sort_ranged_potential', - frame={t=4, l=65, w=17}, + view_id='sort_ranged_combat_potential', + frame={t=4, l=39, w=17}, options={ {label='ranged potential', value=sort_noop}, - {label='ranged potential'..CH_DN, value=sort_by_ranged_potential_desc, pen=COLOR_GREEN}, - {label='ranged potential'..CH_UP, value=sort_by_ranged_potential_asc, pen=COLOR_YELLOW}, + {label='ranged potential'..CH_DN, value=sort_by_ranged_combat_potential_desc, pen=COLOR_GREEN}, + {label='ranged potential'..CH_UP, value=sort_by_ranged_combat_potential_asc, pen=COLOR_YELLOW}, }, option_gap=0, - on_change=self:callback('refresh_list', 'sort_ranged_potential'), + on_change=self:callback('refresh_list', 'sort_ranged_combat_potential'), }, } }, @@ -767,9 +809,8 @@ local SORT_WIDGET_NAMES = { 'sort_spear', 'sort_crossbow', 'sort_mental_stability', - 'sort_solo_combat_potential', - 'sort_group_combat_potential', - 'sort_ranged_potential', + 'sort_melee_combat_potential', + 'sort_ranged_combat_potential', } function SquadAssignmentOverlay:refresh_list(sort_widget, sort_fn) From ff82cb2dfca7e24c8b2eaefebddbb3d545f6050b Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 10:05:23 +0300 Subject: [PATCH 412/851] docs work --- docs/dev/Lua API.rst | 100 ++++++++++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 35 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 110834c34..f983031ee 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2596,6 +2596,55 @@ a ``dfhack.penarray`` instance to cache their output. ``bufferx`` and ``buffery`` default to 0. + +Textures Module +--------------- + +In order for the game to render a particular tile (graphic), it needs to know ``texpos`` - the position in the vector of the registered game textures (also the graphical tile id passed as the tile field in a `Pen `). +Add your own texture to it and get ``texpos`` is not difficult. But the game periodically deletes textures that are in the vector, and that's the problem. +Because the ``texpos`` we got earlier no longer points to our added texture. +The ``texture`` module solves this problem. Instead of ``texpos`` directly, it operates on the ``TexposHandle`` entity, which is essentially a reference to ``texpos``. +Thanks to this handle, it is possible to get a valid ``texpos`` at any time. + +* ``loadTileset(file, tile_px_w, tile_px_h)`` + + Loads tileset from the image ``file`` with give tile dimension in pixels (image will be sliced in row major order). + + Returns an array of ``TexposHandle`` + + Example usage:: + + local logo_textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) + local first_texposhandle = logo_textures[1] + +* ``getTexposByHandle(handle)`` + + Get ``texpos`` by ``TexposHandle``. + Always use this method if you need to get valid texpos for your texture. + ``texpos`` can change on game textures reset, but the handle will be the same. + +* ``createTile(pixels, tile_px_w, tile_px_h)`` + + Create and register new a texture with the given tile dimension and array of ``pixels`` as data in row major order. + Each pixel is an integer representing color in packed RBGA format (for example, #0022FF11). + + Returns ``TexposHandle``. + +* ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h)`` + + Create and register a new texture with the given texture dimension and array of ``pixels`` as data in row major order. + Then slice it on tiles with the given dimension in row major order. + Each pixel is an integer representing color in packed RBGA format (for example #0022FF11). + + Returns an array of ``TexposHandle``. + +* ``deleteHandle(handle)`` + + ``handle`` here can be signle ``TexposHandle``, or array of ``TexposHandle``. + Deletes all metadata and texture(s) itself by given handle(s). + You must be sure that the game does not use this texture in rendering process. + + Filesystem module ----------------- @@ -5345,47 +5394,28 @@ The parent widget owns the range values, and can control them independently (e.g :on_left_change: Callback executed when moving the left handle. :on_right_change: Callback executed when moving the right handle. -textures -======== - -In order for the game to render a particular tile (graphic), it needs to know ``texpos`` - the position in the vector of the registered game textures. -Add your own texture to it and get ``texpos`` is not difficult. But the game periodically deletes textures that are in the vector, and that's the problem. -Because the ``texpos`` we got earlier no longer points to our added texture. -The ``texture`` module solves this problem. Instead of ``texpos`` directly, it operates on the ``TexposHandle`` entity, which is essentially a reference to ``texpos``. -Thanks to this handle, it is possible to get a valid ``texpos`` at any time. - -* ``loadTileset(file, tile_px_w, tile_px_h)`` - - Loads tileset from the image ``file`` with give tile dimension in pixels (image will be sliced in row major order). - - Returns an array of ``TexposHandle`` -* ``getTexposByHandle(handle)`` - - Get ``texpos`` by ``TexposHandle``. - Always use this method if you need to get valid texpos for your texture. - ``texpos`` can change on game textures reset, but the handle will be the same. +gui.textures +============ -* ``createTile(pixels, tile_px_w, tile_px_h)`` +This module contains preloaded ``DFHack`` graphic assets and provide several helper methods to get ``texpos`` by offset in tilest (in row major position). - Create and register new a texture with the given tile dimension and array of ``pixels`` as data in row major order. - Each pixel is an integer representing color in packed RBGA format (for example, #0022FF11). +* ``tp_green_pin(offset)`` tileset: ``hack/data/art/green-pin.png`` +* ``tp_red_pin(offset)`` tileset: ``hack/data/art/red-pin.png`` +* ``tp_icons(offset)`` tileset: ``hack/data/art/icons.png`` +* ``tp_on_off(offset)`` tileset: ``hack/data/art/on-off.png`` +* ``tp_control_panel(offset)`` tileset: ``hack/data/art/control-panel.png`` +* ``tp_border_thin(offset)`` tileset: ``hack/data/art/border-thin.png`` +* ``tp_border_medium(offset)`` tileset: ``hack/data/art/border-medium.png`` +* ``tp_border_bold(offset)`` tileset: ``hack/data/art/border-bold.png`` +* ``tp_border_panel(offset)`` tileset: ``hack/data/art/border-panel.png`` +* ``tp_border_window(offset)`` tileset: ``hack/data/art/order-window.png`` - Returns ``TexposHandle``. +Example usega:: -* ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h)`` + local textures = require('gui.textures') + local first_border_texpos = textures.tp_border_thin(1) - Create and register a new texture with the given texture dimension and array of ``pixels`` as data in row major order. - Then slice it on tiles with the given dimension in row major order. - Each pixel is an integer representing color in packed RBGA format (for example #0022FF11). - - Returns an array of ``TexposHandle``. - -* ``deleteHandle(handle)`` - - ``handle`` here can be signle ``TexposHandle``, or array of ``TexposHandle``. - Deletes all metadata and texture(s) itself by given handle(s). - You must be sure that the game does not use this texture in rendering process. .. _lua-plugins: From a1fe49e52af2d1f34c7c1a4e46d65965291e7ce1 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 10:37:23 +0300 Subject: [PATCH 413/851] typo --- 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 f983031ee..c52f39269 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2597,7 +2597,7 @@ a ``dfhack.penarray`` instance to cache their output. ``bufferx`` and ``buffery`` default to 0. -Textures Module +Textures module --------------- In order for the game to render a particular tile (graphic), it needs to know ``texpos`` - the position in the vector of the registered game textures (also the graphical tile id passed as the tile field in a `Pen `). From 5c6942a89cf7145a6501fcfab76443932741d509 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 10:45:17 +0300 Subject: [PATCH 414/851] intendation for example --- docs/dev/Lua API.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index c52f39269..e4bbd59e2 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2614,8 +2614,8 @@ Thanks to this handle, it is possible to get a valid ``texpos`` at any time. Example usage:: - local logo_textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) - local first_texposhandle = logo_textures[1] + local logo_textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) + local first_texposhandle = logo_textures[1] * ``getTexposByHandle(handle)`` From 7ce7bd15f655d9d9f88be7683bc5167b7c44bc49 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 12:48:14 +0300 Subject: [PATCH 415/851] Update docs/dev/Lua API.rst Co-authored-by: Myk --- docs/dev/Lua API.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index e4bbd59e2..f002297ad 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2600,7 +2600,9 @@ a ``dfhack.penarray`` instance to cache their output. Textures module --------------- -In order for the game to render a particular tile (graphic), it needs to know ``texpos`` - the position in the vector of the registered game textures (also the graphical tile id passed as the tile field in a `Pen `). +In order for the game to render a particular tile (graphic), it needs to know the +``texpos`` - the position in the vector of the registered game textures (also the +graphical tile id passed as the ``tile`` field in a `Pen `). Add your own texture to it and get ``texpos`` is not difficult. But the game periodically deletes textures that are in the vector, and that's the problem. Because the ``texpos`` we got earlier no longer points to our added texture. The ``texture`` module solves this problem. Instead of ``texpos`` directly, it operates on the ``TexposHandle`` entity, which is essentially a reference to ``texpos``. From b3d423b8a4bc654b39cf5da5c916d84f918bbb7c Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 12:48:26 +0300 Subject: [PATCH 416/851] Update docs/dev/Lua API.rst Co-authored-by: Myk --- docs/dev/Lua API.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index f002297ad..0dac09a64 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2603,8 +2603,9 @@ Textures module In order for the game to render a particular tile (graphic), it needs to know the ``texpos`` - the position in the vector of the registered game textures (also the graphical tile id passed as the ``tile`` field in a `Pen `). -Add your own texture to it and get ``texpos`` is not difficult. But the game periodically deletes textures that are in the vector, and that's the problem. -Because the ``texpos`` we got earlier no longer points to our added texture. +Adding new textures to the vector is not difficult, but the game periodically +deletes textures that are in the vector, and that's a problem since it +invalidates the ``texpos`` value that used to point to that texture. The ``texture`` module solves this problem. Instead of ``texpos`` directly, it operates on the ``TexposHandle`` entity, which is essentially a reference to ``texpos``. Thanks to this handle, it is possible to get a valid ``texpos`` at any time. From 13e0a49eef12e008aa24159c4f52f8ec43d5cf2a Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 12:48:36 +0300 Subject: [PATCH 417/851] Update docs/dev/Lua API.rst Co-authored-by: Myk --- docs/dev/Lua API.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 0dac09a64..3f93a09b4 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2606,8 +2606,9 @@ graphical tile id passed as the ``tile`` field in a `Pen `). Adding new textures to the vector is not difficult, but the game periodically deletes textures that are in the vector, and that's a problem since it invalidates the ``texpos`` value that used to point to that texture. -The ``texture`` module solves this problem. Instead of ``texpos`` directly, it operates on the ``TexposHandle`` entity, which is essentially a reference to ``texpos``. -Thanks to this handle, it is possible to get a valid ``texpos`` at any time. +The ``textures`` module solves this problem by providing a stable handle instead of a +raw ``texpos``. When we need to draw a particular tile, we can look up the current +``texpos`` value via the handle. * ``loadTileset(file, tile_px_w, tile_px_h)`` From c0ac7ad8a259ba88fbfe1906adf2b2a2aacbced4 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 12:48:47 +0300 Subject: [PATCH 418/851] Update docs/dev/Lua API.rst Co-authored-by: Myk --- docs/dev/Lua API.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 3f93a09b4..b7c226ff1 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2612,9 +2612,8 @@ raw ``texpos``. When we need to draw a particular tile, we can look up the curre * ``loadTileset(file, tile_px_w, tile_px_h)`` - Loads tileset from the image ``file`` with give tile dimension in pixels (image will be sliced in row major order). - - Returns an array of ``TexposHandle`` + Loads a tileset from the image ``file`` with give tile dimensions in pixels. The + image will be sliced in row major order. Returns an array of ``TexposHandle``. Example usage:: From 72dbb68a5cf38c22104426618d16cd677e3b75d9 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 12:48:54 +0300 Subject: [PATCH 419/851] Update docs/dev/Lua API.rst Co-authored-by: Myk --- docs/dev/Lua API.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index b7c226ff1..35e2372f3 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2622,9 +2622,9 @@ raw ``texpos``. When we need to draw a particular tile, we can look up the curre * ``getTexposByHandle(handle)`` - Get ``texpos`` by ``TexposHandle``. - Always use this method if you need to get valid texpos for your texture. - ``texpos`` can change on game textures reset, but the handle will be the same. + Get the current ``texpos`` for the given ``TexposHandle``. Always use this method to + get the ``texpos`` for your texture. ``texpos`` can change when game textures are + reset, but the handle will be the same. * ``createTile(pixels, tile_px_w, tile_px_h)`` From 14c4e948ba4115b1c9f236ce7fde340113460472 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 12:49:01 +0300 Subject: [PATCH 420/851] Update docs/dev/Lua API.rst Co-authored-by: Myk --- docs/dev/Lua API.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 35e2372f3..44512c010 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2635,11 +2635,10 @@ raw ``texpos``. When we need to draw a particular tile, we can look up the curre * ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h)`` - Create and register a new texture with the given texture dimension and array of ``pixels`` as data in row major order. - Then slice it on tiles with the given dimension in row major order. - Each pixel is an integer representing color in packed RBGA format (for example #0022FF11). - - Returns an array of ``TexposHandle``. + Create and register a new texture with the given texture dimensions and an array of + ``pixels`` in row major order. Then slice it into tiles with the given tile + dimensions. Each pixel is an integer representing color in packed RBGA format (for + example #0022FF11). Returns an array of ``TexposHandle``. * ``deleteHandle(handle)`` From a2d1d416c432aad961a9261a34be0f1247959112 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 12:49:09 +0300 Subject: [PATCH 421/851] Update docs/dev/Lua API.rst Co-authored-by: Myk --- docs/dev/Lua API.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 44512c010..e06d75b09 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5400,7 +5400,9 @@ The parent widget owns the range values, and can control them independently (e.g gui.textures ============ -This module contains preloaded ``DFHack`` graphic assets and provide several helper methods to get ``texpos`` by offset in tilest (in row major position). +This module contains convenience methods for accessing default DFHack graphic assets. +Pass the ``offset`` in tiles (in row major position) to get a particular tile from the +asset. ``offset`` 0 is the first tile. * ``tp_green_pin(offset)`` tileset: ``hack/data/art/green-pin.png`` * ``tp_red_pin(offset)`` tileset: ``hack/data/art/red-pin.png`` From 72a985c3b0c74b3dcd6c5a6e7a4330b72973679f Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 12:49:17 +0300 Subject: [PATCH 422/851] Update docs/dev/Lua API.rst Co-authored-by: Myk --- 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 e06d75b09..c25de597a 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5415,7 +5415,7 @@ asset. ``offset`` 0 is the first tile. * ``tp_border_panel(offset)`` tileset: ``hack/data/art/border-panel.png`` * ``tp_border_window(offset)`` tileset: ``hack/data/art/order-window.png`` -Example usega:: +Example usage:: local textures = require('gui.textures') local first_border_texpos = textures.tp_border_thin(1) From 63913567cf75d67229f40856c1dc83567c840997 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 12:49:28 +0300 Subject: [PATCH 423/851] Update docs/dev/Lua API.rst Co-authored-by: Myk --- docs/dev/Lua API.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index c25de597a..fe5e19865 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3915,9 +3915,6 @@ These modules make extensive use of the ``class`` module, and define things ranging from the basic ``Painter``, ``View`` and ``Screen`` classes, to fully functional predefined dialogs. -In addition to the ``gui`` module, there is a ``textures`` module that allows -you to perform actions on textures to use them as tiles during rendering. - gui === From 02d33e532dd78b8693d7134159816894dedbee98 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 12:49:40 +0300 Subject: [PATCH 424/851] Update docs/dev/Lua API.rst Co-authored-by: Myk --- docs/dev/Lua API.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index fe5e19865..63901529a 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2642,9 +2642,9 @@ raw ``texpos``. When we need to draw a particular tile, we can look up the curre * ``deleteHandle(handle)`` - ``handle`` here can be signle ``TexposHandle``, or array of ``TexposHandle``. - Deletes all metadata and texture(s) itself by given handle(s). - You must be sure that the game does not use this texture in rendering process. + ``handle`` here can be single ``TexposHandle`` or an array of ``TexposHandle``. + Deletes all metadata and texture(s) related to the given handle(s). The handles + become invalid after this call. Filesystem module From 47a22025a0dedf2eca1ade4cf55adabda21530a8 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Wed, 30 Aug 2023 12:49:48 +0300 Subject: [PATCH 425/851] Update docs/dev/Lua API.rst Co-authored-by: Myk --- docs/dev/Lua API.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 63901529a..8096b1375 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2628,10 +2628,9 @@ raw ``texpos``. When we need to draw a particular tile, we can look up the curre * ``createTile(pixels, tile_px_w, tile_px_h)`` - Create and register new a texture with the given tile dimension and array of ``pixels`` as data in row major order. - Each pixel is an integer representing color in packed RBGA format (for example, #0022FF11). - - Returns ``TexposHandle``. + Create and register a new texture with the given tile dimensions and an array of + ``pixels`` in row major order. Each pixel is an integer representing color in packed + RBGA format (for example, #0022FF11). Returns a ``TexposHandle``. * ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h)`` From 2c97ab9c8db9cfe75560c73ab4d958f2e399784e Mon Sep 17 00:00:00 2001 From: Mikhail Date: Wed, 30 Aug 2023 17:16:59 +0300 Subject: [PATCH 426/851] Tidying up melee skill and ranged skill funcitons in sort.lua. --- plugins/lua/sort.lua | 93 +++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 02431bd7f..09740f7c3 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -16,12 +16,10 @@ local MELEE_WEAPON_SKILLS = { df.job_skill.MACE, df.job_skill.HAMMER, df.job_skill.SPEAR, - -- df.job_skill.MELEE_COMBAT, --Fighter } local RANGED_WEAPON_SKILLS = { df.job_skill.CROSSBOW, - -- df.job_skill.RANGED_COMBAT, } local LEADERSHIP_SKILLS = { @@ -125,9 +123,7 @@ local function get_max_skill(unit_id, list) return max end -local function melee_skill_effectiveness(unit_id, skill_list) - local unit = df.unit.find(unit_id) - +local function melee_skill_effectiveness(unit, skill_list) -- Physical attributes local strength = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.STRENGTH) local agility = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.AGILITY) @@ -141,15 +137,15 @@ local function melee_skill_effectiveness(unit_id, skill_list) local kinesthetic_sense = dfhack.units.getMentalAttrValue(unit, df.mental_attribute_type.KINESTHETIC_SENSE) -- Skills - local melee_skill = get_max_skill(unit_id, skill_list) - if melee_skill then - melee_skill = melee_skill.rating - else - melee_skill = 0 + -- Finding the highest skill + skill_rating = 0 + for _, skill in ipairs(skill_list) do + melee_skill = dfhack.units.getNominalSkill(unit, skill, true) + skill_rating = math.max(skill_rating, melee_skill) end - local melee_combat = dfhack.units.getNominalSkill(unit, df.job_skill.MELEE_COMBAT, true) + local melee_combat_rating = dfhack.units.getNominalSkill(unit, df.job_skill.MELEE_COMBAT, true) - local rating = melee_skill * 27000 + melee_combat * 9000 + local rating = skill_rating * 27000 + melee_combat_rating * 9000 + strength * 180 + body_size_base * 100 + kinesthetic_sense * 50 + endurance * 50 + agility * 30 + toughness * 20 + willpower * 20 + spatial_sense * 20 return rating @@ -158,30 +154,33 @@ end local function make_sort_by_melee_skill_effectiveness_desc(list) return function(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end - if unit_id_1 == -1 then return -1 end - if unit_id_2 == -1 then return 1 end - local rating1 = melee_skill_effectiveness(unit_id_1, list) - local rating2 = melee_skill_effectiveness(unit_id_2, list) + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = melee_skill_effectiveness(unit1, list) + local rating2 = melee_skill_effectiveness(unit2, list) if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end - if rating1 ~= rating2 then return utils.compare(rating2, rating1) end + return utils.compare(rating2, rating1) end end local function make_sort_by_melee_skill_effectiveness_asc(list) return function(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end - if unit_id_1 == -1 then return -1 end - if unit_id_2 == -1 then return 1 end - local rating1 = melee_skill_effectiveness(unit_id_1, list) - local rating2 = melee_skill_effectiveness(unit_id_2, list) + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = melee_skill_effectiveness(unit1, list) + local rating2 = melee_skill_effectiveness(unit2, list) if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end - if rating1 ~= rating2 then return utils.compare(rating1, rating2) end + return utils.compare(rating1, rating2) end end -local function ranged_skill_effectiveness(unit_id, skill_list) - local unit = df.unit.find(unit_id) - +-- FUnction could easily be adapted to different weapon types. +local function ranged_skill_effectiveness(unit, skill_list) -- Physical attributes local agility = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.AGILITY) @@ -191,15 +190,15 @@ local function ranged_skill_effectiveness(unit_id, skill_list) local focus = dfhack.units.getMentalAttrValue(unit, df.mental_attribute_type.FOCUS) -- Skills - local ranged_skill = get_max_skill(unit_id, skill_list) - if ranged_skill then - ranged_skill = ranged_skill.rating - else - ranged_skill = 0 + -- Finding the highest skill + skill_rating = 0 + for _, skill in ipairs(skill_list) do + ranged_skill = dfhack.units.getNominalSkill(unit, skill, true) + skill_rating = math.max(skill_rating, ranged_skill) end local ranged_combat = dfhack.units.getNominalSkill(unit, df.job_skill.RANGED_COMBAT, true) - local rating = ranged_skill * 24000 + ranged_combat * 8000 + local rating = skill_rating * 24000 + ranged_combat * 8000 + agility * 15 + spatial_sense * 15 + kinesthetic_sense * 6 + focus * 6 return rating end @@ -207,24 +206,28 @@ end local function make_sort_by_ranged_skill_effectiveness_desc(list) return function(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end - if unit_id_1 == -1 then return -1 end - if unit_id_2 == -1 then return 1 end - local rating1 = ranged_skill_effectiveness(unit_id_1, list) - local rating2 = ranged_skill_effectiveness(unit_id_2, list) + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = ranged_skill_effectiveness(unit1, list) + local rating2 = ranged_skill_effectiveness(unit2, list) if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end - if rating1 ~= rating2 then return utils.compare(rating2, rating1) end + return utils.compare(rating2, rating1) end end local function make_sort_by_ranged_skill_effectiveness_asc(list) return function(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end - if unit_id_1 == -1 then return -1 end - if unit_id_2 == -1 then return 1 end - local rating1 = ranged_skill_effectiveness(unit_id_1, list) - local rating2 = ranged_skill_effectiveness(unit_id_2, list) + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = ranged_skill_effectiveness(unit1, list) + local rating2 = ranged_skill_effectiveness(unit2, list) if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end - if rating1 ~= rating2 then return utils.compare(rating1, rating2) end + return utils.compare(rating1, rating2) end end @@ -308,7 +311,7 @@ local function make_sort_by_skill_asc(sort_skill) end end --- Statistical rating that is bigger for dwarves that are mentally stable +-- Statistical rating that is higher for dwarves that are mentally stable local function mental_stability(unit) local ALTRUISM = unit.status.current_soul.personality.traits.ALTRUISM local ANXIETY_PROPENSITY = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY @@ -379,7 +382,7 @@ local function sort_by_mental_stability_asc(unit_id_1, unit_id_2) return utils.compare(rating1, rating2) end --- Statistical rating that is bigger for more potent dwarves in long run melee military training +-- Statistical rating that is higher for more potent dwarves in long run melee military training -- Rating considers fighting melee opponents -- Wounds are not considered! local function melee_combat_potential(unit) @@ -429,7 +432,7 @@ local function sort_by_melee_combat_potential_asc(unit_id_1, unit_id_2) return utils.compare(rating1, rating2) end --- Statistical rating that is bigger for more potent dwarves in long run ranged military training +-- Statistical rating that is higher for more potent dwarves in long run ranged military training -- Wounds are not considered! local function ranged_combat_potential(unit) -- Physical attributes @@ -506,7 +509,7 @@ SquadAssignmentOverlay.ATTRS{ default_pos={x=-33, y=40}, default_enabled=true, viewscreens='dwarfmode/UnitSelector/SQUAD_FILL_POSITION', - frame={w=65, h=9}, + frame={w=75, h=9}, frame_style=gui.FRAME_PANEL, frame_background=gui.CLEAR_PEN, } From 4a788e79c3d8355e52a1a2ab4e499394307c9ffe Mon Sep 17 00:00:00 2001 From: Myk Date: Wed, 30 Aug 2023 23:26:03 -0700 Subject: [PATCH 427/851] Apply suggestions from code review --- plugins/lua/sort.lua | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 09740f7c3..0f6f73558 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -81,6 +81,9 @@ local function sort_by_stress_desc(unit_id_1, unit_id_2) if not unit2 then return 1 end local happiness1 = unit1.status.current_soul.personality.stress local happiness2 = unit2.status.current_soul.personality.stress + if happiness1 == happiness2 then + return sort_by_name_desc(unit_id_1, unit_id_2) + end return utils.compare(happiness2, happiness1) end @@ -92,6 +95,9 @@ local function sort_by_stress_asc(unit_id_1, unit_id_2) if not unit2 then return 1 end local happiness1 = unit1.status.current_soul.personality.stress local happiness2 = unit2.status.current_soul.personality.stress + if happiness1 == happiness2 then + return sort_by_name_desc(unit_id_1, unit_id_2) + end return utils.compare(happiness1, happiness2) end @@ -138,16 +144,16 @@ local function melee_skill_effectiveness(unit, skill_list) -- Skills -- Finding the highest skill - skill_rating = 0 + local skill_rating = 0 for _, skill in ipairs(skill_list) do - melee_skill = dfhack.units.getNominalSkill(unit, skill, true) + local melee_skill = dfhack.units.getNominalSkill(unit, skill, true) skill_rating = math.max(skill_rating, melee_skill) end local melee_combat_rating = dfhack.units.getNominalSkill(unit, df.job_skill.MELEE_COMBAT, true) local rating = skill_rating * 27000 + melee_combat_rating * 9000 - + strength * 180 + body_size_base * 100 + kinesthetic_sense * 50 + endurance * 50 - + agility * 30 + toughness * 20 + willpower * 20 + spatial_sense * 20 + + strength * 180 + body_size_base * 100 + kinesthetic_sense * 50 + endurance * 50 + + agility * 30 + toughness * 20 + willpower * 20 + spatial_sense * 20 return rating end @@ -191,9 +197,9 @@ local function ranged_skill_effectiveness(unit, skill_list) -- Skills -- Finding the highest skill - skill_rating = 0 + local skill_rating = 0 for _, skill in ipairs(skill_list) do - ranged_skill = dfhack.units.getNominalSkill(unit, skill, true) + local ranged_skill = dfhack.units.getNominalSkill(unit, skill, true) skill_rating = math.max(skill_rating, ranged_skill) end local ranged_combat = dfhack.units.getNominalSkill(unit, df.job_skill.RANGED_COMBAT, true) @@ -400,7 +406,7 @@ local function melee_combat_potential(unit) -- melee combat potential rating local rating = strength * 264 + endurance * 84 + body_size_base * 77 + kinesthetic_sense * 74 - + agility * 33 + willpower * 31 + spatial_sense * 27 + toughness * 25 + + agility * 33 + willpower * 31 + spatial_sense * 27 + toughness * 25 return rating end From 742c8bbfb82237b7620de9d7b155e7b70832b9a0 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 31 Aug 2023 06:32:03 +0000 Subject: [PATCH 428/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 0d5b6e691..3ed41e415 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 0d5b6e6918e39454bf24855198598866c13a3568 +Subproject commit 3ed41e4152c6d973783d7bfc0a30cb3d1a6ac1a3 From 38ece5aa937d569f64536467f3e4e8102f7ade96 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 31 Aug 2023 06:03:52 -0700 Subject: [PATCH 429/851] fix status output character encoding so dwarf and item names and item descriptions are printed correctly --- plugins/tailor.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/plugins/tailor.cpp b/plugins/tailor.cpp index af2a61e4a..e74a07330 100644 --- a/plugins/tailor.cpp +++ b/plugins/tailor.cpp @@ -222,7 +222,7 @@ public: // only count dyed std::string d; i->getItemDescription(&d, 0); - TRACE(cycle).print("tailor: skipping undyed %s\n", d.c_str()); + TRACE(cycle).print("tailor: skipping undyed %s\n", DF2CONSOLE(d).c_str()); continue; } MaterialInfo mat(i); @@ -242,7 +242,7 @@ public: { std::string d; i->getItemDescription(&d, 0); - DEBUG(cycle).print("tailor: weird cloth item found: %s (%d)\n", d.c_str(), i->id); + DEBUG(cycle).print("tailor: weird cloth item found: %s (%d)\n", DF2CONSOLE(d).c_str(), i->id); } } } @@ -301,14 +301,14 @@ public: available[std::make_pair(ty, usize)] -= 1; DEBUG(cycle).print("tailor: allocating a %s (size %d) to %s\n", ENUM_KEY_STR(item_type, ty).c_str(), usize, - Translation::TranslateName(&u->name, false).c_str()); + DF2CONSOLE(Translation::TranslateName(&u->name, false)).c_str()); wearing.insert(ty); } else if (ordered.count(ty) == 0) { DEBUG(cycle).print ("tailor: %s (size %d) worn by %s (size %d) needs replacement, but none available\n", - description.c_str(), isize, - Translation::TranslateName(&u->name, false).c_str(), usize); + DF2CONSOLE(description).c_str(), isize, + DF2CONSOLE(Translation::TranslateName(&u->name, false)).c_str(), usize); needed[std::make_pair(ty, usize)] += 1; ordered.insert(ty); } @@ -323,8 +323,8 @@ public: INFO(cycle).print( "tailor: %s %s from %s.\n", (confiscated ? "confiscated" : "could not confiscate"), - description.c_str(), - Translation::TranslateName(&u->name, false).c_str() + DF2CONSOLE(description).c_str(), + DF2CONSOLE(Translation::TranslateName(&u->name, false)).c_str() ); } @@ -341,7 +341,7 @@ public: TRACE(cycle).print("tailor: one %s of size %d needed to cover %s\n", ENUM_KEY_STR(item_type, ty).c_str(), usize, - Translation::TranslateName(&u->name, false).c_str()); + DF2CONSOLE(Translation::TranslateName(&u->name, false)).c_str()); needed[std::make_pair(ty, usize)] += 1; } } @@ -416,7 +416,7 @@ public: { supply[m] -= o->amount_left; TRACE(cycle).print("tailor: supply of %s reduced by %d due to being required for an existing order\n", - m.name.c_str(), o->amount_left); + DF2CONSOLE(m.name).c_str(), o->amount_left); } } @@ -508,11 +508,11 @@ public: if (!can_make) { - INFO(cycle).print("tailor: civilization cannot make %s, skipped\n", name_p.c_str()); + INFO(cycle).print("tailor: civilization cannot make %s, skipped\n", DF2CONSOLE(name_p).c_str()); continue; } - DEBUG(cycle).print("tailor: ordering %d %s\n", count, name_p.c_str()); + DEBUG(cycle).print("tailor: ordering %d %s\n", count, DF2CONSOLE(name_p).c_str()); for (auto& m : material_order) { @@ -528,7 +528,7 @@ public: { c = supply[m] - res; TRACE(cycle).print("tailor: order reduced from %d to %d to protect reserves of %s\n", - count, c, m.name.c_str()); + count, c, DF2CONSOLE(m.name).c_str()); } supply[m] -= c; @@ -552,8 +552,8 @@ public: order->id, c, bitfield_to_string(order->material_category).c_str(), - (c > 1) ? name_p.c_str() : name_s.c_str(), - world->raws.creatures.all[order->hist_figure_id]->name[1].c_str() + DF2CONSOLE((c > 1) ? name_p : name_s).c_str(), + DF2CONSOLE(world->raws.creatures.all[order->hist_figure_id]->name[1]).c_str() ); count -= c; @@ -561,7 +561,7 @@ public: } else { - TRACE(cycle).print("tailor: material %s skipped due to lack of reserves, %d available\n", m.name.c_str(), supply[m]); + TRACE(cycle).print("tailor: material %s skipped due to lack of reserves, %d available\n", DF2CONSOLE(m.name).c_str(), supply[m]); } } From 088fa9a35c55d313f8311742042972fe496d3ec3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 31 Aug 2023 10:53:43 -0700 Subject: [PATCH 430/851] instrument textures module and clean up gui --- library/lua/gui.lua | 10 +++++----- library/modules/Textures.cpp | 5 +++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 1a4a7f197..bba7222b9 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -940,21 +940,21 @@ function FRAME_WINDOW(resizable) end return frame end -function FRAME_PANEL(resizable) +function FRAME_PANEL() return make_frame(textures.tp_border_panel, false) end -function FRAME_MEDIUM(resizable) +function FRAME_MEDIUM() return make_frame(textures.tp_border_medium, false) end -function FRAME_BOLD(resizable) +function FRAME_BOLD() return make_frame(textures.tp_border_bold, true) end -function FRAME_INTERIOR(resizable) +function FRAME_INTERIOR() local frame = make_frame(textures.tp_border_thin, false) frame.signature_pen = false return frame end -function FRAME_INTERIOR_MEDIUM(resizable) +function FRAME_INTERIOR_MEDIUM() local frame = make_frame(textures.tp_border_medium, false) frame.signature_pen = false return frame diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 25af2135a..7a6964732 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -191,6 +191,7 @@ void Textures::deleteHandle(TexposHandle handle) { } static void reset_texpos() { + DEBUG(textures).print("resetting texture mappings\n"); g_handle_to_texpos.clear(); } @@ -207,6 +208,7 @@ struct tracking_stage_new_region : df::viewscreen_new_regionst { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_raw_load_stage != this->raw_load_stage) { + TRACE(textures).print("raw_load_stage %d -> %d\n", this->m_raw_load_stage, this->raw_load_stage); this->m_raw_load_stage = this->raw_load_stage; if (this->m_raw_load_stage == 1) reset_texpos(); @@ -225,6 +227,7 @@ struct tracking_stage_adopt_region : df::viewscreen_adopt_regionst { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { + TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); this->m_cur_step = this->cur_step; if (this->m_cur_step == 1) reset_texpos(); @@ -243,6 +246,7 @@ struct tracking_stage_load_region : df::viewscreen_loadgamest { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { + TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); this->m_cur_step = this->cur_step; if (this->m_cur_step == 1) reset_texpos(); @@ -261,6 +265,7 @@ struct tracking_stage_new_arena : df::viewscreen_new_arenast { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { + TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); this->m_cur_step = this->cur_step; if (this->m_cur_step == 0) reset_texpos(); From cf53283f335f03e5c774d38deea00427dde96f4e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 31 Aug 2023 14:14:45 -0700 Subject: [PATCH 431/851] remove unneeded modification of CMAKE_CXX_FLAGS_RELWITHDEBINFO -g is already in the flags, we just end up adding it a second time --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b8c29b91..edbe5d935 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -228,7 +228,6 @@ if(UNIX) # ensure compatibility with older CPUs add_definitions(-DLINUX_BUILD) set(GCC_COMMON_FLAGS "-fvisibility=hidden -mtune=generic -Wall -Werror -Wl,--disable-new-dtags") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COMMON_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_COMMON_FLAGS}") if(DFHACK_BUILD_64) From 40bfb6b8fffaebf5d258918977ce028e4748cfd3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 31 Aug 2023 17:24:02 -0400 Subject: [PATCH 432/851] Hack to force GCC to invoke cancel_job() through DF's vtable GCC appears to be optimizing the call to `cancel_job()` to use the stub in *DFHack's* job_handler vtable, which is a no-op. Lua was unaffected because it invokes vmethods through method pointers (without knowing the target instance at compile time), so use a similar approach here for now. As mentioned by @ab9rf on Discord, we should pursue an alternative like asking Bay12 to expose the relevant code through a global `std::function` instead of a vmethod. --- library/modules/Job.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index 1976d2e12..869a6b329 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -387,7 +387,14 @@ bool DFHack::Job::removeJob(df::job* job) { // call the job cancel vmethod graciously provided by The Toady One. // job_handler::cancel_job calls job::~job, and then deletes job (this has // been confirmed by disassembly). - world->jobs.cancel_job(job); + + // HACK: GCC (starting around GCC 10 targeting C++20 as of v50.09) optimizes + // out the vmethod call here regardless of optimization level, so we need to + // invoke the vmethod manually through a pointer, as the Lua wrapper does. + // `volatile` does not seem to be necessary but is included for good + // measure. + volatile auto cancel_job_method = &df::job_handler::cancel_job; + (world->jobs.*cancel_job_method)(job); return true; } From bb79755efd62489f98f69c0401645d1b019f2ad5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 31 Aug 2023 17:41:52 -0400 Subject: [PATCH 433/851] Add test that removeJob() actually removes jobs --- test/modules/job.lua | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 test/modules/job.lua diff --git a/test/modules/job.lua b/test/modules/job.lua new file mode 100644 index 000000000..518cb26a3 --- /dev/null +++ b/test/modules/job.lua @@ -0,0 +1,19 @@ +config.target = 'core' +config.mode = 'title' -- alters world state, not safe when a world is loaded + +function test.removeJob() + -- removeJob() calls DF code, so ensure that that DF code is actually running + + -- for an explanation of why this is necessary to check, + -- see https://github.com/DFHack/dfhack/pull/3713 and Job.cpp:removeJob() + + expect.nil_(df.global.world.jobs.list.next, 'job list is not empty') + + local job = df.job:new() -- will be deleted by removeJob() if the test passes + dfhack.job.linkIntoWorld(job) + expect.true_(df.global.world.jobs.list.next, 'job list is empty') + expect.eq(df.global.world.jobs.list.next.item, job, 'expected job not found in list') + + expect.true_(dfhack.job.removeJob(job)) + expect.nil_(df.global.world.jobs.list.next, 'job list is not empty after removeJob()') +end From afb26b9ddd1302e937b09abec32f21fed3ad3024 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 31 Aug 2023 19:10:18 -0700 Subject: [PATCH 434/851] add requested filters for squad assignment screen and redo layout as a vertical panel since there's not enough space otherwise --- plugins/lua/sort.lua | 355 +++++++++++++++++++++++++------------------ plugins/lua/zone.lua | 4 +- 2 files changed, 209 insertions(+), 150 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 0f6f73558..73b06a2a8 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -2,11 +2,10 @@ local _ENV = mkmodule('plugins.sort') local gui = require('gui') local overlay = require('plugins.overlay') +local setbelief = reqscript('modtools/set-belief') local utils = require('utils') local widgets = require('gui.widgets') -local setbelief = reqscript("modtools/set-belief") - local CH_UP = string.char(30) local CH_DN = string.char(31) @@ -22,12 +21,6 @@ local RANGED_WEAPON_SKILLS = { df.job_skill.CROSSBOW, } -local LEADERSHIP_SKILLS = { - df.job_skill.MILITARY_TACTICS, - df.job_skill.LEADERSHIP, - df.job_skill.TEACHING, -} - local function sort_noop(a, b) -- this function is used as a marker and never actually gets called error('sort_noop should not be called') @@ -237,46 +230,6 @@ local function make_sort_by_ranged_skill_effectiveness_asc(list) end end -local function make_sort_by_skill_list_desc(list) - return function(unit_id_1, unit_id_2) - if unit_id_1 == unit_id_2 then return 0 end - if unit_id_1 == -1 then return -1 end - if unit_id_2 == -1 then return 1 end - local s1 = get_max_skill(unit_id_1, list) - local s2 = get_max_skill(unit_id_2, list) - if s1 == s2 then return sort_by_name_desc(unit_id_1, unit_id_2) end - if not s2 then return -1 end - if not s1 then return 1 end - if s1.rating ~= s2.rating then - return utils.compare(s2.rating, s1.rating) - end - if s1.experience ~= s2.experience then - return utils.compare(s2.experience, s1.experience) - end - return sort_by_name_desc(unit_id_1, unit_id_2) - end -end - -local function make_sort_by_skill_list_asc(list) - return function(unit_id_1, unit_id_2) - if unit_id_1 == unit_id_2 then return 0 end - if unit_id_1 == -1 then return -1 end - if unit_id_2 == -1 then return 1 end - local s1 = get_max_skill(unit_id_1, list) - local s2 = get_max_skill(unit_id_2, list) - if s1 == s2 then return sort_by_name_desc(unit_id_1, unit_id_2) end - if not s2 then return 1 end - if not s1 then return -1 end - if s1.rating ~= s2.rating then - return utils.compare(s1.rating, s2.rating) - end - if s1.experience ~= s2.experience then - return utils.compare(s1.experience, s2.experience) - end - return sort_by_name_desc(unit_id_1, unit_id_2) - end -end - local function make_sort_by_skill_desc(sort_skill) return function(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end @@ -490,8 +443,10 @@ local SORT_FNS = { sort_by_any_melee_asc=make_sort_by_melee_skill_effectiveness_asc(MELEE_WEAPON_SKILLS), sort_by_any_ranged_desc=make_sort_by_ranged_skill_effectiveness_desc(RANGED_WEAPON_SKILLS), sort_by_any_ranged_asc=make_sort_by_ranged_skill_effectiveness_asc(RANGED_WEAPON_SKILLS), - sort_by_leadership_desc=make_sort_by_skill_list_desc(LEADERSHIP_SKILLS), - sort_by_leadership_asc=make_sort_by_skill_list_asc(LEADERSHIP_SKILLS), + sort_by_teacher_desc=make_sort_by_skill_desc(df.job_skill.TEACHING), + sort_by_teacher_asc=make_sort_by_skill_asc(df.job_skill.TEACHING), + sort_by_tactics_desc=make_sort_by_skill_desc(df.job_skill.MILITARY_TACTICS), + sort_by_tactics_asc=make_sort_by_skill_asc(df.job_skill.MILITARY_TACTICS), sort_by_axe_desc=make_sort_by_skill_desc(df.job_skill.AXE), sort_by_axe_asc=make_sort_by_skill_asc(df.job_skill.AXE), sort_by_sword_desc=make_sort_by_skill_desc(df.job_skill.SWORD), @@ -512,71 +467,76 @@ local SORT_FNS = { SquadAssignmentOverlay = defclass(SquadAssignmentOverlay, overlay.OverlayWidget) SquadAssignmentOverlay.ATTRS{ - default_pos={x=-33, y=40}, + default_pos={x=23, y=5}, default_enabled=true, viewscreens='dwarfmode/UnitSelector/SQUAD_FILL_POSITION', - frame={w=75, h=9}, + frame={w=38, h=25}, frame_style=gui.FRAME_PANEL, frame_background=gui.CLEAR_PEN, + autoarrange_subviews=true, + autoarrange_gap=1, } function SquadAssignmentOverlay:init() self.dirty = true self:addviews{ - widgets.CycleHotkeyLabel{ - view_id='sort', - frame={l=0, t=0, w=29}, - label='Sort by:', - key='CUSTOM_SHIFT_S', - options={ - {label='any melee skill'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc, pen=COLOR_GREEN}, - {label='any melee skill'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc, pen=COLOR_YELLOW}, - {label='any ranged skill'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc, pen=COLOR_GREEN}, - {label='any ranged skill'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc, pen=COLOR_YELLOW}, - {label='any leader skill'..CH_DN, value=SORT_FNS.sort_by_leadership_desc, pen=COLOR_GREEN}, - {label='any leader skill'..CH_UP, value=SORT_FNS.sort_by_leadership_asc, pen=COLOR_YELLOW}, - {label='name'..CH_DN, value=sort_by_name_desc, pen=COLOR_GREEN}, - {label='name'..CH_UP, value=sort_by_name_asc, pen=COLOR_YELLOW}, - {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc, pen=COLOR_GREEN}, - {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc, pen=COLOR_YELLOW}, - {label='stress'..CH_DN, value=sort_by_stress_desc, pen=COLOR_GREEN}, - {label='stress'..CH_UP, value=sort_by_stress_asc, pen=COLOR_YELLOW}, - {label='axe skill'..CH_DN, value=SORT_FNS.sort_by_axe_desc, pen=COLOR_GREEN}, - {label='axe skill'..CH_UP, value=SORT_FNS.sort_by_axe_asc, pen=COLOR_YELLOW}, - {label='sword skill'..CH_DN, value=SORT_FNS.sort_by_sword_desc, pen=COLOR_GREEN}, - {label='sword skill'..CH_UP, value=SORT_FNS.sort_by_sword_asc, pen=COLOR_YELLOW}, - {label='mace skill'..CH_DN, value=SORT_FNS.sort_by_mace_desc, pen=COLOR_GREEN}, - {label='mace skill'..CH_UP, value=SORT_FNS.sort_by_mace_asc, pen=COLOR_YELLOW}, - {label='hammer skill'..CH_DN, value=SORT_FNS.sort_by_hammer_desc, pen=COLOR_GREEN}, - {label='hammer skill'..CH_UP, value=SORT_FNS.sort_by_hammer_asc, pen=COLOR_YELLOW}, - {label='spear skill'..CH_DN, value=SORT_FNS.sort_by_spear_desc, pen=COLOR_GREEN}, - {label='spear skill'..CH_UP, value=SORT_FNS.sort_by_spear_asc, pen=COLOR_YELLOW}, - {label='crossbow skill'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc, pen=COLOR_GREEN}, - {label='crossbow skill'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc, pen=COLOR_YELLOW}, - {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, - {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, - {label='melee potential'..CH_DN, value=sort_by_melee_combat_potential_desc, pen=COLOR_GREEN}, - {label='melee potential'..CH_UP, value=sort_by_melee_combat_potential_asc, pen=COLOR_YELLOW}, - {label='ranged potential'..CH_DN, value=sort_by_ranged_combat_potential_desc, pen=COLOR_GREEN}, - {label='ranged potential'..CH_UP, value=sort_by_ranged_combat_potential_asc, pen=COLOR_YELLOW}, - }, - initial_option=SORT_FNS.sort_by_any_melee_desc, - on_change=self:callback('refresh_list', 'sort'), - }, widgets.EditField{ view_id='search', - frame={l=32, t=0}, + frame={l=0}, label_text='Search: ', on_char=function(ch) return ch:match('[%l _-]') end, on_change=function() self:refresh_list() end, }, widgets.Panel{ - frame={t=2, l=0, r=0, b=0}, + frame={l=0, r=0, h=15}, + frame_style=gui.FRAME_INTERIOR, subviews={ + widgets.CycleHotkeyLabel{ + view_id='sort', + frame={t=0, l=0}, + label='Sort by:', + key='CUSTOM_SHIFT_S', + options={ + {label='melee effectiveness'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc, pen=COLOR_GREEN}, + {label='melee effectiveness'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc, pen=COLOR_YELLOW}, + {label='ranged effectiveness'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc, pen=COLOR_GREEN}, + {label='ranged effectiveness'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc, pen=COLOR_YELLOW}, + {label='name'..CH_DN, value=sort_by_name_desc, pen=COLOR_GREEN}, + {label='name'..CH_UP, value=sort_by_name_asc, pen=COLOR_YELLOW}, + {label='teacher skill'..CH_DN, value=SORT_FNS.sort_by_teacher_desc, pen=COLOR_GREEN}, + {label='teacher skill'..CH_UP, value=SORT_FNS.sort_by_teacher_asc, pen=COLOR_YELLOW}, + {label='tactics skill'..CH_DN, value=SORT_FNS.sort_by_tactics_desc, pen=COLOR_GREEN}, + {label='tactics skill'..CH_UP, value=SORT_FNS.sort_by_tactics_asc, pen=COLOR_YELLOW}, + {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc, pen=COLOR_GREEN}, + {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc, pen=COLOR_YELLOW}, + {label='stress'..CH_DN, value=sort_by_stress_desc, pen=COLOR_GREEN}, + {label='stress'..CH_UP, value=sort_by_stress_asc, pen=COLOR_YELLOW}, + {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, + {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, + {label='axe skill'..CH_DN, value=SORT_FNS.sort_by_axe_desc, pen=COLOR_GREEN}, + {label='axe skill'..CH_UP, value=SORT_FNS.sort_by_axe_asc, pen=COLOR_YELLOW}, + {label='sword skill'..CH_DN, value=SORT_FNS.sort_by_sword_desc, pen=COLOR_GREEN}, + {label='sword skill'..CH_UP, value=SORT_FNS.sort_by_sword_asc, pen=COLOR_YELLOW}, + {label='mace skill'..CH_DN, value=SORT_FNS.sort_by_mace_desc, pen=COLOR_GREEN}, + {label='mace skill'..CH_UP, value=SORT_FNS.sort_by_mace_asc, pen=COLOR_YELLOW}, + {label='hammer skill'..CH_DN, value=SORT_FNS.sort_by_hammer_desc, pen=COLOR_GREEN}, + {label='hammer skill'..CH_UP, value=SORT_FNS.sort_by_hammer_asc, pen=COLOR_YELLOW}, + {label='spear skill'..CH_DN, value=SORT_FNS.sort_by_spear_desc, pen=COLOR_GREEN}, + {label='spear skill'..CH_UP, value=SORT_FNS.sort_by_spear_asc, pen=COLOR_YELLOW}, + {label='crossbow skill'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc, pen=COLOR_GREEN}, + {label='crossbow skill'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc, pen=COLOR_YELLOW}, + {label='melee potential'..CH_DN, value=sort_by_melee_combat_potential_desc, pen=COLOR_GREEN}, + {label='melee potential'..CH_UP, value=sort_by_melee_combat_potential_asc, pen=COLOR_YELLOW}, + {label='ranged potential'..CH_DN, value=sort_by_ranged_combat_potential_desc, pen=COLOR_GREEN}, + {label='ranged potential'..CH_UP, value=sort_by_ranged_combat_potential_asc, pen=COLOR_YELLOW}, + }, + initial_option=SORT_FNS.sort_by_any_melee_desc, + on_change=self:callback('refresh_list', 'sort'), + }, widgets.CycleHotkeyLabel{ view_id='sort_any_melee', - frame={t=0, l=0, w=10}, + frame={t=2, l=0, w=10}, options={ {label='any melee', value=sort_noop}, {label='any melee'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc, pen=COLOR_GREEN}, @@ -588,7 +548,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_any_ranged', - frame={t=0, l=13, w=11}, + frame={t=2, r=9, w=11}, options={ {label='any ranged', value=sort_noop}, {label='any ranged'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc, pen=COLOR_GREEN}, @@ -597,20 +557,9 @@ function SquadAssignmentOverlay:init() option_gap=0, on_change=self:callback('refresh_list', 'sort_any_ranged'), }, - widgets.CycleHotkeyLabel{ - view_id='sort_leadership', - frame={t=0, l=27, w=11}, - options={ - {label='leadership', value=sort_noop}, - {label='leadership'..CH_DN, value=SORT_FNS.sort_by_leadership_desc, pen=COLOR_GREEN}, - {label='leadership'..CH_UP, value=SORT_FNS.sort_by_leadership_asc, pen=COLOR_YELLOW}, - }, - option_gap=0, - on_change=self:callback('refresh_list', 'sort_leadership'), - }, widgets.CycleHotkeyLabel{ view_id='sort_name', - frame={t=0, l=41, w=5}, + frame={t=2, r=0, w=5}, options={ {label='name', value=sort_noop}, {label='name'..CH_DN, value=sort_by_name_desc, pen=COLOR_GREEN}, @@ -619,9 +568,31 @@ function SquadAssignmentOverlay:init() option_gap=0, on_change=self:callback('refresh_list', 'sort_name'), }, + widgets.CycleHotkeyLabel{ + view_id='sort_teacher', + frame={t=4, l=0, w=8}, + options={ + {label='teacher', value=sort_noop}, + {label='teacher'..CH_DN, value=SORT_FNS.sort_by_teacher_desc, pen=COLOR_GREEN}, + {label='teacher'..CH_UP, value=SORT_FNS.sort_by_teacher_asc, pen=COLOR_YELLOW}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_teacher'), + }, + widgets.CycleHotkeyLabel{ + view_id='sort_tactics', + frame={t=4, l=10, w=8}, + options={ + {label='tactics', value=sort_noop}, + {label='tactics'..CH_DN, value=SORT_FNS.sort_by_tactics_desc, pen=COLOR_GREEN}, + {label='tactics'..CH_UP, value=SORT_FNS.sort_by_tactics_asc, pen=COLOR_YELLOW}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_tactics'), + }, widgets.CycleHotkeyLabel{ view_id='sort_migrant_wave', - frame={t=0, l=49, w=13}, + frame={t=4, r=0, w=13}, options={ {label='migrant wave', value=sort_noop}, {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc, pen=COLOR_GREEN}, @@ -632,7 +603,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_stress', - frame={t=0, l=65, w=7}, + frame={t=6, l=0, w=7}, options={ {label='stress', value=sort_noop}, {label='stress'..CH_DN, value=sort_by_stress_desc, pen=COLOR_GREEN}, @@ -641,9 +612,20 @@ function SquadAssignmentOverlay:init() option_gap=0, on_change=self:callback('refresh_list', 'sort_stress'), }, + widgets.CycleHotkeyLabel{ + view_id='sort_mental_stability', + frame={t=6, r=0, w=17}, + options={ + {label='mental stability', value=sort_noop}, + {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, + {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, + }, + option_gap=0, + on_change=self:callback('refresh_list', 'sort_mental_stability'), + }, widgets.CycleHotkeyLabel{ view_id='sort_axe', - frame={t=2, l=0, w=4}, + frame={t=8, l=0, w=4}, options={ {label='axe', value=sort_noop}, {label='axe'..CH_DN, value=SORT_FNS.sort_by_axe_desc, pen=COLOR_GREEN}, @@ -654,7 +636,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_sword', - frame={t=2, l=7, w=6}, + frame={t=8, w=6}, options={ {label='sword', value=sort_noop}, {label='sword'..CH_DN, value=SORT_FNS.sort_by_sword_desc, pen=COLOR_GREEN}, @@ -665,7 +647,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_mace', - frame={t=2, l=16, w=5}, + frame={t=8, r=0, w=5}, options={ {label='mace', value=sort_noop}, {label='mace'..CH_DN, value=SORT_FNS.sort_by_mace_desc, pen=COLOR_GREEN}, @@ -676,7 +658,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_hammer', - frame={t=2, l=23, w=7}, + frame={t=10, l=0, w=7}, options={ {label='hammer', value=sort_noop}, {label='hammer'..CH_DN, value=SORT_FNS.sort_by_hammer_desc, pen=COLOR_GREEN}, @@ -687,7 +669,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_spear', - frame={t=2, l=34, w=6}, + frame={t=10, w=6}, options={ {label='spear', value=sort_noop}, {label='spear'..CH_DN, value=SORT_FNS.sort_by_spear_desc, pen=COLOR_GREEN}, @@ -698,7 +680,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_crossbow', - frame={t=2, l=43, w=9}, + frame={t=10, r=0, w=9}, options={ {label='crossbow', value=sort_noop}, {label='crossbow'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc, pen=COLOR_GREEN}, @@ -707,20 +689,9 @@ function SquadAssignmentOverlay:init() option_gap=0, on_change=self:callback('refresh_list', 'sort_crossbow'), }, - widgets.CycleHotkeyLabel{ - view_id='sort_mental_stability', - frame={t=4, l=0, w=17}, - options={ - {label='mental stability', value=sort_noop}, - {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, - {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, - }, - option_gap=0, - on_change=self:callback('refresh_list', 'sort_mental_stability'), - }, widgets.CycleHotkeyLabel{ view_id='sort_melee_combat_potential', - frame={t=4, l=20, w=16}, + frame={t=12, l=0, w=16}, options={ {label='melee potential', value=sort_noop}, {label='melee potential'..CH_DN, value=sort_by_melee_combat_potential_desc, pen=COLOR_GREEN}, @@ -731,7 +702,7 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_ranged_combat_potential', - frame={t=4, l=39, w=17}, + frame={t=12, r=0, w=17}, options={ {label='ranged potential', value=sort_noop}, {label='ranged potential'..CH_DN, value=sort_by_ranged_combat_potential_desc, pen=COLOR_GREEN}, @@ -740,7 +711,46 @@ function SquadAssignmentOverlay:init() option_gap=0, on_change=self:callback('refresh_list', 'sort_ranged_combat_potential'), }, - } + }, + }, + widgets.CycleHotkeyLabel{ + view_id='military', + frame={l=0}, + key='CUSTOM_SHIFT_Q', + label='Units in other squads:', + options={ + {label='Include', value='include', pen=COLOR_GREEN}, + {label='Only', value='only', pen=COLOR_YELLOW}, + {label='Exclude', value='exclude', pen=COLOR_RED}, + }, + initial_option='include', + on_change=function() self:refresh_list() end, + }, + widgets.CycleHotkeyLabel{ + view_id='officials', + frame={l=0}, + key='CUSTOM_SHIFT_O', + label='Appointed officials:', + options={ + {label='Include', value='include', pen=COLOR_GREEN}, + {label='Only', value='only', pen=COLOR_YELLOW}, + {label='Exclude', value='exclude', pen=COLOR_RED}, + }, + initial_option='include', + on_change=function() self:refresh_list() end, + }, + widgets.CycleHotkeyLabel{ + view_id='nobles', + frame={l=0, w=20}, + key='CUSTOM_SHIFT_N', + label='Nobility:', + options={ + {label='Include', value='include', pen=COLOR_GREEN}, + {label='Only', value='only', pen=COLOR_YELLOW}, + {label='Exclude', value='exclude', pen=COLOR_RED}, + }, + initial_option='include', + on_change=function() self:refresh_list() end, }, } end @@ -753,26 +763,69 @@ local function normalize_search_key(search_key) return out end -local function filter_matches(unit_id, search) +local function is_in_military(unit) + return unit.military.squad_id > -1 +end + +local function is_elected_or_appointed_official(unit) + if #unit.occupations > 0 then return true end + for _, noble_pos in ipairs(dfhack.units.getNoblePositions(unit) or {}) do + if noble_pos.position.flags.ELECTED or + (noble_pos.position.mandate_max == 0 and noble_pos.position.demand_max == 0) + then + return true + end + end + return false +end + +local function is_nobility(unit) + for _, noble_pos in ipairs(dfhack.units.getNoblePositions(unit) or {}) do + if not noble_pos.position.flags.ELECTED and + (noble_pos.position.mandate_max > 0 or noble_pos.position.demand_max > 0) + then + return true + end + end + return false +end + +local function filter_matches(unit_id, filter) if unit_id == -1 then return true end local unit = df.unit.find(unit_id) - if not unit then return true end + if not unit then return false end + if filter.military == 'only' and not is_in_military(unit) then return false end + if filter.military == 'exclude' and is_in_military(unit) then return false end + if filter.officials == 'only' and not is_elected_or_appointed_official(unit) then return false end + if filter.officials == 'exclude' and is_elected_or_appointed_official(unit) then return false end + if filter.nobles == 'only' and not is_nobility(unit) then return false end + if filter.nobles == 'exclude' and is_nobility(unit) then return false end + if #filter.search == 0 then return true end local search_key = dfhack.TranslateName(dfhack.units.getVisibleName(unit)) - if unit.status.current_soul then - for _,skill in ipairs(unit.status.current_soul.skills) do - search_key = (search_key or '') .. ' ' .. (df.job_skill[skill.id] or '') - end - end - return normalize_search_key(search_key):find(dfhack.toSearchNormalized(search)) + return normalize_search_key(search_key):find(dfhack.toSearchNormalized(filter.search)) +end + +local function is_noop_filter(filter) + return #filter.search == 0 and + filter.military == 'include' and + filter.officials == 'include' and + filter.nobles == 'include' +end + +local function is_filter_equal(a, b) + return a.search == b.search and + a.military == b.military and + a.officials == b.officials and + a.nobles == b.nobles end local unit_selector = df.global.game.main_interface.unit_selector -- this function uses the unused itemid and selected vectors to keep state, -- taking advantage of the fact that they are reset by DF when the list of units changes -local function filter_vector(search, prev_search) +local function filter_vector(filter, prev_filter) local unid_is_filtered = #unit_selector.selected >= 0 and unit_selector.selected[0] ~= 0 - if #search == 0 or #unit_selector.selected == 0 then + if is_noop_filter(filter) or #unit_selector.selected == 0 then if not unid_is_filtered then -- we haven't modified the unid vector; nothing to do here return @@ -783,8 +836,8 @@ local function filter_vector(search, prev_search) unit_selector.selected[0] = 0 return end - if unid_is_filtered and search == prev_search then - -- prev filter still stands + if unid_is_filtered and is_filter_equal(filter, prev_filter) then + -- filter hasn't changed; we don't need to refilter return end if unid_is_filtered then @@ -797,7 +850,7 @@ local function filter_vector(search, prev_search) end -- do the actual filtering for idx=#unit_selector.unid-1,0,-1 do - if not filter_matches(unit_selector.unid[idx], search) then + if not filter_matches(unit_selector.unid[idx], filter) then unit_selector.unid:erase(idx) end end @@ -807,17 +860,18 @@ local SORT_WIDGET_NAMES = { 'sort', 'sort_any_melee', 'sort_any_ranged', - 'sort_leadership', 'sort_name', + 'sort_teacher', + 'sort_tactics', 'sort_migrant_wave', 'sort_stress', + 'sort_mental_stability', 'sort_axe', 'sort_sword', 'sort_mace', 'sort_hammer', 'sort_spear', 'sort_crossbow', - 'sort_mental_stability', 'sort_melee_combat_potential', 'sort_ranged_combat_potential', } @@ -832,9 +886,14 @@ function SquadAssignmentOverlay:refresh_list(sort_widget, sort_fn) for _,widget_name in ipairs(SORT_WIDGET_NAMES) do self.subviews[widget_name]:setOption(sort_fn) end - local search = self.subviews.search.text - filter_vector(search, self.prev_search) - self.prev_search = search + local filter = { + search=self.subviews.search.text, + military=self.subviews.military:getOptionValue(), + officials=self.subviews.officials:getOptionValue(), + nobles=self.subviews.nobles:getOptionValue(), + } + filter_vector(filter, self.prev_filter or {}) + self.prev_filter = filter utils.sort_vector(unit_selector.unid, nil, sort_fn) end diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index b98ba8f08..bfdff01f0 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -279,7 +279,7 @@ function AssignAnimal:init() {label='Exclude', value='exclude', pen=COLOR_RED}, }, initial_option='include', - on_change=self:callback('refresh_list'), + on_change=function() self:refresh_list() end, }, widgets.CycleHotkeyLabel{ view_id='graze', @@ -293,7 +293,7 @@ function AssignAnimal:init() {label='Exclude', value='exclude', pen=COLOR_RED}, }, initial_option='include', - on_change=self:callback('refresh_list'), + on_change=function() self:refresh_list() end, }, }, }, From 52543f9fc0f2c4acb674bcf5a81099578ee3b6b4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 31 Aug 2023 19:14:47 -0700 Subject: [PATCH 435/851] clean out unused code/vars --- plugins/lua/sort.lua | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 73b06a2a8..cee694a4e 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -101,27 +101,6 @@ local function get_skill(unit_id, skill, unit) utils.binsearch(unit.status.current_soul.skills, skill, 'id') end -local function get_max_skill(unit_id, list) - local unit = df.unit.find(unit_id) - if not unit or not unit.status.current_soul then return end - local max - for _,skill in ipairs(list) do - local s = get_skill(unit_id, skill, unit) - if s then - if not max then - max = s - else - if max.rating == s.rating and max.experience < s.experience then - max = s - elseif max.rating < s.rating then - max = s - end - end - end - end - return max -end - local function melee_skill_effectiveness(unit, skill_list) -- Physical attributes local strength = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.STRENGTH) @@ -396,12 +375,9 @@ end local function ranged_combat_potential(unit) -- Physical attributes local agility = unit.body.physical_attrs.AGILITY.max_value - local toughness = unit.body.physical_attrs.TOUGHNESS.max_value - local endurance = unit.body.physical_attrs.ENDURANCE.max_value -- Mental attributes local focus = unit.status.current_soul.mental_attrs.FOCUS.max_value - local willpower = unit.status.current_soul.mental_attrs.WILLPOWER.max_value local spatial_sense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value local kinesthetic_sense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value From ffc884d69daed7b1f4e604b161b46218e92e5be4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 31 Aug 2023 19:42:02 -0700 Subject: [PATCH 436/851] fix migrant wave ordering use active index instead of unit id --- plugins/lua/sort.lua | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index cee694a4e..c15051ee9 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -48,22 +48,33 @@ local function sort_by_name_asc(unit_id_1, unit_id_2) return utils.compare_name(name2, name1) end +local active_units = df.global.world.units.active +local active_idx_cache = {} +local function get_active_idx_cache() + local num_active_units = #active_units + if num_active_units == 0 or active_idx_cache[active_units[num_active_units-1].id] ~= num_active_units-1 then + active_idx_cache = {} + for i,active_unit in ipairs(active_units) do + active_idx_cache[active_unit.id] = i + end + end + return active_idx_cache +end + local function sort_by_migrant_wave_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end - local unit1 = df.unit.find(unit_id_1) - local unit2 = df.unit.find(unit_id_2) - if not unit1 then return -1 end - if not unit2 then return 1 end - return utils.compare(unit2.id, unit1.id) + local cache = get_active_idx_cache() + if not cache[unit_id_1] then return -1 end + if not cache[unit_id_2] then return 1 end + return utils.compare(cache[unit_id_2], cache[unit_id_1]) end local function sort_by_migrant_wave_asc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end - local unit1 = df.unit.find(unit_id_1) - local unit2 = df.unit.find(unit_id_2) - if not unit1 then return -1 end - if not unit2 then return 1 end - return utils.compare(unit1.id, unit2.id) + local cache = get_active_idx_cache() + if not cache[unit_id_1] then return -1 end + if not cache[unit_id_2] then return 1 end + return utils.compare(cache[unit_id_1], cache[unit_id_2]) end local function sort_by_stress_desc(unit_id_1, unit_id_2) @@ -453,6 +464,13 @@ SquadAssignmentOverlay.ATTRS{ autoarrange_gap=1, } +-- allow initial spacebar or two successive spacebars to fall through and +-- pause/unpause the game +local function search_on_char(ch, text) + if ch == ' ' then return text:match('%S$') end + return ch:match('[%l _-]') +end + function SquadAssignmentOverlay:init() self.dirty = true @@ -461,7 +479,7 @@ function SquadAssignmentOverlay:init() view_id='search', frame={l=0}, label_text='Search: ', - on_char=function(ch) return ch:match('[%l _-]') end, + on_char=search_on_char, on_change=function() self:refresh_list() end, }, widgets.Panel{ From 8791825ccc66618b00712613feb357e68975c15c Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 1 Sep 2023 03:26:52 +0000 Subject: [PATCH 437/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 3ed41e415..dfdda68ad 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 3ed41e4152c6d973783d7bfc0a30cb3d1a6ac1a3 +Subproject commit dfdda68ad6279beabf063b5dbf2f1772810132a1 From 702992b6f54555d380ae7a1a21c5d83dc1f14b17 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 31 Aug 2023 23:06:05 -0700 Subject: [PATCH 438/851] hide the DFHack logo while loading a game so the textures don't visibly flicker revert this once textures are flicker free --- plugins/lua/hotkeys.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index d380eba84..43d11bbda 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -37,8 +37,8 @@ HotspotMenuWidget.ATTRS{ 'export_region', 'game_cleaner', 'initial_prep', - --'legends', -- conflicts with vanilla export button and info text - 'loadgame', + -- 'legends', -- conflicts with vanilla export button and info text + -- 'loadgame', -- disable temporarily while we get texture reloading sorted -- 'new_arena', -- conflicts with vanilla panel layouts -- 'new_region', -- conflicts with vanilla panel layouts 'savegame', From 0550562859fae87f2055bda4662bffb16821b291 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 1 Sep 2023 11:44:51 -0700 Subject: [PATCH 439/851] bump to 50.09-r3rc3 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index edbe5d935..483142fe9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.09") -set(DFHACK_RELEASE "r3rc2") +set(DFHACK_RELEASE "r3rc3") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") From 7abb82d7e9f343c17a04a3493565bd2375dfdd39 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 1 Sep 2023 12:20:52 -0700 Subject: [PATCH 440/851] zero ccache stats between runs and allow the cache to expand past the persisted max size during the build --- .github/workflows/build-linux.yml | 4 +++- .github/workflows/build-windows.yml | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 55761f18b..6ea827e1e 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -142,9 +142,11 @@ jobs: - name: Finalize cache if: inputs.platform-files run: | + ccache --show-stats --verbose ccache --max-size 40M ccache --cleanup - ccache --show-stats --verbose + ccache --max-size 500M + ccache --zero-stats - name: Save ccache if: inputs.platform-files && !inputs.cache-readonly uses: actions/cache/save@v3 diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 67bcf08a5..aee5caefd 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -45,6 +45,7 @@ on: type: boolean default: false + jobs: build-win64: name: Build win64 @@ -101,9 +102,11 @@ jobs: - name: Finalize cache run: | cd build + ccache -d win64-cross/ccache --show-stats --verbose ccache -d win64-cross/ccache --max-size 150M ccache -d win64-cross/ccache --cleanup - ccache -d win64-cross/ccache --show-stats --verbose + ccache -d win64-cross/ccache --max-size 500M + ccache -d win64-cross/ccache --zero-stats - name: Save ccache if: inputs.platform-files && !inputs.cache-readonly uses: actions/cache/save@v3 From a3f6447aab32864c01d422e5e43d2478c227c22f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 1 Sep 2023 12:45:36 -0700 Subject: [PATCH 441/851] light help wording update for Dreamfort blueprints --- data/blueprints/dreamfort.csv | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/data/blueprints/dreamfort.csv b/data/blueprints/dreamfort.csv index 8111c60e9..f82fa3584 100644 --- a/data/blueprints/dreamfort.csv +++ b/data/blueprints/dreamfort.csv @@ -61,7 +61,7 @@ gui/quickfort,/perimeter,,Run at embark. Don't actually apply the blueprint -- i -- Dig -- DFHack command,Blueprint,Generate orders,Notes gui/quickfort,/surface1,,Clear some trees and dig central staircase. Run when you find your center tile. Deconstruct your wagon if it is in the way. -gui/quickfort,/dig_all,,"Run when you find a suitable (non-aquifer) rock layer for the industry level. It designates digging for industry, services, guildhall, suites, apartments, and the crypt all in one go. This list does not include the farming level, which we'll 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." +gui/quickfort,/dig_all,,"Run when you find a suitable (non-aquifer) rock layer for the industry level. It designates digging for industry, services, guildhall, suites, apartments, and the crypt all in one go. This list does not include the farming level, which we'll designate in the uppermost soil layer once the surface miasma channels are dug. Note that it is more efficient for your miners if you designate the digging for a level before they dig the central stairs past that level. The stairs down on each level are designated at priority 5 instead of the regular priority 4. This lets the miners focus on one z-level at a time and not run up and down the stairs attempting to dig out two blueprints simultaneously. If you need to designate your levels individually due to caverns interrupting the sequence or just because it is your preference, run the level-specific dig blueprints (i.e. /industry1, /services1, /guildhall1, /suites1, 3 levels of /apartments1, and /crypt1) instead of running /dig_all." "" -- Core fort (should finish at about the third migration wave) -- DFHack command,Blueprint,Generate orders,Notes @@ -81,7 +81,7 @@ gui/quickfort,/surface6,Yes,Build security perimeter. Run once you have linked a gui/quickfort,/surface7,Yes,Build roof. Run after the surface walls are completed and any marked trees are chopped down. Be sure to give your haulers some time to fill the stonecutter's stockpile with some stone first so your stonecutters won't be hauling it up from the depths by hand. "" -- Plumbing -- -"If you haven't done it already, this is a good time to fill your well cisterns, either with a bucket brigade or by routing water from a freshwater stream or an aquifer (see the library/aquifer_tap.csv blueprint for help with this)." +"If you haven't done it already, this is a good time to fill your well cisterns, either with a bucket brigade or by routing water from a freshwater stream or an aquifer (see the aquifer_tap library blueprint for help with this)." Also consider bringing magma up to your services level so you can replace the forge and furnaces on your industry level with more powerful magma versions. This is especially important if your embark has insufficient trees to convert into charcoal. Keep in mind that moving magma is a tricky process and can take a long time. Don't forget to continue making progress through this checklist! "" -- Mature fort (fourth migration wave onward) -- @@ -293,11 +293,11 @@ Here are some tips and procedures for handling seiges -- including how to clean "" "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 ""stripcaged all"" in the DFHack gui/launcher." +"- Once the prisoners are hauled to the ""prisoner quantum"" stockpile, run ""stripcaged all"" in DFHack's gui/launcher." "" "- After all the prisoners' items have been confiscated, bring your military dwarves to the barracks (if they aren't already there)." "" -- Assign a group prisoners to the pasture that overlaps the prisoner quantum stockpile +- Assign a group of prisoners to the pasture that overlaps the prisoner quantum stockpile "" "- Hauler dwarves will come and release prisoners one by one. Your military dwarves will immediately pounce on the released prisoner and chop them to bits, saving the hauler dwarves from being attacked. Repeat until all prisoners have been ""processed""." #dig label(central_stairs_odd) start(2;2) hidden() carved spiral stairs odd levels @@ -858,7 +858,6 @@ You might also want to set the ""trade goods quantum"" stockpile to autotrade.) -#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" @@ -1710,7 +1709,7 @@ build2/industry_build2 ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"wj{name=""Encruster"" take_from=""Goods/wood quantum,Stoneworker quantum,Gem feeder""}",`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,"wr{name=""Stone craftsdwarf""}",`,`,`,`,`,`,`,wt,`,`,`,`,`,`,`,`,` @@ -1746,7 +1745,7 @@ build2/industry_build2 ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,`,` -,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,"wj{name=""Encruster"" take_from=""Goods/wood quantum,Stoneworker quantum,Gem feeder""}",`,`,`,`,`,`,`,`,`,`,`,`,` +,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,` ,,,,`,`,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,~,`,`,`,`,`,`,`,`,` From 426099f82b3c18a0a21dc250ae63ddd097a13f9b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 1 Sep 2023 14:35:55 -0700 Subject: [PATCH 442/851] label updates for squad sort options --- plugins/lua/sort.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index c15051ee9..e775f1ddf 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -504,8 +504,8 @@ function SquadAssignmentOverlay:init() {label='tactics skill'..CH_UP, value=SORT_FNS.sort_by_tactics_asc, pen=COLOR_YELLOW}, {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc, pen=COLOR_GREEN}, {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc, pen=COLOR_YELLOW}, - {label='stress'..CH_DN, value=sort_by_stress_desc, pen=COLOR_GREEN}, - {label='stress'..CH_UP, value=sort_by_stress_asc, pen=COLOR_YELLOW}, + {label='stress level'..CH_DN, value=sort_by_stress_desc, pen=COLOR_GREEN}, + {label='stress level'..CH_UP, value=sort_by_stress_asc, pen=COLOR_YELLOW}, {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, {label='axe skill'..CH_DN, value=SORT_FNS.sort_by_axe_desc, pen=COLOR_GREEN}, @@ -530,11 +530,11 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_any_melee', - frame={t=2, l=0, w=10}, + frame={t=2, l=0, w=11}, options={ - {label='any melee', value=sort_noop}, - {label='any melee'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc, pen=COLOR_GREEN}, - {label='any melee'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc, pen=COLOR_YELLOW}, + {label='melee eff.', value=sort_noop}, + {label='melee eff.'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc, pen=COLOR_GREEN}, + {label='melee eff.'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc, pen=COLOR_YELLOW}, }, initial_option=SORT_FNS.sort_by_any_melee_desc, option_gap=0, @@ -542,11 +542,11 @@ function SquadAssignmentOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='sort_any_ranged', - frame={t=2, r=9, w=11}, + frame={t=2, r=8, w=12}, options={ - {label='any ranged', value=sort_noop}, - {label='any ranged'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc, pen=COLOR_GREEN}, - {label='any ranged'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc, pen=COLOR_YELLOW}, + {label='ranged eff.', value=sort_noop}, + {label='ranged eff.'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc, pen=COLOR_GREEN}, + {label='ranged eff.'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_any_ranged'), From 8e6775a05312161bdefca8e44e4ff65f916a36cf Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 1 Sep 2023 18:45:50 -0700 Subject: [PATCH 443/851] document stockpiles/logistics overlay --- docs/plugins/logistics.rst | 3 +++ docs/plugins/stockpiles.rst | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/docs/plugins/logistics.rst b/docs/plugins/logistics.rst index dff142390..a65571484 100644 --- a/docs/plugins/logistics.rst +++ b/docs/plugins/logistics.rst @@ -17,6 +17,9 @@ For autotrade, items will be marked for trading only when a caravan is approaching or is already at the trade depot. Items (or bins that contain items) of which a noble has forbidden export will not be marked for trade. +Stockpiles can be registered for ``logistics`` features by toggling the options +in the `stockpiles` overlay that comes up when you select a stockpile in the UI. + Usage ----- diff --git a/docs/plugins/stockpiles.rst b/docs/plugins/stockpiles.rst index da9b77dc5..249a27d13 100644 --- a/docs/plugins/stockpiles.rst +++ b/docs/plugins/stockpiles.rst @@ -95,6 +95,13 @@ file are: specific item types, and any toggles the category might have (like Prepared meals for the Food category). +Overlay +------- + +This plugin provides a panel that appears when you select a stockpile via an +`overlay` widget. You can use it to easily toggle `logistics` plugin features +like autotrade, automelt, or autotrain. + .. _stockpiles-library: The stockpiles settings library From 0bdba60ede26c563889b7ce62808304b1a70db9e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 1 Sep 2023 23:43:49 -0700 Subject: [PATCH 444/851] fix build command --- build/build-win64-from-linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/build-win64-from-linux.sh b/build/build-win64-from-linux.sh index c0559a999..9404188fd 100755 --- a/build/build-win64-from-linux.sh +++ b/build/build-win64-from-linux.sh @@ -45,7 +45,7 @@ if ! docker run --rm -i -v "$srcdir":/src -v "$srcdir/build/win64-cross/":/src/b -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" \ + bash -c "cd /src/build && dfhack-configure windows 64 Release -DCMAKE_INSTALL_PREFIX=/src/build/output -DBUILD_DOCS=1 $CMAKE_EXTRA_ARGS && dfhack-make -j$jobs install" \ ; then echo echo "Build failed" From 2349c6f1dedf1b74357a89b363d709f63a6dce33 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 2 Sep 2023 07:11:38 +0000 Subject: [PATCH 445/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index dfdda68ad..b139aed81 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit dfdda68ad6279beabf063b5dbf2f1772810132a1 +Subproject commit b139aed81c81ce470b5eb7a902d17f1f18035dbe From d9c9c7c53bfd5033fbe3a988dd4224a9c8cb71ce Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 2 Sep 2023 00:32:51 -0700 Subject: [PATCH 446/851] update libzip ref --- depends/libzip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/libzip b/depends/libzip index 081249cce..fc4a77ea2 160000 --- a/depends/libzip +++ b/depends/libzip @@ -1 +1 @@ -Subproject commit 081249cceb59adc857a72d67e60c32047680f787 +Subproject commit fc4a77ea28eb5eba0ecd11443f291335ec3d2aa0 From 6096165eeedeee9e4e0f84975794f0284a6fa2dc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 2 Sep 2023 02:03:03 -0700 Subject: [PATCH 447/851] fix handling of ticks parameter --- docs/changelog.txt | 5 +++-- plugins/lua/autobutcher.lua | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index f84526ebd..51d09b18d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -29,8 +29,6 @@ Template for new versions: ## New Features ## Fixes -- `tailor`: remove crash caused by clothing items with an invalid ``maker_race`` -- `seedwatch`: seedwatch will now ignore (unplantable) tree seeds entirely ## Misc Improvements @@ -64,6 +62,9 @@ Template for new versions: - Core: fix text getting added to DFHack text entry widgets when Alt- or Ctrl- keys are hit - `orders`: prevent import/export overlay from appearing on the create workorder screen - `caravan`: corrected prices for cages that have units inside of them +- `tailor`: remove crash caused by clothing items with an invalid ``maker_race`` +- `seedwatch`: seedwatch will now ignore (unplantable) tree seeds entirely +- `autobutcher`: fix ``ticks`` commandline option incorrectly rejecting positive integers as valid values ## Misc Improvements - Surround DFHack-specific UI elements with square brackets instead of red-yellow blocks for better readability diff --git a/plugins/lua/autobutcher.lua b/plugins/lua/autobutcher.lua index f357f8fb1..51417bf9f 100644 --- a/plugins/lua/autobutcher.lua +++ b/plugins/lua/autobutcher.lua @@ -19,7 +19,7 @@ end local function process_args(opts, args) if args[1] == 'help' then opts.help = true - return + return {} end return argparse.processArgsGetopt(args, { @@ -67,7 +67,7 @@ function parse_commandline(opts, ...) process_races(opts, positionals, 6) elseif command == 'ticks' then local ticks = tonumber(positionals[2]) - if not is_positive_int(arg) then + if not is_positive_int(ticks) then qerror('number of ticks must be a positive integer: ' .. ticks) else opts.ticks = ticks From 874fb5535be6f8f204b4747d3f93538bb7a94cc0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 2 Sep 2023 02:41:26 -0700 Subject: [PATCH 448/851] fix spacing around messagebox text when a scrollbar is involved --- docs/changelog.txt | 1 + library/lua/gui/dialogs.lua | 15 ++++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 51d09b18d..83fbf8c20 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -63,6 +63,7 @@ Template for new versions: - `orders`: prevent import/export overlay from appearing on the create workorder screen - `caravan`: corrected prices for cages that have units inside of them - `tailor`: remove crash caused by clothing items with an invalid ``maker_race`` +- ``dialogs.MessageBox``: fix spacing around scrollable text - `seedwatch`: seedwatch will now ignore (unplantable) tree seeds entirely - `autobutcher`: fix ``ticks`` commandline option incorrectly rejecting positive integers as valid values diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua index 1b7858416..499fa6305 100644 --- a/library/lua/gui/dialogs.lua +++ b/library/lua/gui/dialogs.lua @@ -11,7 +11,7 @@ MessageBox.focus_path = 'MessageBox' MessageBox.ATTRS{ frame_style = gui.WINDOW_FRAME, - frame_inset = 1, + frame_inset = {l=1, t=1, b=1, r=0}, -- new attrs on_accept = DEFAULT_NIL, on_cancel = DEFAULT_NIL, @@ -33,13 +33,14 @@ end function MessageBox:getWantedFrameSize() local label = self.subviews.label local width = math.max(self.frame_width or 0, 20, #(self.frame_title or '') + 4) - local text_area_width = label:getTextWidth() - if label.frame_inset then - -- account for scroll icons - text_area_width = text_area_width + (label.frame_inset.l or 0) - text_area_width = text_area_width + (label.frame_inset.r or 0) + local text_area_width = label:getTextWidth() + 1 + local text_height = label:getTextHeight() + local sw, sh = dfhack.screen.getWindowSize() + if text_height > sh - 4 then + -- account for scrollbar + text_area_width = text_area_width + 2 end - return math.max(width, text_area_width), label:getTextHeight() + return math.max(width, text_area_width), text_height end function MessageBox:onRenderFrame(dc,rect) From b489fceaeaba88721a314840d30a5d6d51d1ddcb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 2 Sep 2023 03:22:10 -0700 Subject: [PATCH 449/851] clarify error message about the terminal --- library/Core.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/Core.cpp b/library/Core.cpp index fd5dc7f65..353e99ef3 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1249,7 +1249,14 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, s } else if (res == CR_NEEDS_CONSOLE) con.printerr("%s needs an interactive console to work.\n" - "Please run this command from the DFHack terminal.\n", first.c_str()); + "Please run this command from the DFHack terminal.\n\n" +#ifdef WIN32 + "You can show the terminal with the 'show' command." +#else + "The terminal is accessible when you run DF from the commandline\n" + "via the './dfhack' script." +#endif + "\n", first.c_str()); return res; } From ce0eb1aa48fb6f6e6d1926d2db98f10a985d3265 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 2 Sep 2023 11:18:15 +0000 Subject: [PATCH 450/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index b139aed81..af4cef206 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit b139aed81c81ce470b5eb7a902d17f1f18035dbe +Subproject commit af4cef206d7e607063de09eb3d966f56084c264d From 4c938905382024d160f307ebc108c19ad1cd1d2a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 2 Sep 2023 04:16:21 -0700 Subject: [PATCH 451/851] avoid warning about unused config var --- .github/workflows/build-linux.yml | 2 +- .github/workflows/build-windows.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 6ea827e1e..16f75118c 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -131,7 +131,7 @@ jobs: -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} \ -DBUILD_TESTS:BOOL=${{ inputs.tests }} \ -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }} \ - -DINSTALL_XMLDUMP:BOOL=1 \ + ${{ inputs.xml-dump-type-sizes && '-DINSTALL_XMLDUMP:BOOL=1' || ''}} \ -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} \ -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} - name: Build DFHack diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index aee5caefd..795482d80 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -95,7 +95,7 @@ jobs: win-msvc - name: Cross-compile env: - CMAKE_EXTRA_ARGS: '-DBUILD_LIBRARY=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} -DBUILD_TESTS:BOOL=${{ inputs.tests }} -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }} -DINSTALL_XMLDUMP:BOOL=1' + CMAKE_EXTRA_ARGS: -DBUILD_LIBRARY=${{ inputs.platform-files }} -DBUILD_STONESENSE:BOOL=${{ inputs.stonesense }} -DBUILD_DOCS:BOOL=${{ inputs.docs }} -DBUILD_DOCS_NO_HTML:BOOL=${{ !inputs.html }} -DINSTALL_DATA_FILES:BOOL=${{ inputs.common-files }} -DINSTALL_SCRIPTS:BOOL=${{ inputs.common-files }} -DBUILD_DFLAUNCH:BOOL=${{ inputs.launchdf }} -DBUILD_TESTS:BOOL=${{ inputs.tests }} -DBUILD_XMLDUMP:BOOL=${{ inputs.xml-dump-type-sizes }} ${{ inputs.xml-dump-type-sizes && '-DINSTALL_XMLDUMP:BOOL=1' || '' }} run: | cd build bash -x build-win64-from-linux.sh From 3f1eac720f91224e8cf6e0470a9e81b0be6402f1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 3 Sep 2023 07:08:57 -0700 Subject: [PATCH 452/851] respect empty and lye_milk_free flags --- plugins/buildingplan/buildingplan_cycle.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/plugins/buildingplan/buildingplan_cycle.cpp b/plugins/buildingplan/buildingplan_cycle.cpp index 45cafe474..f7c23d8ce 100644 --- a/plugins/buildingplan/buildingplan_cycle.cpp +++ b/plugins/buildingplan/buildingplan_cycle.cpp @@ -88,6 +88,20 @@ bool matchesFilters(df::item * item, const df::job_item * job_item, HeatSafety h if (job_item->flags2.bits.building_material && !item->isBuildMat()) return false; + if ((job_item->flags1.bits.empty || job_item->flags2.bits.lye_milk_free)) { + auto gref = Items::getGeneralRef(item, df::general_ref_type::CONTAINS_ITEM); + if (gref) { + if (job_item->flags1.bits.empty) + return false; + if (auto contained_item = gref->getItem(); contained_item) { + MaterialInfo mi; + mi.decode(contained_item); + if (mi.getToken() != "WATER") + return false; + } + } + } + if (job_item->metal_ore > -1 && !item->isMetalOre(job_item->metal_ore)) return false; From dc22c596d4f837293a6cfd705cd34db281f89f4c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 3 Sep 2023 07:11:18 -0700 Subject: [PATCH 453/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 83fbf8c20..425e570eb 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -60,6 +60,7 @@ Template for new versions: ## Fixes - Core: reload scripts in mods when a world is unloaded and immediately loaded again - Core: fix text getting added to DFHack text entry widgets when Alt- or Ctrl- keys are hit +- `buildingplan`: ensure selected barrels and buckets are empty (or at least free of lye and milk) as per the requirements of the building - `orders`: prevent import/export overlay from appearing on the create workorder screen - `caravan`: corrected prices for cages that have units inside of them - `tailor`: remove crash caused by clothing items with an invalid ``maker_race`` From b8fc6e210f5727fcee2324ccc8467930a3bb45b6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 3 Sep 2023 07:12:30 -0700 Subject: [PATCH 454/851] add note about handling bags --- library/modules/Items.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index bf4437ef7..983921576 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -420,6 +420,7 @@ bool ItemTypeInfo::matches(const df::job_item &item, MaterialInfo *mat, xmask1.bits.cookable = true; break; + // TODO: split this into BOX and BAG case BOX: OK(1,bag); OK(1,sand_bearing); OK(1,milk); OK(2,dye); OK(2,plaster_containing); From a2b50a88a548076264e33f700346509291474c3a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 3 Sep 2023 07:12:41 -0700 Subject: [PATCH 455/851] reorder branches for better readability --- plugins/lua/buildingplan/planneroverlay.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index 803e9ae99..643852a6e 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -775,7 +775,9 @@ function PlannerOverlay:onInput(keys) local filters = get_cur_filters() local num_filters = #filters local choose = self.subviews.choose:getOptionValue() - if choose > 0 then + if choose == 0 then + self:place_building(get_placement_data()) + else local bounds = get_selected_bounds() self:save_placement() local autoselect = choose == 2 @@ -806,7 +808,7 @@ function PlannerOverlay:onInput(keys) end end, on_cancel=function() - for i,scr in pairs(active_screens) do + for _,scr in pairs(active_screens) do scr:dismiss() end df.global.game.main_interface.bottom_mode_selected = df.main_bottom_mode_type.BUILDING_PLACEMENT @@ -820,8 +822,6 @@ function PlannerOverlay:onInput(keys) active_screens[idx] = selection_screen:show() end end - else - self:place_building(get_placement_data()) end return true elseif not is_choosing_area() then From 9ddb52767b5ab4d444821c23eca543381d6c83ad Mon Sep 17 00:00:00 2001 From: Timur Kelman Date: Sun, 3 Sep 2023 19:24:11 +0200 Subject: [PATCH 456/851] keybindings: add `/Default` to `Ctrl-D@dwarfmode gui/design` --- data/init/dfhack.keybindings.init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/init/dfhack.keybindings.init b/data/init/dfhack.keybindings.init index 22dc931f4..ce4a8a490 100644 --- a/data/init/dfhack.keybindings.init +++ b/data/init/dfhack.keybindings.init @@ -157,7 +157,7 @@ keybinding add Alt-K@dwarfmode toggle-kbd-cursor #keybinding add Ctrl-Shift-T@dwarfmode|unit|unitlist|joblist|dungeon_monsterstatus|layer_unit_relationship|item|workshop_profile|layer_noblelist|locations|pets|layer_overall_health|textviewer|reportlist|announcelist|layer_military|layer_unit_health|customize_unit "gui/rename unit-profession" # gui/design -keybinding add Ctrl-D@dwarfmode gui/design +keybinding add Ctrl-D@dwarfmode/Default gui/design From 1d6ae37a66f918c4d286a3c0acb01ad2af7e42af Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 3 Sep 2023 11:49:13 -0700 Subject: [PATCH 457/851] fix and reinstate heat safety filter --- docs/changelog.txt | 1 + library/include/modules/Job.h | 4 +- library/modules/Job.cpp | 4 +- library/modules/Materials.cpp | 6 ++- plugins/buildingplan/buildingplan.cpp | 20 ++++----- plugins/buildingplan/buildingplan.h | 2 +- plugins/buildingplan/buildingplan_cycle.cpp | 49 ++++++++++++--------- plugins/buildingplan/plannedbuilding.cpp | 3 +- plugins/lua/buildingplan/planneroverlay.lua | 1 - 9 files changed, 47 insertions(+), 43 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 425e570eb..b4447283f 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -56,6 +56,7 @@ Template for new versions: ## New Features - `sort`: search and sort for squad assignment screen - `zone`: advanced unit assignment screens for cages, restraints, and pits/ponds +- `buildingplan`: one-click magma/fire safety filter for planned buildings ## Fixes - Core: reload scripts in mods when a world is unloaded and immediately loaded again diff --git a/library/include/modules/Job.h b/library/include/modules/Job.h index 2a874dc5e..fa10173a0 100644 --- a/library/include/modules/Job.h +++ b/library/include/modules/Job.h @@ -101,8 +101,8 @@ namespace DFHack df::job_item_ref::T_role role, int filter_idx = -1, int insert_idx = -1); - DFHACK_EXPORT bool isSuitableItem(df::job_item *item, df::item_type itype, int isubtype); - DFHACK_EXPORT bool isSuitableMaterial(df::job_item *item, int mat_type, + DFHACK_EXPORT bool isSuitableItem(const df::job_item *item, df::item_type itype, int isubtype); + DFHACK_EXPORT bool isSuitableMaterial(const df::job_item *item, int mat_type, int mat_index, df::item_type itype); DFHACK_EXPORT std::string getName(df::job *job); diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index 869a6b329..87301fef2 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -567,7 +567,7 @@ bool DFHack::Job::attachJobItem(df::job *job, df::item *item, return true; } -bool Job::isSuitableItem(df::job_item *item, df::item_type itype, int isubtype) +bool Job::isSuitableItem(const df::job_item *item, df::item_type itype, int isubtype) { CHECK_NULL_POINTER(item); @@ -581,7 +581,7 @@ bool Job::isSuitableItem(df::job_item *item, df::item_type itype, int isubtype) } bool Job::isSuitableMaterial( - df::job_item *item, int mat_type, int mat_index, df::item_type itype) + const df::job_item *item, int mat_type, int mat_index, df::item_type itype) { CHECK_NULL_POINTER(item); diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index 7922b5417..1c2d736da 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -517,11 +517,13 @@ void MaterialInfo::getMatchBits(df::job_item_flags2 &ok, df::job_item_flags2 &ma TEST(fire_safe, material->heat.melting_point > 11000 && material->heat.boiling_point > 11000 && material->heat.ignite_point > 11000 - && material->heat.heatdam_point > 11000); + && material->heat.heatdam_point > 11000 + && (material->heat.colddam_point == 60001 || material->heat.colddam_point < 11000)); TEST(magma_safe, material->heat.melting_point > 12000 && material->heat.boiling_point > 12000 && material->heat.ignite_point > 12000 - && material->heat.heatdam_point > 12000); + && material->heat.heatdam_point > 12000 + && (material->heat.colddam_point == 60001 || material->heat.colddam_point < 12000)); TEST(deep_material, FLAG(inorganic, inorganic_flags::SPECIAL)); TEST(non_economic, !inorganic || !(plotinfo && vector_get(plotinfo->economic_stone, index))); diff --git a/plugins/buildingplan/buildingplan.cpp b/plugins/buildingplan/buildingplan.cpp index ce424f9c6..540420749 100644 --- a/plugins/buildingplan/buildingplan.cpp +++ b/plugins/buildingplan/buildingplan.cpp @@ -216,9 +216,8 @@ static void load_material_cache() { } static HeatSafety get_heat_safety_filter(const BuildingTypeKey &key) { - // comment out until we can get heat safety working as intended - // if (cur_heat_safety.count(key)) - // return cur_heat_safety.at(key); + if (cur_heat_safety.count(key)) + return cur_heat_safety.at(key); return HEAT_SAFETY_ANY; } @@ -948,22 +947,19 @@ static int getMaterialFilter(lua_State *L) { map counts; scanAvailableItems(*out, type, subtype, custom, index, false, NULL, &counts); HeatSafety heat = get_heat_safety_filter(key); - df::job_item jitem_cur_heat = getJobItemWithHeatSafety( - get_job_items(*out, key)[index], heat); - df::job_item jitem_fire = getJobItemWithHeatSafety( - get_job_items(*out, key)[index], HEAT_SAFETY_FIRE); - df::job_item jitem_magma = getJobItemWithHeatSafety( - get_job_items(*out, key)[index], HEAT_SAFETY_MAGMA); + const df::job_item *jitem = get_job_items(*out, key)[index]; // name -> {count=int, enabled=bool, category=string, heat=string} map> ret; for (auto & entry : mat_cache) { auto &mat = entry.second.first; - if (!mat.matches(jitem_cur_heat)) + if (!mat.matches(jitem)) + continue; + if (!matchesHeatSafety(mat.type, mat.index, heat)) continue; string heat_safety = ""; - if (mat.matches(jitem_magma)) + if (matchesHeatSafety(mat.type, mat.index, HEAT_SAFETY_MAGMA)) heat_safety = "magma-safe"; - else if (mat.matches(jitem_fire)) + else if (matchesHeatSafety(mat.type, mat.index, HEAT_SAFETY_FIRE)) heat_safety = "fire-safe"; auto &name = entry.first; auto &cat = entry.second.second; diff --git a/plugins/buildingplan/buildingplan.h b/plugins/buildingplan/buildingplan.h index 9bfd38731..a17f408a8 100644 --- a/plugins/buildingplan/buildingplan.h +++ b/plugins/buildingplan/buildingplan.h @@ -55,7 +55,7 @@ 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(DFHack::color_ostream& out, df::item* item); -df::job_item getJobItemWithHeatSafety(const df::job_item *job_item, HeatSafety heat); +bool matchesHeatSafety(int16_t mat_type, int32_t mat_index, 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); void finalizeBuilding(DFHack::color_ostream &out, df::building *bld, bool unsuspend_on_finalize); diff --git a/plugins/buildingplan/buildingplan_cycle.cpp b/plugins/buildingplan/buildingplan_cycle.cpp index f7c23d8ce..c6e0fbc9a 100644 --- a/plugins/buildingplan/buildingplan_cycle.cpp +++ b/plugins/buildingplan/buildingplan_cycle.cpp @@ -66,32 +66,38 @@ bool itemPassesScreen(color_ostream& out, df::item* item) { && isAccessible(out, item); } -df::job_item getJobItemWithHeatSafety(const df::job_item *job_item, HeatSafety heat) { - df::job_item jitem = *job_item; - if (heat >= HEAT_SAFETY_MAGMA) { - jitem.flags2.bits.magma_safe = true; - jitem.flags2.bits.fire_safe = false; - } else if (heat == HEAT_SAFETY_FIRE && !jitem.flags2.bits.magma_safe) - jitem.flags2.bits.fire_safe = true; - return jitem; +bool matchesHeatSafety(int16_t mat_type, int32_t mat_index, HeatSafety heat) { + if (heat == HEAT_SAFETY_ANY) + return true; + + MaterialInfo minfo(mat_type, mat_index); + df::job_item_flags2 ok; + df::job_item_flags2 mask; + minfo.getMatchBits(ok, mask); + + if (heat >= HEAT_SAFETY_MAGMA) + return ok.bits.magma_safe; + if (heat == HEAT_SAFETY_FIRE) + return ok.bits.fire_safe || ok.bits.magma_safe; + return false; } -bool matchesFilters(df::item * item, const df::job_item * job_item, HeatSafety heat, const ItemFilter &item_filter, const std::set &specials) { +bool matchesFilters(df::item * item, const df::job_item * jitem, HeatSafety heat, const ItemFilter &item_filter, const std::set &specials) { // check the properties that are not checked by Job::isSuitableItem() - if (job_item->item_type > -1 && job_item->item_type != item->getType()) + if (jitem->item_type > -1 && jitem->item_type != item->getType()) return false; - if (job_item->item_subtype > -1 && - job_item->item_subtype != item->getSubtype()) + if (jitem->item_subtype > -1 && + jitem->item_subtype != item->getSubtype()) return false; - if (job_item->flags2.bits.building_material && !item->isBuildMat()) + if (jitem->flags2.bits.building_material && !item->isBuildMat()) return false; - if ((job_item->flags1.bits.empty || job_item->flags2.bits.lye_milk_free)) { + if ((jitem->flags1.bits.empty || jitem->flags2.bits.lye_milk_free)) { auto gref = Items::getGeneralRef(item, df::general_ref_type::CONTAINS_ITEM); if (gref) { - if (job_item->flags1.bits.empty) + if (jitem->flags1.bits.empty) return false; if (auto contained_item = gref->getItem(); contained_item) { MaterialInfo mi; @@ -102,23 +108,24 @@ bool matchesFilters(df::item * item, const df::job_item * job_item, HeatSafety h } } - if (job_item->metal_ore > -1 && !item->isMetalOre(job_item->metal_ore)) + if (jitem->metal_ore > -1 && !item->isMetalOre(jitem->metal_ore)) return false; - if (job_item->has_tool_use > df::tool_uses::NONE - && !item->hasToolUse(job_item->has_tool_use)) + if (jitem->has_tool_use > df::tool_uses::NONE + && !item->hasToolUse(jitem->has_tool_use)) return false; if (item->getType() == df::item_type::SLAB && specials.count("engraved") && static_cast(item)->engraving_type != df::slab_engraving_type::Memorial) return false; - df::job_item jitem = getJobItemWithHeatSafety(job_item, heat); + if (!matchesHeatSafety(item->getMaterial(), item->getMaterialIndex(), heat)) + return false; return Job::isSuitableItem( - &jitem, item->getType(), item->getSubtype()) + jitem, item->getType(), item->getSubtype()) && Job::isSuitableMaterial( - &jitem, item->getMaterial(), item->getMaterialIndex(), + jitem, item->getMaterial(), item->getMaterialIndex(), item->getType()) && item_filter.matches(item); } diff --git a/plugins/buildingplan/plannedbuilding.cpp b/plugins/buildingplan/plannedbuilding.cpp index a20d7b29a..b16da01cb 100644 --- a/plugins/buildingplan/plannedbuilding.cpp +++ b/plugins/buildingplan/plannedbuilding.cpp @@ -109,8 +109,7 @@ PlannedBuilding::PlannedBuilding(color_ostream &out, df::building *bld, HeatSafe PlannedBuilding::PlannedBuilding(color_ostream &out, PersistentDataItem &bld_config) : id(get_config_val(bld_config, BLD_CONFIG_ID)), vector_ids(deserialize_vector_ids(out, bld_config)), - //heat_safety((HeatSafety)get_config_val(bld_config, BLD_CONFIG_HEAT)), // until this works - heat_safety(HEAT_SAFETY_ANY), + heat_safety((HeatSafety)get_config_val(bld_config, BLD_CONFIG_HEAT)), item_filters(get_item_filters(out, bld_config)), specials(get_specials(out, bld_config)), bld_config(bld_config) { } diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index 643852a6e..9a47b8fed 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -548,7 +548,6 @@ function PlannerOverlay:init() on_change=function(heat) buildingplan.setHeatSafetyFilter(uibs.building_type, uibs.building_subtype, uibs.custom_type, heat) end, - visible=false, -- until we can make this work the way it's intended }, }, }, From 4316879d4e180376c0a7e9c0852ca7fb2d84e305 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 3 Sep 2023 19:37:07 +0000 Subject: [PATCH 458/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index af4cef206..65e2ca0df 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit af4cef206d7e607063de09eb3d966f56084c264d +Subproject commit 65e2ca0df28ede6b6d22f5fa220a4fe886717631 From cbe4f538233fc4134a2d60ebcdf7023b33525847 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 3 Sep 2023 12:50:12 -0700 Subject: [PATCH 459/851] add focus string details for orders context --- library/modules/Gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index b7cffc72f..4934c9787 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -434,7 +434,7 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) } if (game->main_interface.job_details.open) { newFocusString = baseFocus; - newFocusString += "/JobDetails"; + newFocusString += "/JobDetails/" + enum_item_key(game->main_interface.job_details.context); focusStrings.push_back(newFocusString); } if (game->main_interface.assign_trade.open) { From d291e2b3597be5c14e0b41c057971c5ac98b43a7 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 4 Sep 2023 00:48:48 +0000 Subject: [PATCH 460/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 65e2ca0df..412cf9e87 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 65e2ca0df28ede6b6d22f5fa220a4fe886717631 +Subproject commit 412cf9e876be35cfd03d94e49a8e37bf43a6b6f2 From 45770aef3ef8e52dd1b978629e0f9cae2ed9ca98 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 4 Sep 2023 07:13:19 +0000 Subject: [PATCH 461/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 412cf9e87..0cda060cd 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 412cf9e876be35cfd03d94e49a8e37bf43a6b6f2 +Subproject commit 0cda060cdad309884ed4fb0b0f9914be4bd68143 From 457a998bef632e38c5b6ef5c3824764cdbefffb3 Mon Sep 17 00:00:00 2001 From: dikbutdagrate <73856869+Tjudge1@users.noreply.github.com> Date: Mon, 4 Sep 2023 19:36:01 -0400 Subject: [PATCH 462/851] Update strangemood.rst example section Updated example to accurately reflect arguments. Compliant with getopt-style parameter syntax. --- docs/plugins/strangemood.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/strangemood.rst b/docs/plugins/strangemood.rst index 12e814c55..898f9e181 100644 --- a/docs/plugins/strangemood.rst +++ b/docs/plugins/strangemood.rst @@ -12,10 +12,10 @@ Usage strangemood [] -Examples +Example -------- -``strangemood -force -unit -type secretive -skill armorsmith`` +``strangemood --force --unit --type secretive --skill armorsmith`` Trigger a strange mood for the selected unit that will cause them to become a legendary armorsmith. From 29ccdcf4b9a205448599935b702d4279f02a811b Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 4 Sep 2023 20:45:53 -0700 Subject: [PATCH 463/851] Remove leftover debug print --- plugins/lua/dwarfvet.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/lua/dwarfvet.lua b/plugins/lua/dwarfvet.lua index 64538bac0..a976b91c8 100644 --- a/plugins/lua/dwarfvet.lua +++ b/plugins/lua/dwarfvet.lua @@ -17,7 +17,6 @@ local function get_cur_patients() for _,job in utils.listpairs(df.global.world.jobs.list) do if job.job_type ~= df.job_type.Rest then goto continue end local unit = dfhack.job.getWorker(job) - print(unit.id) if is_valid_animal(unit) then cur_patients[unit] = true end From 9dd8a8501d4d713ba83a68c0702658834534cb2b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 04:05:29 +0000 Subject: [PATCH 464/851] [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.23.3 → 0.26.3](https://github.com/python-jsonschema/check-jsonschema/compare/0.23.3...0.26.3) - [github.com/Lucas-C/pre-commit-hooks: v1.5.1 → v1.5.4](https://github.com/Lucas-C/pre-commit-hooks/compare/v1.5.1...v1.5.4) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e7d0e23cf..d9c148058 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,11 +20,11 @@ repos: args: ['--fix=lf'] - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.23.3 + rev: 0.26.3 hooks: - id: check-github-workflows - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.5.1 + rev: v1.5.4 hooks: - id: forbid-tabs exclude_types: From ff3d4c5b3823f02cc5f103fef96064fd15d352ac Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 5 Sep 2023 00:31:35 -0700 Subject: [PATCH 465/851] support creating items inside of bags --- docs/changelog.txt | 1 + plugins/createitem.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index b4447283f..aa03e408d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -74,6 +74,7 @@ Template for new versions: - `autobutcher`: don't mark animals for butchering if they are already marked for some kind of training (war, hunt) - `hotkeys`: don't display DFHack logo in legends mode since it covers up important interface elements. the Ctrl-Shift-C hotkey to bring up the menu and the mouseover hotspot still function, though. - `sort`: animals are now sortable by race on the assignment screens +- `createitem`: support creating items inside of bags ## Documentation diff --git a/plugins/createitem.cpp b/plugins/createitem.cpp index 499814adc..ebc6eb7fe 100644 --- a/plugins/createitem.cpp +++ b/plugins/createitem.cpp @@ -178,6 +178,7 @@ command_result df_createitem (color_ostream &out, vector & parameters) case item_type::BUCKET: case item_type::ANIMALTRAP: case item_type::BOX: + case item_type::BAG: case item_type::BIN: case item_type::BACKPACK: case item_type::QUIVER: From 9143a8eb50c7d640dfbab550a8bc0ada4a0e2997 Mon Sep 17 00:00:00 2001 From: Myk Date: Tue, 5 Sep 2023 00:46:00 -0700 Subject: [PATCH 466/851] Update docs/plugins/strangemood.rst --- docs/plugins/strangemood.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/strangemood.rst b/docs/plugins/strangemood.rst index 898f9e181..f99be26eb 100644 --- a/docs/plugins/strangemood.rst +++ b/docs/plugins/strangemood.rst @@ -13,7 +13,7 @@ Usage strangemood [] Example --------- +------- ``strangemood --force --unit --type secretive --skill armorsmith`` Trigger a strange mood for the selected unit that will cause them to become From 7d128adadab74c9f429ab1db3671a612318ca15c Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:10:07 +0000 Subject: [PATCH 467/851] 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 ae56641b1..40b1f9a87 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ae56641b1ae986a01ebd64c701b7758d64a41d51 +Subproject commit 40b1f9a8742ee19b527f7f74831751599fd468b8 diff --git a/scripts b/scripts index 0cda060cd..2edfc11e0 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 0cda060cdad309884ed4fb0b0f9914be4bd68143 +Subproject commit 2edfc11e0ca4c042cd70a5ea8f40be7323104242 From 45640fdd2678a823d23e54e9ec63f71da49e5456 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:26:48 +0000 Subject: [PATCH 468/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 2edfc11e0..058c4db87 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 2edfc11e0ca4c042cd70a5ea8f40be7323104242 +Subproject commit 058c4db87b83348789a9ee55926b9ae3c8a1a324 From c63906a91c6fd532502950db38c418742fa985f6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 5 Sep 2023 01:54:57 -0700 Subject: [PATCH 469/851] add clsocket to the update manifest --- ci/update-submodules.manifest | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/update-submodules.manifest b/ci/update-submodules.manifest index e97cae6f3..0c8f03e81 100644 --- a/ci/update-submodules.manifest +++ b/ci/update-submodules.manifest @@ -2,6 +2,7 @@ library/xml master scripts master plugins/stonesense master plugins/isoworld dfhack +depends/clsocket master depends/libzip dfhack depends/libexpat dfhack depends/xlsxio dfhack From db67ff735a2332db7b51745e9900ccad58d6a458 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 5 Sep 2023 08:56:05 +0000 Subject: [PATCH 470/851] Auto-update submodules depends/clsocket: master --- depends/clsocket | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/clsocket b/depends/clsocket index d5e17c601..8cf949340 160000 --- a/depends/clsocket +++ b/depends/clsocket @@ -1 +1 @@ -Subproject commit d5e17c6012e7eefb0cbe3e130a56c24bd11f0094 +Subproject commit 8cf949340e22001bee1ca25c9d6c1d6a89e8faf2 From 229e7aef8743ea88e48487995600db1a985be1ad Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 5 Sep 2023 17:49:58 -0700 Subject: [PATCH 471/851] enable filtering by race --- plugins/lua/zone.lua | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index bfdff01f0..3c07b609f 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -410,12 +410,19 @@ function AssignAnimal:refresh_list(sort_widget, sort_fn) list:setFilter(saved_filter) end -local function make_search_key(desc) - local out = '' - for c in dfhack.toSearchNormalized(desc):gmatch("[%w%s]") do - out = out .. c:lower() +function add_words(words, str) + for word in dfhack.toSearchNormalized(str):gmatch("[%w-]+") do + table.insert(words, word:lower()) end - return out +end + +function make_search_key(desc, race_raw) + local words = {} + add_words(words, desc) + if race_raw then + add_words(words, race_raw.name[0]) + end + return table.concat(words, ' ') end function AssignAnimal:make_choice_text(data) @@ -551,7 +558,7 @@ function AssignAnimal:cache_choices() graze=dfhack.units.isGrazer(unit), } local choice = { - search_key=make_search_key(data.desc), + search_key=make_search_key(data.desc, raw), data=data, text=self:make_choice_text(data), } @@ -570,7 +577,7 @@ function AssignAnimal:cache_choices() disposition=get_item_disposition(vermin), } local choice = { - search_key=make_search_key(data.desc), + search_key=make_search_key(data.desc, raw), data=data, text=self:make_choice_text(data), } @@ -589,7 +596,7 @@ function AssignAnimal:cache_choices() disposition=get_item_disposition(small_pet), } local choice = { - search_key=make_search_key(data.desc), + search_key=make_search_key(data.desc, raw), data=data, text=self:make_choice_text(data), } From 3cc59bd3b9150f1722c18bb97db7fe9289398d66 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 6 Sep 2023 19:41:52 +0000 Subject: [PATCH 472/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 058c4db87..4440e6ada 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 058c4db87b83348789a9ee55926b9ae3c8a1a324 +Subproject commit 4440e6ada6f0d03013cfbb38a4b5579256c2b098 From 31fbd0dab542c772cf3fd4cf10ed8887b0f2b186 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 6 Sep 2023 13:43:11 -0700 Subject: [PATCH 473/851] bump to 50.09-r3 --- CMakeLists.txt | 4 ++-- docs/changelog.txt | 24 ++++++++++++++++++------ library/xml | 2 +- scripts | 2 +- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 483142fe9..5bb5cab7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.09") -set(DFHACK_RELEASE "r3rc3") -set(DFHACK_PRERELEASE TRUE) +set(DFHACK_RELEASE "r3") +set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_ABI_VERSION 1) diff --git a/docs/changelog.txt b/docs/changelog.txt index aa03e408d..9b0a1d30e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -54,7 +54,23 @@ Template for new versions: ## New Tools ## New Features -- `sort`: search and sort for squad assignment screen + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 50.09-r3 + +## New Features +- `sort`: search, sort, and filter for squad assignment screen - `zone`: advanced unit assignment screens for cages, restraints, and pits/ponds - `buildingplan`: one-click magma/fire safety filter for planned buildings @@ -66,7 +82,7 @@ Template for new versions: - `caravan`: corrected prices for cages that have units inside of them - `tailor`: remove crash caused by clothing items with an invalid ``maker_race`` - ``dialogs.MessageBox``: fix spacing around scrollable text -- `seedwatch`: seedwatch will now ignore (unplantable) tree seeds entirely +- `seedwatch`: ignore unplantable tree seeds - `autobutcher`: fix ``ticks`` commandline option incorrectly rejecting positive integers as valid values ## Misc Improvements @@ -76,8 +92,6 @@ Template for new versions: - `sort`: animals are now sortable by race on the assignment screens - `createitem`: support creating items inside of bags -## Documentation - ## API - ``Items::getValue()``: remove ``caravan_buying`` parameter since the identity of the selling party doesn't actually affect the item value - `RemoteFortressReader`: add a ``force_reload`` option to the GetBlockList RPC API to return blocks regardless of whether they have changed since the last request @@ -93,8 +107,6 @@ Template for new versions: - ``dfhack.units``: new animal propery check functions ``isMarkedForTraining(unit)``, ``isMarkedForTaming(unit)``, ``isMarkedForWarTraining(unit)``, and ``isMarkedForHuntTraining(unit)`` - ``dfhack.gui``: new ``getAnyCivZone`` and ``getAnyStockpile`` functions; also behavior of ``getSelectedCivZone`` and ``getSelectedStockpile`` functions has changes as per the related API notes -## Removed - # 50.09-r2 ## New Plugins diff --git a/library/xml b/library/xml index 40b1f9a87..1cb9a9613 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 40b1f9a8742ee19b527f7f74831751599fd468b8 +Subproject commit 1cb9a961351db5c2988cee3a194eb24eac4abc1a diff --git a/scripts b/scripts index 4440e6ada..16b77541a 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 4440e6ada6f0d03013cfbb38a4b5579256c2b098 +Subproject commit 16b77541abf43e14a7283f04bdce8964db6bba22 From 47666e12cd7a235e08b2361ffaf06e34b19fdd53 Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 6 Sep 2023 18:09:07 -0400 Subject: [PATCH 474/851] terminal -> console for consistency followup to #3723 --- library/Core.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 353e99ef3..176d5014d 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1249,11 +1249,11 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, s } else if (res == CR_NEEDS_CONSOLE) con.printerr("%s needs an interactive console to work.\n" - "Please run this command from the DFHack terminal.\n\n" + "Please run this command from the DFHack console.\n\n" #ifdef WIN32 - "You can show the terminal with the 'show' command." + "You can show the console with the 'show' command." #else - "The terminal is accessible when you run DF from the commandline\n" + "The console is accessible when you run DF from the commandline\n" "via the './dfhack' script." #endif "\n", first.c_str()); From 337260ab0c201f0328d75914214723feddeb908d Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 6 Sep 2023 18:19:31 -0400 Subject: [PATCH 475/851] Fix unchecked lua_tostring calls --- library/LuaApi.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 1e89d7b45..f792cff90 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1368,8 +1368,8 @@ static CommandHistory * ensureCommandHistory(std::string id, static int getCommandHistory(lua_State *state) { - std::string id = lua_tostring(state, 1); - std::string src_file = lua_tostring(state, 2); + std::string id = luaL_checkstring(state, 1); + std::string src_file = luaL_checkstring(state, 2); std::vector entries; ensureCommandHistory(id, src_file)->getEntries(entries); Lua::PushVector(state, entries); @@ -2030,7 +2030,7 @@ static int units_getCitizens(lua_State *L) { } static int units_getUnitsByNobleRole(lua_State *L) { - std::string role_name = lua_tostring(L, -1); + std::string role_name = luaL_checkstring(L, -1); std::vector units; Units::getUnitsByNobleRole(units, role_name); Lua::PushVector(L, units); From ce2f35a2f1e113b9be3a2353058e0d15674fa3dd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 6 Sep 2023 15:25:13 -0700 Subject: [PATCH 476/851] fix pattern matching for release tags --- .github/workflows/github-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index e455ea34d..692897898 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -40,7 +40,7 @@ jobs: run: | TAG=$(git describe --tags --abbrev=0 --exact-match) echo name="$TAG" >> $GITHUB_OUTPUT - echo type=$(echo "$TAG" | egrep '-r[0-9]+$' && echo "release" || echo "prerelease") >> $GITHUB_OUTPUT + echo type=$(echo "$TAG" | egrep 'r[0-9]+$' && echo "release" || echo "prerelease") >> $GITHUB_OUTPUT - name: Generate release text run: | python docs/gen_changelog.py -a From 73df72ce6276b201ce5fc9f84a67f4e5f878dd7b Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 6 Sep 2023 22:37:07 +0000 Subject: [PATCH 477/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 16b77541a..4dfb75dd1 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 16b77541abf43e14a7283f04bdce8964db6bba22 +Subproject commit 4dfb75dd1b0df0af4fb9b5a04f5a2dbba19dff11 From 5611cdd99900007c05e5a0a4d76379f4eef6420e Mon Sep 17 00:00:00 2001 From: Andriel Chaoti <3628387+AndrielChaoti@users.noreply.github.com> Date: Wed, 6 Sep 2023 16:42:05 -0600 Subject: [PATCH 478/851] add `boolean` function for argparse implements a test for boolean values into the argparse utility that checks for truthy style values and converts them to a lua boolean. --- library/lua/argparse.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/lua/argparse.lua b/library/lua/argparse.lua index 36b80feb1..8da11cb28 100644 --- a/library/lua/argparse.lua +++ b/library/lua/argparse.lua @@ -196,4 +196,17 @@ function coords(arg, arg_name, skip_validation) return pos end +function boolean(arg, arg_name) + local toBool={["true"]=true,["yes"]=true,["y"]=true,["on"]=true,["1"]=true, + ["false"]=false,["no"]=false,["n"]=false,["off"]=false,["0"]=false} + + arg = string.lower(arg) + if toBool[arg] == nil then + arg_error(arg_name, + 'unknown value: "%s"; expected "true", "yes", "false", or "no"') + end + + return toBool[arg] +end + return _ENV From f0b0c2093b1b035ca43a85f5fa3179f75c8734dd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 7 Sep 2023 11:30:08 -0700 Subject: [PATCH 479/851] flatten sort functions --- plugins/lua/sort.lua | 126 +++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 64 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index e775f1ddf..3aabec544 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -425,28 +425,26 @@ local function sort_by_ranged_combat_potential_asc(unit_id_1, unit_id_2) return utils.compare(rating1, rating2) end -local SORT_FNS = { - sort_by_any_melee_desc=make_sort_by_melee_skill_effectiveness_desc(MELEE_WEAPON_SKILLS), - sort_by_any_melee_asc=make_sort_by_melee_skill_effectiveness_asc(MELEE_WEAPON_SKILLS), - sort_by_any_ranged_desc=make_sort_by_ranged_skill_effectiveness_desc(RANGED_WEAPON_SKILLS), - sort_by_any_ranged_asc=make_sort_by_ranged_skill_effectiveness_asc(RANGED_WEAPON_SKILLS), - sort_by_teacher_desc=make_sort_by_skill_desc(df.job_skill.TEACHING), - sort_by_teacher_asc=make_sort_by_skill_asc(df.job_skill.TEACHING), - sort_by_tactics_desc=make_sort_by_skill_desc(df.job_skill.MILITARY_TACTICS), - sort_by_tactics_asc=make_sort_by_skill_asc(df.job_skill.MILITARY_TACTICS), - sort_by_axe_desc=make_sort_by_skill_desc(df.job_skill.AXE), - sort_by_axe_asc=make_sort_by_skill_asc(df.job_skill.AXE), - sort_by_sword_desc=make_sort_by_skill_desc(df.job_skill.SWORD), - sort_by_sword_asc=make_sort_by_skill_asc(df.job_skill.SWORD), - sort_by_mace_desc=make_sort_by_skill_desc(df.job_skill.MACE), - sort_by_mace_asc=make_sort_by_skill_asc(df.job_skill.MACE), - sort_by_hammer_desc=make_sort_by_skill_desc(df.job_skill.HAMMER), - sort_by_hammer_asc=make_sort_by_skill_asc(df.job_skill.HAMMER), - sort_by_spear_desc=make_sort_by_skill_desc(df.job_skill.SPEAR), - sort_by_spear_asc=make_sort_by_skill_asc(df.job_skill.SPEAR), - sort_by_crossbow_desc=make_sort_by_skill_desc(df.job_skill.CROSSBOW), - sort_by_crossbow_asc=make_sort_by_skill_asc(df.job_skill.CROSSBOW), -} +local sort_by_any_melee_desc=make_sort_by_melee_skill_effectiveness_desc(MELEE_WEAPON_SKILLS) +local sort_by_any_melee_asc=make_sort_by_melee_skill_effectiveness_asc(MELEE_WEAPON_SKILLS) +local sort_by_any_ranged_desc=make_sort_by_ranged_skill_effectiveness_desc(RANGED_WEAPON_SKILLS) +local sort_by_any_ranged_asc=make_sort_by_ranged_skill_effectiveness_asc(RANGED_WEAPON_SKILLS) +local sort_by_teacher_desc=make_sort_by_skill_desc(df.job_skill.TEACHING) +local sort_by_teacher_asc=make_sort_by_skill_asc(df.job_skill.TEACHING) +local sort_by_tactics_desc=make_sort_by_skill_desc(df.job_skill.MILITARY_TACTICS) +local sort_by_tactics_asc=make_sort_by_skill_asc(df.job_skill.MILITARY_TACTICS) +local sort_by_axe_desc=make_sort_by_skill_desc(df.job_skill.AXE) +local sort_by_axe_asc=make_sort_by_skill_asc(df.job_skill.AXE) +local sort_by_sword_desc=make_sort_by_skill_desc(df.job_skill.SWORD) +local sort_by_sword_asc=make_sort_by_skill_asc(df.job_skill.SWORD) +local sort_by_mace_desc=make_sort_by_skill_desc(df.job_skill.MACE) +local sort_by_mace_asc=make_sort_by_skill_asc(df.job_skill.MACE) +local sort_by_hammer_desc=make_sort_by_skill_desc(df.job_skill.HAMMER) +local sort_by_hammer_asc=make_sort_by_skill_asc(df.job_skill.HAMMER) +local sort_by_spear_desc=make_sort_by_skill_desc(df.job_skill.SPEAR) +local sort_by_spear_asc=make_sort_by_skill_asc(df.job_skill.SPEAR) +local sort_by_crossbow_desc=make_sort_by_skill_desc(df.job_skill.CROSSBOW) +local sort_by_crossbow_asc=make_sort_by_skill_asc(df.job_skill.CROSSBOW) -- ---------------------- -- SquadAssignmentOverlay @@ -492,40 +490,40 @@ function SquadAssignmentOverlay:init() label='Sort by:', key='CUSTOM_SHIFT_S', options={ - {label='melee effectiveness'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc, pen=COLOR_GREEN}, - {label='melee effectiveness'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc, pen=COLOR_YELLOW}, - {label='ranged effectiveness'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc, pen=COLOR_GREEN}, - {label='ranged effectiveness'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc, pen=COLOR_YELLOW}, + {label='melee effectiveness'..CH_DN, value=sort_by_any_melee_desc, pen=COLOR_GREEN}, + {label='melee effectiveness'..CH_UP, value=sort_by_any_melee_asc, pen=COLOR_YELLOW}, + {label='ranged effectiveness'..CH_DN, value=sort_by_any_ranged_desc, pen=COLOR_GREEN}, + {label='ranged effectiveness'..CH_UP, value=sort_by_any_ranged_asc, pen=COLOR_YELLOW}, {label='name'..CH_DN, value=sort_by_name_desc, pen=COLOR_GREEN}, {label='name'..CH_UP, value=sort_by_name_asc, pen=COLOR_YELLOW}, - {label='teacher skill'..CH_DN, value=SORT_FNS.sort_by_teacher_desc, pen=COLOR_GREEN}, - {label='teacher skill'..CH_UP, value=SORT_FNS.sort_by_teacher_asc, pen=COLOR_YELLOW}, - {label='tactics skill'..CH_DN, value=SORT_FNS.sort_by_tactics_desc, pen=COLOR_GREEN}, - {label='tactics skill'..CH_UP, value=SORT_FNS.sort_by_tactics_asc, pen=COLOR_YELLOW}, + {label='teacher skill'..CH_DN, value=sort_by_teacher_desc, pen=COLOR_GREEN}, + {label='teacher skill'..CH_UP, value=sort_by_teacher_asc, pen=COLOR_YELLOW}, + {label='tactics skill'..CH_DN, value=sort_by_tactics_desc, pen=COLOR_GREEN}, + {label='tactics skill'..CH_UP, value=sort_by_tactics_asc, pen=COLOR_YELLOW}, {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc, pen=COLOR_GREEN}, {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc, pen=COLOR_YELLOW}, {label='stress level'..CH_DN, value=sort_by_stress_desc, pen=COLOR_GREEN}, {label='stress level'..CH_UP, value=sort_by_stress_asc, pen=COLOR_YELLOW}, {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, - {label='axe skill'..CH_DN, value=SORT_FNS.sort_by_axe_desc, pen=COLOR_GREEN}, - {label='axe skill'..CH_UP, value=SORT_FNS.sort_by_axe_asc, pen=COLOR_YELLOW}, - {label='sword skill'..CH_DN, value=SORT_FNS.sort_by_sword_desc, pen=COLOR_GREEN}, - {label='sword skill'..CH_UP, value=SORT_FNS.sort_by_sword_asc, pen=COLOR_YELLOW}, - {label='mace skill'..CH_DN, value=SORT_FNS.sort_by_mace_desc, pen=COLOR_GREEN}, - {label='mace skill'..CH_UP, value=SORT_FNS.sort_by_mace_asc, pen=COLOR_YELLOW}, - {label='hammer skill'..CH_DN, value=SORT_FNS.sort_by_hammer_desc, pen=COLOR_GREEN}, - {label='hammer skill'..CH_UP, value=SORT_FNS.sort_by_hammer_asc, pen=COLOR_YELLOW}, - {label='spear skill'..CH_DN, value=SORT_FNS.sort_by_spear_desc, pen=COLOR_GREEN}, - {label='spear skill'..CH_UP, value=SORT_FNS.sort_by_spear_asc, pen=COLOR_YELLOW}, - {label='crossbow skill'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc, pen=COLOR_GREEN}, - {label='crossbow skill'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc, pen=COLOR_YELLOW}, + {label='axe skill'..CH_DN, value=sort_by_axe_desc, pen=COLOR_GREEN}, + {label='axe skill'..CH_UP, value=sort_by_axe_asc, pen=COLOR_YELLOW}, + {label='sword skill'..CH_DN, value=sort_by_sword_desc, pen=COLOR_GREEN}, + {label='sword skill'..CH_UP, value=sort_by_sword_asc, pen=COLOR_YELLOW}, + {label='mace skill'..CH_DN, value=sort_by_mace_desc, pen=COLOR_GREEN}, + {label='mace skill'..CH_UP, value=sort_by_mace_asc, pen=COLOR_YELLOW}, + {label='hammer skill'..CH_DN, value=sort_by_hammer_desc, pen=COLOR_GREEN}, + {label='hammer skill'..CH_UP, value=sort_by_hammer_asc, pen=COLOR_YELLOW}, + {label='spear skill'..CH_DN, value=sort_by_spear_desc, pen=COLOR_GREEN}, + {label='spear skill'..CH_UP, value=sort_by_spear_asc, pen=COLOR_YELLOW}, + {label='crossbow skill'..CH_DN, value=sort_by_crossbow_desc, pen=COLOR_GREEN}, + {label='crossbow skill'..CH_UP, value=sort_by_crossbow_asc, pen=COLOR_YELLOW}, {label='melee potential'..CH_DN, value=sort_by_melee_combat_potential_desc, pen=COLOR_GREEN}, {label='melee potential'..CH_UP, value=sort_by_melee_combat_potential_asc, pen=COLOR_YELLOW}, {label='ranged potential'..CH_DN, value=sort_by_ranged_combat_potential_desc, pen=COLOR_GREEN}, {label='ranged potential'..CH_UP, value=sort_by_ranged_combat_potential_asc, pen=COLOR_YELLOW}, }, - initial_option=SORT_FNS.sort_by_any_melee_desc, + initial_option=sort_by_any_melee_desc, on_change=self:callback('refresh_list', 'sort'), }, widgets.CycleHotkeyLabel{ @@ -533,10 +531,10 @@ function SquadAssignmentOverlay:init() frame={t=2, l=0, w=11}, options={ {label='melee eff.', value=sort_noop}, - {label='melee eff.'..CH_DN, value=SORT_FNS.sort_by_any_melee_desc, pen=COLOR_GREEN}, - {label='melee eff.'..CH_UP, value=SORT_FNS.sort_by_any_melee_asc, pen=COLOR_YELLOW}, + {label='melee eff.'..CH_DN, value=sort_by_any_melee_desc, pen=COLOR_GREEN}, + {label='melee eff.'..CH_UP, value=sort_by_any_melee_asc, pen=COLOR_YELLOW}, }, - initial_option=SORT_FNS.sort_by_any_melee_desc, + initial_option=sort_by_any_melee_desc, option_gap=0, on_change=self:callback('refresh_list', 'sort_any_melee'), }, @@ -545,8 +543,8 @@ function SquadAssignmentOverlay:init() frame={t=2, r=8, w=12}, options={ {label='ranged eff.', value=sort_noop}, - {label='ranged eff.'..CH_DN, value=SORT_FNS.sort_by_any_ranged_desc, pen=COLOR_GREEN}, - {label='ranged eff.'..CH_UP, value=SORT_FNS.sort_by_any_ranged_asc, pen=COLOR_YELLOW}, + {label='ranged eff.'..CH_DN, value=sort_by_any_ranged_desc, pen=COLOR_GREEN}, + {label='ranged eff.'..CH_UP, value=sort_by_any_ranged_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_any_ranged'), @@ -567,8 +565,8 @@ function SquadAssignmentOverlay:init() frame={t=4, l=0, w=8}, options={ {label='teacher', value=sort_noop}, - {label='teacher'..CH_DN, value=SORT_FNS.sort_by_teacher_desc, pen=COLOR_GREEN}, - {label='teacher'..CH_UP, value=SORT_FNS.sort_by_teacher_asc, pen=COLOR_YELLOW}, + {label='teacher'..CH_DN, value=sort_by_teacher_desc, pen=COLOR_GREEN}, + {label='teacher'..CH_UP, value=sort_by_teacher_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_teacher'), @@ -578,8 +576,8 @@ function SquadAssignmentOverlay:init() frame={t=4, l=10, w=8}, options={ {label='tactics', value=sort_noop}, - {label='tactics'..CH_DN, value=SORT_FNS.sort_by_tactics_desc, pen=COLOR_GREEN}, - {label='tactics'..CH_UP, value=SORT_FNS.sort_by_tactics_asc, pen=COLOR_YELLOW}, + {label='tactics'..CH_DN, value=sort_by_tactics_desc, pen=COLOR_GREEN}, + {label='tactics'..CH_UP, value=sort_by_tactics_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_tactics'), @@ -622,8 +620,8 @@ function SquadAssignmentOverlay:init() frame={t=8, l=0, w=4}, options={ {label='axe', value=sort_noop}, - {label='axe'..CH_DN, value=SORT_FNS.sort_by_axe_desc, pen=COLOR_GREEN}, - {label='axe'..CH_UP, value=SORT_FNS.sort_by_axe_asc, pen=COLOR_YELLOW}, + {label='axe'..CH_DN, value=sort_by_axe_desc, pen=COLOR_GREEN}, + {label='axe'..CH_UP, value=sort_by_axe_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_axe'), @@ -633,8 +631,8 @@ function SquadAssignmentOverlay:init() frame={t=8, w=6}, options={ {label='sword', value=sort_noop}, - {label='sword'..CH_DN, value=SORT_FNS.sort_by_sword_desc, pen=COLOR_GREEN}, - {label='sword'..CH_UP, value=SORT_FNS.sort_by_sword_asc, pen=COLOR_YELLOW}, + {label='sword'..CH_DN, value=sort_by_sword_desc, pen=COLOR_GREEN}, + {label='sword'..CH_UP, value=sort_by_sword_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_sword'), @@ -644,8 +642,8 @@ function SquadAssignmentOverlay:init() frame={t=8, r=0, w=5}, options={ {label='mace', value=sort_noop}, - {label='mace'..CH_DN, value=SORT_FNS.sort_by_mace_desc, pen=COLOR_GREEN}, - {label='mace'..CH_UP, value=SORT_FNS.sort_by_mace_asc, pen=COLOR_YELLOW}, + {label='mace'..CH_DN, value=sort_by_mace_desc, pen=COLOR_GREEN}, + {label='mace'..CH_UP, value=sort_by_mace_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_mace'), @@ -655,8 +653,8 @@ function SquadAssignmentOverlay:init() frame={t=10, l=0, w=7}, options={ {label='hammer', value=sort_noop}, - {label='hammer'..CH_DN, value=SORT_FNS.sort_by_hammer_desc, pen=COLOR_GREEN}, - {label='hammer'..CH_UP, value=SORT_FNS.sort_by_hammer_asc, pen=COLOR_YELLOW}, + {label='hammer'..CH_DN, value=sort_by_hammer_desc, pen=COLOR_GREEN}, + {label='hammer'..CH_UP, value=sort_by_hammer_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_hammer'), @@ -666,8 +664,8 @@ function SquadAssignmentOverlay:init() frame={t=10, w=6}, options={ {label='spear', value=sort_noop}, - {label='spear'..CH_DN, value=SORT_FNS.sort_by_spear_desc, pen=COLOR_GREEN}, - {label='spear'..CH_UP, value=SORT_FNS.sort_by_spear_asc, pen=COLOR_YELLOW}, + {label='spear'..CH_DN, value=sort_by_spear_desc, pen=COLOR_GREEN}, + {label='spear'..CH_UP, value=sort_by_spear_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_spear'), @@ -677,8 +675,8 @@ function SquadAssignmentOverlay:init() frame={t=10, r=0, w=9}, options={ {label='crossbow', value=sort_noop}, - {label='crossbow'..CH_DN, value=SORT_FNS.sort_by_crossbow_desc, pen=COLOR_GREEN}, - {label='crossbow'..CH_UP, value=SORT_FNS.sort_by_crossbow_asc, pen=COLOR_YELLOW}, + {label='crossbow'..CH_DN, value=sort_by_crossbow_desc, pen=COLOR_GREEN}, + {label='crossbow'..CH_UP, value=sort_by_crossbow_asc, pen=COLOR_YELLOW}, }, option_gap=0, on_change=self:callback('refresh_list', 'sort_crossbow'), From d0f08dcc0d1cc6c9a9309321c67c80dddec87b8d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 7 Sep 2023 16:14:20 -0700 Subject: [PATCH 480/851] implement rating overlay --- plugins/lua/sort.lua | 319 +++++++++++++++++++++++++++++++------------ 1 file changed, 228 insertions(+), 91 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 3aabec544..4638c8ffe 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -9,31 +9,33 @@ local widgets = require('gui.widgets') local CH_UP = string.char(30) local CH_DN = string.char(31) -local MELEE_WEAPON_SKILLS = { - df.job_skill.AXE, - df.job_skill.SWORD, - df.job_skill.MACE, - df.job_skill.HAMMER, - df.job_skill.SPEAR, -} - -local RANGED_WEAPON_SKILLS = { - df.job_skill.CROSSBOW, -} +local function get_rating(val, max, med, low) + val = math.min(max, val) + local percent = (val * 100) // max + local color = COLOR_GREEN + if percent < (low or 50) then color = COLOR_RED + elseif percent < (med or 75) then color = COLOR_YELLOW + end + return percent, color +end local function sort_noop(a, b) -- this function is used as a marker and never actually gets called error('sort_noop should not be called') end +local function get_name(unit) + return unit and dfhack.toSearchNormalized(dfhack.TranslateName(dfhack.units.getVisibleName(unit))) +end + local function sort_by_name_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local name1 = dfhack.TranslateName(dfhack.units.getVisibleName(unit1)) - local name2 = dfhack.TranslateName(dfhack.units.getVisibleName(unit2)) + local name1 = get_name(unit1) + local name2 = get_name(unit2) return utils.compare_name(name1, name2) end @@ -43,8 +45,8 @@ local function sort_by_name_asc(unit_id_1, unit_id_2) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local name1 = dfhack.TranslateName(dfhack.units.getVisibleName(unit1)) - local name2 = dfhack.TranslateName(dfhack.units.getVisibleName(unit2)) + local name1 = get_name(unit1) + local name2 = get_name(unit2) return utils.compare_name(name2, name1) end @@ -61,6 +63,11 @@ local function get_active_idx_cache() return active_idx_cache end +local function get_migrant_wave_rating(unit) + -- TODO: return green for most recent wave, red for the first wave, yellow for all others + return 1, nil +end + local function sort_by_migrant_wave_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local cache = get_active_idx_cache() @@ -77,17 +84,29 @@ local function sort_by_migrant_wave_asc(unit_id_1, unit_id_2) return utils.compare(cache[unit_id_1], cache[unit_id_2]) end +local function get_stress(unit) + return unit and + unit.status.current_soul and + unit.status.current_soul.personality.stress +end + +local function get_stress_rating(unit) + return get_rating(-get_stress(unit) + 100000, 200000, 50, 25) +end + local function sort_by_stress_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local happiness1 = unit1.status.current_soul.personality.stress - local happiness2 = unit2.status.current_soul.personality.stress + local happiness1 = get_stress(unit1) + local happiness2 = get_stress(unit2) if happiness1 == happiness2 then return sort_by_name_desc(unit_id_1, unit_id_2) end + if not happiness2 then return -1 end + if not happiness1 then return 1 end return utils.compare(happiness2, happiness1) end @@ -97,22 +116,37 @@ local function sort_by_stress_asc(unit_id_1, unit_id_2) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local happiness1 = unit1.status.current_soul.personality.stress - local happiness2 = unit2.status.current_soul.personality.stress + local happiness1 = get_stress(unit1) + local happiness2 = get_stress(unit2) if happiness1 == happiness2 then return sort_by_name_desc(unit_id_1, unit_id_2) end + if not happiness2 then return 1 end + if not happiness1 then return -1 end return utils.compare(happiness1, happiness2) end -local function get_skill(unit_id, skill, unit) - unit = unit or df.unit.find(unit_id) +local function get_skill(skill, unit) return unit and unit.status.current_soul and - utils.binsearch(unit.status.current_soul.skills, skill, 'id') + (utils.binsearch(unit.status.current_soul.skills, skill, 'id')) end -local function melee_skill_effectiveness(unit, skill_list) +local function get_skill_rating(skill, unit) + local uskill = get_skill(skill, unit) + if not uskill then return nil end + return get_rating(uskill.rating, 100, 5, 0) +end + +local MELEE_WEAPON_SKILLS = { + df.job_skill.AXE, + df.job_skill.SWORD, + df.job_skill.MACE, + df.job_skill.HAMMER, + df.job_skill.SPEAR, +} + +local function melee_skill_effectiveness(unit) -- Physical attributes local strength = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.STRENGTH) local agility = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.AGILITY) @@ -128,7 +162,7 @@ local function melee_skill_effectiveness(unit, skill_list) -- Skills -- Finding the highest skill local skill_rating = 0 - for _, skill in ipairs(skill_list) do + for _, skill in ipairs(MELEE_WEAPON_SKILLS) do local melee_skill = dfhack.units.getNominalSkill(unit, skill, true) skill_rating = math.max(skill_rating, melee_skill) end @@ -140,36 +174,44 @@ local function melee_skill_effectiveness(unit, skill_list) return rating end -local function make_sort_by_melee_skill_effectiveness_desc(list) +local function get_melee_skill_effectiveness_rating(unit) + return get_rating(melee_skill_effectiveness(unit), 2000000) +end + +local function make_sort_by_melee_skill_effectiveness_desc() return function(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = melee_skill_effectiveness(unit1, list) - local rating2 = melee_skill_effectiveness(unit2, list) + local rating1 = melee_skill_effectiveness(unit1) + local rating2 = melee_skill_effectiveness(unit2) if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end return utils.compare(rating2, rating1) end end -local function make_sort_by_melee_skill_effectiveness_asc(list) +local function make_sort_by_melee_skill_effectiveness_asc() return function(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = melee_skill_effectiveness(unit1, list) - local rating2 = melee_skill_effectiveness(unit2, list) + local rating1 = melee_skill_effectiveness(unit1) + local rating2 = melee_skill_effectiveness(unit2) if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end return utils.compare(rating1, rating2) end end --- FUnction could easily be adapted to different weapon types. -local function ranged_skill_effectiveness(unit, skill_list) +local RANGED_WEAPON_SKILLS = { + df.job_skill.CROSSBOW, +} + +-- Function could easily be adapted to different weapon types. +local function ranged_skill_effectiveness(unit) -- Physical attributes local agility = dfhack.units.getPhysicalAttrValue(unit, df.physical_attribute_type.AGILITY) @@ -181,7 +223,7 @@ local function ranged_skill_effectiveness(unit, skill_list) -- Skills -- Finding the highest skill local skill_rating = 0 - for _, skill in ipairs(skill_list) do + for _, skill in ipairs(RANGED_WEAPON_SKILLS) do local ranged_skill = dfhack.units.getNominalSkill(unit, skill, true) skill_rating = math.max(skill_rating, ranged_skill) end @@ -192,6 +234,10 @@ local function ranged_skill_effectiveness(unit, skill_list) return rating end +local function get_ranged_skill_effectiveness_rating(unit) + return get_rating(ranged_skill_effectiveness(unit), 500000) +end + local function make_sort_by_ranged_skill_effectiveness_desc(list) return function(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end @@ -225,8 +271,8 @@ local function make_sort_by_skill_desc(sort_skill) if unit_id_1 == unit_id_2 then return 0 end if unit_id_1 == -1 then return -1 end if unit_id_2 == -1 then return 1 end - local s1 = get_skill(unit_id_1, sort_skill) - local s2 = get_skill(unit_id_2, sort_skill) + local s1 = get_skill(sort_skill, df.unit.find(unit_id_1)) + local s2 = get_skill(sort_skill, df.unit.find(unit_id_2)) if s1 == s2 then return sort_by_name_desc(unit_id_1, unit_id_2) end if not s2 then return -1 end if not s1 then return 1 end @@ -245,8 +291,8 @@ local function make_sort_by_skill_asc(sort_skill) if unit_id_1 == unit_id_2 then return 0 end if unit_id_1 == -1 then return -1 end if unit_id_2 == -1 then return 1 end - local s1 = get_skill(unit_id_1, sort_skill) - local s2 = get_skill(unit_id_2, sort_skill) + local s1 = get_skill(sort_skill, df.unit.find(unit_id_1)) + local s2 = get_skill(sort_skill, df.unit.find(unit_id_2)) if s1 == s2 then return sort_by_name_desc(unit_id_1, unit_id_2) end if not s2 then return 1 end if not s1 then return -1 end @@ -261,7 +307,7 @@ local function make_sort_by_skill_asc(sort_skill) end -- Statistical rating that is higher for dwarves that are mentally stable -local function mental_stability(unit) +local function get_mental_stability(unit) local ALTRUISM = unit.status.current_soul.personality.traits.ALTRUISM local ANXIETY_PROPENSITY = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY local BRAVERY = unit.status.current_soul.personality.traits.BRAVERY @@ -301,14 +347,18 @@ local function mental_stability(unit) return rating end +local function get_mental_stability_rating(unit) + return get_rating(get_mental_stability(unit), 100, 10, 0) +end + local function sort_by_mental_stability_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = mental_stability(unit1) - local rating2 = mental_stability(unit2) + local rating1 = get_mental_stability(unit1) + local rating2 = get_mental_stability(unit2) if rating1 == rating2 then -- sorting by stress is opposite -- more mental stable dwarves should have less stress @@ -323,8 +373,8 @@ local function sort_by_mental_stability_asc(unit_id_1, unit_id_2) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = mental_stability(unit1) - local rating2 = mental_stability(unit2) + local rating1 = get_mental_stability(unit1) + local rating2 = get_mental_stability(unit2) if rating1 == rating2 then return sort_by_stress_desc(unit_id_1, unit_id_2) end @@ -334,7 +384,7 @@ end -- Statistical rating that is higher for more potent dwarves in long run melee military training -- Rating considers fighting melee opponents -- Wounds are not considered! -local function melee_combat_potential(unit) +local function get_melee_combat_potential(unit) -- Physical attributes local strength = unit.body.physical_attrs.STRENGTH.max_value local agility = unit.body.physical_attrs.AGILITY.max_value @@ -353,14 +403,18 @@ local function melee_combat_potential(unit) return rating end +local function get_melee_combat_potential_rating(unit) + return get_rating(get_melee_combat_potential(unit), 2000000) +end + local function sort_by_melee_combat_potential_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = melee_combat_potential(unit1) - local rating2 = melee_combat_potential(unit2) + local rating1 = get_melee_combat_potential(unit1) + local rating2 = get_melee_combat_potential(unit2) if rating1 == rating2 then return sort_by_mental_stability_desc(unit_id_1, unit_id_2) end @@ -373,8 +427,8 @@ local function sort_by_melee_combat_potential_asc(unit_id_1, unit_id_2) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = melee_combat_potential(unit1) - local rating2 = melee_combat_potential(unit2) + local rating1 = get_melee_combat_potential(unit1) + local rating2 = get_melee_combat_potential(unit2) if rating1 == rating2 then return sort_by_mental_stability_asc(unit_id_1, unit_id_2) end @@ -383,7 +437,7 @@ end -- Statistical rating that is higher for more potent dwarves in long run ranged military training -- Wounds are not considered! -local function ranged_combat_potential(unit) +local function get_ranged_combat_potential(unit) -- Physical attributes local agility = unit.body.physical_attrs.AGILITY.max_value @@ -397,14 +451,18 @@ local function ranged_combat_potential(unit) return rating end +local function get_ranged_combat_potential_rating(unit) + return get_rating(get_ranged_combat_potential(unit), 40000) +end + local function sort_by_ranged_combat_potential_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = ranged_combat_potential(unit1) - local rating2 = ranged_combat_potential(unit2) + local rating1 = get_ranged_combat_potential(unit1) + local rating2 = get_ranged_combat_potential(unit2) if rating1 == rating2 then return sort_by_mental_stability_desc(unit_id_1, unit_id_2) end @@ -417,18 +475,18 @@ local function sort_by_ranged_combat_potential_asc(unit_id_1, unit_id_2) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = ranged_combat_potential(unit1) - local rating2 = ranged_combat_potential(unit2) + local rating1 = get_ranged_combat_potential(unit1) + local rating2 = get_ranged_combat_potential(unit2) if rating1 == rating2 then return sort_by_mental_stability_asc(unit_id_1, unit_id_2) end return utils.compare(rating1, rating2) end -local sort_by_any_melee_desc=make_sort_by_melee_skill_effectiveness_desc(MELEE_WEAPON_SKILLS) -local sort_by_any_melee_asc=make_sort_by_melee_skill_effectiveness_asc(MELEE_WEAPON_SKILLS) -local sort_by_any_ranged_desc=make_sort_by_ranged_skill_effectiveness_desc(RANGED_WEAPON_SKILLS) -local sort_by_any_ranged_asc=make_sort_by_ranged_skill_effectiveness_asc(RANGED_WEAPON_SKILLS) +local sort_by_any_melee_desc=make_sort_by_melee_skill_effectiveness_desc() +local sort_by_any_melee_asc=make_sort_by_melee_skill_effectiveness_asc() +local sort_by_any_ranged_desc=make_sort_by_ranged_skill_effectiveness_desc() +local sort_by_any_ranged_asc=make_sort_by_ranged_skill_effectiveness_asc() local sort_by_teacher_desc=make_sort_by_skill_desc(df.job_skill.TEACHING) local sort_by_teacher_asc=make_sort_by_skill_asc(df.job_skill.TEACHING) local sort_by_tactics_desc=make_sort_by_skill_desc(df.job_skill.MILITARY_TACTICS) @@ -446,13 +504,38 @@ local sort_by_spear_asc=make_sort_by_skill_asc(df.job_skill.SPEAR) local sort_by_crossbow_desc=make_sort_by_skill_desc(df.job_skill.CROSSBOW) local sort_by_crossbow_asc=make_sort_by_skill_asc(df.job_skill.CROSSBOW) +local SORT_LIBRARY = { + {label='melee effectiveness', desc_fn=sort_by_any_melee_desc, asc_fn=sort_by_any_melee_asc, rating_fn=get_melee_skill_effectiveness_rating}, + {label='ranged effectiveness', desc_fn=sort_by_any_ranged_desc, asc_fn=sort_by_any_ranged_asc, rating_fn=get_ranged_skill_effectiveness_rating}, + {label='name', desc_fn=sort_by_name_desc, asc_fn=sort_by_name_asc}, + {label='teacher skill', desc_fn=sort_by_teacher_desc, asc_fn=sort_by_teacher_asc, rating_fn=curry(get_skill_rating, df.job_skill.TEACHING)}, + {label='tactics skill', desc_fn=sort_by_tactics_desc, asc_fn=sort_by_tactics_asc, rating_fn=curry(get_skill_rating, df.job_skill.MILITARY_TACTICS)}, + {label='migrant wave', desc_fn=sort_by_migrant_wave_desc, asc_fn=sort_by_migrant_wave_asc, rating_fn=get_migrant_wave_rating}, + {label='stress level', desc_fn=sort_by_stress_desc, asc_fn=sort_by_stress_asc, rating_fn=get_stress_rating}, + {label='mental stability', desc_fn=sort_by_mental_stability_desc, asc_fn=sort_by_mental_stability_asc, rating_fn=get_mental_stability_rating}, + {label='axe skill', desc_fn=sort_by_axe_desc, asc_fn=sort_by_axe_asc, rating_fn=curry(get_skill_rating, df.job_skill.AXE)}, + {label='sword skill', desc_fn=sort_by_sword_desc, asc_fn=sort_by_sword_asc, rating_fn=curry(get_skill_rating, df.job_skill.SWORD)}, + {label='mace skill', desc_fn=sort_by_mace_desc, asc_fn=sort_by_mace_asc, rating_fn=curry(get_skill_rating, df.job_skill.MACE)}, + {label='hammer skill', desc_fn=sort_by_hammer_desc, asc_fn=sort_by_hammer_asc, rating_fn=curry(get_skill_rating, df.job_skill.HAMMER)}, + {label='spear skill', desc_fn=sort_by_spear_desc, asc_fn=sort_by_spear_asc, rating_fn=curry(get_skill_rating, df.job_skill.SPEAR)}, + {label='crossbow skill', desc_fn=sort_by_crossbow_desc, asc_fn=sort_by_crossbow_asc, rating_fn=curry(get_skill_rating, df.job_skill.CROSSBOW)}, + {label='melee potential', desc_fn=sort_by_melee_combat_potential_desc, asc_fn=sort_by_melee_combat_potential_asc, rating_fn=get_melee_combat_potential_rating}, + {label='ranged potential', desc_fn=sort_by_ranged_combat_potential_desc, asc_fn=sort_by_ranged_combat_potential_asc, rating_fn=get_ranged_combat_potential_rating}, +} + +local RATING_FNS = {} +for _, opt in ipairs(SORT_LIBRARY) do + RATING_FNS[opt.desc_fn] = opt.rating_fn + RATING_FNS[opt.asc_fn] = opt.rating_fn +end + -- ---------------------- -- SquadAssignmentOverlay -- SquadAssignmentOverlay = defclass(SquadAssignmentOverlay, overlay.OverlayWidget) SquadAssignmentOverlay.ATTRS{ - default_pos={x=23, y=5}, + default_pos={x=18, y=5}, default_enabled=true, viewscreens='dwarfmode/UnitSelector/SQUAD_FILL_POSITION', frame={w=38, h=25}, @@ -472,6 +555,20 @@ end function SquadAssignmentOverlay:init() self.dirty = true + local sort_options = {} + for _, opt in ipairs(SORT_LIBRARY) do + table.insert(sort_options, { + label=opt.label..CH_DN, + value=opt.desc_fn, + pen=COLOR_GREEN, + }) + table.insert(sort_options, { + label=opt.label..CH_UP, + value=opt.asc_fn, + pen=COLOR_YELLOW, + }) + end + self:addviews{ widgets.EditField{ view_id='search', @@ -489,40 +586,7 @@ function SquadAssignmentOverlay:init() frame={t=0, l=0}, label='Sort by:', key='CUSTOM_SHIFT_S', - options={ - {label='melee effectiveness'..CH_DN, value=sort_by_any_melee_desc, pen=COLOR_GREEN}, - {label='melee effectiveness'..CH_UP, value=sort_by_any_melee_asc, pen=COLOR_YELLOW}, - {label='ranged effectiveness'..CH_DN, value=sort_by_any_ranged_desc, pen=COLOR_GREEN}, - {label='ranged effectiveness'..CH_UP, value=sort_by_any_ranged_asc, pen=COLOR_YELLOW}, - {label='name'..CH_DN, value=sort_by_name_desc, pen=COLOR_GREEN}, - {label='name'..CH_UP, value=sort_by_name_asc, pen=COLOR_YELLOW}, - {label='teacher skill'..CH_DN, value=sort_by_teacher_desc, pen=COLOR_GREEN}, - {label='teacher skill'..CH_UP, value=sort_by_teacher_asc, pen=COLOR_YELLOW}, - {label='tactics skill'..CH_DN, value=sort_by_tactics_desc, pen=COLOR_GREEN}, - {label='tactics skill'..CH_UP, value=sort_by_tactics_asc, pen=COLOR_YELLOW}, - {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc, pen=COLOR_GREEN}, - {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc, pen=COLOR_YELLOW}, - {label='stress level'..CH_DN, value=sort_by_stress_desc, pen=COLOR_GREEN}, - {label='stress level'..CH_UP, value=sort_by_stress_asc, pen=COLOR_YELLOW}, - {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, - {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, - {label='axe skill'..CH_DN, value=sort_by_axe_desc, pen=COLOR_GREEN}, - {label='axe skill'..CH_UP, value=sort_by_axe_asc, pen=COLOR_YELLOW}, - {label='sword skill'..CH_DN, value=sort_by_sword_desc, pen=COLOR_GREEN}, - {label='sword skill'..CH_UP, value=sort_by_sword_asc, pen=COLOR_YELLOW}, - {label='mace skill'..CH_DN, value=sort_by_mace_desc, pen=COLOR_GREEN}, - {label='mace skill'..CH_UP, value=sort_by_mace_asc, pen=COLOR_YELLOW}, - {label='hammer skill'..CH_DN, value=sort_by_hammer_desc, pen=COLOR_GREEN}, - {label='hammer skill'..CH_UP, value=sort_by_hammer_asc, pen=COLOR_YELLOW}, - {label='spear skill'..CH_DN, value=sort_by_spear_desc, pen=COLOR_GREEN}, - {label='spear skill'..CH_UP, value=sort_by_spear_asc, pen=COLOR_YELLOW}, - {label='crossbow skill'..CH_DN, value=sort_by_crossbow_desc, pen=COLOR_GREEN}, - {label='crossbow skill'..CH_UP, value=sort_by_crossbow_asc, pen=COLOR_YELLOW}, - {label='melee potential'..CH_DN, value=sort_by_melee_combat_potential_desc, pen=COLOR_GREEN}, - {label='melee potential'..CH_UP, value=sort_by_melee_combat_potential_asc, pen=COLOR_YELLOW}, - {label='ranged potential'..CH_DN, value=sort_by_ranged_combat_potential_desc, pen=COLOR_GREEN}, - {label='ranged potential'..CH_UP, value=sort_by_ranged_combat_potential_asc, pen=COLOR_YELLOW}, - }, + options=sort_options, initial_option=sort_by_any_melee_desc, on_change=self:callback('refresh_list', 'sort'), }, @@ -846,6 +910,29 @@ local function filter_vector(filter, prev_filter) unit_selector.unid:erase(idx) end end + -- fix up scroll position if it would be off the end of the list + if unit_selector.scroll_position + 10 > #unit_selector.unid then + unit_selector.scroll_position = math.max(0, #unit_selector.unid - 10) + end +end + +local rating_annotations = {} + +local function annotate_visible_units(sort_fn) + rating_annotations = {} + rating_fn = RATING_FNS[sort_fn] + local max_idx = math.min(#unit_selector.unid-1, unit_selector.scroll_position+9) + for idx = unit_selector.scroll_position, max_idx do + local annotation_idx = idx - unit_selector.scroll_position + 1 + local unit = df.unit.find(unit_selector.unid[idx]) + rating_annotations[annotation_idx] = nil + if unit and rating_fn then + local val, color = rating_fn(unit) + if val then + rating_annotations[annotation_idx] = {val=val, color=color} + end + end + end end local SORT_WIDGET_NAMES = { @@ -887,6 +974,8 @@ function SquadAssignmentOverlay:refresh_list(sort_widget, sort_fn) filter_vector(filter, self.prev_filter or {}) self.prev_filter = filter utils.sort_vector(unit_selector.unid, nil, sort_fn) + annotate_visible_units(sort_fn) + self.saved_scroll_position = unit_selector.scroll_position end function SquadAssignmentOverlay:onInput(keys) @@ -904,11 +993,59 @@ function SquadAssignmentOverlay:onRenderFrame(dc, frame_rect) if self.dirty then self:refresh_list() self.dirty = false + elseif self.saved_scroll_position ~= unit_selector.scroll_position then + annotate_visible_units(self.subviews.sort:getOptionValue()) + self.saved_scroll_position = unit_selector.scroll_position + end +end + +-- ---------------------- +-- SquadAnnotationOverlay +-- + +SquadAnnotationOverlay = defclass(SquadAnnotationOverlay, overlay.OverlayWidget) +SquadAnnotationOverlay.ATTRS{ + default_pos={x=56, y=5}, + default_enabled=true, + viewscreens='dwarfmode/UnitSelector/SQUAD_FILL_POSITION', + frame={w=5, h=35}, + frame_style=gui.FRAME_INTERIOR_MEDIUM, + frame_background=gui.CLEAR_PEN, +} + +function get_annotation_text(idx) + local elem = rating_annotations[idx] + if not elem or not tonumber(elem.val) then return ' - ' end + + return tostring(math.tointeger(elem.val)) +end + +function get_annotation_color(idx) + local elem = rating_annotations[idx] + return elem and elem.color or nil +end + +function SquadAnnotationOverlay:init() + for idx = 1, 10 do + self:addviews{ + widgets.Label{ + frame={t=idx*3+1, h=1, w=3}, + text={ + { + text=curry(get_annotation_text, idx), + pen=curry(get_annotation_color, idx), + width=3, + rjustify=true, + }, + }, + }, + } end end OVERLAY_WIDGETS = { squad_assignment=SquadAssignmentOverlay, + squad_annotation=SquadAnnotationOverlay, } --[[ From 0d366740e76e9ae006dff1448b88be78e6880ae9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 7 Sep 2023 18:29:29 -0700 Subject: [PATCH 481/851] move the dimensions readout out from under the heat safety filter --- docs/changelog.txt | 1 + plugins/lua/buildingplan/planneroverlay.lua | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 9b0a1d30e..e192fda72 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -56,6 +56,7 @@ Template for new versions: ## New Features ## Fixes +- `buildingplan`: make the construction dimensions readout visible again ## Misc Improvements diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index 9a47b8fed..ebd8e6e02 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -478,7 +478,7 @@ function PlannerOverlay:init() end, }, widgets.Label{ - frame={b=2, l=23}, + frame={b=4, l=23}, text_pen=COLOR_DARKGREY, text={ 'Selected area: ', From 5f32042f1a70b69cc893a7323e9afe8a27d51486 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 8 Sep 2023 16:44:59 -0700 Subject: [PATCH 482/851] adjust colorization of ratings move mental stability from a sort to a filter --- plugins/lua/sort.lua | 176 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 146 insertions(+), 30 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 4638c8ffe..96280a79a 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -9,14 +9,15 @@ local widgets = require('gui.widgets') local CH_UP = string.char(30) local CH_DN = string.char(31) -local function get_rating(val, max, med, low) - val = math.min(max, val) - local percent = (val * 100) // max - local color = COLOR_GREEN - if percent < (low or 50) then color = COLOR_RED - elseif percent < (med or 75) then color = COLOR_YELLOW - end - return percent, color +local function get_rating(val, baseline, range, highest, high, med, low) + val = val - (baseline or 0) + range = range or 100 + local percentile = (math.min(range, val) * 100) // range + if percentile < (low or 25) then return percentile, COLOR_RED end + if percentile < (med or 50) then return percentile, COLOR_LIGHTRED end + if percentile < (high or 75) then return percentile, COLOR_YELLOW end + if percentile < (highest or 90) then return percentile, COLOR_GREEN end + return percentile, COLOR_LIGHTGREEN end local function sort_noop(a, b) @@ -91,7 +92,7 @@ local function get_stress(unit) end local function get_stress_rating(unit) - return get_rating(-get_stress(unit) + 100000, 200000, 50, 25) + return get_rating(dfhack.units.getStressCategory(unit), 0, 100, 4, 3, 2, 1) end local function sort_by_stress_desc(unit_id_1, unit_id_2) @@ -135,7 +136,7 @@ end local function get_skill_rating(skill, unit) local uskill = get_skill(skill, unit) if not uskill then return nil end - return get_rating(uskill.rating, 100, 5, 0) + return get_rating(uskill.rating, 0, 100, 10, 5, 1, 0) end local MELEE_WEAPON_SKILLS = { @@ -175,7 +176,7 @@ local function melee_skill_effectiveness(unit) end local function get_melee_skill_effectiveness_rating(unit) - return get_rating(melee_skill_effectiveness(unit), 2000000) + return get_rating(melee_skill_effectiveness(unit), 350000, 2350000, 78, 64, 49, 35) end local function make_sort_by_melee_skill_effectiveness_desc() @@ -235,7 +236,7 @@ local function ranged_skill_effectiveness(unit) end local function get_ranged_skill_effectiveness_rating(unit) - return get_rating(ranged_skill_effectiveness(unit), 500000) + return get_rating(ranged_skill_effectiveness(unit), 0, 500000, 90, 62, 44, 27) end local function make_sort_by_ranged_skill_effectiveness_desc(list) @@ -347,10 +348,6 @@ local function get_mental_stability(unit) return rating end -local function get_mental_stability_rating(unit) - return get_rating(get_mental_stability(unit), 100, 10, 0) -end - local function sort_by_mental_stability_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) @@ -404,7 +401,7 @@ local function get_melee_combat_potential(unit) end local function get_melee_combat_potential_rating(unit) - return get_rating(get_melee_combat_potential(unit), 2000000) + return get_rating(get_melee_combat_potential(unit), 300000, 2600000, 81, 64, 46, 29) end local function sort_by_melee_combat_potential_desc(unit_id_1, unit_id_2) @@ -447,12 +444,12 @@ local function get_ranged_combat_potential(unit) local kinesthetic_sense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value -- ranged combat potential formula - local rating = agility * 5 + kinesthetic_sense * 5 + spatial_sense * 2 + focus * 2 + local rating = agility * 5 + kinesthetic_sense * 2 + spatial_sense * 5 + focus * 2 return rating end local function get_ranged_combat_potential_rating(unit) - return get_rating(get_ranged_combat_potential(unit), 40000) + return get_rating(get_ranged_combat_potential(unit), 0, 70000, 73, 57, 41, 25) end local function sort_by_ranged_combat_potential_desc(unit_id_1, unit_id_2) @@ -483,6 +480,54 @@ local function sort_by_ranged_combat_potential_asc(unit_id_1, unit_id_2) return utils.compare(rating1, rating2) end +local function get_need(unit) + if not unit or not unit.status.current_soul then return end + for _, need in ipairs(unit.status.current_soul.personality.needs) do + if need.id == df.need_type.MartialTraining and need.focus_level < 0 then + return -need.focus_level + end + end +end + +local function get_need_rating(unit) + local focus_level = get_need(unit) + if not focus_level then return end + focus_level = math.min(focus_level, 100000) + return get_rating(100000 - focus_level, 0, 100000, 100, 99, 90, 0) +end + +local function sort_by_need_desc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = get_need(unit1) + local rating2 = get_need(unit2) + if rating1 == rating2 then + return sort_by_stress_desc(unit_id_1, unit_id_2) + end + if not rating2 then return -1 end + if not rating1 then return 1 end + return utils.compare(rating2, rating1) +end + +local function sort_by_need_asc(unit_id_1, unit_id_2) + if unit_id_1 == unit_id_2 then return 0 end + local unit1 = df.unit.find(unit_id_1) + local unit2 = df.unit.find(unit_id_2) + if not unit1 then return -1 end + if not unit2 then return 1 end + local rating1 = get_need(unit1) + local rating2 = get_need(unit2) + if rating1 == rating2 then + return sort_by_stress_asc(unit_id_1, unit_id_2) + end + if not rating2 then return 1 end + if not rating1 then return -1 end + return utils.compare(rating1, rating2) +end + local sort_by_any_melee_desc=make_sort_by_melee_skill_effectiveness_desc() local sort_by_any_melee_asc=make_sort_by_melee_skill_effectiveness_asc() local sort_by_any_ranged_desc=make_sort_by_ranged_skill_effectiveness_desc() @@ -512,7 +557,7 @@ local SORT_LIBRARY = { {label='tactics skill', desc_fn=sort_by_tactics_desc, asc_fn=sort_by_tactics_asc, rating_fn=curry(get_skill_rating, df.job_skill.MILITARY_TACTICS)}, {label='migrant wave', desc_fn=sort_by_migrant_wave_desc, asc_fn=sort_by_migrant_wave_asc, rating_fn=get_migrant_wave_rating}, {label='stress level', desc_fn=sort_by_stress_desc, asc_fn=sort_by_stress_asc, rating_fn=get_stress_rating}, - {label='mental stability', desc_fn=sort_by_mental_stability_desc, asc_fn=sort_by_mental_stability_asc, rating_fn=get_mental_stability_rating}, + {label='need for training', desc_fn=sort_by_need_desc, asc_fn=sort_by_need_asc, rating_fn=get_need_rating}, {label='axe skill', desc_fn=sort_by_axe_desc, asc_fn=sort_by_axe_asc, rating_fn=curry(get_skill_rating, df.job_skill.AXE)}, {label='sword skill', desc_fn=sort_by_sword_desc, asc_fn=sort_by_sword_asc, rating_fn=curry(get_skill_rating, df.job_skill.SWORD)}, {label='mace skill', desc_fn=sort_by_mace_desc, asc_fn=sort_by_mace_asc, rating_fn=curry(get_skill_rating, df.job_skill.MACE)}, @@ -538,7 +583,7 @@ SquadAssignmentOverlay.ATTRS{ default_pos={x=18, y=5}, default_enabled=true, viewscreens='dwarfmode/UnitSelector/SQUAD_FILL_POSITION', - frame={w=38, h=25}, + frame={w=38, h=31}, frame_style=gui.FRAME_PANEL, frame_background=gui.CLEAR_PEN, autoarrange_subviews=true, @@ -669,15 +714,15 @@ function SquadAssignmentOverlay:init() on_change=self:callback('refresh_list', 'sort_stress'), }, widgets.CycleHotkeyLabel{ - view_id='sort_mental_stability', - frame={t=6, r=0, w=17}, + view_id='sort_need', + frame={t=6, r=0, w=18}, options={ - {label='mental stability', value=sort_noop}, - {label='mental stability'..CH_DN, value=sort_by_mental_stability_desc, pen=COLOR_GREEN}, - {label='mental stability'..CH_UP, value=sort_by_mental_stability_asc, pen=COLOR_YELLOW}, + {label='need for training', value=sort_noop}, + {label='need for training'..CH_DN, value=sort_by_need_desc, pen=COLOR_GREEN}, + {label='need for training'..CH_UP, value=sort_by_need_asc, pen=COLOR_YELLOW}, }, option_gap=0, - on_change=self:callback('refresh_list', 'sort_mental_stability'), + on_change=self:callback('refresh_list', 'sort_need'), }, widgets.CycleHotkeyLabel{ view_id='sort_axe', @@ -808,6 +853,45 @@ function SquadAssignmentOverlay:init() initial_option='include', on_change=function() self:refresh_list() end, }, + widgets.CycleHotkeyLabel{ + view_id='infant', + frame={l=0}, + key='CUSTOM_SHIFT_M', + label='Mothers carrying infants:', + options={ + {label='Include', value='include', pen=COLOR_GREEN}, + {label='Only', value='only', pen=COLOR_YELLOW}, + {label='Exclude', value='exclude', pen=COLOR_RED}, + }, + initial_option='include', + on_change=function() self:refresh_list() end, + }, + widgets.CycleHotkeyLabel{ + view_id='unstable', + frame={l=0}, + key='CUSTOM_SHIFT_U', + label='Easily stressed units:', + options={ + {label='Include', value='include', pen=COLOR_GREEN}, + {label='Only', value='only', pen=COLOR_YELLOW}, + {label='Exclude', value='exclude', pen=COLOR_RED}, + }, + initial_option='include', + on_change=function() self:refresh_list() end, + }, + widgets.CycleHotkeyLabel{ + view_id='maimed', + frame={l=0}, + key='CUSTOM_SHIFT_I', + label='Critically injured:', + options={ + {label='Include', value='include', pen=COLOR_GREEN}, + {label='Only', value='only', pen=COLOR_YELLOW}, + {label='Exclude', value='exclude', pen=COLOR_RED}, + }, + initial_option='include', + on_change=function() self:refresh_list() end, + }, } end @@ -846,6 +930,23 @@ local function is_nobility(unit) return false end +local function has_infant(unit) + -- TODO + return false +end + +local function is_unstable(unit) + -- stddev percentiles are 61, 48, 35, 23 + -- let's go with one stddev below the mean (35) as the cutoff + local _, color = get_rating(get_mental_stability(unit), -40, 80, 35, 0, 0, 0) + return color ~= COLOR_LIGHTGREEN +end + +local function is_maimed(unit) + -- TODO + return false +end + local function filter_matches(unit_id, filter) if unit_id == -1 then return true end local unit = df.unit.find(unit_id) @@ -856,6 +957,12 @@ local function filter_matches(unit_id, filter) if filter.officials == 'exclude' and is_elected_or_appointed_official(unit) then return false end if filter.nobles == 'only' and not is_nobility(unit) then return false end if filter.nobles == 'exclude' and is_nobility(unit) then return false end + if filter.infant == 'only' and not has_infant(unit) then return false end + if filter.infant == 'exclude' and has_infant(unit) then return false end + if filter.unstable == 'only' and not is_unstable(unit) then return false end + if filter.unstable == 'exclude' and is_unstable(unit) then return false end + if filter.maimed == 'only' and not is_maimed(unit) then return false end + if filter.maimed == 'exclude' and is_maimed(unit) then return false end if #filter.search == 0 then return true end local search_key = dfhack.TranslateName(dfhack.units.getVisibleName(unit)) return normalize_search_key(search_key):find(dfhack.toSearchNormalized(filter.search)) @@ -865,14 +972,20 @@ local function is_noop_filter(filter) return #filter.search == 0 and filter.military == 'include' and filter.officials == 'include' and - filter.nobles == 'include' + filter.nobles == 'include' and + filter.infant == 'include' and + filter.unstable == 'include' and + filter.maimed == 'include' end local function is_filter_equal(a, b) return a.search == b.search and a.military == b.military and a.officials == b.officials and - a.nobles == b.nobles + a.nobles == b.nobles and + a.infant == b.infant and + a.unstable == b.unstable and + a.maimed == b.maimed end local unit_selector = df.global.game.main_interface.unit_selector @@ -944,7 +1057,7 @@ local SORT_WIDGET_NAMES = { 'sort_tactics', 'sort_migrant_wave', 'sort_stress', - 'sort_mental_stability', + 'sort_need', 'sort_axe', 'sort_sword', 'sort_mace', @@ -970,6 +1083,9 @@ function SquadAssignmentOverlay:refresh_list(sort_widget, sort_fn) military=self.subviews.military:getOptionValue(), officials=self.subviews.officials:getOptionValue(), nobles=self.subviews.nobles:getOptionValue(), + infant=self.subviews.infant:getOptionValue(), + unstable=self.subviews.unstable:getOptionValue(), + maimed=self.subviews.maimed:getOptionValue(), } filter_vector(filter, self.prev_filter or {}) self.prev_filter = filter From 603f1b16c2dece804d80dac2a6ed50224cb2c277 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 8 Sep 2023 18:48:05 -0700 Subject: [PATCH 483/851] use stress face icons for stress and training need --- plugins/lua/sort.lua | 83 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 10 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 96280a79a..30205b300 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -492,8 +492,12 @@ end local function get_need_rating(unit) local focus_level = get_need(unit) if not focus_level then return end - focus_level = math.min(focus_level, 100000) - return get_rating(100000 - focus_level, 0, 100000, 100, 99, 90, 0) + -- convert to stress ratings so we can use stress faces as labels + if focus_level > 100000 then return 0 end + if focus_level > 10000 then return 1 end + if focus_level > 1000 then return 2 end + if focus_level > 100 then return 3 end + return 6 end local function sort_by_need_desc(unit_id_1, unit_id_2) @@ -556,8 +560,8 @@ local SORT_LIBRARY = { {label='teacher skill', desc_fn=sort_by_teacher_desc, asc_fn=sort_by_teacher_asc, rating_fn=curry(get_skill_rating, df.job_skill.TEACHING)}, {label='tactics skill', desc_fn=sort_by_tactics_desc, asc_fn=sort_by_tactics_asc, rating_fn=curry(get_skill_rating, df.job_skill.MILITARY_TACTICS)}, {label='migrant wave', desc_fn=sort_by_migrant_wave_desc, asc_fn=sort_by_migrant_wave_asc, rating_fn=get_migrant_wave_rating}, - {label='stress level', desc_fn=sort_by_stress_desc, asc_fn=sort_by_stress_asc, rating_fn=get_stress_rating}, - {label='need for training', desc_fn=sort_by_need_desc, asc_fn=sort_by_need_asc, rating_fn=get_need_rating}, + {label='stress level', desc_fn=sort_by_stress_desc, asc_fn=sort_by_stress_asc, rating_fn=get_stress_rating, use_stress_faces=true}, + {label='need for training', desc_fn=sort_by_need_desc, asc_fn=sort_by_need_asc, rating_fn=get_need_rating, use_stress_faces=true}, {label='axe skill', desc_fn=sort_by_axe_desc, asc_fn=sort_by_axe_asc, rating_fn=curry(get_skill_rating, df.job_skill.AXE)}, {label='sword skill', desc_fn=sort_by_sword_desc, asc_fn=sort_by_sword_asc, rating_fn=curry(get_skill_rating, df.job_skill.SWORD)}, {label='mace skill', desc_fn=sort_by_mace_desc, asc_fn=sort_by_mace_asc, rating_fn=curry(get_skill_rating, df.job_skill.MACE)}, @@ -569,9 +573,14 @@ local SORT_LIBRARY = { } local RATING_FNS = {} +local STRESS_FACE_FNS = {} for _, opt in ipairs(SORT_LIBRARY) do RATING_FNS[opt.desc_fn] = opt.rating_fn RATING_FNS[opt.asc_fn] = opt.rating_fn + if opt.use_stress_faces then + STRESS_FACE_FNS[opt.desc_fn] = true + STRESS_FACE_FNS[opt.asc_fn] = true + end end -- ---------------------- @@ -857,7 +866,7 @@ function SquadAssignmentOverlay:init() view_id='infant', frame={l=0}, key='CUSTOM_SHIFT_M', - label='Mothers carrying infants:', + label='Mothers with infants:', options={ {label='Include', value='include', pen=COLOR_GREEN}, {label='Only', value='only', pen=COLOR_YELLOW}, @@ -869,8 +878,8 @@ function SquadAssignmentOverlay:init() widgets.CycleHotkeyLabel{ view_id='unstable', frame={l=0}, - key='CUSTOM_SHIFT_U', - label='Easily stressed units:', + key='CUSTOM_SHIFT_F', + label='Weak mental fortitude:', options={ {label='Include', value='include', pen=COLOR_GREEN}, {label='Only', value='only', pen=COLOR_YELLOW}, @@ -931,7 +940,11 @@ local function is_nobility(unit) end local function has_infant(unit) - -- TODO + for _, baby in ipairs(df.global.world.units.other.ANY_BABY2) do + if baby.relationship_ids.Mother == unit.id then + return true + end + end return false end @@ -943,8 +956,9 @@ local function is_unstable(unit) end local function is_maimed(unit) - -- TODO - return false + return unit.flags2.vision_missing or + unit.status2.limbs_grasp_count == 0 or + unit.status2.limbs_stand_count == 0 end local function filter_matches(unit_id, filter) @@ -1029,9 +1043,11 @@ local function filter_vector(filter, prev_filter) end end +local use_stress_faces = false local rating_annotations = {} local function annotate_visible_units(sort_fn) + use_stress_faces = STRESS_FACE_FNS[sort_fn] rating_annotations = {} rating_fn = RATING_FNS[sort_fn] local max_idx = math.min(#unit_selector.unid-1, unit_selector.scroll_position+9) @@ -1141,6 +1157,40 @@ function get_annotation_color(idx) return elem and elem.color or nil end +local to_pen = dfhack.pen.parse +local DASH_PEN = to_pen{ch='-', fg=COLOR_WHITE, keep_lower=true} + +local FACE_TILES = {} +for idx=0,6 do + FACE_TILES[idx] = {} + local face_off = (6 - idx) * 2 + for y=0,1 do + for x=0,1 do + local tile = dfhack.screen.findGraphicsTile('INTERFACE_BITS', 32 + face_off + x, 6 + y) + ensure_key(FACE_TILES[idx], y)[x] = tile + end + end +end + +local ASCII_FACE_TILES = {} +for idx,color in ipairs{COLOR_RED, COLOR_LIGHTRED, COLOR_YELLOW, COLOR_WHITE, COLOR_GREEN, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN} do + local face = {} + ensure_key(face, 0)[0] = to_pen{ch=1, fg=color} + ensure_key(face, 0)[1] = to_pen{ch='\\', fg=color} + ensure_key(face, 1)[0] = to_pen{ch='\\', fg=color} + ensure_key(face, 1)[1] = to_pen{ch='/', fg=color} + ASCII_FACE_TILES[idx-1] = face +end + +function get_stress_face_tile(idx, x, y) + local elem = rating_annotations[idx] + if not elem or not elem.val or elem.val < 0 then + return x == 0 and y == 1 and DASH_PEN or gui.CLEAR_PEN + end + local val = math.min(6, elem.val) + return (dfhack.screen.inGraphicsMode() and FACE_TILES or ASCII_FACE_TILES)[val][y][x] +end + function SquadAnnotationOverlay:init() for idx = 1, 10 do self:addviews{ @@ -1154,6 +1204,19 @@ function SquadAnnotationOverlay:init() rjustify=true, }, }, + visible=function() return not use_stress_faces end, + }, + widgets.Label{ + frame={t=idx*3, r=0, h=2, w=2}, + auto_height=false, + text={ + {width=1, tile=curry(get_stress_face_tile, idx, 0, 0)}, + {width=1, tile=curry(get_stress_face_tile, idx, 1, 0)}, + NEWLINE, + {width=1, tile=curry(get_stress_face_tile, idx, 0, 1)}, + {width=1, tile=curry(get_stress_face_tile, idx, 1, 1)}, + }, + visible=function() return use_stress_faces end, }, } end From 1e9e38a0de23620710c97f289bbf8e5b4748b3cd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 8 Sep 2023 20:06:51 -0700 Subject: [PATCH 484/851] implement ratings for arrival order --- plugins/lua/sort.lua | 62 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 30205b300..ad4f78ed6 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -64,12 +64,46 @@ local function get_active_idx_cache() return active_idx_cache end -local function get_migrant_wave_rating(unit) - -- TODO: return green for most recent wave, red for the first wave, yellow for all others - return 1, nil +local function is_original_dwarf(unit) + return df.global.plotinfo.fortress_age == unit.curse.time_on_site // 10 end -local function sort_by_migrant_wave_desc(unit_id_1, unit_id_2) +local WAVE_END_GAP = 10000 + +local function get_most_recent_wave_oldest_active_idx(cache) + local oldest_unit + for idx=#active_units-1,0,-1 do + local unit = active_units[idx] + if not dfhack.units.isCitizen(unit) then goto continue end + if oldest_unit and unit.curse.time_on_site - oldest_unit.curse.time_on_site > WAVE_END_GAP then + return cache[oldest_unit.id] + else + oldest_unit = unit + end + ::continue:: + end +end + +-- return green for most recent wave, red for the first wave, yellow for all others +-- rating is a three digit number that indicates the (potentially approximate) order +local function get_arrival_rating(unit) + local cache = get_active_idx_cache() + local unit_active_idx = cache[unit.id] + if not unit_active_idx then return end + local most_recent_wave_oldest_active_idx = get_most_recent_wave_oldest_active_idx(cache) + if not most_recent_wave_oldest_active_idx then return end + local num_active_units = #active_units + local rating = num_active_units < 1000 and unit_active_idx or ((unit_active_idx * 1000) // #active_units) + if most_recent_wave_oldest_active_idx < unit_active_idx then + return rating, COLOR_LIGHTGREEN + end + if is_original_dwarf(unit) then + return rating, COLOR_RED + end + return rating, COLOR_YELLOW +end + +local function sort_by_arrival_desc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local cache = get_active_idx_cache() if not cache[unit_id_1] then return -1 end @@ -77,7 +111,7 @@ local function sort_by_migrant_wave_desc(unit_id_1, unit_id_2) return utils.compare(cache[unit_id_2], cache[unit_id_1]) end -local function sort_by_migrant_wave_asc(unit_id_1, unit_id_2) +local function sort_by_arrival_asc(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local cache = get_active_idx_cache() if not cache[unit_id_1] then return -1 end @@ -559,7 +593,7 @@ local SORT_LIBRARY = { {label='name', desc_fn=sort_by_name_desc, asc_fn=sort_by_name_asc}, {label='teacher skill', desc_fn=sort_by_teacher_desc, asc_fn=sort_by_teacher_asc, rating_fn=curry(get_skill_rating, df.job_skill.TEACHING)}, {label='tactics skill', desc_fn=sort_by_tactics_desc, asc_fn=sort_by_tactics_asc, rating_fn=curry(get_skill_rating, df.job_skill.MILITARY_TACTICS)}, - {label='migrant wave', desc_fn=sort_by_migrant_wave_desc, asc_fn=sort_by_migrant_wave_asc, rating_fn=get_migrant_wave_rating}, + {label='arrival order', desc_fn=sort_by_arrival_desc, asc_fn=sort_by_arrival_asc, rating_fn=get_arrival_rating}, {label='stress level', desc_fn=sort_by_stress_desc, asc_fn=sort_by_stress_asc, rating_fn=get_stress_rating, use_stress_faces=true}, {label='need for training', desc_fn=sort_by_need_desc, asc_fn=sort_by_need_asc, rating_fn=get_need_rating, use_stress_faces=true}, {label='axe skill', desc_fn=sort_by_axe_desc, asc_fn=sort_by_axe_asc, rating_fn=curry(get_skill_rating, df.job_skill.AXE)}, @@ -701,15 +735,15 @@ function SquadAssignmentOverlay:init() on_change=self:callback('refresh_list', 'sort_tactics'), }, widgets.CycleHotkeyLabel{ - view_id='sort_migrant_wave', - frame={t=4, r=0, w=13}, + view_id='sort_arrival', + frame={t=4, r=0, w=14}, options={ - {label='migrant wave', value=sort_noop}, - {label='migrant wave'..CH_DN, value=sort_by_migrant_wave_desc, pen=COLOR_GREEN}, - {label='migrant wave'..CH_UP, value=sort_by_migrant_wave_asc, pen=COLOR_YELLOW}, + {label='arrival order', value=sort_noop}, + {label='arrival order'..CH_DN, value=sort_by_arrival_desc, pen=COLOR_GREEN}, + {label='arrival order'..CH_UP, value=sort_by_arrival_asc, pen=COLOR_YELLOW}, }, option_gap=0, - on_change=self:callback('refresh_list', 'sort_migrant_wave'), + on_change=self:callback('refresh_list', 'sort_arrival'), }, widgets.CycleHotkeyLabel{ view_id='sort_stress', @@ -957,7 +991,7 @@ end local function is_maimed(unit) return unit.flags2.vision_missing or - unit.status2.limbs_grasp_count == 0 or + unit.status2.limbs_grasp_count < 2 or unit.status2.limbs_stand_count == 0 end @@ -1071,7 +1105,7 @@ local SORT_WIDGET_NAMES = { 'sort_name', 'sort_teacher', 'sort_tactics', - 'sort_migrant_wave', + 'sort_arrival', 'sort_stress', 'sort_need', 'sort_axe', From 9bcb31f1eb6c09df1dc323cf32a01a4f1238a38d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 8 Sep 2023 20:09:55 -0700 Subject: [PATCH 485/851] update changelog --- docs/changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 9b0a1d30e..01dc0e277 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,6 +58,9 @@ Template for new versions: ## Fixes ## Misc Improvements +- `sort`: sort by need for training on squad assignment screen +- `sort`: filter mothers with infants, units with weak mental fortitude, and critically injured units on the squad assignment screen +- `sort`: display a rating relative to the current sort order next to the visible units on the squad assignment screen ## Documentation From 8f1889edf2f9f7d6127d57a3d5ecfd494a542094 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 8 Sep 2023 20:22:44 -0700 Subject: [PATCH 486/851] increment overlay widget version so pos is reset --- plugins/lua/sort.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index ad4f78ed6..67d8c9e0f 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -626,6 +626,7 @@ SquadAssignmentOverlay.ATTRS{ default_pos={x=18, y=5}, default_enabled=true, viewscreens='dwarfmode/UnitSelector/SQUAD_FILL_POSITION', + version='2', frame={w=38, h=31}, frame_style=gui.FRAME_PANEL, frame_background=gui.CLEAR_PEN, From a061a418a141b656d19528ab0751418332351259 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 8 Sep 2023 20:25:20 -0700 Subject: [PATCH 487/851] allow reset to defaults by changing version attribute --- docs/dev/overlay-dev-guide.rst | 4 ++++ plugins/lua/overlay.lua | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/docs/dev/overlay-dev-guide.rst b/docs/dev/overlay-dev-guide.rst index 4ec226d30..54e200700 100644 --- a/docs/dev/overlay-dev-guide.rst +++ b/docs/dev/overlay-dev-guide.rst @@ -90,6 +90,10 @@ The ``overlay.OverlayWidget`` superclass defines the following class attributes: This will be filled in with the display name of your widget, in case you have multiple widgets with the same implementation but different configurations. +- ``version`` + You can set this to any string. If the version string of a loaded widget + does not match the saved settings for that widget, then the configuration + for the widget (position, enabled status) will be reset to defaults. - ``default_pos`` (default: ``{x=-2, y=-2}``) Override this attribute with your desired default widget position. See the `overlay` docs for information on what positive and negative numbers diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index 68582e8eb..55ca44bc9 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -261,7 +261,11 @@ local function load_widget(name, widget_class) next_update_ms=widget.overlay_onupdate and 0 or math.huge, } if not overlay_config[name] then overlay_config[name] = {} end + if widget.version ~= overlay_config[name].version then + overlay_config[name] = {} + end local config = overlay_config[name] + config.version = widget.version if config.enabled == nil then config.enabled = widget.default_enabled end From b5cf849ba243e3f816d89b86730faf21bf3e168f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 8 Sep 2023 20:25:37 -0700 Subject: [PATCH 488/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 9b0a1d30e..76ca6e235 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,6 +62,7 @@ Template for new versions: ## Documentation ## API +- `overlay`: overlay widgets can now declare a ``version`` attribute. changing the version of a widget will reset its settings to defaults. this is useful when changing the overlay layout and old saved positions will no longer be valid. ## Lua From d4b3c1b3ec51e78fe9cc72bb8fc3bb2dccafcb40 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 8 Sep 2023 21:04:42 -0700 Subject: [PATCH 489/851] update docs for sort overlay --- docs/plugins/sort.rst | 111 +++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index f142534db..72f8c372e 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -14,54 +14,75 @@ Searching and sorting functionality is provided by `overlay` widgets, and widget Squad assignment overlay ------------------------ -The squad assignment screen can be sorted by name, by migrant wave, by stress, -by various military-related skills or by long-term military potential. - -If sorted by "any melee", then the citizen is sorted according to the "melee -skill effectiveness". This rating uses the highest skill they have in axes, short -swords, maces, warhammers or spears along with physical and mental attributes and -general fighting skill. Citizens with higher rating are expected to be more -effective in melee combat with their corresponding weapon. - -If sorted by "any ranged", then the citizen is sorted according to the "ranged -skill effectiveness". This rating uses crossbow and general archery skills -along with mental and physical attributes. Citizens with higher rating are -expected to be more effective in ranged combat. - -If sorted by "leadership", then the citizen is sorted according to the highest -skill they have in leader, teacher, or military tactics. - -If sorting is done by "mental stability" citizens are arranged based on their -mental stability rating. This rating is a measure that takes into account -facets and values of an individual and correlates to better stress values. -It is designed to be higher for more stress-resistant citizens. - -If sorting is done by "melee potential" citizens are arranged based on -their "melee combat potential" rating. This rating is a statistical measure -that takes into account genetic predispositions in physical and mental -attributes, as well as body size. Dwarves (and other humanoid creatures) with -higher rating are expected to be more effective in melee combat if they train -their attributes to their genetic maximum. - -If sorting is done by "ranged potential" citizens are arranged based on their -ranged combat potential rating. This rating is a statistical measure that takes into -account genetic predispositions in physical and mental attributes. Dwarves -(and other humanoid creatures) with higher rating are expected to be more -effective in ranged combat if they train their attributes to the maximum. - -You can search for a dwarf by name by typing in the Search field. You can also -type in the name of any job skill (military-related or not) and dwarves with -any experience in that skill will be shown. For example, to only see citizens -with military tactics skill, type in "tactics". +You can search for a dwarf by name by typing in the Search field. The search +field is always focused, so any lowercase letter you type will appear there. + +The squad assignment screen can be sorted by name, by arrival order, by stress, +by various military-related skills, or by long-term military potential. + +If sorted by "melee effectiveness" (the default), then the citizens are sorted +according to how well they will perform in battle when using the weapon they +have the most skill in. The effectiveness rating also takes into account +physical and mental attributes as well as general fighting (non-weapon) skills. + +The "ranged effectiveness" sort order does a similar sort for expected +effectiveness with a crossbow. This sort also takes into account relevant +physical and mental attributes. + +The "effectiveness" sorts are the ones you should be using if you need the best +squad you can make right now. The numbers to the left of the unit list indicate +exactly how effective that dwarf is expected to be. Light green numbers +indicate the best of the best, while red numbers indicate dwarves that will not +be effective in the military in their current state (though see "melee +potential" and "ranged potential" sorts below for predictions about future +effectiveness). + +The "arrival order" sort shows the order that your dwarves appeared at your +fort. The numbers on the left indicate the relative arrival order, and the +numbers for the most recent migration wave will be colored bright green. +Dwarves that arrived earlier will have numbers in yellow, and your original +dwarves (if any still survive) will have numbers in red. + +The "stress" sort order will bring your most stressed dwarves to the top, ready +for addition to a :wiki:`therapy squad ` to +help improve their mood. + +Similarly, sorting by "need for training" will show you the dwarves that are +feeling the most unfocused because they are having their military training +needs unmet. + +Both "stress" and "need for training" sorts use the dwarf happiness indicators +to show how dire the dwarf's situation is and how much their mood might be +improved if you add them to an appropriate squad. + +If sorting is done by "melee potential", then citizens are arranged based on +genetic predispositions in physical and mental attributes, as well as body +size. Dwarves (and other humanoid creatures) with higher ratings are expected +to be more effective in melee combat if they train their attributes to their +genetic maximum. + +Similarly, the "ranged potential" sort orders citizens by genetic +predispositions in physical and mental attributes that are relevant to ranged +combat. Dwarves (and other humanoid creatures) with higher rating are expected +to be more effective in ranged combat if they train their attributes to the +maximum. + +The squad assignment panel also offers options for filtering which dwarves are +shown. Each filter option can by cycled through "Include", "Only", and +"Exclude" settings. "Include" does no filtering, "Only" shows only units that +match the filter, and "Exclude" shows only units that do *not* match the filter. + +The following filters are provided: + +- Units that are assigned to other squads +- Elected and appointed officials (e.g. mayor, priests, tavern keepers, etc.) +- Nobility (e.g. monarch, barons, counts, etc.) +- Mothers with infants (you may not want mothers using their babies as shields) +- Weak mental fortitude (units that have facets and values that indicate that they will react poorly to the stresses of battle) +- Critically injured (units that have lost their ability to grasp weapons or walk) "Melee skill effectiveness", "ranged skill effectiveness", "melee combat potential" and "ranged combat potential" are explained in detail here: https://www.reddit.com/r/dwarffortress/comments/163kczo/enhancing_military_candidate_selection_part_3/ "Mental stability" is explained here: https://www.reddit.com/r/dwarffortress/comments/1617s11/enhancing_military_candidate_selection_part_2/ - -You can see all the job skill names that you can search for by running:: - - :lua @df.job_skill - -in `gui/launcher`. From 6ec5e0e1a9accbb3b32025da1aef9aa3476c1765 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 9 Sep 2023 07:11:39 +0000 Subject: [PATCH 490/851] 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 1cb9a9613..e2e369242 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 1cb9a961351db5c2988cee3a194eb24eac4abc1a +Subproject commit e2e369242253b556f6eba7e419aa5f833ff8a46e From 9d233e6e3470ea3c9e9cdf65775448bd96496ace Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 9 Sep 2023 07:00:17 -0700 Subject: [PATCH 491/851] unify stress face pens and rewrite arrival sort docs --- docs/plugins/sort.rst | 11 +++++++---- plugins/lua/sort.lua | 15 +++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 72f8c372e..15257e3d2 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -37,11 +37,14 @@ be effective in the military in their current state (though see "melee potential" and "ranged potential" sorts below for predictions about future effectiveness). -The "arrival order" sort shows the order that your dwarves appeared at your -fort. The numbers on the left indicate the relative arrival order, and the -numbers for the most recent migration wave will be colored bright green. +The "arrival order" sorts your citizens according to the most recent time they +entered your map. The numbers on the left indicate the relative arrival order, +and the numbers for the group of dwarves that most recently entered the map +will be at the top and be colored bright green. If you run this sort after you +get a new group of migrants, the migrant wave will be colored bright green. Dwarves that arrived earlier will have numbers in yellow, and your original -dwarves (if any still survive) will have numbers in red. +dwarves (if any still survive and have never left and re-entered the map) will +have numbers in red. The "stress" sort order will bring your most stressed dwarves to the top, ready for addition to a :wiki:`therapy squad ` to diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 67d8c9e0f..5a5cd2613 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -991,7 +991,7 @@ local function is_unstable(unit) end local function is_maimed(unit) - return unit.flags2.vision_missing or + return not unit.flags2.vision_good or unit.status2.limbs_grasp_count < 2 or unit.status2.limbs_stand_count == 0 end @@ -1207,14 +1207,13 @@ for idx=0,6 do end end -local ASCII_FACE_TILES = {} for idx,color in ipairs{COLOR_RED, COLOR_LIGHTRED, COLOR_YELLOW, COLOR_WHITE, COLOR_GREEN, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN} do local face = {} - ensure_key(face, 0)[0] = to_pen{ch=1, fg=color} - ensure_key(face, 0)[1] = to_pen{ch='\\', fg=color} - ensure_key(face, 1)[0] = to_pen{ch='\\', fg=color} - ensure_key(face, 1)[1] = to_pen{ch='/', fg=color} - ASCII_FACE_TILES[idx-1] = face + ensure_key(face, 0)[0] = to_pen{tile=FACE_TILES[idx-1][0][0], ch=1, fg=color} + ensure_key(face, 0)[1] = to_pen{tile=FACE_TILES[idx-1][0][1], ch='\\', fg=color} + ensure_key(face, 1)[0] = to_pen{tile=FACE_TILES[idx-1][1][0], ch='\\', fg=color} + ensure_key(face, 1)[1] = to_pen{tile=FACE_TILES[idx-1][1][1], ch='/', fg=color} + FACE_TILES[idx-1] = face end function get_stress_face_tile(idx, x, y) @@ -1223,7 +1222,7 @@ function get_stress_face_tile(idx, x, y) return x == 0 and y == 1 and DASH_PEN or gui.CLEAR_PEN end local val = math.min(6, elem.val) - return (dfhack.screen.inGraphicsMode() and FACE_TILES or ASCII_FACE_TILES)[val][y][x] + return FACE_TILES[val][y][x] end function SquadAnnotationOverlay:init() From 45e5168a91cf9b7ec283d6c0eda2df30db55c8ea Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 9 Sep 2023 07:20:59 -0700 Subject: [PATCH 492/851] ensure face textures get reloaded on map load --- plugins/lua/sort.lua | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 5a5cd2613..15d9ebabb 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -6,6 +6,8 @@ local setbelief = reqscript('modtools/set-belief') local utils = require('utils') local widgets = require('gui.widgets') +local GLOBAL_KEY = 'sort' + local CH_UP = string.char(30) local CH_DN = string.char(31) @@ -1196,24 +1198,26 @@ local to_pen = dfhack.pen.parse local DASH_PEN = to_pen{ch='-', fg=COLOR_WHITE, keep_lower=true} local FACE_TILES = {} -for idx=0,6 do - FACE_TILES[idx] = {} - local face_off = (6 - idx) * 2 - for y=0,1 do - for x=0,1 do - local tile = dfhack.screen.findGraphicsTile('INTERFACE_BITS', 32 + face_off + x, 6 + y) - ensure_key(FACE_TILES[idx], y)[x] = tile +local function init_face_tiles() + for idx=0,6 do + FACE_TILES[idx] = {} + local face_off = (6 - idx) * 2 + for y=0,1 do + for x=0,1 do + local tile = dfhack.screen.findGraphicsTile('INTERFACE_BITS', 32 + face_off + x, 6 + y) + ensure_key(FACE_TILES[idx], y)[x] = tile + end end end -end -for idx,color in ipairs{COLOR_RED, COLOR_LIGHTRED, COLOR_YELLOW, COLOR_WHITE, COLOR_GREEN, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN} do - local face = {} - ensure_key(face, 0)[0] = to_pen{tile=FACE_TILES[idx-1][0][0], ch=1, fg=color} - ensure_key(face, 0)[1] = to_pen{tile=FACE_TILES[idx-1][0][1], ch='\\', fg=color} - ensure_key(face, 1)[0] = to_pen{tile=FACE_TILES[idx-1][1][0], ch='\\', fg=color} - ensure_key(face, 1)[1] = to_pen{tile=FACE_TILES[idx-1][1][1], ch='/', fg=color} - FACE_TILES[idx-1] = face + for idx,color in ipairs{COLOR_RED, COLOR_LIGHTRED, COLOR_YELLOW, COLOR_WHITE, COLOR_GREEN, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN} do + local face = {} + ensure_key(face, 0)[0] = to_pen{tile=FACE_TILES[idx-1][0][0], ch=1, fg=color} + ensure_key(face, 0)[1] = to_pen{tile=FACE_TILES[idx-1][0][1], ch='\\', fg=color} + ensure_key(face, 1)[0] = to_pen{tile=FACE_TILES[idx-1][1][0], ch='\\', fg=color} + ensure_key(face, 1)[1] = to_pen{tile=FACE_TILES[idx-1][1][1], ch='/', fg=color} + FACE_TILES[idx-1] = face + end end function get_stress_face_tile(idx, x, y) @@ -1261,6 +1265,14 @@ OVERLAY_WIDGETS = { squad_annotation=SquadAnnotationOverlay, } +dfhack.onStateChange[GLOBAL_KEY] = function(sc) + if sc ~= SC_MAP_LOADED or df.global.gamemode ~= df.game_mode.DWARF then + return + end + + init_face_tiles() +end + --[[ local utils = require('utils') local units = require('plugins.sort.units') From c37d3e66b28ba0d56d419d02b6d3de4b816514f5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 9 Sep 2023 07:48:24 -0700 Subject: [PATCH 493/851] small edit for sort docs --- docs/plugins/sort.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 15257e3d2..31ab2d3fc 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -81,8 +81,10 @@ The following filters are provided: - Elected and appointed officials (e.g. mayor, priests, tavern keepers, etc.) - Nobility (e.g. monarch, barons, counts, etc.) - Mothers with infants (you may not want mothers using their babies as shields) -- Weak mental fortitude (units that have facets and values that indicate that they will react poorly to the stresses of battle) -- Critically injured (units that have lost their ability to grasp weapons or walk) +- Weak mental fortitude (units that have facets and values that indicate that + they will react poorly to the stresses of battle) +- Critically injured (units that have lost their ability to see, grasp weapons, + or walk) "Melee skill effectiveness", "ranged skill effectiveness", "melee combat potential" and "ranged combat potential" are explained in detail here: From e4edc9be4e4233579a904f87f2836f961f821d08 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 9 Sep 2023 07:49:35 -0700 Subject: [PATCH 494/851] fix crash on invalid saved seed id --- docs/changelog.txt | 1 + plugins/seedwatch.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 609ad09cc..432b936b0 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,6 +57,7 @@ Template for new versions: ## Fixes - `buildingplan`: make the construction dimensions readout visible again +- `seedwatch`: fix a crash when reading data saved by very very old versions of the plugin ## Misc Improvements - `sort`: sort by need for training on squad assignment screen diff --git a/plugins/seedwatch.cpp b/plugins/seedwatch.cpp index df49efec2..7cbdcbd2a 100644 --- a/plugins/seedwatch.cpp +++ b/plugins/seedwatch.cpp @@ -103,6 +103,10 @@ static bool validate_seed_config(color_ostream& out, PersistentDataItem c) { int seed_id = get_config_val(c, SEED_CONFIG_ID); auto plant = binsearch_in_vector(world->raws.plants.all, &df::plant_raw::index, seed_id); + if (!plant) { + WARN(config, out).print("discarded invalid seed id: %d\n", seed_id); + return false; + } bool valid = (!plant->flags.is_set(df::enums::plant_raw_flags::TREE)); if (!valid) { DEBUG(config, out).print("invalid configuration for %s discarded\n", plant->id.c_str()); From ee61c76bc08226d375f7aa5d1cd858765c5df9bc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 9 Sep 2023 10:42:20 -0700 Subject: [PATCH 495/851] use find method instead of binsearch --- plugins/seedwatch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/seedwatch.cpp b/plugins/seedwatch.cpp index 7cbdcbd2a..f56470c66 100644 --- a/plugins/seedwatch.cpp +++ b/plugins/seedwatch.cpp @@ -102,7 +102,7 @@ static void remove_seed_config(color_ostream &out, int id) { static bool validate_seed_config(color_ostream& out, PersistentDataItem c) { int seed_id = get_config_val(c, SEED_CONFIG_ID); - auto plant = binsearch_in_vector(world->raws.plants.all, &df::plant_raw::index, seed_id); + auto plant = df::plant_raw::find(seed_id); if (!plant) { WARN(config, out).print("discarded invalid seed id: %d\n", seed_id); return false; From 85cd0cd01cffd37472d56e5119e76370109b221d Mon Sep 17 00:00:00 2001 From: Andriel Chaoti <3628387+AndrielChaoti@users.noreply.github.com> Date: Sat, 9 Sep 2023 12:56:10 -0600 Subject: [PATCH 496/851] improvements to argparse remove need to reparse table constantly, included original arg for error message. --- library/lua/argparse.lua | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/library/lua/argparse.lua b/library/lua/argparse.lua index 8da11cb28..0a652f428 100644 --- a/library/lua/argparse.lua +++ b/library/lua/argparse.lua @@ -196,17 +196,16 @@ function coords(arg, arg_name, skip_validation) return pos end +local toBool={["true"]=true,["yes"]=true,["y"]=true,["on"]=true,["1"]=true, + ["false"]=false,["no"]=false,["n"]=false,["off"]=false,["0"]=false} function boolean(arg, arg_name) - local toBool={["true"]=true,["yes"]=true,["y"]=true,["on"]=true,["1"]=true, - ["false"]=false,["no"]=false,["n"]=false,["off"]=false,["0"]=false} - - arg = string.lower(arg) - if toBool[arg] == nil then + local arg_lower = string.lower(arg) + if toBool[arg_lower] == nil then arg_error(arg_name, - 'unknown value: "%s"; expected "true", "yes", "false", or "no"') + 'unknown value: "%s"; expected "true", "yes", "false", or "no"', arg) end - return toBool[arg] + return toBool[arg_lower] end return _ENV From 652349c7e7615aa7c6e6e9473e61dcfbef49d785 Mon Sep 17 00:00:00 2001 From: Andriel Chaoti <3628387+AndrielChaoti@users.noreply.github.com> Date: Sat, 9 Sep 2023 14:30:20 -0600 Subject: [PATCH 497/851] add docs for argparse.boolean added entry to changelog as well. --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 9b0a1d30e..b9ceb618a 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -64,6 +64,7 @@ Template for new versions: ## API ## Lua +- ``argparse.boolean``: convert arguments to lua boolean values. ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index f6af309d4..a267545ca 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3538,6 +3538,12 @@ parameters. ``tonumber(arg)``. If ``arg_name`` is specified, it is used to make error messages more useful. +* ``argparse.boolean(arg, arg_name)`` + Converts ``string.lower(arg)`` from "yes/no/on/off/true/false/etc..." to a lua + boolean. Throws if the value can't be converted, otherwise returns + ``true``/``false``. If ``arg_name`` is specified, it is used to make error + messages more useful. + dumper ====== From 529e51e28c4684fd75e6719220f87fa27887ba79 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 9 Sep 2023 16:13:00 -0700 Subject: [PATCH 498/851] the addition of gui/stockpiles to the removed list was premature since it obviously still exists in scripts --- docs/about/Removed.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index 34d44ab0d..4b61c951e 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -192,13 +192,6 @@ Tool that warned the user when the ``dfhack.init`` file did not exist. Now that ``dfhack.init`` is autogenerated in ``dfhack-config/init``, this warning is no longer necessary. -.. _gui/stockpiles: - -gui/stockpiles -============== -Provided import/export dialogs. Converted to an `overlay` that displays when -a stockpile is selected. - .. _masspit: masspit From 4aa5bb510dcd28fc54c7152c284562583496f66f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 9 Sep 2023 17:22:57 -0700 Subject: [PATCH 499/851] retroactively add a changelog entry for the SDL2 migration largely because with an empty changelog section, 50.09-r1 wasn't sorting correctly in the list of versions on NEWS.rst --- docs/changelog.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 432b936b0..7e1ec721f 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -155,6 +155,10 @@ Template for new versions: # 50.09-r1 +## Internals + +- Core: update SDL interface from SDL1 to SDL2 + # 50.08-r4 ## New Plugins From d118a37be67895ff28970f513c63e5464b09e4b3 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 10 Sep 2023 07:12:04 +0000 Subject: [PATCH 500/851] 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 e2e369242..4097a59a4 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e2e369242253b556f6eba7e419aa5f833ff8a46e +Subproject commit 4097a59a467b497d4d97c640e6b96b7d90b69dee diff --git a/scripts b/scripts index 4dfb75dd1..e383d9aaa 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 4dfb75dd1b0df0af4fb9b5a04f5a2dbba19dff11 +Subproject commit e383d9aaa231fb30a5c8c494ecf0924d4413865f From cf4be69d7e766e3b949acd01526458474c40abfe Mon Sep 17 00:00:00 2001 From: Andriel Chaoti <3628387+AndrielChaoti@users.noreply.github.com> Date: Sun, 10 Sep 2023 01:15:43 -0600 Subject: [PATCH 501/851] [argparse] fix documentation error --- 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 a267545ca..4f182d132 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3539,6 +3539,7 @@ parameters. messages more useful. * ``argparse.boolean(arg, arg_name)`` + Converts ``string.lower(arg)`` from "yes/no/on/off/true/false/etc..." to a lua boolean. Throws if the value can't be converted, otherwise returns ``true``/``false``. If ``arg_name`` is specified, it is used to make error From 5a557f232ffcde7b0ce1af39bf85c0c18df3fdc7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 01:42:35 -0700 Subject: [PATCH 502/851] disable texture loading if enabler isn't present --- library/modules/Textures.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 7a6964732..c957bd878 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -119,7 +119,7 @@ std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int } TexposHandle Textures::loadTexture(SDL_Surface* surface) { - if (!surface) + if (!surface || !enabler) return 0; // should be some error, i guess auto handle = reinterpret_cast(surface); @@ -132,6 +132,9 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface) { std::vector Textures::loadTileset(const std::string& file, int tile_px_w, int tile_px_h) { + if (!enabler) + return std::vector{}; + SDL_Surface* surface = DFIMG_Load(file.c_str()); if (!surface) { ERR(textures).printerr("unable to load textures from '%s'\n", file.c_str()); @@ -147,7 +150,7 @@ std::vector Textures::loadTileset(const std::string& file, int til } long Textures::getTexposByHandle(TexposHandle handle) { - if (!handle) + if (!handle || !enabler) return -1; if (g_handle_to_texpos.contains(handle)) @@ -164,6 +167,9 @@ long Textures::getTexposByHandle(TexposHandle handle) { } TexposHandle Textures::createTile(std::vector& pixels, int tile_px_w, int tile_px_h) { + if (!enabler) + return 0; + auto texture = create_texture(pixels, tile_px_w, tile_px_h); auto handle = Textures::loadTexture(texture); return handle; @@ -171,12 +177,18 @@ TexposHandle Textures::createTile(std::vector& pixels, int tile_px_w, std::vector Textures::createTileset(std::vector& pixels, int texture_px_w, int texture_px_h, int tile_px_w, int tile_px_h) { + if (!enabler) + return std::vector{}; + auto texture = create_texture(pixels, texture_px_w, texture_px_h); auto handles = slice_tileset(texture, tile_px_w, tile_px_h); return handles; } void Textures::deleteHandle(TexposHandle handle) { + if (!enabler) + return; + auto texpos = Textures::getTexposByHandle(handle); if (texpos > 0) delete_texture(texpos); @@ -293,11 +305,17 @@ static void uninstall_reset_point() { } void Textures::init(color_ostream& out) { + if (!enabler) + return; + install_reset_point(); DEBUG(textures, out).print("dynamic texture loading ready"); } void Textures::cleanup() { + if (!enabler) + return; + reset_texpos(); reset_surface(); uninstall_reset_point(); From 4f8c7a6e0ec2abbe6036c08a7a96d33b9979775a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 03:47:21 -0700 Subject: [PATCH 503/851] add missing docs for design plugin --- docs/plugins/design.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 docs/plugins/design.rst diff --git a/docs/plugins/design.rst b/docs/plugins/design.rst new file mode 100644 index 000000000..0a6d0ad01 --- /dev/null +++ b/docs/plugins/design.rst @@ -0,0 +1,10 @@ +design +====== + +.. dfhack-tool:: + :summary: Draws designations in shapes. + :tags: fort dev design map + :no-command: + +This plugin provides a Lua API, but no direct commands. See `gui/design` for +the user interface. From a7121a2f80252155f94f56a4befd7d4aed47c3cb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 04:26:02 -0700 Subject: [PATCH 504/851] revert the temporary linux structures override now that the windows and linux structures are aligned again --- .github/workflows/build-linux.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index 16f75118c..aa5571e0b 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -92,13 +92,6 @@ jobs: repository: ${{ inputs.structures_ref && github.repository || 'DFHack/df-structures' }} ref: ${{ inputs.structures_ref }} path: library/xml - - name: Clone structures (temporary override) - if: '!inputs.structures_ref' - uses: actions/checkout@v3 - with: - repository: DFHack/df-structures - ref: refs/heads/linux - path: library/xml - name: Fetch ccache if: inputs.platform-files uses: actions/cache/restore@v3 From a0919ec316aa6fb5c11890d86873f252f0834c9e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 05:29:55 -0700 Subject: [PATCH 505/851] add ASCII-mode highlight for smoothing and carving designations --- docs/changelog.txt | 1 + docs/plugins/dig.rst | 19 ++++++-- library/include/modules/Maps.h | 6 +-- plugins/lua/dig.lua | 24 +++++++++- plugins/pathable.cpp | 80 ++++++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 9 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0465609e9..3ac2e3c48 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -54,6 +54,7 @@ Template for new versions: ## New Tools ## New Features +- `dig`: new overlay for ASCII mode that visualizes designations for smoothing, engraving, carving tracks, and carving fortifications ## Fixes - `buildingplan`: make the construction dimensions readout visible again diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index 310bd1647..77b3137ae 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -183,8 +183,19 @@ After you have a pattern set, you can use ``expdig`` to apply it again. Overlay ------- -This tool also provides an overlay that is managed by the `overlay` framework. -When the ``dig.asciiwarmdamp`` overlay is enabled and you are in non-graphics -(ASCII) mode, warm tiles will be highlighted in red and damp tiles will be -highlighted in blue. Box selection characters and the keyboard cursor will also +This tool also provides two overlays that are managed by the `overlay` +framework. Both have no effect when in graphics mode, but when in ASCII mode, +they display useful highlights that are otherwise missing from the ASCII mode +interface. + +The ``dig.asciiwarmdamp`` overlay highlights warm tiles red and damp tiles in +blue. Box selection characters and the keyboard cursor will also change color as appropriate when over the warm or damp tile. + +The ``dig.asciicarve`` overlay highlights tiles that are designated for +smoothing, engraving, track carving, or fortification carving. The designations +blink so you can still see what is underneath them. + +Note that due to the limitations of the ASCII mode screen buffer, the +designation highlights may show through other interface elements that overlap +the designated area. diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index e468dcf9c..2b7d768d0 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -293,13 +293,13 @@ extern DFHACK_EXPORT df::tiletype *getTileType(int32_t x, int32_t y, int32_t z); extern DFHACK_EXPORT df::tile_designation *getTileDesignation(int32_t x, int32_t y, int32_t z); extern DFHACK_EXPORT df::tile_occupancy *getTileOccupancy(int32_t x, int32_t y, int32_t z); -inline df::tiletype *getTileType(df::coord pos) { +inline df::tiletype *getTileType(const df::coord &pos) { return getTileType(pos.x, pos.y, pos.z); } -inline df::tile_designation *getTileDesignation(df::coord pos) { +inline df::tile_designation *getTileDesignation(const df::coord &pos) { return getTileDesignation(pos.x, pos.y, pos.z); } -inline df::tile_occupancy *getTileOccupancy(df::coord pos) { +inline df::tile_occupancy *getTileOccupancy(const df::coord &pos) { return getTileOccupancy(pos.x, pos.y, pos.z); } diff --git a/plugins/lua/dig.lua b/plugins/lua/dig.lua index 43012d5d2..e24885c08 100644 --- a/plugins/lua/dig.lua +++ b/plugins/lua/dig.lua @@ -20,10 +20,30 @@ WarmDampOverlay.ATTRS{ overlay_only=true, } -function WarmDampOverlay:onRenderFrame(dc) +function WarmDampOverlay:onRenderFrame() pathable.paintScreenWarmDamp() end -OVERLAY_WIDGETS = {asciiwarmdamp=WarmDampOverlay} +CarveOverlay = defclass(CarveOverlay, overlay.OverlayWidget) +CarveOverlay.ATTRS{ + viewscreens={ + 'dwarfmode/Designate/SMOOTH', + 'dwarfmode/Designate/ENGRAVE', + 'dwarfmode/Designate/TRACK', + 'dwarfmode/Designate/FORTIFY', + 'dwarfmode/Designate/ERASE', + }, + default_enabled=true, + overlay_only=true, +} + +function CarveOverlay:onRenderFrame() + pathable.paintScreenCarve() +end + +OVERLAY_WIDGETS = { + asciiwarmdamp=WarmDampOverlay, + asciicarve=CarveOverlay, +} return _ENV diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 12a69dd31..83918fd4b 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -1,4 +1,5 @@ #include "Debug.h" +#include "MemAccess.h" #include "PluginManager.h" #include "TileTypes.h" @@ -209,8 +210,87 @@ static void paintScreenWarmDamp(bool show_hidden = false) { } } +static bool is_designated_for_smoothing(const df::coord &pos) { + auto des = Maps::getTileDesignation(pos); + if (!des) + return false; + return des->bits.smooth == 1; +} + +static bool is_designated_for_engraving(const df::coord &pos) { + auto des = Maps::getTileDesignation(pos); + if (!des) + return false; + return des->bits.smooth == 2; +} + +static bool is_designated_for_track_carving(const df::coord &pos) { + auto occ = Maps::getTileOccupancy(pos); + if (!occ) + return false; + return occ->bits.carve_track_east || occ->bits.carve_track_north || occ->bits.carve_track_south || occ->bits.carve_track_west; +} + +static bool is_smooth_wall(const df::coord &pos) { + df::tiletype *tt = Maps::getTileType(pos); + return tt && tileSpecial(*tt) == df::tiletype_special::SMOOTH + && tileShape(*tt) == df::tiletype_shape::WALL; +} + +static bool blink(int delay) { + return (Core::getInstance().p->getTickCount()/delay) % 2 == 0; +} + +static void paintScreenCarve() { + DEBUG(log).print("entering paintScreenCarve\n"); + + if (Screen::inGraphicsMode() || blink(500)) + return; + + auto dims = Gui::getDwarfmodeViewDims().map(); + for (int y = dims.first.y; y <= dims.second.y; ++y) { + for (int x = dims.first.x; x <= dims.second.x; ++x) { + df::coord map_pos(*window_x + x, *window_y + y, *window_z); + + if (!Maps::isValidTilePos(map_pos)) + continue; + + if (!Maps::isTileVisible(map_pos)) { + TRACE(log).print("skipping hidden tile\n"); + continue; + } + + TRACE(log).print("scanning map tile at (%d, %d, %d) screen offset (%d, %d)\n", + map_pos.x, map_pos.y, map_pos.z, x, y); + + Screen::Pen cur_tile; + cur_tile.fg = COLOR_DARKGREY; + + if (is_designated_for_smoothing(map_pos)) { + if (is_smooth_wall(map_pos)) + cur_tile.ch = 206; // hash, indicating a fortification designation + else + cur_tile.ch = 219; // solid block, indicating a smoothing designation + } + else if (is_designated_for_engraving(map_pos)) { + cur_tile.ch = 10; // solid block with a circle on it + } + else if (is_designated_for_track_carving(map_pos)) { + cur_tile.ch = 186; // parallel tracks + } + else { + TRACE(log).print("skipping tile with no carving designation\n"); + continue; + } + + Screen::paintTile(cur_tile, x, y, true); + } + } +} + DFHACK_PLUGIN_LUA_FUNCTIONS { DFHACK_LUA_FUNCTION(paintScreenPathable), DFHACK_LUA_FUNCTION(paintScreenWarmDamp), + DFHACK_LUA_FUNCTION(paintScreenCarve), DFHACK_LUA_END }; From 24b27c79b6a9f399d8cbab88bc9a4d08abd9c570 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 12:11:06 -0700 Subject: [PATCH 506/851] draw directional tracks --- plugins/pathable.cpp | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 83918fd4b..e63947caf 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -231,6 +231,41 @@ static bool is_designated_for_track_carving(const df::coord &pos) { return occ->bits.carve_track_east || occ->bits.carve_track_north || occ->bits.carve_track_south || occ->bits.carve_track_west; } +static char get_track_char(const df::coord &pos) { + auto occ = Maps::getTileOccupancy(pos); + if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_south && occ->bits.carve_track_west) + return 0xCE; // NSEW + if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_south) + return 0xCC; // NSE + if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_west) + return 0xCA; // NEW + if (occ->bits.carve_track_east && occ->bits.carve_track_south && occ->bits.carve_track_west) + return 0xCB; // SEW + if (occ->bits.carve_track_north && occ->bits.carve_track_south && occ->bits.carve_track_west) + return 0xB9; // NSW + if (occ->bits.carve_track_north && occ->bits.carve_track_south) + return 0xBA; // NS + if (occ->bits.carve_track_east && occ->bits.carve_track_west) + return 0xCD; // EW + if (occ->bits.carve_track_east && occ->bits.carve_track_north) + return 0xC8; // NE + if (occ->bits.carve_track_north && occ->bits.carve_track_west) + return 0xBC; // NW + if (occ->bits.carve_track_east && occ->bits.carve_track_south) + return 0xC9; // SE + if (occ->bits.carve_track_south && occ->bits.carve_track_west) + return 0xBB; // SW + if (occ->bits.carve_track_north) + return 0xD0; // N + if (occ->bits.carve_track_south) + return 0xD2; // S + if (occ->bits.carve_track_east) + return 0xC6; // E + if (occ->bits.carve_track_west) + return 0xB5; // W + return 0xC5; // single line cross; should never happen +} + static bool is_smooth_wall(const df::coord &pos) { df::tiletype *tt = Maps::getTileType(pos); return tt && tileSpecial(*tt) == df::tiletype_special::SMOOTH @@ -268,15 +303,15 @@ static void paintScreenCarve() { if (is_designated_for_smoothing(map_pos)) { if (is_smooth_wall(map_pos)) - cur_tile.ch = 206; // hash, indicating a fortification designation + cur_tile.ch = (char)206; // hash, indicating a fortification designation else - cur_tile.ch = 219; // solid block, indicating a smoothing designation + cur_tile.ch = (char)219; // solid block, indicating a smoothing designation } else if (is_designated_for_engraving(map_pos)) { - cur_tile.ch = 10; // solid block with a circle on it + cur_tile.ch = (char)10; // solid block with a circle on it } else if (is_designated_for_track_carving(map_pos)) { - cur_tile.ch = 186; // parallel tracks + cur_tile.ch = get_track_char(map_pos); // directional track } else { TRACE(log).print("skipping tile with no carving designation\n"); From a02d14bb5fcfdd0c25a9add6edd49109d5ff8755 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 12:29:31 -0700 Subject: [PATCH 507/851] alternate drawing designation and priority --- plugins/pathable.cpp | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index e63947caf..1ba88631e 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -11,6 +11,7 @@ #include "df/init.h" #include "df/map_block.h" #include "df/tile_designation.h" +#include "df/block_square_event_designation_priorityst.h" #include @@ -276,12 +277,35 @@ static bool blink(int delay) { return (Core::getInstance().p->getTickCount()/delay) % 2 == 0; } +static char get_tile_char(const df::coord &pos, char desig_char, bool draw_priority) { + if (!draw_priority) + return desig_char; + + std::vector priorities; + Maps::SortBlockEvents(Maps::getTileBlock(pos), NULL, NULL, NULL, NULL, NULL, NULL, NULL, &priorities); + if (priorities.empty()) + return '4'; + switch (priorities[0]->priority[pos.x % 16][pos.y % 16] / 1000) { + case 1: return '1'; + case 2: return '2'; + case 3: return '3'; + case 4: return '4'; + case 5: return '5'; + case 6: return '6'; + case 7: return '7'; + default: + return '0'; + } +} + static void paintScreenCarve() { DEBUG(log).print("entering paintScreenCarve\n"); if (Screen::inGraphicsMode() || blink(500)) return; + bool draw_priority = blink(1000); + auto dims = Gui::getDwarfmodeViewDims().map(); for (int y = dims.first.y; y <= dims.second.y; ++y) { for (int x = dims.first.x; x <= dims.second.x; ++x) { @@ -303,15 +327,15 @@ static void paintScreenCarve() { if (is_designated_for_smoothing(map_pos)) { if (is_smooth_wall(map_pos)) - cur_tile.ch = (char)206; // hash, indicating a fortification designation + cur_tile.ch = get_tile_char(map_pos, 206, draw_priority); // hash, indicating a fortification designation else - cur_tile.ch = (char)219; // solid block, indicating a smoothing designation + cur_tile.ch = get_tile_char(map_pos, 219, draw_priority); // solid block, indicating a smoothing designation } else if (is_designated_for_engraving(map_pos)) { - cur_tile.ch = (char)10; // solid block with a circle on it + cur_tile.ch = get_tile_char(map_pos, 10, draw_priority); // solid block with a circle on it } else if (is_designated_for_track_carving(map_pos)) { - cur_tile.ch = get_track_char(map_pos); // directional track + cur_tile.ch = get_tile_char(map_pos, get_track_char(map_pos), draw_priority); // directional track } else { TRACE(log).print("skipping tile with no carving designation\n"); From 898e98bea762b9814ca3fa89ec615e5839ef6e4b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 12:33:22 -0700 Subject: [PATCH 508/851] don't display priority if there is no priority block --- plugins/pathable.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 1ba88631e..800681d56 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -284,7 +284,7 @@ static char get_tile_char(const df::coord &pos, char desig_char, bool draw_prior std::vector priorities; Maps::SortBlockEvents(Maps::getTileBlock(pos), NULL, NULL, NULL, NULL, NULL, NULL, NULL, &priorities); if (priorities.empty()) - return '4'; + return desig_char; switch (priorities[0]->priority[pos.x % 16][pos.y % 16] / 1000) { case 1: return '1'; case 2: return '2'; @@ -294,7 +294,7 @@ static char get_tile_char(const df::coord &pos, char desig_char, bool draw_prior case 6: return '6'; case 7: return '7'; default: - return '0'; + return '4'; } } From 9951e5f505e501339fc2ef9605e5e144e811827f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 12:39:41 -0700 Subject: [PATCH 509/851] cast chars to chars --- plugins/pathable.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 800681d56..e93905a71 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -235,36 +235,36 @@ static bool is_designated_for_track_carving(const df::coord &pos) { static char get_track_char(const df::coord &pos) { auto occ = Maps::getTileOccupancy(pos); if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_south && occ->bits.carve_track_west) - return 0xCE; // NSEW + return (char)0xCE; // NSEW if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_south) - return 0xCC; // NSE + return (char)0xCC; // NSE if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_west) - return 0xCA; // NEW + return (char)0xCA; // NEW if (occ->bits.carve_track_east && occ->bits.carve_track_south && occ->bits.carve_track_west) - return 0xCB; // SEW + return (char)0xCB; // SEW if (occ->bits.carve_track_north && occ->bits.carve_track_south && occ->bits.carve_track_west) - return 0xB9; // NSW + return (char)0xB9; // NSW if (occ->bits.carve_track_north && occ->bits.carve_track_south) - return 0xBA; // NS + return (char)0xBA; // NS if (occ->bits.carve_track_east && occ->bits.carve_track_west) - return 0xCD; // EW + return (char)0xCD; // EW if (occ->bits.carve_track_east && occ->bits.carve_track_north) - return 0xC8; // NE + return (char)0xC8; // NE if (occ->bits.carve_track_north && occ->bits.carve_track_west) - return 0xBC; // NW + return (char)0xBC; // NW if (occ->bits.carve_track_east && occ->bits.carve_track_south) - return 0xC9; // SE + return (char)0xC9; // SE if (occ->bits.carve_track_south && occ->bits.carve_track_west) - return 0xBB; // SW + return (char)0xBB; // SW if (occ->bits.carve_track_north) - return 0xD0; // N + return (char)0xD0; // N if (occ->bits.carve_track_south) - return 0xD2; // S + return (char)0xD2; // S if (occ->bits.carve_track_east) - return 0xC6; // E + return (char)0xC6; // E if (occ->bits.carve_track_west) - return 0xB5; // W - return 0xC5; // single line cross; should never happen + return (char)0xB5; // W + return (char)0xC5; // single line cross; should never happen } static bool is_smooth_wall(const df::coord &pos) { @@ -327,12 +327,12 @@ static void paintScreenCarve() { if (is_designated_for_smoothing(map_pos)) { if (is_smooth_wall(map_pos)) - cur_tile.ch = get_tile_char(map_pos, 206, draw_priority); // hash, indicating a fortification designation + cur_tile.ch = get_tile_char(map_pos, (char)206, draw_priority); // hash, indicating a fortification designation else - cur_tile.ch = get_tile_char(map_pos, 219, draw_priority); // solid block, indicating a smoothing designation + cur_tile.ch = get_tile_char(map_pos, (char)219, draw_priority); // solid block, indicating a smoothing designation } else if (is_designated_for_engraving(map_pos)) { - cur_tile.ch = get_tile_char(map_pos, 10, draw_priority); // solid block with a circle on it + cur_tile.ch = get_tile_char(map_pos, (char)10, draw_priority); // solid block with a circle on it } else if (is_designated_for_track_carving(map_pos)) { cur_tile.ch = get_tile_char(map_pos, get_track_char(map_pos), draw_priority); // directional track From 45f58aa512ca93b8caf25320bbda184a702989ca Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:25:31 +0000 Subject: [PATCH 510/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index e383d9aaa..2b16f8d6b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit e383d9aaa231fb30a5c8c494ecf0924d4413865f +Subproject commit 2b16f8d6bb09652458771439072d29823aa8c264 From e325f3b6d97ccae4121482adca81feac21098106 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 16:32:52 -0700 Subject: [PATCH 511/851] differentiate the new region loading screen in the focus string --- docs/changelog.txt | 1 + library/modules/Gui.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 3ac2e3c48..3ae9fd2a6 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -59,6 +59,7 @@ Template for new versions: ## Fixes - `buildingplan`: make the construction dimensions readout visible again - `seedwatch`: fix a crash when reading data saved by very very old versions of the plugin +- `gui/mod-manager`: don't continue to display overlay after the raws loading progress bar appears ## Misc Improvements - `sort`: sort by need for training on squad assignment screen diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 4934c9787..9eee284ac 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -161,7 +161,9 @@ DEFINE_GET_FOCUS_STRING_HANDLER(title) DEFINE_GET_FOCUS_STRING_HANDLER(new_region) { - if (screen->doing_mods) + if (screen->raw_load) + focusStrings.push_back(baseFocus + "/Loading"); + else if (screen->doing_mods) focusStrings.push_back(baseFocus + "/Mods"); else if (screen->doing_simple_params) focusStrings.push_back(baseFocus + "/Basic"); From 1032ae41fd3b49f2aac727cf97bbd84753d46c48 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 16:53:14 -0700 Subject: [PATCH 512/851] add instructions for downloading dev builds --- docs/Installing.rst | 29 +++++++++++++++++++++++++---- docs/changelog.txt | 1 + 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/docs/Installing.rst b/docs/Installing.rst index 8a04b7cb9..14b5a0f93 100644 --- a/docs/Installing.rst +++ b/docs/Installing.rst @@ -48,10 +48,6 @@ DF version - see `above ` for details. For example: * ``dfhack-50.07-r1-Windows-64bit.zip`` supports 64-bit DF on Windows -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:: Do *not* download the source code from GitHub, either from the releases page @@ -60,6 +56,31 @@ Github page as a pre-release tagged with a "beta" suffix. you want to compile DFHack instead of using a pre-built release, see `building-dfhack-index` for instructions.) +Beta releases +------------- + +In between stable releases, we may create beta releases to test new features. +These are available via the ``beta`` release channel on Steam or from our +regular Github page as a pre-release tagged with a "beta" or "rc" suffix. + +Development builds +------------------ + +If you are actively working with the DFHack team on testing a feature, you may +want to download and install a development build. They are available via the +``testing`` release channel on Steam or can be downloaded from the build +artifact list on GitHub for specific repository commits. + +To download a development build from GitHub: + +- Ensure you are logged into your GitHub account +- Go to https://github.com/DFHack/dfhack/actions/workflows/build.yml?query=branch%3Adevelop+event%3Apush +- Click on the first entry that has a green checkmark +- Click the number under "Artifacts" (or scroll down) +- Click on the "dfhack-*-build-*" artifact for your platform to download + +You can extract this package the same as if you are doing a manual install (see the next section). + Installing DFHack ================= diff --git a/docs/changelog.txt b/docs/changelog.txt index 3ac2e3c48..3ba19679c 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -66,6 +66,7 @@ Template for new versions: - `sort`: display a rating relative to the current sort order next to the visible units on the squad assignment screen ## Documentation +- add instructions for downloading development builds to the ``Installing`` page ## API - `overlay`: overlay widgets can now declare a ``version`` attribute. changing the version of a widget will reset its settings to defaults. this is useful when changing the overlay layout and old saved positions will no longer be valid. From 73b5f0ced11d711f506e36f077689535c0d43ce1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 20:20:04 -0700 Subject: [PATCH 513/851] continue to highlight designations once they have become jobs --- plugins/pathable.cpp | 149 ++++++++++++++++++++++++++++++++----------- 1 file changed, 112 insertions(+), 37 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index e93905a71..57f5a5853 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -3,15 +3,18 @@ #include "PluginManager.h" #include "TileTypes.h" +#include "modules/EventManager.h" #include "modules/Gui.h" #include "modules/Maps.h" #include "modules/Screen.h" #include "modules/Textures.h" +#include "df/block_square_event_designation_priorityst.h" #include "df/init.h" +#include "df/job_list_link.h" #include "df/map_block.h" #include "df/tile_designation.h" -#include "df/block_square_event_designation_priorityst.h" +#include "df/world.h" #include @@ -23,6 +26,7 @@ REQUIRE_GLOBAL(init); REQUIRE_GLOBAL(window_x); REQUIRE_GLOBAL(window_y); REQUIRE_GLOBAL(window_z); +REQUIRE_GLOBAL(world); namespace DFHack { DBG_DECLARE(pathable, log, DebugCategory::LINFO); @@ -211,58 +215,126 @@ static void paintScreenWarmDamp(bool show_hidden = false) { } } -static bool is_designated_for_smoothing(const df::coord &pos) { - auto des = Maps::getTileDesignation(pos); - if (!des) - return false; - return des->bits.smooth == 1; +struct designation{ + df::coord pos; + df::tile_designation td; + df::tile_occupancy to; + designation() = default; + designation(const df::coord &c, const df::tile_designation &td, const df::tile_occupancy &to) : pos(c), td(td), to(to) {} + + bool operator==(const designation &rhs) const { + return pos == rhs.pos; + } + + bool operator!=(const designation &rhs) const { + return !(rhs == *this); + } +}; + +namespace std { + template<> + struct hash { + std::size_t operator()(const designation &c) const { + std::hash hash_coord; + return hash_coord(c.pos); + } + }; } -static bool is_designated_for_engraving(const df::coord &pos) { - auto des = Maps::getTileDesignation(pos); - if (!des) - return false; - return des->bits.smooth == 2; +class Designations { +private: + std::unordered_map designations; +public: + Designations() { + df::job_list_link *link = world->jobs.list.next; + for (; link; link = link->next) { + df::job *job = link->item; + + if(!job || !Maps::isValidTilePos(job->pos)) + continue; + + df::tile_designation td; + df::tile_occupancy to; + switch (job->job_type) { + case df::job_type::SmoothWall: + case df::job_type::SmoothFloor: + case df::job_type::CarveFortification: + td.bits.smooth = 1; + break; + case df::job_type::DetailWall: + case df::job_type::DetailFloor: + td.bits.smooth = 2; + 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; + to.bits.carve_track_west = (job->item_category.whole >> 20) & 1; + to.bits.carve_track_east = (job->item_category.whole >> 21) & 1; + break; + default: + break; + } + designations.emplace(job->pos, designation(job->pos, td, to)); + } + } + + // get from job; if no job, then fall back to querying map + designation get(const df::coord &pos) const { + if (designations.count(pos)) { + return designations.at(pos); + } + auto pdes = Maps::getTileDesignation(pos); + auto pocc = Maps::getTileOccupancy(pos); + if (!pdes || !pocc) + return {}; + return designation(pos, *pdes, *pocc); + } +}; + +static bool is_designated_for_smoothing(const designation &designation) { + return designation.td.bits.smooth == 1; } -static bool is_designated_for_track_carving(const df::coord &pos) { - auto occ = Maps::getTileOccupancy(pos); - if (!occ) - return false; - return occ->bits.carve_track_east || occ->bits.carve_track_north || occ->bits.carve_track_south || occ->bits.carve_track_west; +static bool is_designated_for_engraving(const designation &designation) { + return designation.td.bits.smooth == 2; } -static char get_track_char(const df::coord &pos) { - auto occ = Maps::getTileOccupancy(pos); - if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_south && occ->bits.carve_track_west) +static bool is_designated_for_track_carving(const designation &designation) { + const df::tile_occupancy &occ = designation.to; + return occ.bits.carve_track_east || occ.bits.carve_track_north || occ.bits.carve_track_south || occ.bits.carve_track_west; +} + +static char get_track_char(const designation &designation) { + const df::tile_occupancy &occ = designation.to; + if (occ.bits.carve_track_east && occ.bits.carve_track_north && occ.bits.carve_track_south && occ.bits.carve_track_west) return (char)0xCE; // NSEW - if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_south) + if (occ.bits.carve_track_east && occ.bits.carve_track_north && occ.bits.carve_track_south) return (char)0xCC; // NSE - if (occ->bits.carve_track_east && occ->bits.carve_track_north && occ->bits.carve_track_west) + if (occ.bits.carve_track_east && occ.bits.carve_track_north && occ.bits.carve_track_west) return (char)0xCA; // NEW - if (occ->bits.carve_track_east && occ->bits.carve_track_south && occ->bits.carve_track_west) + if (occ.bits.carve_track_east && occ.bits.carve_track_south && occ.bits.carve_track_west) return (char)0xCB; // SEW - if (occ->bits.carve_track_north && occ->bits.carve_track_south && occ->bits.carve_track_west) + if (occ.bits.carve_track_north && occ.bits.carve_track_south && occ.bits.carve_track_west) return (char)0xB9; // NSW - if (occ->bits.carve_track_north && occ->bits.carve_track_south) + if (occ.bits.carve_track_north && occ.bits.carve_track_south) return (char)0xBA; // NS - if (occ->bits.carve_track_east && occ->bits.carve_track_west) + if (occ.bits.carve_track_east && occ.bits.carve_track_west) return (char)0xCD; // EW - if (occ->bits.carve_track_east && occ->bits.carve_track_north) + if (occ.bits.carve_track_east && occ.bits.carve_track_north) return (char)0xC8; // NE - if (occ->bits.carve_track_north && occ->bits.carve_track_west) + if (occ.bits.carve_track_north && occ.bits.carve_track_west) return (char)0xBC; // NW - if (occ->bits.carve_track_east && occ->bits.carve_track_south) + if (occ.bits.carve_track_east && occ.bits.carve_track_south) return (char)0xC9; // SE - if (occ->bits.carve_track_south && occ->bits.carve_track_west) + if (occ.bits.carve_track_south && occ.bits.carve_track_west) return (char)0xBB; // SW - if (occ->bits.carve_track_north) + if (occ.bits.carve_track_north) return (char)0xD0; // N - if (occ->bits.carve_track_south) + if (occ.bits.carve_track_south) return (char)0xD2; // S - if (occ->bits.carve_track_east) + if (occ.bits.carve_track_east) return (char)0xC6; // E - if (occ->bits.carve_track_west) + if (occ.bits.carve_track_west) return (char)0xB5; // W return (char)0xC5; // single line cross; should never happen } @@ -304,6 +376,7 @@ static void paintScreenCarve() { if (Screen::inGraphicsMode() || blink(500)) return; + Designations designations; bool draw_priority = blink(1000); auto dims = Gui::getDwarfmodeViewDims().map(); @@ -325,17 +398,19 @@ static void paintScreenCarve() { Screen::Pen cur_tile; cur_tile.fg = COLOR_DARKGREY; - if (is_designated_for_smoothing(map_pos)) { + auto des = designations.get(map_pos); + + if (is_designated_for_smoothing(des)) { if (is_smooth_wall(map_pos)) cur_tile.ch = get_tile_char(map_pos, (char)206, draw_priority); // hash, indicating a fortification designation else cur_tile.ch = get_tile_char(map_pos, (char)219, draw_priority); // solid block, indicating a smoothing designation } - else if (is_designated_for_engraving(map_pos)) { + else if (is_designated_for_engraving(des)) { cur_tile.ch = get_tile_char(map_pos, (char)10, draw_priority); // solid block with a circle on it } - else if (is_designated_for_track_carving(map_pos)) { - cur_tile.ch = get_tile_char(map_pos, get_track_char(map_pos), draw_priority); // directional track + else if (is_designated_for_track_carving(des)) { + cur_tile.ch = get_tile_char(map_pos, get_track_char(des), draw_priority); // directional track } else { TRACE(log).print("skipping tile with no carving designation\n"); From 70b48dfa6f363206e64fc6afed7228fdef2fe0ec Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 21:14:59 -0700 Subject: [PATCH 514/851] let vanilla blinking take over when possible --- plugins/pathable.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 57f5a5853..12852a894 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -5,6 +5,7 @@ #include "modules/EventManager.h" #include "modules/Gui.h" +#include "modules/Job.h" #include "modules/Maps.h" #include "modules/Screen.h" #include "modules/Textures.h" @@ -255,9 +256,13 @@ public: df::tile_designation td; df::tile_occupancy to; + bool keep_if_taken = false; + switch (job->job_type) { case df::job_type::SmoothWall: case df::job_type::SmoothFloor: + keep_if_taken = true; + // fallthrough case df::job_type::CarveFortification: td.bits.smooth = 1; break; @@ -272,9 +277,10 @@ public: to.bits.carve_track_east = (job->item_category.whole >> 21) & 1; break; default: - break; + continue; } - designations.emplace(job->pos, designation(job->pos, td, to)); + if (keep_if_taken || !Job::getWorker(job)) + designations.emplace(job->pos, designation(job->pos, td, to)); } } From 2e11c91a103c784e5e16d5e4295ac9fe7cedc7c3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 10 Sep 2023 03:00:42 -0700 Subject: [PATCH 515/851] format string didn't match my system; generalizing --- library/Process-linux.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/Process-linux.cpp b/library/Process-linux.cpp index e50750015..0509f5710 100644 --- a/library/Process-linux.cpp +++ b/library/Process-linux.cpp @@ -138,7 +138,7 @@ void Process::getMemRanges( vector & ranges ) { t_memrange temp; temp.name[0] = 0; - sscanf(buffer, "%zx-%zx %s %zx %2zx:%2zx %zu %[^\n]", + sscanf(buffer, "%zx-%zx %s %zx %zx:%zx %zu %[^\n]", &start, &end, (char*)&permissions, From 6a99e97371d4b33aefaee67b8d901b39962b3d9a Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 11 Sep 2023 14:56:15 -0700 Subject: [PATCH 516/851] Update Authors.rst --- docs/about/Authors.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/about/Authors.rst b/docs/about/Authors.rst index ed9d59e62..4b5d4e0c2 100644 --- a/docs/about/Authors.rst +++ b/docs/about/Authors.rst @@ -3,7 +3,7 @@ List of authors The following is a list of people who have contributed to DFHack, in alphabetical order. -If you should be here and aren't, please get in touch on IRC or the forums, +If you should be here and aren't, please get in touch on Discord or the forums, or make a pull request! ======================= ======================= =========================== From 905438be9694ba1c098c797d31e773996d6a1f6b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 11 Sep 2023 23:21:55 -0700 Subject: [PATCH 517/851] update xml ref to 5010-testing --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 4097a59a4..2ff6363ac 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 4097a59a467b497d4d97c640e6b96b7d90b69dee +Subproject commit 2ff6363ac748deec3bb5a024e22792716003fc9b From 51772430f22a8a686b794b6058a4fe07e9101fde Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 12 Sep 2023 07:12:47 +0000 Subject: [PATCH 518/851] 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 4097a59a4..ecbd6f684 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 4097a59a467b497d4d97c640e6b96b7d90b69dee +Subproject commit ecbd6f684abd79d4438fe4ab48b3b0126bbc21d1 From 22f68223a195ca1683660591a1abde79e653e6af Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 12 Sep 2023 01:03:36 -0700 Subject: [PATCH 519/851] update structures ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 2ff6363ac..11e6d859a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 2ff6363ac748deec3bb5a024e22792716003fc9b +Subproject commit 11e6d859a03e3530d67514aa9305c7be73442e67 From a829358af095933b68b9dc9e3f2a1eeb7e69da7c Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 12 Sep 2023 15:57:04 -0500 Subject: [PATCH 520/851] update structures --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 11e6d859a..7cc3ffe35 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 11e6d859a03e3530d67514aa9305c7be73442e67 +Subproject commit 7cc3ffe3542a7736ae5fa458f2d5382eeeb6ead5 From f8b2297ddc2210649e36e73cb64282b7fb083f23 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 12 Sep 2023 18:41:50 -0700 Subject: [PATCH 521/851] update xml ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 7cc3ffe35..7c2a6fc6f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 7cc3ffe3542a7736ae5fa458f2d5382eeeb6ead5 +Subproject commit 7c2a6fc6f94de4512c25fffb6937e81987a84c92 From 8b1b413195a742071f21e1b06c766fc855b94b2d Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 12 Sep 2023 21:34:57 -0500 Subject: [PATCH 522/851] update version spec --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bb5cab7a..a6d1b7c41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,9 +7,9 @@ cmake_policy(SET CMP0074 NEW) project(dfhack) # set up versioning. -set(DF_VERSION "50.09") -set(DFHACK_RELEASE "r3") -set(DFHACK_PRERELEASE FALSE) +set(DF_VERSION "50.10") +set(DFHACK_RELEASE "beta1") +set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_ABI_VERSION 1) From 673d9d523099a2497a7c3f24f256dcae0893d0e6 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 12 Sep 2023 21:55:55 -0500 Subject: [PATCH 523/851] bodge DataIdentity to get 50.10 working --- library/DataIdentity.cpp | 3 +++ library/include/DataIdentity.h | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/library/DataIdentity.cpp b/library/DataIdentity.cpp index 8e9467c5b..767724931 100644 --- a/library/DataIdentity.cpp +++ b/library/DataIdentity.cpp @@ -47,7 +47,10 @@ namespace df { STL_OPAQUE_IDENTITY_TRAITS(condition_variable); STL_OPAQUE_IDENTITY_TRAITS(fstream); STL_OPAQUE_IDENTITY_TRAITS(mutex); + STL_OPAQUE_IDENTITY_TRAITS(shared_ptr); STL_OPAQUE_IDENTITY_TRAITS(future); + STL_OPAQUE_IDENTITY_TRAITS(function); + STL_OPAQUE_IDENTITY_TRAITS(optional >); buffer_container_identity buffer_container_identity::base_instance; } diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index 07e85e8a8..4f275b854 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -30,6 +30,7 @@ distribution. #include #include #include +#include #include "DataDefs.h" @@ -38,6 +39,10 @@ namespace std { class mutex; }; +namespace df { + class widget; +} + /* * Definitions of DFHack namespace structs used by generated headers. */ @@ -573,6 +578,9 @@ namespace df OPAQUE_IDENTITY_TRAITS(std::fstream); OPAQUE_IDENTITY_TRAITS(std::mutex); OPAQUE_IDENTITY_TRAITS(std::future); + OPAQUE_IDENTITY_TRAITS(std::shared_ptr); + OPAQUE_IDENTITY_TRAITS(std::function); + OPAQUE_IDENTITY_TRAITS(std::optional >); template<> struct DFHACK_EXPORT identity_traits { static bool_identity identity; From dbee92cd817dd2760a8c406a042327977d30f2c7 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 12 Sep 2023 22:01:58 -0500 Subject: [PATCH 524/851] `widget` is a `struct` not a `class` at least as far as df-structures is concerned... --- library/include/DataIdentity.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index 4f275b854..ff15535d1 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -40,7 +40,7 @@ namespace std { }; namespace df { - class widget; + struct widget; } /* From fd676fa70f0870dce209f8554dca40b551ed8ec0 Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 12 Sep 2023 23:37:56 -0400 Subject: [PATCH 525/851] Add identity_traits for std::unordered_map --- library/include/DataIdentity.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index ff15535d1..05df82e79 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -25,12 +25,13 @@ distribution. #pragma once #include +#include #include +#include #include #include +#include #include -#include -#include #include "DataDefs.h" @@ -661,6 +662,10 @@ namespace df static container_identity *get(); }; + template struct identity_traits> { + static container_identity *get(); + }; + template<> struct identity_traits > { static bit_array_identity identity; static bit_container_identity *get() { return &identity; } @@ -738,6 +743,13 @@ namespace df return &identity; } + template + inline container_identity *identity_traits>::get() { + typedef std::unordered_map container; + static ro_stl_assoc_container_identity identity("unordered_map", identity_traits::get(), identity_traits::get()); + return &identity; + } + template inline bit_container_identity *identity_traits >::get() { static bit_array_identity identity(identity_traits::get()); From a43522351f60c3a13be145390dd3230835dc31ab Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 12 Sep 2023 23:42:50 -0400 Subject: [PATCH 526/851] check-structures-sanity: ignore std::unordered_map --- plugins/devel/check-structures-sanity/dispatch.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/plugins/devel/check-structures-sanity/dispatch.cpp b/plugins/devel/check-structures-sanity/dispatch.cpp index d57beb0cb..c0d4764f9 100644 --- a/plugins/devel/check-structures-sanity/dispatch.cpp +++ b/plugins/devel/check-structures-sanity/dispatch.cpp @@ -377,10 +377,14 @@ void Checker::dispatch_container(const QueueItem & item, const CheckedStructure { // TODO: check DfArray } - else if (base_container.substr(0, 4) == "map<") + else if (base_container.starts_with("map<")) { // TODO: check map } + else if (base_container.starts_with("unordered_map<")) + { + // TODO: check unordered_map + } else { UNEXPECTED; From d2ae5463df742df1d0cec2ad5f9976cc3eb5ed8c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 12 Sep 2023 22:58:26 -0700 Subject: [PATCH 527/851] update xml ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 7c2a6fc6f..3875c956f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 7c2a6fc6f94de4512c25fffb6937e81987a84c92 +Subproject commit 3875c956f125105eaf430b5ccc4b5c00d72dc7e2 From 863df21dd216e51dce1dd0756a908f4726be6505 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 12 Sep 2023 23:08:55 -0700 Subject: [PATCH 528/851] protect against missing keys param --- library/modules/Screen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index cce06d284..5f98c40e5 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -962,6 +962,7 @@ int dfhack_lua_viewscreen::do_input(lua_State *L) if (!self) return 0; auto keys = (std::set*)lua_touserdata(L, 2); + if (!keys) return 0; lua_getfield(L, -1, "onInput"); From 9ea68d38c57497876e59f3b076489af564452a43 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Wed, 13 Sep 2023 13:57:55 -0500 Subject: [PATCH 529/851] sync structures --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 3875c956f..9fb4bb450 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 3875c956f125105eaf430b5ccc4b5c00d72dc7e2 +Subproject commit 9fb4bb45022361704daf14f59de4160d518503d3 From a7e59c8f77e068370f4cf77d57ee2b572ed75a47 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 13 Sep 2023 17:06:33 -0700 Subject: [PATCH 530/851] update xml ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 9fb4bb450..ce3982598 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9fb4bb45022361704daf14f59de4160d518503d3 +Subproject commit ce39825984a344a0b569c66ea08d29529e00cf37 From d9cae63e4e127ecc4291bd8cd54f4cc262535b0f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 13 Sep 2023 18:02:44 -0700 Subject: [PATCH 531/851] move dfhack logo over a little --- plugins/lua/hotkeys.lua | 11 +++++++++-- plugins/lua/overlay.lua | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 43d11bbda..be1a95570 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -26,9 +26,10 @@ end HotspotMenuWidget = defclass(HotspotMenuWidget, overlay.OverlayWidget) HotspotMenuWidget.ATTRS{ - default_pos={x=2,y=2}, + default_pos={x=5,y=1}, default_enabled=true, - hotspot=true, + hotspot=false, + version=2, viewscreens={ 'adopt_region', 'choose_game_type', @@ -170,10 +171,16 @@ end function Menu:init() local hotkeys, bindings = getHotkeys() + if #hotkeys == 0 then + hotkeys = {''} + bindings = {['']='gui/launcher'} + end local is_inverted = not not self.hotspot.frame.b local choices,list_width = get_choices(hotkeys, bindings, is_inverted) + list_width = math.max(35, list_width) + local list_frame = copyall(self.hotspot.frame) local list_widget_frame = {h=math.min(#choices, MAX_LIST_HEIGHT)} local quickstart_frame = {} diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index 55ca44bc9..d3f0b9c9d 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -581,7 +581,8 @@ end TitleVersionOverlay = defclass(TitleVersionOverlay, OverlayWidget) TitleVersionOverlay.ATTRS{ - default_pos={x=7, y=2}, + default_pos={x=11, y=1}, + version=2, default_enabled=true, viewscreens='title/Default', frame={w=35, h=5}, From 96f6893a320607a700ab74eb35be0e5bccf28bac Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 13 Sep 2023 18:02:52 -0700 Subject: [PATCH 532/851] update xml ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index ce3982598..649505331 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ce39825984a344a0b569c66ea08d29529e00cf37 +Subproject commit 649505331539bbdccccd900e751ff9ee9b2d1665 From 561f447a548da02c252609adf3d0abf8036b9fc0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 13 Sep 2023 18:17:23 -0700 Subject: [PATCH 533/851] update xml ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 649505331..3d9c46b10 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 649505331539bbdccccd900e751ff9ee9b2d1665 +Subproject commit 3d9c46b105181cc9afde943993aa4ad433bf87cf From 49e449a422cf746d87813cb7f3a1c1ceb12bcde6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 13 Sep 2023 18:20:49 -0700 Subject: [PATCH 534/851] update xml ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 3d9c46b10..be6abfb4a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 3d9c46b105181cc9afde943993aa4ad433bf87cf +Subproject commit be6abfb4af929c1445dc91aa51aade44ca62ac57 From 017e280b181bb4a31f29bfd382bb9b6a80b732af Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 13 Sep 2023 21:57:28 -0400 Subject: [PATCH 535/851] Define identity_traits> for all T (opaque for now) --- library/DataIdentity.cpp | 1 - library/include/DataIdentity.h | 17 ++++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/library/DataIdentity.cpp b/library/DataIdentity.cpp index 767724931..c041b009d 100644 --- a/library/DataIdentity.cpp +++ b/library/DataIdentity.cpp @@ -47,7 +47,6 @@ namespace df { STL_OPAQUE_IDENTITY_TRAITS(condition_variable); STL_OPAQUE_IDENTITY_TRAITS(fstream); STL_OPAQUE_IDENTITY_TRAITS(mutex); - STL_OPAQUE_IDENTITY_TRAITS(shared_ptr); STL_OPAQUE_IDENTITY_TRAITS(future); STL_OPAQUE_IDENTITY_TRAITS(function); STL_OPAQUE_IDENTITY_TRAITS(optional >); diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index 05df82e79..035f59d4b 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -40,10 +40,6 @@ namespace std { class mutex; }; -namespace df { - struct widget; -} - /* * Definitions of DFHack namespace structs used by generated headers. */ @@ -579,10 +575,21 @@ namespace df OPAQUE_IDENTITY_TRAITS(std::fstream); OPAQUE_IDENTITY_TRAITS(std::mutex); OPAQUE_IDENTITY_TRAITS(std::future); - OPAQUE_IDENTITY_TRAITS(std::shared_ptr); OPAQUE_IDENTITY_TRAITS(std::function); OPAQUE_IDENTITY_TRAITS(std::optional >); +#ifdef BUILD_DFHACK_LIB + template + struct DFHACK_EXPORT identity_traits> { + static opaque_identity *get() { + typedef std::shared_ptr type; + static std::string name = std::string("shared_ptr<") + typeid(T).name() + ">"; + static opaque_identity identity(sizeof(type), allocator_noassign_fn, name); + return &identity; + } + }; +#endif + template<> struct DFHACK_EXPORT identity_traits { static bool_identity identity; static bool_identity *get() { return &identity; } From 74390cca768c23a8969c0acd225aae969bfb6baf Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 14 Sep 2023 07:13:19 +0000 Subject: [PATCH 536/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 2b16f8d6b..2ecd256e7 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 2b16f8d6bb09652458771439072d29823aa8c264 +Subproject commit 2ecd256e7a15fd9134e0a27fbcacae419cf94a23 From b11a3ead1e1e711453c6875f15d445ca75aceb08 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 14 Sep 2023 01:31:19 -0700 Subject: [PATCH 537/851] make DFHack logo respond to clicks, not mouseover --- data/art/{dfhack.png => logo.png} | Bin data/art/logo_hovered.png | Bin 0 -> 997 bytes plugins/lua/hotkeys.lua | 82 ++++++++++++++---------------- 3 files changed, 39 insertions(+), 43 deletions(-) rename data/art/{dfhack.png => logo.png} (100%) create mode 100644 data/art/logo_hovered.png diff --git a/data/art/dfhack.png b/data/art/logo.png similarity index 100% rename from data/art/dfhack.png rename to data/art/logo.png diff --git a/data/art/logo_hovered.png b/data/art/logo_hovered.png new file mode 100644 index 0000000000000000000000000000000000000000..133dc5aaf8c98921bcc0203ebd986d4915c726cd GIT binary patch literal 997 zcmVnc%n2qL3P&<7QL*(pc~60K|QZ+CX5 z;r-SBwq*l8=FOWo^ZxVkd(Y-drP9<$GT^te@}oi4gTZeG=04pzox7!}!DP^iPEJnb z^z!l&qtEASZEgJ@4@hz}8uNO+&2_22zyJ337RqaDYr4vy~Zk>hAI`tBScAgimZ zJPiZ_7~9&~q>eIup96fgoK8=bN~1dPHe{4v-m7)1n7!BRz#ibbDJ`dCz-2uqU5 zBr#0u>+4lQw7I#7Zv-4MGJ{8Cuqp!rA&?odB25~dPA9EG&RAU&u3;1=BnV4nhBLkl z0No@!I5^;2LF+&bQAbAyU5%(2Vq&ovuRc9J?eFiSw6KaVW>n{Xo|u>b`l2^$HX2OG zn4%AMc6JEP$o<8|1sI3JL2C2!^ER7}lzV%70eLkWjhY3gqb>#X!$c;Nq5kUb?$%yM zur9#|R|NodZf@@8=BA1RqtS>F8o+wK0M5_PF^-RqQ!8CxUo$|#0a*t_`a?rQ0|Ns( z&lW-g9G?o2;)68a-QAI0ATt=qv8p^|AVCb3>qyOk#bV(TF%^qN+6e;g)5Wr}vB3(2 z-U>je4({*oF+M&%YSG{2av@5rGc`3u)s@TT@x<_IAkWC_OzrD)xN@i{x{N2+d4wh^Ns$-9OL7E%=7wV?~0|2#6)Vmyserf;!01jnXNoGw=04e|g00;m800000 T0Mb*F00000NkvXXu0mjfn&!gY literal 0 HcmV?d00001 diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index be1a95570..f74b54416 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -5,7 +5,8 @@ local helpdb = require('helpdb') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') -local textures = dfhack.textures.loadTileset('hack/data/art/dfhack.png', 8, 12) +local logo_textures = dfhack.textures.loadTileset('hack/data/art/logo.png', 8, 12) +local logo_hovered_textures = dfhack.textures.loadTileset('hack/data/art/logo_hovered.png', 8, 12) local function get_command(cmdline) local first_word = cmdline:trim():split(' +')[1] @@ -28,7 +29,6 @@ HotspotMenuWidget = defclass(HotspotMenuWidget, overlay.OverlayWidget) HotspotMenuWidget.ATTRS{ default_pos={x=5,y=1}, default_enabled=true, - hotspot=false, version=2, viewscreens={ 'adopt_region', @@ -48,54 +48,50 @@ HotspotMenuWidget.ATTRS{ 'update_region', 'world' }, - overlay_onupdate_max_freq_seconds=0, frame={w=4, h=3} } function HotspotMenuWidget:init() - self.mouseover = false -end - -function HotspotMenuWidget:overlay_onupdate() - local hasMouse = self:getMousePos() - if hasMouse and not self.mouseover then - self.mouseover = true - return true + local to_pen = dfhack.pen.parse + local function tp(idx, ch) + return to_pen{ + tile=function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end, + ch=ch, + fg=COLOR_GREY, + } + end + local function tph(idx, ch) + return to_pen{ + tile=function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, + ch=ch, + fg=COLOR_WHITE, + } + end + local function get_tile_token(idx, ch) + return { + tile=tp(idx, ch), + htile=tph(idx, ch), + width=1, + } end - self.mouseover = hasMouse -end -function HotspotMenuWidget:overlay_trigger() - return MenuScreen{hotspot=self}:show() + self:addviews{ + widgets.Label{ + text={ + get_tile_token(1, '!'), get_tile_token(2, 'D'), get_tile_token(3, 'F'), get_tile_token(4, '!'), NEWLINE, + get_tile_token(5, '!'), get_tile_token(6, 'H'), get_tile_token(7, 'a'), get_tile_token(8, '!'), NEWLINE, + get_tile_token(9, '!'), get_tile_token(10, 'c'), get_tile_token(11, 'k'), get_tile_token(12, '!'), + }, + }, + } end -local dscreen = dfhack.screen - -function HotspotMenuWidget:onRenderBody(dc) - local x, y = dc.x, dc.y - local tp = function(offset) - return dfhack.textures.getTexposByHandle(textures[offset]) - end - - if tp(1) == nil then - dscreen.paintString(COLOR_WHITE, x, y + 0, '!DF!') - dscreen.paintString(COLOR_WHITE, x, y + 1, '!Ha!') - dscreen.paintString(COLOR_WHITE, x, y + 2, '!ck!') - else - dscreen.paintTile(COLOR_WHITE, x + 0, y + 0, '!', tp(1)) - dscreen.paintTile(COLOR_WHITE, x + 1, y + 0, 'D', tp(2)) - dscreen.paintTile(COLOR_WHITE, x + 2, y + 0, 'F', tp(3)) - dscreen.paintTile(COLOR_WHITE, x + 3, y + 0, '!', tp(4)) - - dscreen.paintTile(COLOR_WHITE, x + 0, y + 1, '!', tp(5)) - dscreen.paintTile(COLOR_WHITE, x + 1, y + 1, 'H', tp(6)) - dscreen.paintTile(COLOR_WHITE, x + 2, y + 1, 'a', tp(7)) - dscreen.paintTile(COLOR_WHITE, x + 3, y + 1, '!', tp(8)) - - dscreen.paintTile(COLOR_WHITE, x + 0, y + 2, '!', tp(9)) - dscreen.paintTile(COLOR_WHITE, x + 1, y + 2, 'c', tp(10)) - dscreen.paintTile(COLOR_WHITE, x + 2, y + 2, 'k', tp(11)) - dscreen.paintTile(COLOR_WHITE, x + 3, y + 2, '!', tp(12)) +function HotspotMenuWidget:onInput(keys) + if HotspotMenuWidget.super.onInput(self, keys) then + return true + elseif keys._MOUSE_L_DOWN and self:getMousePos() then + MenuScreen{hotspot=self}:show() + return true end end @@ -290,7 +286,7 @@ function Menu:onInput(keys) df.global.enabler.mouse_lbut = 0 return true end - if not self:getMouseFramePos() and not self.hotspot:getMousePos() then + if not self:getMouseFramePos() then self.parent_view:dismiss() return true end From b6c4eb77010fe956812710cbb70d44ba12410cb7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 14 Sep 2023 09:59:36 -0700 Subject: [PATCH 538/851] realign tooltip ids in confirm --- plugins/lua/confirm.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/lua/confirm.lua b/plugins/lua/confirm.lua index 1ddf190b4..2fcbfa721 100644 --- a/plugins/lua/confirm.lua +++ b/plugins/lua/confirm.lua @@ -82,7 +82,7 @@ haul_delete_stop.message = "Are you sure you want to delete this stop?" depot_remove = defconf('depot-remove') function depot_remove.intercept_key(key) - if df.global.game.main_interface.current_hover == 299 and + if df.global.game.main_interface.current_hover == 301 and key == MOUSE_LEFT and df.building_tradedepotst:is_instance(dfhack.gui.getSelectedBuilding(true)) then for _, caravan in pairs(df.global.plotinfo.caravans) do @@ -98,7 +98,7 @@ depot_remove.message = "Are you sure you want to remove this depot?\n" .. squad_disband = defconf('squad-disband') function squad_disband.intercept_key(key) - return key == MOUSE_LEFT and df.global.game.main_interface.current_hover == 341 + return key == MOUSE_LEFT and df.global.game.main_interface.current_hover == 343 end squad_disband.title = "Disband squad" squad_disband.message = "Are you sure you want to disband this squad?" From 3634075df0f9ffb9b88b7c8cac9ff11f57cee3be Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 14 Sep 2023 10:12:25 -0700 Subject: [PATCH 539/851] make DFHack logo glow on hover --- data/art/logo_hovered.png | Bin 997 -> 5124 bytes plugins/lua/hotkeys.lua | 10 +--------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/data/art/logo_hovered.png b/data/art/logo_hovered.png index 133dc5aaf8c98921bcc0203ebd986d4915c726cd..fe82cc1aed28be37d973b2f915e16be918785e4d 100644 GIT binary patch literal 5124 zcmeHKYg7~079KzpDcGQ>NWnV>RJ2Z#NkT|cf+7To5Y9%lb7K!bO7ysTa&y40 zUxXj+HJyf{$9i4-uGd=7^(lqF^zZU_R%+q08h0G9vZ0iL zRW3fA9%}}(NT*1mTyv{bZp$W7Rm8hLymg|9IJ)~T_mTe>!w)liMrdoq5~Vbo1L?Zz zZaAuaW+?`WcQ#!446S<#kMwHD=Sn7@yhDW`lP!doSAf9F>v=vPi@c3HdA?sQ zbGZ2awUxog$XZg|rGWgNLULxMCI3i3%+?S`KgzRB3#LfbT3uE?BB@rQPMO?_+uHRQJOvYSF zPcBjC-*%ZES~oqAH1A*f0xOFJ-0N^uPL>3{g$8iZz?vA``Zo zQFJLkFN~l&ulVDdt)+R#vyaa&nqt*vdTxVUadKmx2Q;U9ae|qHgJ~E4o5(@EP8X#Z z*-tziG-KRQW$fCS+79YYPk{Og75Z_-3K<2HC`33#FH?fTgCO^%dL<^_fNNk89!1D` zJ3{$XGysYoQJTZAuNq)rxqP z80TwoxyETCghV`UuZ&m48q<-8sdy|d1FCA^6@AI&3V|?S+`>RX6d_X@tpM3CX=(`R z3$k8{&9GujXJR10d>r>B?dQ20m4TK}$n{o;;|<{nym@4Uf38F!CL~fuY=#?S0+c|m)?jimZh!*d6awI&I0u-qaD+v7lORmG zgoR)nmK5QLIZ`(k9c8lF_yh=l6#=Rei=7yi0ZIa(FfmQ)hOsz^2&KCrOeOI|&&Ug;SOCD5DPp;atxE0gp_l&|XLaVlj;r81Tq` zggjpVVj+l-;cGRRflZXfVY;Cx>WYGp8En=Ir4U@D29;>QL}?TT)3{>T7A{Bz5Q`b= z6aX0IAQ!He3db}GRggjv%Oe{?f(@4A%Rjl)HmK`4z&bLF}M z`rWv+3Hk~NAx-#S+J@$V-AA|Fmrw)$2}aRqN3F%TP5YD|ku zjBx_2(Is&-CXd3w=`mKW&*jA5l!8ctqiz@tM=-G)iZDT8AtDJ=gkWx<7BF1u>dG9= zY8+jykZN?83ipfxJOZvjc^bKbU5p#G=;c^+(YRq30AUD?gZz~+>R7^5!BOgLnK-KY#4Uf?XGjvt0&oPl`%$=}#s{F5$V__dQ);`cROujzUv23|?|b#=X_ z>y;RICFR%E^?#$w^2K!umxHe$9k?vze!jQ`T(l;OR;}q5Y4>?6Tgn!aR8obQJZ{$zhqMLg4SaCdqu0~o77sIsV4YVvr<24EVB8yu(R9#El!1n zO-1Xv{(MD$@9i{!iqn^r`otEy-MDXfNnhiWFShrUfB)vWItcnUx%;=~dwahdnbvXl za!zUT(}ApijhLi(+(jpc3un)s-81m$(JUw=BxI83kYieXc#X@4={^U~7c9@lThC0L zmxgKL9}RzSBPQ5(sr&bjYivl%&&qO(iQKQluij%0PYVvdS(JEgwZ+kp<2wpFT1du_spD@0?nFFjUX8?-qTxJX-d z{(O5bZO?AXq`Voc9}K%c8E%kFpOJzdu$w!#m!i$d$?4ftOk5Q0`Qr ze&xra7$a($g0 z>hFa{XZUQ+AUq1Fww5kYzR7B}8KhRL@6O7qKU`eg#IdvLu4*rDDhs85W)*T258Hpo z(a{mxDD?AFzGLp0Uf*?MXwS+bU*}VmmGQ~RKc%gYj<$fvJAEr|9EcPcukj=`C2O@>skHcVh56nKrlyOzHMn~>Dd|3@&hDRc2}3UJEgmEs;&S1fq_X7l}bI?T~k&@`sm`3 z?{3|)Z!g)lZHksUe|^!t_tL-lRaG8Zm+9+ux}w5qhX^K}t*Wx0GsiQDlC#$K*QZaP z4h%5utQPEUXl`C}`PBWj3l=U+`2ES!@avDm%Vlp}ZeljpME0}~R(<`S52zi#J$(Pj Z2o#j-Nb=lLw87Bo0{&|6lI80+{TEB3t%Cpn delta 975 zcmV;=12FuADCGx`B!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o000AR zNklIMuJ-o!v_=t}TK@FQbar-Dencvj!dNbsrOxQ+Xp5lg4mvwK zVuhku8Mf2?e))v8E_hld9T2in>qHrlmMir6cXf*on93UX8tE)T>1Ogb_+S;U!GJT%|e6^fTPfu$TMsT9z zKvAOU*4CChJ`zX?pqMb3OeTG>J3T#>3&4rp-Cb!N(Vv-_A^!02P%0}$RR!!6Y>@s3Ouxw(mN1ROCkgGXerDgy!` zkQuQeO&Xm}C#^!xSX~pYVH74L2uoy!GrkM}-6T9XIN)1B>p%@rM@I);ji?!7VzC&n zK0Q6{@9(3uu!=8cROf!4n3w?iqBm#X!$c;Nq5kUb?$%yMur9#|R|NodZf@@8=BA1RqtS>F8o+wK z0M5_PF^-RqQ!8CxUo$|#0a*t_`a?rQ0|Ns(&lW-g9G?o2;)68a-QAI0ATt=qv8p^| zAb&v&mFq~&fyH9s6EPKwMcN4h?$gDxv9ZAlgx(53sSfV%?=e0;K5Eh5<#HiPtTQz= zMb(wd<>X#=Aff3`h){fhHo6fxM2m}yNH|V+c6Meqn@NsFMS&h29c^!Kqim4>_V#wj z=_oxtJu3En1dHTzhzQM0ZHTAQN3lq@7)TSIIVi2y*H?ZTebwu_asNS@8~qpRrvL*0 xwN2E!9EpBv0000EWmrjOO-%qQ00008000000002eQ Date: Thu, 14 Sep 2023 10:18:49 -0700 Subject: [PATCH 540/851] update structures ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index be6abfb4a..71889ec62 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit be6abfb4af929c1445dc91aa51aade44ca62ac57 +Subproject commit 71889ec62cf615c9c0f1346402b858718d16cf3c From e7762e7bc6124cc5c51a3725a1ca7d48703bfdbf Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 14 Sep 2023 10:20:20 -0700 Subject: [PATCH 541/851] update structures ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 71889ec62..46a365e05 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 71889ec62cf615c9c0f1346402b858718d16cf3c +Subproject commit 46a365e0533f0dffac9f3ce44f3dc992153b1c41 From 04999cae8dfd7c27afcfa57ef0670174299110af Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 14 Sep 2023 10:43:35 -0700 Subject: [PATCH 542/851] unbreak Ctrl-Shift-C --- plugins/lua/hotkeys.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index a366e45bb..ac62b49e0 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -82,11 +82,15 @@ function HotspotMenuWidget:init() get_tile_token(5, '!'), get_tile_token(6, 'H'), get_tile_token(7, 'a'), get_tile_token(8, '!'), NEWLINE, get_tile_token(9, '!'), get_tile_token(10, 'c'), get_tile_token(11, 'k'), get_tile_token(12, '!'), }, - on_click=function() MenuScreen{hotspot=self}:show() end, + on_click=function() dfhack.run_command('hotkeys') end, }, } end +function HotspotMenuWidget:overlay_trigger() + return MenuScreen{hotspot=self}:show() +end + -- register the menu hotspot with the overlay OVERLAY_WIDGETS = {menu=HotspotMenuWidget} @@ -267,7 +271,7 @@ end function Menu:onInput(keys) if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then return false - elseif keys.STANDARDSCROLL_RIGHT then + elseif keys.KEYBOARD_CURSOR_RIGHT then self:onSubmit2(self.subviews.list:getSelected()) return true elseif keys._MOUSE_L_DOWN then From fc88bfcbbcf8b3a03c39cb6d1692612dffe772b6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 14 Sep 2023 11:46:30 -0700 Subject: [PATCH 543/851] don't close the logo menu on mouseout now that we no longer open on hover, it doesn't make as much sense, and the behavior can be frustrating when the mouse is moved unintentionally --- docs/plugins/hotkeys.rst | 15 +++++++++------ plugins/lua/hotkeys.lua | 11 ++--------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/docs/plugins/hotkeys.rst b/docs/plugins/hotkeys.rst index 6b2ef3f0c..561a34382 100644 --- a/docs/plugins/hotkeys.rst +++ b/docs/plugins/hotkeys.rst @@ -19,14 +19,17 @@ Usage Menu overlay widget ------------------- -The in-game hotkeys menu is registered with the `overlay` framework and can be -enabled as a hotspot in the upper-left corner of the screen. You can bring up -the menu by hovering the mouse cursor over the hotspot and can select a command -to run from the list by clicking on it with the mouse or by using the keyboard -to select a command with the arrow keys and hitting :kbd:`Enter`. +The in-game hotkeys menu is registered with the `overlay` framework and appears +as a DFHack logo in the upper-left corner of the screen. You can bring up the +menu by clicking on the logo or by hitting the global :kbd:`Ctrl`:kbd:`Shift`:kbd:`c` hotkey. You can select a command to run from +the list by clicking on it with the mouse or by using the keyboard to select a +command with the arrow keys and hitting :kbd:`Enter`. + +The menu closes automatically when an action is taken or when you click or +right click anywhere else on the screen. A short description of the command will appear in a nearby textbox. If you'd like to see the full help text for the command or edit the command before -running, you can open it for editing in `gui/launcher` by right clicking on the +running, you can open it for editing in `gui/launcher` by shift clicking on the command, left clicking on the arrow to the left of the command, or by pressing the right arrow key while the command is selected. diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index ac62b49e0..fae138353 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -297,7 +297,7 @@ function Menu:onRenderFrame(dc, rect) self.initialize() self.initialize = nil end - Menu.super.onRenderFrame(dc, rect) + Menu.super.onRenderFrame(self, dc, rect) end function Menu:getMouseFramePos() @@ -306,7 +306,7 @@ function Menu:getMouseFramePos() end function Menu:onRenderBody(dc) - local panel = self.subviews.list_panel + Menu.super.onRenderBody(self, dc) local list = self.subviews.list local idx = list:getIdxUnderMouse() if idx and idx ~= self.last_mouse_idx then @@ -316,13 +316,6 @@ function Menu:onRenderBody(dc) list:setSelected(idx) self.last_mouse_idx = idx end - if self:getMouseFramePos() then - self.mouseover = true - elseif self.mouseover then - -- once the mouse has entered the list area, leaving the frame should - -- close the menu screen - self.parent_view:dismiss() - end end -- ---------- -- From 540bd602af8f0e96313ab480e6f2ba17ae21f4b5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 14 Sep 2023 11:47:15 -0700 Subject: [PATCH 544/851] revise quickstart guide --- docs/Quickstart.rst | 220 +++++++++++++++++++++++--------------------- 1 file changed, 116 insertions(+), 104 deletions(-) diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst index f4a022a9c..8016a99b2 100644 --- a/docs/Quickstart.rst +++ b/docs/Quickstart.rst @@ -45,67 +45,75 @@ Here are some common tasks people use DFHack tools to accomplish: - Quickly scan the map for visible ores of specific types so you can focus your mining efforts -Some tools are one-shot commands. For example, you can run `unforbid all ` -to claim all (reachable) items on the map after a messy siege. - -Other tools must be `enabled ` and then they will run in the background. -For example, `enable seedwatch ` will start monitoring your stocks of -seeds and prevent your chefs from cooking seeds that you need for planting. -Tools that are enabled in the context of a fort will save their state with that -fort, and they will remember that they are enabled the next time you load your save. - -A third class of tools add information to the screen or provide new integrated -functionality via the DFHack `overlay` framework. For example, the `unsuspend` -tool, in addition to its basic function of unsuspending all building construction -jobs, can also overlay a marker on suspended buildings to indicate that they are -suspended (and will use different markers to tell you whether this is a problem). +Some tools are one-shot commands. For example, you can run +`unforbid all ` to claim all (reachable) items on the map after a +messy siege. + +Other tools must be `enabled ` once and then they will run in the +background. For example, once enabled, `seedwatch` will start monitoring your +stocks of seeds and prevent your chefs from cooking seeds that you need for +planting. Tools that are enabled in the context of a fort will save their state +with that fort, and they will remember that they are enabled the next time you +load your save. + +A third class of tools adds information to the screen or provides new integrated +functionality via the DFHack `overlay` framework. For example, the `sort` tool +adds widgets to the squad member selection screen that allow you to search, +sort, and filter the list of military candidates. You don't have to run any +command to get the benefits of the tool, it appears automatically when you're +on the relevant screen. How can I figure out which commands to run? ------------------------------------------- -There are several ways to scan DFHack tools and find the ones you need right now. +There are several ways to scan DFHack tools and find the ones you need right +now. -The first place to check is the DFHack logo hover hotspot. It's in the upper -left corner of the screen by default, though you can move it anywhere you want -with the `gui/overlay` configuration UI. +The first place to check is the DFHack logo menu. It's in the upper left corner +of the screen by default, though you can move it anywhere you want with the +`gui/overlay` configuration UI. -When you hover the mouse over the logo (or hit the Ctrl-Shift-C keyboard shortcut) -a list of DFHack tools relevant to the current context comes up. For example, when -you have a unit selected, the hotspot will show a list of tools that inspect -units, allow you to edit them, or maybe even teleport them. Next to each tool, -you'll see the hotkey you can hit to invoke the command without even opening the -hover list. +When you click on the logo (or hit the Ctrl-Shift-C keyboard shortcut), a short +list of popular, relevant DFHack tools comes up. These are the tools that have +been assigned hotkeys that are active in the current context. For example, when +you're looking at a fort map, the list will contain fortress design tools like +`gui/quickfort` and `gui/design`. You can click on the tools in the list, or +note the hotkeys listed next to them and maybe use them to launch the tool next +time without even opening the logo menu. The second place to check is the DFHack control panel: `gui/control-panel`. It will give you an overview of which tools are currently enabled, and will allow you to toggle them on or off, see help text for them, or launch their dedicated configuration UIs. You can open the control panel from anywhere with the -Ctrl-Shift-E hotkey or by selecting it from the logo hover list. +Ctrl-Shift-E hotkey or by selecting it from the logo menu list. In the control panel, you can also select which tools you'd like to be -automatically enabled when you start a new fort. There are also system settings -you can change, like whether DFHack windows will pause the game when they come -up. - -Finally, you can explore the full extent of the DFHack catalog in `gui/launcher`, -which is always listed first in the DFHack logo hover list. You can also bring up -the launcher by tapping the backtick key (\`) or hitting Ctrl-Shift-D. In the -launcher, you can quickly autocomplete any command name by selecting it in the -list on the right side of the window. Commands are ordered by how often you run -them, so your favorite commands will always be on top. You can also pull full -commandlines out of your history with Alt-S or by clicking on the "history search" -hotkey hint. - -Once you have typed (or autocompleted, or searched for) a command, other commands -related to the one you have selected will appear in the right-hand panel. Scanning -through that list is a great way to learn about new tools that you might find -useful. You can also see how commands are grouped by running the `tags` command. +automatically enabled and popular commands you'd like to run when you start a +new fort. On the "Preferences" tab, there are settings you can change, like +whether you want to limit DFHack functionality to interface improvements, +bugfixes, and productivity tools, hiding the god-mode tools ("mortal mode") or +whether you want DFHack windows to pause the game when they come up. + +Finally, you can explore the full extent of the DFHack catalog in +`gui/launcher`, which is always listed first in the DFHack logo menu list. You +can also bring up the launcher by tapping the backtick key (\`) or hitting +Ctrl-Shift-D. In the launcher, you can quickly autocomplete any command name by +selecting it in the list on the right side of the window. Commands are ordered +by how often you run them, so your favorite commands will always be on top. You +can also pull full commandlines out of your history with Alt-S or by clicking +on the "history search" hotkey hint. + +Once you have typed (or autocompleted, or searched for) a command, other +commands related to the one you have selected will appear in the right-hand +panel. Scanning through that list is a great way to learn about new tools that +you might find useful. You can also see how commands are grouped by running the +`tags` command. The bottom panel will show the full help text for the command you are running, -allowing you to refer to the usage documentation and examples when you are typing -your command. After you run a command, the bottom panel switches to command output -mode, but you can get back to the help text by hitting Ctrl-T or clicking on the -``Help`` tab. +allowing you to refer to the usage documentation and examples when you are +typing your command. After you run a command, the bottom panel switches to +command output mode, but you can get back to the help text by hitting Ctrl-T or +clicking on the ``Help`` tab. How do DFHack in-game windows work? ----------------------------------- @@ -122,84 +130,88 @@ you type at the keyboard. Hit Esc or right click to close the window or cancel the current action. You can click anywhere on the screen that is not a DFHack window to unfocus the window and let it just sit in the background. It won't respond to key presses or mouse clicks until you click on it again to give it -focus. If no DFHack windows are focused, you can right click directly on a window -to close it without left clicking to focus it first. +focus. If no DFHack windows are focused, you can right click directly on a +window to close it without left clicking to focus it first. DFHack windows are draggable from the title bar or from anywhere on the window that doesn't have a mouse-clickable widget on it. Many are resizable as well (if the tool window has components that can reasonably be resized). -You can generally use DFHack tools without interrupting the game. That is, if the -game is unpaused, it can continue to run while a DFHack window is open. If configured -to do so in `gui/control-panel`, tools will initially pause the game to let you -focus on the task at hand, but you can unpause like normal if you want. You can -also interact with the map, scrolling it with the keyboard or mouse and selecting -units, buildings, and items. Some tools will intercept all mouse clicks to allow -you to select regions on the map. When these tools have focus, you will not be able -to use the mouse to interact with map elements or pause/unpause the game. Therefore, -these tools will pause the game when they open, regardless of your settings in -`gui/control-panel`. You can still unpause with the keyboard (spacebar by default), -though. +You can generally use DFHack tools without interrupting the game. That is, if +the game is unpaused, it can continue to run while a DFHack window is open. If +configured to do so in `gui/control-panel`, tools will initially pause the game +to let you focus on the task at hand, but you can unpause like normal if you +want. You can also interact with the map, scrolling it with the keyboard or +mouse and selecting units, buildings, and items. Some tools will intercept all +mouse clicks to allow you to select regions of the map. When these tools have +focus, you will not be able to use the mouse to interact with map elements or +pause/unpause the game. Therefore, these tools will pause the game when they +open, regardless of your settings in `gui/control-panel`. You can still unpause +with the keyboard (spacebar by default), though. Where do I go next? ------------------- To recap: -You can get to popular, relevant tools for the current context by hovering -the mouse over the DFHack logo or by hitting Ctrl-Shift-C. +You can get to popular, relevant tools for the current context by clicking on +the DFHack logo or by hitting Ctrl-Shift-C. You can enable DFHack tools and configure settings with `gui/control-panel`, -which you can access directly with the Ctrl-Shift-E hotkey. +which you can open from the DFHack logo or access directly with the +Ctrl-Shift-E hotkey. You can get to the launcher and its integrated autocomplete, history search, and help text by hitting backtick (\`) or Ctrl-Shift-D, or, of course, by -running it from the logo hover list. +running it from the logo menu list. With those three interfaces, you have the complete DFHack tool suite at your -fingertips. So what to run first? Here are a few commands to get you started. -You can run them all from the launcher. +fingertips. So what to run first? Here are a few examples to get you started. First, let's import some useful manager orders to keep your fort stocked with basic necessities. Run ``orders import library/basic``. If you go to your -manager orders screen, you can see all the orders that have been created for you. -Note that you could have imported the orders directly from this screen as well, -using the DFHack `overlay` widget at the bottom of the manager orders panel. - -Next, try setting up `autochop` to automatically designate trees for chopping when -you get low on usable logs. Run `gui/control-panel` and select ``autochop`` in the -``Fort`` list. Click on the button to the left of the name or hit Enter to enable -it. You can then click on the configure button (the gear icon) to launch -`gui/autochop` if you'd like to customize its settings. If you have the extra -screen space, you can go ahead and set the `gui/autochop` window to minimal mode -(click on the hint near the upper right corner of the window or hit Alt-M) and -click on the map so the window loses keyboard focus. As you play the game, you can -glance at the live status panel to check on your stocks of wood. - -Finally, let's do some fort design copy-pasting. Go to some bedrooms that you have -set up in your fort. Run `gui/blueprint`, set a name for your blueprint by -clicking on the name field (or hitting the 'n' hotkey), typing "rooms" (or whatever) -and hitting Enter to set. Then draw a box around the target area by clicking with -the mouse. When you select the second corner, the blueprint will be saved to your -``blueprints`` subfolder. - -Now open up `gui/quickfort`. You can search for the blueprint you just created by -typing its name, but it should be up near the top already. If you copied a dug-out -area with furniture in it, your blueprint will have two labels: "/dig" and "/build". -Click on the "/dig" blueprint or select it with the keyboard arrow keys and hit Enter. -You can rotate or flip the blueprint around if you need to with the transform hotkeys. -You'll see a preview of where the blueprint will be applied as you move the mouse -cursor around the map. Red outlines mean that the blueprint may fail to fully apply -at that location, so be sure to choose a spot where all the preview tiles are shown -with green diamonds. Click the mouse or hit Enter to apply the blueprint and -designate the tiles for digging. Your dwarves will come and dig it out as if you -had designated the tiles yourself. - -Once the area is dug out, run `gui/quickfort` again and select the "/build" blueprint -this time. Apply the blueprint in the dug-out area, and your furniture will be -designated. It's just that easy! Note that `quickfort` uses `buildingplan` to place -buildings, so you don't even need to have the relevant furniture or building -materials in stock. The planned furniture/buildings will get built whenever you are -able to produce the building materials. +manager orders screen, you can see all the orders that have been created for +you. Note that you could have imported the orders directly from this screen as +well, using the DFHack `overlay` widget at the bottom of the manager orders +panel. + +Next, try setting up `autochop` to automatically designate trees for chopping +when you get low on usable logs. Run `gui/control-panel` and select +``autochop`` in the ``Fort`` list. Click on the button to the left of the name +or hit Enter to enable it. You can then click on the configure button (the gear +icon) to launch `gui/autochop` if you'd like to customize its settings. If you +have the extra screen space, you can go ahead and set the `gui/autochop` window +to minimal mode (click on the hint near the upper right corner of the window or +hit Alt-M) and click on the map so the window loses keyboard focus. As you play +the game, you can glance at the live status panel to check on your stocks of +wood. + +Finally, let's do some fort design copy-pasting. Go to some bedrooms that you +have set up in your fort. Run `gui/blueprint`, set a name for your blueprint by +clicking on the name field (or hitting the 'n' hotkey), typing "rooms" (or +whatever) and hitting Enter to set. Then draw a box around the target area by +clicking with the mouse. When you select the second corner, the blueprint will +be saved to your ``dfhack-config/blueprints`` subfolder. + +Now open up `gui/quickfort`. You can search for the blueprint you just created +by typing its name, but it should be up near the top already. If you copied a +dug-out area with furniture in it, your blueprint will have two labels: "/dig" +and "/build". Click on the "/dig" blueprint or select it with the keyboard +arrow keys and hit Enter. You can rotate or flip the blueprint around if you +need to with the transform hotkeys. You'll see a preview of where the blueprint +will be applied as you move the mouse cursor around the map. Red outlines mean +that the blueprint may fail to fully apply at that location, so be sure to +choose a spot where all the preview tiles are shown with green diamonds. Click +the mouse or hit Enter to apply the blueprint and designate the tiles for +digging. Your dwarves will come and dig it out as if you had designated the +tiles yourself. + +Once the area is dug out, run `gui/quickfort` again and select your "/build" +blueprint this time. Hit `o` to generate manager orders for the required +furniture. Apply the blueprint in the dug-out area, and your furniture will be +designated. It's just that easy! Note that `quickfort` uses `buildingplan` to +place buildings, so you don't even need to have the relevant furniture or +building materials in stock yet. The planned furniture/buildings will get built +whenever you are able to produce the building materials. There are many, many more tools to explore. Have fun! From 2a0f5a547402af84d2ad0d46532537bac80081cc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 14 Sep 2023 11:54:41 -0700 Subject: [PATCH 545/851] fix typo in quickstart guide --- docs/Quickstart.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst index 8016a99b2..10349a65f 100644 --- a/docs/Quickstart.rst +++ b/docs/Quickstart.rst @@ -207,7 +207,7 @@ digging. Your dwarves will come and dig it out as if you had designated the tiles yourself. Once the area is dug out, run `gui/quickfort` again and select your "/build" -blueprint this time. Hit `o` to generate manager orders for the required +blueprint this time. Hit ``o`` to generate manager orders for the required furniture. Apply the blueprint in the dug-out area, and your furniture will be designated. It's just that easy! Note that `quickfort` uses `buildingplan` to place buildings, so you don't even need to have the relevant furniture or From ca32e6a1aec3475e169e9659c252cb726745909c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 14 Sep 2023 12:38:19 -0700 Subject: [PATCH 546/851] update version and refs for 50.09-r4 --- CMakeLists.txt | 2 +- docs/changelog.txt | 20 +++++++++++++++++--- library/xml | 2 +- scripts | 2 +- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5bb5cab7a..2fd499c1c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.09") -set(DFHACK_RELEASE "r3") +set(DFHACK_RELEASE "r4") set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/docs/changelog.txt b/docs/changelog.txt index 36636d001..c29879631 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -53,6 +53,22 @@ Template for new versions: ## New Tools +## New Features + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 50.09-r4 + ## New Features - `dig`: new overlay for ASCII mode that visualizes designations for smoothing, engraving, carving tracks, and carving fortifications @@ -62,7 +78,7 @@ Template for new versions: - `gui/mod-manager`: don't continue to display overlay after the raws loading progress bar appears ## Misc Improvements -- `sort`: sort by need for training on squad assignment screen +- `sort`: add sort option for training need on squad assignment screen - `sort`: filter mothers with infants, units with weak mental fortitude, and critically injured units on the squad assignment screen - `sort`: display a rating relative to the current sort order next to the visible units on the squad assignment screen @@ -75,8 +91,6 @@ Template for new versions: ## Lua - ``argparse.boolean``: convert arguments to lua boolean values. -## Removed - # 50.09-r3 ## New Features diff --git a/library/xml b/library/xml index ecbd6f684..d5f808c73 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ecbd6f684abd79d4438fe4ab48b3b0126bbc21d1 +Subproject commit d5f808c73973432b7d04277acaa571e0ab385141 diff --git a/scripts b/scripts index 2ecd256e7..0f457b565 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 2ecd256e7a15fd9134e0a27fbcacae419cf94a23 +Subproject commit 0f457b56595f0e7eaba8300a6870af406b1154f6 From a13159bc35265ec169fa6597f09e8b0e7e8f5822 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Thu, 14 Sep 2023 17:42:15 -0500 Subject: [PATCH 547/851] use `TerminateProcess` for die on windows evades issues with the stacktrace logger in 50.10 --- library/Core.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/Core.cpp b/library/Core.cpp index 176d5014d..032e2b0be 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1033,7 +1033,11 @@ command_result Core::runCommand(color_ostream &con, const std::string &first_, s } else if (first == "die") { +#ifdef WIN32 + TerminateProcess(GetCurrentProcess(),666); +#else std::_Exit(666); +#endif } else if (first == "kill-lua") { From ac5d9decd2ed57e0569fb8cf0db5cf18a1fa8663 Mon Sep 17 00:00:00 2001 From: Jacek Konieczny Date: Fri, 15 Sep 2023 20:04:24 +0200 Subject: [PATCH 548/851] linux: preserve existing LD_PRELOAD content that is needed for Steam overlay and game streaming to work fixes https://github.com/DFHack/dfhack/issues/3768 --- docs/about/Authors.rst | 1 + docs/changelog.txt | 1 + package/linux/dfhack | 16 ++++++++-------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/about/Authors.rst b/docs/about/Authors.rst index 4b5d4e0c2..e81649d8d 100644 --- a/docs/about/Authors.rst +++ b/docs/about/Authors.rst @@ -83,6 +83,7 @@ Herwig Hochleitner bendlas Hevlikn Hevlikn Ian S kremlin- IndigoFenix +Jacek Konieczny Jajcus James 20k James Gilles kazimuth James Logsdon jlogsdon diff --git a/docs/changelog.txt b/docs/changelog.txt index c29879631..6579cf1a8 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -56,6 +56,7 @@ Template for new versions: ## New Features ## Fixes +- Linux launcher: preserve LD_PRELOAD set by Steam, so Steam Overlay and game streaming works ## Misc Improvements diff --git a/package/linux/dfhack b/package/linux/dfhack index a83da71b4..fab3d0602 100755 --- a/package/linux/dfhack +++ b/package/linux/dfhack @@ -60,7 +60,7 @@ fi case "$1" in -g | --gdb) shift - echo "set exec-wrapper env LD_LIBRARY_PATH='$LD_LIBRARY_PATH' LD_PRELOAD='$PRELOAD_LIB' MALLOC_PERTURB_=45" > gdbcmd.tmp + echo "set exec-wrapper env LD_LIBRARY_PATH='$LD_LIBRARY_PATH' LD_PRELOAD='${LD_PRELOAD:+$LD_PRELOAD:}$PRELOAD_LIB' MALLOC_PERTURB_=45" > gdbcmd.tmp gdb $DF_GDB_OPTS -x gdbcmd.tmp --args ./dwarfort "$@" rm gdbcmd.tmp ret=$? @@ -95,35 +95,35 @@ case "$1" in ;; -h | --helgrind) shift - LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_HELGRIND_OPTS --tool=helgrind --log-file=helgrind.log ./dwarfort "$@" + LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_HELGRIND_OPTS --tool=helgrind --log-file=helgrind.log ./dwarfort "$@" ret=$? ;; -v | --valgrind) shift - LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_VALGRIND_OPTS --log-file=valgrind.log ./dwarfort "$@" + LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_VALGRIND_OPTS --log-file=valgrind.log ./dwarfort "$@" ret=$? ;; -c | --callgrind) shift - LD_PRELOAD="$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_CALLGRIND_OPTS --tool=callgrind --separate-threads=yes --dump-instr=yes --instr-atstart=no --log-file=callgrind.log ./dwarfort "$@" + LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}$PRELOAD_LIB" setarch "$setarch_arch" -R valgrind $DF_CALLGRIND_OPTS --tool=callgrind --separate-threads=yes --dump-instr=yes --instr-atstart=no --log-file=callgrind.log ./dwarfort "$@" ret=$? ;; --strace) shift - strace -f setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./dwarfort "$@" 2> strace.log + strace -f setarch "$setarch_arch" -R env LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}$PRELOAD_LIB" ./dwarfort "$@" 2> strace.log ret=$? ;; -x | --exec) - exec setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./dwarfort "$@" + exec setarch "$setarch_arch" -R env LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}$PRELOAD_LIB" ./dwarfort "$@" # script does not resume ;; --sc | --sizecheck) PRELOAD_LIB="${PRELOAD_LIB:+$PRELOAD_LIB:}./hack/libsizecheck.so" - MALLOC_PERTURB_=45 setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./dwarfort "$@" + MALLOC_PERTURB_=45 setarch "$setarch_arch" -R env LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}$PRELOAD_LIB" ./dwarfort "$@" ret=$? ;; *) - setarch "$setarch_arch" -R env LD_PRELOAD="$PRELOAD_LIB" ./dwarfort "$@" + setarch "$setarch_arch" -R env LD_PRELOAD="${LD_PRELOAD:+$LD_PRELOAD:}$PRELOAD_LIB" ./dwarfort "$@" ret=$? ;; esac From 28b00d9f210fca0fa6810a0aa61cbeb3f87263c0 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sat, 16 Sep 2023 01:24:47 +0300 Subject: [PATCH 549/851] Tweaked military formula to be more informative about strong warriors. Added options to sort and reset manager orders to the 'o' screen. --- plugins/lua/orders.lua | 37 +++++++++++- plugins/lua/sort.lua | 74 +++++++++++------------ plugins/orders.cpp | 131 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+), 39 deletions(-) diff --git a/plugins/lua/orders.lua b/plugins/lua/orders.lua index 7a87e529f..91fd3bef6 100644 --- a/plugins/lua/orders.lua +++ b/plugins/lua/orders.lua @@ -62,12 +62,24 @@ local function do_export() }:show() end +local function do_reset() + dfhack.run_command('orders', 'reset') +end + +local function do_sort_type() + dfhack.run_command('orders', 'sort_type') +end + +local function do_sort_mat() + dfhack.run_command('orders', 'sort_material') +end + OrdersOverlay = defclass(OrdersOverlay, overlay.OverlayWidget) OrdersOverlay.ATTRS{ default_pos={x=53,y=-6}, default_enabled=true, viewscreens='dwarfmode/Info/WORK_ORDERS/Default', - frame={w=30, h=4}, + frame={w=75, h=4}, } function OrdersOverlay:init() @@ -95,13 +107,34 @@ function OrdersOverlay:init() }, widgets.HotkeyLabel{ frame={t=0, l=15}, - label='sort', + label='sort by freq', key='CUSTOM_CTRL_O', auto_width=true, on_activate=do_sort, }, widgets.HotkeyLabel{ frame={t=1, l=15}, + label='sort by type', + key='CUSTOM_CTRL_T', + auto_width=true, + on_activate=do_sort_type, + }, + widgets.HotkeyLabel{ + frame={t=0, l=35}, + label='sort by mat', + key='CUSTOM_CTRL_T', + auto_width=true, + on_activate=do_sort_mat, + }, + widgets.HotkeyLabel{ + frame={t=1, l=35}, + label='reset', + key='CUSTOM_CTRL_R', + auto_width=true, + on_activate=do_reset, + }, + widgets.HotkeyLabel{ + frame={t=1, l=55}, label='clear', key='CUSTOM_CTRL_C', auto_width=true, diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 15d9ebabb..778bc87b9 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -212,7 +212,7 @@ local function melee_skill_effectiveness(unit) end local function get_melee_skill_effectiveness_rating(unit) - return get_rating(melee_skill_effectiveness(unit), 350000, 2350000, 78, 64, 49, 35) + return get_rating(melee_skill_effectiveness(unit), 350000, 2750000, 64, 52, 40, 28) end local function make_sort_by_melee_skill_effectiveness_desc() @@ -272,7 +272,7 @@ local function ranged_skill_effectiveness(unit) end local function get_ranged_skill_effectiveness_rating(unit) - return get_rating(ranged_skill_effectiveness(unit), 0, 500000, 90, 62, 44, 27) + return get_rating(ranged_skill_effectiveness(unit), 0, 800000, 72, 52, 31, 11) end local function make_sort_by_ranged_skill_effectiveness_desc(list) @@ -345,41 +345,41 @@ end -- Statistical rating that is higher for dwarves that are mentally stable local function get_mental_stability(unit) - local ALTRUISM = unit.status.current_soul.personality.traits.ALTRUISM - local ANXIETY_PROPENSITY = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY - local BRAVERY = unit.status.current_soul.personality.traits.BRAVERY - local CHEER_PROPENSITY = unit.status.current_soul.personality.traits.CHEER_PROPENSITY - local CURIOUS = unit.status.current_soul.personality.traits.CURIOUS - local DISCORD = unit.status.current_soul.personality.traits.DISCORD - local DUTIFULNESS = unit.status.current_soul.personality.traits.DUTIFULNESS - local EMOTIONALLY_OBSESSIVE = unit.status.current_soul.personality.traits.EMOTIONALLY_OBSESSIVE - local HUMOR = unit.status.current_soul.personality.traits.HUMOR - local LOVE_PROPENSITY = unit.status.current_soul.personality.traits.LOVE_PROPENSITY - local PERSEVERENCE = unit.status.current_soul.personality.traits.PERSEVERENCE - local POLITENESS = unit.status.current_soul.personality.traits.POLITENESS - local PRIVACY = unit.status.current_soul.personality.traits.PRIVACY - local STRESS_VULNERABILITY = unit.status.current_soul.personality.traits.STRESS_VULNERABILITY - local TOLERANT = unit.status.current_soul.personality.traits.TOLERANT - - local CRAFTSMANSHIP = setbelief.getUnitBelief(unit, df.value_type['CRAFTSMANSHIP']) - local FAMILY = setbelief.getUnitBelief(unit, df.value_type['FAMILY']) - local HARMONY = setbelief.getUnitBelief(unit, df.value_type['HARMONY']) - local INDEPENDENCE = setbelief.getUnitBelief(unit, df.value_type['INDEPENDENCE']) - local KNOWLEDGE = setbelief.getUnitBelief(unit, df.value_type['KNOWLEDGE']) - local LEISURE_TIME = setbelief.getUnitBelief(unit, df.value_type['LEISURE_TIME']) - local NATURE = setbelief.getUnitBelief(unit, df.value_type['NATURE']) - local SKILL = setbelief.getUnitBelief(unit, df.value_type['SKILL']) - - -- Calculate the rating using the defined variables - local rating = (CRAFTSMANSHIP * -0.01) + (FAMILY * -0.09) + (HARMONY * 0.05) - + (INDEPENDENCE * 0.06) + (KNOWLEDGE * -0.30) + (LEISURE_TIME * 0.24) - + (NATURE * 0.27) + (SKILL * -0.21) + (ALTRUISM * 0.13) - + (ANXIETY_PROPENSITY * -0.06) + (BRAVERY * 0.06) - + (CHEER_PROPENSITY * 0.41) + (CURIOUS * -0.06) + (DISCORD * 0.14) - + (DUTIFULNESS * -0.03) + (EMOTIONALLY_OBSESSIVE * -0.13) - + (HUMOR * -0.05) + (LOVE_PROPENSITY * 0.15) + (PERSEVERENCE * -0.07) - + (POLITENESS * -0.14) + (PRIVACY * 0.03) + (STRESS_VULNERABILITY * -0.20) - + (TOLERANT * -0.11) + local altruism = unit.status.current_soul.personality.traits.ALTRUISM + local anxiety_propensity = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY + local bravery = unit.status.current_soul.personality.traits.BRAVERY + local cheer_propensity = unit.status.current_soul.personality.traits.CHEER_PROPENSITY + local curious = unit.status.current_soul.personality.traits.CURIOUS + local discord = unit.status.current_soul.personality.traits.DISCORD + local dutifulness = unit.status.current_soul.personality.traits.DUTIFULNESS + local emotionally_obsessive = unit.status.current_soul.personality.traits.EMOTIONALLY_OBSESSIVE + local humor = unit.status.current_soul.personality.traits.HUMOR + local love_propensity = unit.status.current_soul.personality.traits.LOVE_PROPENSITY + local perseverence = unit.status.current_soul.personality.traits.PERSEVERENCE + local politeness = unit.status.current_soul.personality.traits.POLITENESS + local privacy = unit.status.current_soul.personality.traits.PRIVACY + local stress_vulnerability = unit.status.current_soul.personality.traits.STRESS_VULNERABILITY + local tolerant = unit.status.current_soul.personality.traits.TOLERANT + + local craftsmanship = setbelief.getUnitBelief(unit, df.value_type['CRAFTSMANSHIP']) + local family = setbelief.getUnitBelief(unit, df.value_type['FAMILY']) + local harmony = setbelief.getUnitBelief(unit, df.value_type['HARMONY']) + local independence = setbelief.getUnitBelief(unit, df.value_type['INDEPENDENCE']) + local knowledge = setbelief.getUnitBelief(unit, df.value_type['KNOWLEDGE']) + local leisure_time = setbelief.getUnitBelief(unit, df.value_type['LEISURE_TIME']) + local nature = setbelief.getUnitBelief(unit, df.value_type['NATURE']) + local skill = setbelief.getUnitBelief(unit, df.value_type['SKILL']) + + -- calculate the rating using the defined variables + local rating = (craftsmanship * -0.01) + (family * -0.09) + (harmony * 0.05) + + (independence * 0.06) + (knowledge * -0.30) + (leisure_time * 0.24) + + (nature * 0.27) + (skill * -0.21) + (altruism * 0.13) + + (anxiety_propensity * -0.06) + (bravery * 0.06) + + (cheer_propensity * 0.41) + (curious * -0.06) + (discord * 0.14) + + (dutifulness * -0.03) + (emotionally_obsessive * -0.13) + + (humor * -0.05) + (love_propensity * 0.15) + (perseverence * -0.07) + + (politeness * -0.14) + (privacy * 0.03) + (stress_vulnerability * -0.20) + + (tolerant * -0.11) return rating end diff --git a/plugins/orders.cpp b/plugins/orders.cpp index e3c57d0f1..ceaf84196 100644 --- a/plugins/orders.cpp +++ b/plugins/orders.cpp @@ -64,6 +64,9 @@ static command_result orders_export_command(color_ostream & out, const std::stri static command_result orders_import_command(color_ostream & out, const std::string & name); static command_result orders_clear_command(color_ostream & out); static command_result orders_sort_command(color_ostream & out); +static command_result orders_sort_type_command(color_ostream & out); +static command_result orders_sort_material_command(color_ostream & out); +static command_result orders_reset_command(color_ostream & out); static command_result orders_command(color_ostream & out, std::vector & parameters) { @@ -111,6 +114,21 @@ static command_result orders_command(color_ostream & out, std::vectorreaction_name.empty(); + bool b_has_reaction_name = !b->reaction_name.empty(); + + if (a_has_reaction_name != b_has_reaction_name) + { + return a_has_reaction_name; + } + else if (a_has_reaction_name && b_has_reaction_name) + { + if (a->reaction_name != b->reaction_name) + { + return a->reaction_name < b->reaction_name; + } + } + + // Compare job_type + return enum_item_key(a->job_type) < enum_item_key(b->job_type); +} + +static command_result orders_sort_type_command(color_ostream & out) +{ + CoreSuspender suspend; + if (!std::is_sorted(world->manager_orders.begin(), + world->manager_orders.end(), + compare_type)) + { + std::stable_sort(world->manager_orders.begin(), + world->manager_orders.end(), + compare_type); + out << "Manager orders are sorted by job type." << std::endl; + } + + return CR_OK; +} + +static bool compare_material(df::manager_order *a, df::manager_order *b) +{ + // Goal: Sort orders to easily find them in the list and to see dupclicated orders. + // Sorting by materials + + // Determine if only one of the orders has mat_type + bool a_has_material = (a->mat_type != -1 || a->mat_index != -1); + bool b_has_material = (b->mat_type != -1 || b->mat_index != -1); + + if (a_has_material != b_has_material) + { + return a_has_material; + } + else if (a_has_material && b_has_material) + { + // Compare mat_type using MaterialInfo + if (MaterialInfo(a).getToken() != MaterialInfo(b).getToken()) + { + return MaterialInfo(a).getToken() < MaterialInfo(b).getToken(); + } + } + + // Determine if only one order has material_category + bool a_has_material_category = (a->material_category.whole != 0); + bool b_has_material_category = (b->material_category.whole != 0); + + if (a_has_material_category != b_has_material_category) + { + return a_has_material_category; + } + else if (a_has_material_category && b_has_material_category) + { + std::vector a_mats, b_mats; + bitfield_to_string(&a_mats, a->material_category); + bitfield_to_string(&b_mats, b->material_category); + + // Checking that mats are not empty just in case + if (!a_mats.empty() && !b_mats.empty() && a_mats[0] != b_mats[0]) + { + return a_mats[0] < b_mats[0]; + } + } + + // By default orders are equal + return false; +} +static command_result orders_sort_material_command(color_ostream & out) +{ + CoreSuspender suspend; + if (!std::is_sorted(world->manager_orders.begin(), + world->manager_orders.end(), + compare_material)) + { + std::stable_sort(world->manager_orders.begin(), + world->manager_orders.end(), + compare_material); + out << "Manager orders are sorted by material." << std::endl; + } + + return CR_OK; +} + +static command_result orders_reset_command(color_ostream & out) +{ + for (auto it : world->manager_orders) + { + it->status.bits.active = false; + it->status.bits.validated = false; + } + return CR_OK; +} \ No newline at end of file From 03a24c7cff4acb99e99b9428647c8373cbcdaad3 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 16 Sep 2023 07:11:54 +0000 Subject: [PATCH 550/851] 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 d5f808c73..d72558199 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit d5f808c73973432b7d04277acaa571e0ab385141 +Subproject commit d72558199aca591cc6cf778d0fe75dba8793059e From 69be3be35963569f9edf56f0e75b2a6ef8407276 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sat, 16 Sep 2023 14:18:06 +0300 Subject: [PATCH 551/851] Added sorting by job type and by material for manager orders. Added shortcuts to the manager menu for new functions. --- docs/plugins/orders.rst | 12 ++++++++++++ plugins/lua/orders.lua | 34 +++++++++++++++++----------------- plugins/orders.cpp | 29 ++++++++++++++++++++++++++--- 3 files changed, 55 insertions(+), 20 deletions(-) diff --git a/docs/plugins/orders.rst b/docs/plugins/orders.rst index 46a004081..4affa01b3 100644 --- a/docs/plugins/orders.rst +++ b/docs/plugins/orders.rst @@ -17,10 +17,22 @@ Usage manager orders. It will not clear the orders that already exist. ``orders clear`` Deletes all manager orders in the current embark. +``orders reset`` + Invalidates manager orders forcing material conditions recheck. ``orders sort`` Sorts current manager orders by repeat frequency so repeating orders don't prevent one-time orders from ever being completed. The sorting order is: one-time orders first, then yearly, seasonally, monthly, and finally, daily. +``orders sort_type`` + Sorts current manager orders by job type, making it easier to locate orders + that produce similar items. The sorting is done by reaction name, job type + and item subtype. If orders are equal by these fields the sorting falls back + to sort by frequency. +``orders sort_material`` + Sorts current manager orders by material, making it easier to locate orders + that produce items of the same material. The sorting is done by material type + and material category. If orders are equal by these fields the sorting falls back + to sort by job type. You can keep your orders automatically sorted by adding the following command to your ``dfhack-config/init/onMapLoad.init`` file:: diff --git a/plugins/lua/orders.lua b/plugins/lua/orders.lua index 91fd3bef6..510e88b8c 100644 --- a/plugins/lua/orders.lua +++ b/plugins/lua/orders.lua @@ -79,7 +79,7 @@ OrdersOverlay.ATTRS{ default_pos={x=53,y=-6}, default_enabled=true, viewscreens='dwarfmode/Info/WORK_ORDERS/Default', - frame={w=75, h=4}, + frame={w=73, h=4}, } function OrdersOverlay:init() @@ -107,39 +107,39 @@ function OrdersOverlay:init() }, widgets.HotkeyLabel{ frame={t=0, l=15}, + label='reset', + key='CUSTOM_CTRL_R', + auto_width=true, + on_activate=do_reset, + }, + widgets.HotkeyLabel{ + frame={t=1, l=15}, + label='clear', + key='CUSTOM_CTRL_C', + auto_width=true, + on_activate=do_clear, + }, + widgets.HotkeyLabel{ + frame={t=0, l=30}, label='sort by freq', key='CUSTOM_CTRL_O', auto_width=true, on_activate=do_sort, }, widgets.HotkeyLabel{ - frame={t=1, l=15}, + frame={t=1, l=30}, label='sort by type', key='CUSTOM_CTRL_T', auto_width=true, on_activate=do_sort_type, }, widgets.HotkeyLabel{ - frame={t=0, l=35}, + frame={t=0, l=52}, label='sort by mat', key='CUSTOM_CTRL_T', auto_width=true, on_activate=do_sort_mat, }, - widgets.HotkeyLabel{ - frame={t=1, l=35}, - label='reset', - key='CUSTOM_CTRL_R', - auto_width=true, - on_activate=do_reset, - }, - widgets.HotkeyLabel{ - frame={t=1, l=55}, - label='clear', - key='CUSTOM_CTRL_C', - auto_width=true, - on_activate=do_clear, - }, }, } diff --git a/plugins/orders.cpp b/plugins/orders.cpp index ceaf84196..7fcefa745 100644 --- a/plugins/orders.cpp +++ b/plugins/orders.cpp @@ -1056,7 +1056,29 @@ static bool compare_type(df::manager_order *a, df::manager_order *b) } // Compare job_type - return enum_item_key(a->job_type) < enum_item_key(b->job_type); + if (enum_item_key(a->job_type) != enum_item_key(b->job_type)) + { + return enum_item_key(a->job_type) < enum_item_key(b->job_type); + } + + // Compare item subtype + bool a_has_item_subtype = (a->item_subtype != -1); + bool b_has_item_subtype = (b->item_subtype != -1); + + if (a_has_item_subtype != b_has_item_subtype) + { + return a_has_item_subtype; + } + else if (a_has_item_subtype && b_has_item_subtype) + { + if (a->item_subtype != b->item_subtype) + { + return a->item_subtype < b->item_subtype; + } + } + + // Fall back to freq sort + return compare_freq(a, b); } static command_result orders_sort_type_command(color_ostream & out) @@ -1118,9 +1140,10 @@ static bool compare_material(df::manager_order *a, df::manager_order *b) } } - // By default orders are equal - return false; + // Fall back to material sort + return compare_type(a, b); } + static command_result orders_sort_material_command(color_ostream & out) { CoreSuspender suspend; From ebb190e3569daa534fe8363b03fe7027d695b427 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 16 Sep 2023 11:37:11 +0000 Subject: [PATCH 552/851] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- plugins/orders.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/orders.cpp b/plugins/orders.cpp index 7fcefa745..12eb08640 100644 --- a/plugins/orders.cpp +++ b/plugins/orders.cpp @@ -1060,7 +1060,7 @@ static bool compare_type(df::manager_order *a, df::manager_order *b) { return enum_item_key(a->job_type) < enum_item_key(b->job_type); } - + // Compare item subtype bool a_has_item_subtype = (a->item_subtype != -1); bool b_has_item_subtype = (b->item_subtype != -1); @@ -1168,4 +1168,4 @@ static command_result orders_reset_command(color_ostream & out) it->status.bits.validated = false; } return CR_OK; -} \ No newline at end of file +} From aec29502777a76c9dd0f025c3f03ac2df3acc5c6 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sun, 17 Sep 2023 01:38:07 -0500 Subject: [PATCH 553/851] update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 2b16f8d6b..0f457b565 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 2b16f8d6bb09652458771439072d29823aa8c264 +Subproject commit 0f457b56595f0e7eaba8300a6870af406b1154f6 From 1c704fad6c47f6149b010a03dbd77019047ed0c0 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 17 Sep 2023 07:11:59 +0000 Subject: [PATCH 554/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 0f457b565..f7706b0b2 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 0f457b56595f0e7eaba8300a6870af406b1154f6 +Subproject commit f7706b0b2ac0f28bcd1f48c05edc5786aaf05b6c From c2448654cae1a78068c025be48fdfbec7fef2962 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sun, 17 Sep 2023 03:03:14 -0500 Subject: [PATCH 555/851] Update scripts --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 0f457b565..f7706b0b2 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 0f457b56595f0e7eaba8300a6870af406b1154f6 +Subproject commit f7706b0b2ac0f28bcd1f48c05edc5786aaf05b6c From 9905fc7eafad5a8b4e4a3658826797bf0f0c0467 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 17 Sep 2023 21:16:17 -0700 Subject: [PATCH 556/851] update version to 50.10-r1 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a6d1b7c41..74c37d4c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.10") -set(DFHACK_RELEASE "beta1") -set(DFHACK_PRERELEASE TRUE) +set(DFHACK_RELEASE "r1") +set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_ABI_VERSION 1) From a8c4456c773e35a786e33a58ecef34ed493dc520 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 17 Sep 2023 21:16:35 -0700 Subject: [PATCH 557/851] update xml ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index d72558199..5f8d3f96f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit d72558199aca591cc6cf778d0fe75dba8793059e +Subproject commit 5f8d3f96f2db6c5bddeb07cfda3c0541a5b3f710 From dc270abd0c431bd9fe9db9a6fbe69b433c1b56e3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 16 Sep 2023 19:07:45 -0700 Subject: [PATCH 558/851] add wheelbarrows back to dreamfort stockpiles --- data/blueprints/dreamfort.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data/blueprints/dreamfort.csv b/data/blueprints/dreamfort.csv index f82fa3584..31ba9512e 100644 --- a/data/blueprints/dreamfort.csv +++ b/data/blueprints/dreamfort.csv @@ -1431,7 +1431,7 @@ doors/farming_doors ,,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{name=""Refuse feeder"" give_to=""Rawhides"" take_from=""Starting cloth/trash""}:+cat_refuse/type(1x3)","y2{name=""Corpse feeder"" take_from=""Starting cloth/trash""}:+cat_refuse/corpses,bodyparts(2x3)",~,,c,c,,,c,c,c,c,c,c,c ,,c,c,c,c,c,c,c,,`,`,`,,~,~,~,,`,`,`,,c,c,c,c,c,c,c ,,c,c,c,c,c,c,c,,`,`,`,,~,~,~,,`,`,`,,c,c,c,c,c,c,c ,,c,c,c,c,c,c,c,,`,`,`,,,`,,,`,`,`,,c,c,c,c,c,c,c @@ -1687,7 +1687,7 @@ build2/industry_build2 ,,w,`,`,`,`,`,`,"w{name=""Wood feeder""}(2x5)",,"g{name=""Goods feeder"" containers=0}:+cat_food/tallow+wax-crafts-goblets(3x3)",,`,,`,`,`,`,`,,"hlS{name=""Cloth/bones feeder"" containers=0}:+cat_refuse/skulls/,bones/,hair/,shells/,teeth/,horns/-adamantinethread(5x5)",,,~,~,`,`,`,`,`,`,c ,,w,`,`,`,`,`,`,~,~,~,~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c ,,`,`,`,`,`,"c{name=""Goods/wood quantum"" quantum=true give_to=""Pots,Barrels,Jugs,Bags,Seeds feeder""}:+all",`,~,~,~,~,~,,`,,`,,`,,~,~,~,~,~,`,"r{name=""Cloth/bones quantum"" quantum=true}:+all",`,`,`,`,c -,,"c{name=""Lye"" barrels=0}:+miscliquid",`,`,`,`,`,`,~,~,"u{name=""Furniture feeder""}:-sand(3x2)",~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c +,,"c{name=""Lye"" barrels=0}:+miscliquid",`,`,`,`,`,`,~,~,"u2{name=""Furniture feeder""}:-sand(3x2)",~,~,`,`,,,,`,`,~,~,~,~,~,`,`,`,`,`,`,c ,,c,`,`,`,`,`,`,~,~,~,~,~,,`,`,`,`,`,,~,~,~,~,~,`,`,`,`,`,`,c ,,c,`,`,`,`,`,`,`,`,`,`,`,,,`,,`,,,`,`,`,`,`,`,`,`,`,`,`,c ,,c,`,`,`,`,`,`,`,`,`,`,`,`,"bnpdz{name=""Bar/military feeder"" containers=0}:-potash+adamantinethread(5x3)",,,,~,`,`,`,`,`,`,`,`,`,`,`,`,c From 48c48baab4a718c7198259b8538425442052cfad Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 16 Sep 2023 19:08:38 -0700 Subject: [PATCH 559/851] allow semi-wild units to be butchered --- docs/changelog.txt | 1 + plugins/autobutcher.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 6579cf1a8..fde3e40a6 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,6 +57,7 @@ Template for new versions: ## Fixes - Linux launcher: preserve LD_PRELOAD set by Steam, so Steam Overlay and game streaming works +- `autobutcher`: allow semi-wild units to be butchered again ## Misc Improvements diff --git a/plugins/autobutcher.cpp b/plugins/autobutcher.cpp index 483e29759..d3d8487de 100644 --- a/plugins/autobutcher.cpp +++ b/plugins/autobutcher.cpp @@ -746,7 +746,8 @@ static bool isInappropriateUnit(df::unit *unit) { static bool isProtectedUnit(df::unit *unit) { return Units::isWar(unit) // ignore war dogs etc || Units::isHunter(unit) // ignore hunting dogs etc - || Units::isMarkedForTraining(unit) // ignore units marked for any kind of training + || Units::isMarkedForWarTraining(unit) // ignore units marked for any kind of training + || Units::isMarkedForHuntTraining(unit) // ignore creatures in built cages which are defined as rooms to leave zoos alone // (TODO: better solution would be to allow some kind of slaughter cages which you can place near the butcher) || (isContainedInItem(unit) && isInBuiltCageRoom(unit)) // !!! see comments in isBuiltCageRoom() From 4695b8c86d0358d0278c0f4f6c7d1d4e73aa825b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 17 Sep 2023 21:22:43 -0700 Subject: [PATCH 560/851] use osyncstream for writing to gamelog.txt --- library/modules/Gui.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 9eee284ac..a191cc130 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -28,7 +28,11 @@ distribution. #include #include #include -using namespace std; +#include + +using std::map; +using std::string; +using std::vector; #include "modules/Gui.h" #include "MemAccess.h" @@ -1397,8 +1401,10 @@ DFHACK_EXPORT void Gui::writeToGamelog(std::string message) return; std::ofstream fseed("gamelog.txt", std::ios::out | std::ios::app); - if(fseed.is_open()) - fseed << message << std::endl; + if(fseed.is_open()) { + std::osyncstream wrapped_fseed(fseed); + wrapped_fseed << message << std::endl; + } fseed.close(); } @@ -1540,7 +1546,7 @@ DFHACK_EXPORT int Gui::makeAnnouncement(df::announcement_type type, df::announce if (flags.bits.D_DISPLAY) { world->status.display_timer = ANNOUNCE_DISPLAY_TIME; - Gui::writeToGamelog('x' + to_string(repeat_count + 1)); + Gui::writeToGamelog('x' + std::to_string(repeat_count + 1)); } return -1; } @@ -1802,7 +1808,7 @@ bool Gui::autoDFAnnouncement(df::report_init r, string message) if (a_flags.bits.D_DISPLAY) { world->status.display_timer = r.display_timer; - Gui::writeToGamelog('x' + to_string(repeat_count + 1)); + Gui::writeToGamelog('x' + std::to_string(repeat_count + 1)); } DEBUG(gui).print("Announcement succeeded as repeat:\n%s\n", message.c_str()); return true; From a61b8d11d09916319e6ed21e7d71bb82138edcc5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 17 Sep 2023 21:38:48 -0700 Subject: [PATCH 561/851] Revert "use osyncstream for writing to gamelog.txt" This reverts commit 4695b8c86d0358d0278c0f4f6c7d1d4e73aa825b. --- library/modules/Gui.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index a191cc130..9eee284ac 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -28,11 +28,7 @@ distribution. #include #include #include -#include - -using std::map; -using std::string; -using std::vector; +using namespace std; #include "modules/Gui.h" #include "MemAccess.h" @@ -1401,10 +1397,8 @@ DFHACK_EXPORT void Gui::writeToGamelog(std::string message) return; std::ofstream fseed("gamelog.txt", std::ios::out | std::ios::app); - if(fseed.is_open()) { - std::osyncstream wrapped_fseed(fseed); - wrapped_fseed << message << std::endl; - } + if(fseed.is_open()) + fseed << message << std::endl; fseed.close(); } @@ -1546,7 +1540,7 @@ DFHACK_EXPORT int Gui::makeAnnouncement(df::announcement_type type, df::announce if (flags.bits.D_DISPLAY) { world->status.display_timer = ANNOUNCE_DISPLAY_TIME; - Gui::writeToGamelog('x' + std::to_string(repeat_count + 1)); + Gui::writeToGamelog('x' + to_string(repeat_count + 1)); } return -1; } @@ -1808,7 +1802,7 @@ bool Gui::autoDFAnnouncement(df::report_init r, string message) if (a_flags.bits.D_DISPLAY) { world->status.display_timer = r.display_timer; - Gui::writeToGamelog('x' + std::to_string(repeat_count + 1)); + Gui::writeToGamelog('x' + to_string(repeat_count + 1)); } DEBUG(gui).print("Announcement succeeded as repeat:\n%s\n", message.c_str()); return true; From 66a93ad0ccf184c8c9594c0d669d15f66f567c02 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 17 Sep 2023 23:32:24 -0700 Subject: [PATCH 562/851] update xml ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 5f8d3f96f..6bf70cdc4 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 5f8d3f96f2db6c5bddeb07cfda3c0541a5b3f710 +Subproject commit 6bf70cdc49837dd55da4a20280fc674cd7991a68 From 64d46af38e33146e62d4e23dde731f9b55dbea80 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 17 Sep 2023 23:52:37 -0700 Subject: [PATCH 563/851] bump to 50.10-r1 --- docs/changelog.txt | 8 ++++++-- library/xml | 2 +- scripts | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fde3e40a6..044cb1ca4 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -56,8 +56,6 @@ Template for new versions: ## New Features ## Fixes -- Linux launcher: preserve LD_PRELOAD set by Steam, so Steam Overlay and game streaming works -- `autobutcher`: allow semi-wild units to be butchered again ## Misc Improvements @@ -69,6 +67,12 @@ Template for new versions: ## Removed +# 50.10-r1 + +## Fixes +- Linux launcher: allow Steam Overlay and game streaming to function +- `autobutcher`: don't ignore semi-wild units when marking units for slaughter + # 50.09-r4 ## New Features diff --git a/library/xml b/library/xml index 6bf70cdc4..53a82ea51 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 6bf70cdc49837dd55da4a20280fc674cd7991a68 +Subproject commit 53a82ea5171cb6fa7e50131eeb0bec801a727fda diff --git a/scripts b/scripts index f7706b0b2..e0591830b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit f7706b0b2ac0f28bcd1f48c05edc5786aaf05b6c +Subproject commit e0591830b72cdfaec5c9bdb1bf713a74fe744788 From 7d3786586acd087aceb5cd005e8e732fe2d8f792 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Mon, 18 Sep 2023 12:28:34 +0300 Subject: [PATCH 564/851] Reverted sort.lua. Changed orders sort by material keybing from T to M. --- plugins/lua/orders.lua | 2 +- plugins/lua/sort.lua | 74 +++++++++++++++++++++--------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/plugins/lua/orders.lua b/plugins/lua/orders.lua index 510e88b8c..a4f3c459f 100644 --- a/plugins/lua/orders.lua +++ b/plugins/lua/orders.lua @@ -136,7 +136,7 @@ function OrdersOverlay:init() widgets.HotkeyLabel{ frame={t=0, l=52}, label='sort by mat', - key='CUSTOM_CTRL_T', + key='CUSTOM_CTRL_M', auto_width=true, on_activate=do_sort_mat, }, diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 778bc87b9..15d9ebabb 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -212,7 +212,7 @@ local function melee_skill_effectiveness(unit) end local function get_melee_skill_effectiveness_rating(unit) - return get_rating(melee_skill_effectiveness(unit), 350000, 2750000, 64, 52, 40, 28) + return get_rating(melee_skill_effectiveness(unit), 350000, 2350000, 78, 64, 49, 35) end local function make_sort_by_melee_skill_effectiveness_desc() @@ -272,7 +272,7 @@ local function ranged_skill_effectiveness(unit) end local function get_ranged_skill_effectiveness_rating(unit) - return get_rating(ranged_skill_effectiveness(unit), 0, 800000, 72, 52, 31, 11) + return get_rating(ranged_skill_effectiveness(unit), 0, 500000, 90, 62, 44, 27) end local function make_sort_by_ranged_skill_effectiveness_desc(list) @@ -345,41 +345,41 @@ end -- Statistical rating that is higher for dwarves that are mentally stable local function get_mental_stability(unit) - local altruism = unit.status.current_soul.personality.traits.ALTRUISM - local anxiety_propensity = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY - local bravery = unit.status.current_soul.personality.traits.BRAVERY - local cheer_propensity = unit.status.current_soul.personality.traits.CHEER_PROPENSITY - local curious = unit.status.current_soul.personality.traits.CURIOUS - local discord = unit.status.current_soul.personality.traits.DISCORD - local dutifulness = unit.status.current_soul.personality.traits.DUTIFULNESS - local emotionally_obsessive = unit.status.current_soul.personality.traits.EMOTIONALLY_OBSESSIVE - local humor = unit.status.current_soul.personality.traits.HUMOR - local love_propensity = unit.status.current_soul.personality.traits.LOVE_PROPENSITY - local perseverence = unit.status.current_soul.personality.traits.PERSEVERENCE - local politeness = unit.status.current_soul.personality.traits.POLITENESS - local privacy = unit.status.current_soul.personality.traits.PRIVACY - local stress_vulnerability = unit.status.current_soul.personality.traits.STRESS_VULNERABILITY - local tolerant = unit.status.current_soul.personality.traits.TOLERANT - - local craftsmanship = setbelief.getUnitBelief(unit, df.value_type['CRAFTSMANSHIP']) - local family = setbelief.getUnitBelief(unit, df.value_type['FAMILY']) - local harmony = setbelief.getUnitBelief(unit, df.value_type['HARMONY']) - local independence = setbelief.getUnitBelief(unit, df.value_type['INDEPENDENCE']) - local knowledge = setbelief.getUnitBelief(unit, df.value_type['KNOWLEDGE']) - local leisure_time = setbelief.getUnitBelief(unit, df.value_type['LEISURE_TIME']) - local nature = setbelief.getUnitBelief(unit, df.value_type['NATURE']) - local skill = setbelief.getUnitBelief(unit, df.value_type['SKILL']) - - -- calculate the rating using the defined variables - local rating = (craftsmanship * -0.01) + (family * -0.09) + (harmony * 0.05) - + (independence * 0.06) + (knowledge * -0.30) + (leisure_time * 0.24) - + (nature * 0.27) + (skill * -0.21) + (altruism * 0.13) - + (anxiety_propensity * -0.06) + (bravery * 0.06) - + (cheer_propensity * 0.41) + (curious * -0.06) + (discord * 0.14) - + (dutifulness * -0.03) + (emotionally_obsessive * -0.13) - + (humor * -0.05) + (love_propensity * 0.15) + (perseverence * -0.07) - + (politeness * -0.14) + (privacy * 0.03) + (stress_vulnerability * -0.20) - + (tolerant * -0.11) + local ALTRUISM = unit.status.current_soul.personality.traits.ALTRUISM + local ANXIETY_PROPENSITY = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY + local BRAVERY = unit.status.current_soul.personality.traits.BRAVERY + local CHEER_PROPENSITY = unit.status.current_soul.personality.traits.CHEER_PROPENSITY + local CURIOUS = unit.status.current_soul.personality.traits.CURIOUS + local DISCORD = unit.status.current_soul.personality.traits.DISCORD + local DUTIFULNESS = unit.status.current_soul.personality.traits.DUTIFULNESS + local EMOTIONALLY_OBSESSIVE = unit.status.current_soul.personality.traits.EMOTIONALLY_OBSESSIVE + local HUMOR = unit.status.current_soul.personality.traits.HUMOR + local LOVE_PROPENSITY = unit.status.current_soul.personality.traits.LOVE_PROPENSITY + local PERSEVERENCE = unit.status.current_soul.personality.traits.PERSEVERENCE + local POLITENESS = unit.status.current_soul.personality.traits.POLITENESS + local PRIVACY = unit.status.current_soul.personality.traits.PRIVACY + local STRESS_VULNERABILITY = unit.status.current_soul.personality.traits.STRESS_VULNERABILITY + local TOLERANT = unit.status.current_soul.personality.traits.TOLERANT + + local CRAFTSMANSHIP = setbelief.getUnitBelief(unit, df.value_type['CRAFTSMANSHIP']) + local FAMILY = setbelief.getUnitBelief(unit, df.value_type['FAMILY']) + local HARMONY = setbelief.getUnitBelief(unit, df.value_type['HARMONY']) + local INDEPENDENCE = setbelief.getUnitBelief(unit, df.value_type['INDEPENDENCE']) + local KNOWLEDGE = setbelief.getUnitBelief(unit, df.value_type['KNOWLEDGE']) + local LEISURE_TIME = setbelief.getUnitBelief(unit, df.value_type['LEISURE_TIME']) + local NATURE = setbelief.getUnitBelief(unit, df.value_type['NATURE']) + local SKILL = setbelief.getUnitBelief(unit, df.value_type['SKILL']) + + -- Calculate the rating using the defined variables + local rating = (CRAFTSMANSHIP * -0.01) + (FAMILY * -0.09) + (HARMONY * 0.05) + + (INDEPENDENCE * 0.06) + (KNOWLEDGE * -0.30) + (LEISURE_TIME * 0.24) + + (NATURE * 0.27) + (SKILL * -0.21) + (ALTRUISM * 0.13) + + (ANXIETY_PROPENSITY * -0.06) + (BRAVERY * 0.06) + + (CHEER_PROPENSITY * 0.41) + (CURIOUS * -0.06) + (DISCORD * 0.14) + + (DUTIFULNESS * -0.03) + (EMOTIONALLY_OBSESSIVE * -0.13) + + (HUMOR * -0.05) + (LOVE_PROPENSITY * 0.15) + (PERSEVERENCE * -0.07) + + (POLITENESS * -0.14) + (PRIVACY * 0.03) + (STRESS_VULNERABILITY * -0.20) + + (TOLERANT * -0.11) return rating end From 68d94ad715797d011d7b52b1cea840a340c73a94 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Mon, 18 Sep 2023 12:49:36 +0300 Subject: [PATCH 565/851] Removed redundant uppercase in mental stability formula. Reworked thresholds for combat skill effectiveness formulas to have a higher 100 cap (more descriptive about very strong warriors). --- plugins/lua/sort.lua | 74 ++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 15d9ebabb..778bc87b9 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -212,7 +212,7 @@ local function melee_skill_effectiveness(unit) end local function get_melee_skill_effectiveness_rating(unit) - return get_rating(melee_skill_effectiveness(unit), 350000, 2350000, 78, 64, 49, 35) + return get_rating(melee_skill_effectiveness(unit), 350000, 2750000, 64, 52, 40, 28) end local function make_sort_by_melee_skill_effectiveness_desc() @@ -272,7 +272,7 @@ local function ranged_skill_effectiveness(unit) end local function get_ranged_skill_effectiveness_rating(unit) - return get_rating(ranged_skill_effectiveness(unit), 0, 500000, 90, 62, 44, 27) + return get_rating(ranged_skill_effectiveness(unit), 0, 800000, 72, 52, 31, 11) end local function make_sort_by_ranged_skill_effectiveness_desc(list) @@ -345,41 +345,41 @@ end -- Statistical rating that is higher for dwarves that are mentally stable local function get_mental_stability(unit) - local ALTRUISM = unit.status.current_soul.personality.traits.ALTRUISM - local ANXIETY_PROPENSITY = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY - local BRAVERY = unit.status.current_soul.personality.traits.BRAVERY - local CHEER_PROPENSITY = unit.status.current_soul.personality.traits.CHEER_PROPENSITY - local CURIOUS = unit.status.current_soul.personality.traits.CURIOUS - local DISCORD = unit.status.current_soul.personality.traits.DISCORD - local DUTIFULNESS = unit.status.current_soul.personality.traits.DUTIFULNESS - local EMOTIONALLY_OBSESSIVE = unit.status.current_soul.personality.traits.EMOTIONALLY_OBSESSIVE - local HUMOR = unit.status.current_soul.personality.traits.HUMOR - local LOVE_PROPENSITY = unit.status.current_soul.personality.traits.LOVE_PROPENSITY - local PERSEVERENCE = unit.status.current_soul.personality.traits.PERSEVERENCE - local POLITENESS = unit.status.current_soul.personality.traits.POLITENESS - local PRIVACY = unit.status.current_soul.personality.traits.PRIVACY - local STRESS_VULNERABILITY = unit.status.current_soul.personality.traits.STRESS_VULNERABILITY - local TOLERANT = unit.status.current_soul.personality.traits.TOLERANT - - local CRAFTSMANSHIP = setbelief.getUnitBelief(unit, df.value_type['CRAFTSMANSHIP']) - local FAMILY = setbelief.getUnitBelief(unit, df.value_type['FAMILY']) - local HARMONY = setbelief.getUnitBelief(unit, df.value_type['HARMONY']) - local INDEPENDENCE = setbelief.getUnitBelief(unit, df.value_type['INDEPENDENCE']) - local KNOWLEDGE = setbelief.getUnitBelief(unit, df.value_type['KNOWLEDGE']) - local LEISURE_TIME = setbelief.getUnitBelief(unit, df.value_type['LEISURE_TIME']) - local NATURE = setbelief.getUnitBelief(unit, df.value_type['NATURE']) - local SKILL = setbelief.getUnitBelief(unit, df.value_type['SKILL']) - - -- Calculate the rating using the defined variables - local rating = (CRAFTSMANSHIP * -0.01) + (FAMILY * -0.09) + (HARMONY * 0.05) - + (INDEPENDENCE * 0.06) + (KNOWLEDGE * -0.30) + (LEISURE_TIME * 0.24) - + (NATURE * 0.27) + (SKILL * -0.21) + (ALTRUISM * 0.13) - + (ANXIETY_PROPENSITY * -0.06) + (BRAVERY * 0.06) - + (CHEER_PROPENSITY * 0.41) + (CURIOUS * -0.06) + (DISCORD * 0.14) - + (DUTIFULNESS * -0.03) + (EMOTIONALLY_OBSESSIVE * -0.13) - + (HUMOR * -0.05) + (LOVE_PROPENSITY * 0.15) + (PERSEVERENCE * -0.07) - + (POLITENESS * -0.14) + (PRIVACY * 0.03) + (STRESS_VULNERABILITY * -0.20) - + (TOLERANT * -0.11) + local altruism = unit.status.current_soul.personality.traits.ALTRUISM + local anxiety_propensity = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY + local bravery = unit.status.current_soul.personality.traits.BRAVERY + local cheer_propensity = unit.status.current_soul.personality.traits.CHEER_PROPENSITY + local curious = unit.status.current_soul.personality.traits.CURIOUS + local discord = unit.status.current_soul.personality.traits.DISCORD + local dutifulness = unit.status.current_soul.personality.traits.DUTIFULNESS + local emotionally_obsessive = unit.status.current_soul.personality.traits.EMOTIONALLY_OBSESSIVE + local humor = unit.status.current_soul.personality.traits.HUMOR + local love_propensity = unit.status.current_soul.personality.traits.LOVE_PROPENSITY + local perseverence = unit.status.current_soul.personality.traits.PERSEVERENCE + local politeness = unit.status.current_soul.personality.traits.POLITENESS + local privacy = unit.status.current_soul.personality.traits.PRIVACY + local stress_vulnerability = unit.status.current_soul.personality.traits.STRESS_VULNERABILITY + local tolerant = unit.status.current_soul.personality.traits.TOLERANT + + local craftsmanship = setbelief.getUnitBelief(unit, df.value_type['CRAFTSMANSHIP']) + local family = setbelief.getUnitBelief(unit, df.value_type['FAMILY']) + local harmony = setbelief.getUnitBelief(unit, df.value_type['HARMONY']) + local independence = setbelief.getUnitBelief(unit, df.value_type['INDEPENDENCE']) + local knowledge = setbelief.getUnitBelief(unit, df.value_type['KNOWLEDGE']) + local leisure_time = setbelief.getUnitBelief(unit, df.value_type['LEISURE_TIME']) + local nature = setbelief.getUnitBelief(unit, df.value_type['NATURE']) + local skill = setbelief.getUnitBelief(unit, df.value_type['SKILL']) + + -- calculate the rating using the defined variables + local rating = (craftsmanship * -0.01) + (family * -0.09) + (harmony * 0.05) + + (independence * 0.06) + (knowledge * -0.30) + (leisure_time * 0.24) + + (nature * 0.27) + (skill * -0.21) + (altruism * 0.13) + + (anxiety_propensity * -0.06) + (bravery * 0.06) + + (cheer_propensity * 0.41) + (curious * -0.06) + (discord * 0.14) + + (dutifulness * -0.03) + (emotionally_obsessive * -0.13) + + (humor * -0.05) + (love_propensity * 0.15) + (perseverence * -0.07) + + (politeness * -0.14) + (privacy * 0.03) + (stress_vulnerability * -0.20) + + (tolerant * -0.11) return rating end From 8826c27fa0f941ee50a866eae74ed969414f4113 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Mon, 18 Sep 2023 13:41:02 +0300 Subject: [PATCH 566/851] Changed 'reset' to recheck for clarity. --- docs/plugins/orders.rst | 2 +- plugins/lua/orders.lua | 8 ++++---- plugins/orders.cpp | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/plugins/orders.rst b/docs/plugins/orders.rst index 4affa01b3..351456e2e 100644 --- a/docs/plugins/orders.rst +++ b/docs/plugins/orders.rst @@ -17,7 +17,7 @@ Usage manager orders. It will not clear the orders that already exist. ``orders clear`` Deletes all manager orders in the current embark. -``orders reset`` +``orders recheck`` Invalidates manager orders forcing material conditions recheck. ``orders sort`` Sorts current manager orders by repeat frequency so repeating orders don't diff --git a/plugins/lua/orders.lua b/plugins/lua/orders.lua index a4f3c459f..b50c28694 100644 --- a/plugins/lua/orders.lua +++ b/plugins/lua/orders.lua @@ -62,8 +62,8 @@ local function do_export() }:show() end -local function do_reset() - dfhack.run_command('orders', 'reset') +local function do_recheck() + dfhack.run_command('orders', 'recheck') end local function do_sort_type() @@ -107,10 +107,10 @@ function OrdersOverlay:init() }, widgets.HotkeyLabel{ frame={t=0, l=15}, - label='reset', + label='recheck', key='CUSTOM_CTRL_R', auto_width=true, - on_activate=do_reset, + on_activate=do_recheck, }, widgets.HotkeyLabel{ frame={t=1, l=15}, diff --git a/plugins/orders.cpp b/plugins/orders.cpp index 12eb08640..4b93cff2d 100644 --- a/plugins/orders.cpp +++ b/plugins/orders.cpp @@ -66,7 +66,7 @@ static command_result orders_clear_command(color_ostream & out); static command_result orders_sort_command(color_ostream & out); static command_result orders_sort_type_command(color_ostream & out); static command_result orders_sort_material_command(color_ostream & out); -static command_result orders_reset_command(color_ostream & out); +static command_result orders_recheck_command(color_ostream & out); static command_result orders_command(color_ostream & out, std::vector & parameters) { @@ -124,9 +124,9 @@ static command_result orders_command(color_ostream & out, std::vectormanager_orders) { From 8e86c5c0ab178930abb072aa5e043c85e81c01bb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 18 Sep 2023 10:06:06 -0700 Subject: [PATCH 567/851] update xml ref --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index 53a82ea51..f1205a08d 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 53a82ea5171cb6fa7e50131eeb0bec801a727fda +Subproject commit f1205a08de0ecfbcf02b641b9591e6d6bb60dc21 From 8d03dd4d71cc8396308f41019d26b49a89f5514c Mon Sep 17 00:00:00 2001 From: lethosor Date: Tue, 19 Sep 2023 18:14:59 -0400 Subject: [PATCH 568/851] Update xml for 50.10-r1.1 --- library/xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/xml b/library/xml index f1205a08d..041493b22 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f1205a08de0ecfbcf02b641b9591e6d6bb60dc21 +Subproject commit 041493b221e0799c106abeac1f86df4535ab80d3 From 3d6d148ad71489acfd705bf0837425a6f250c73a Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Thu, 21 Sep 2023 02:40:03 +0100 Subject: [PATCH 569/851] using namespace std removed and replaced with std:: prefix, to resolve naming conflict of lerp with std::lerp in C++20 --- .../remotefortressreader.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/plugins/remotefortressreader/remotefortressreader.cpp b/plugins/remotefortressreader/remotefortressreader.cpp index 6b5733970..1570a0e60 100644 --- a/plugins/remotefortressreader/remotefortressreader.cpp +++ b/plugins/remotefortressreader/remotefortressreader.cpp @@ -130,7 +130,6 @@ using namespace DFHack; using namespace df::enums; using namespace RemoteFortressReader; -using namespace std; DFHACK_PLUGIN("RemoteFortressReader"); @@ -193,7 +192,7 @@ const char* growth_locations[] = { #include "df/art_image.h" #include "df/art_image_chunk.h" #include "df/art_image_ref.h" -command_result loadArtImageChunk(color_ostream &out, vector & parameters) +command_result loadArtImageChunk(color_ostream &out, std::vector & parameters) { if (parameters.size() != 1) return CR_WRONG_USAGE; @@ -214,7 +213,7 @@ command_result loadArtImageChunk(color_ostream &out, vector & parameter return CR_OK; } -command_result RemoteFortressReader_version(color_ostream &out, vector ¶meters) +command_result RemoteFortressReader_version(color_ostream &out, std::vector ¶meters) { out.print(RFR_VERSION); return CR_OK; @@ -645,7 +644,7 @@ void CopyMat(RemoteFortressReader::MatPair * mat, int type, int index) } -map hashes; +std::map hashes; bool IsTiletypeChanged(DFCoord pos) { @@ -663,7 +662,7 @@ bool IsTiletypeChanged(DFCoord pos) return false; } -map waterHashes; +std::map waterHashes; bool IsDesignationChanged(DFCoord pos) { @@ -681,7 +680,7 @@ bool IsDesignationChanged(DFCoord pos) return false; } -map buildingHashes; +std::map buildingHashes; bool IsBuildingChanged(DFCoord pos) { @@ -700,7 +699,7 @@ bool IsBuildingChanged(DFCoord pos) return changed; } -map spatterHashes; +std::map spatterHashes; bool IsspatterChanged(DFCoord pos) { @@ -737,7 +736,7 @@ bool IsspatterChanged(DFCoord pos) return false; } -map itemHashes; +std::map itemHashes; bool isItemChanged(int i) { @@ -755,7 +754,7 @@ bool isItemChanged(int i) return false; } -bool areItemsChanged(vector * items) +bool areItemsChanged(std::vector * items) { bool result = false; for (size_t i = 0; i < items->size(); i++) @@ -766,7 +765,7 @@ bool areItemsChanged(vector * items) return result; } -map engravingHashes; +std::map engravingHashes; bool isEngravingNew(int index) { From aa6c4094c5fd32ee6e931534cce15cd21194f4bc Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 21 Sep 2023 01:10:52 -0400 Subject: [PATCH 570/851] Use SDL_ShowSimpleMessageBox in Core::fatal() This allows the message to be displayed consistently in a dialog on all platforms. --- library/Core.cpp | 18 ++++++++---------- library/include/modules/DFSDL.h | 2 ++ library/modules/DFSDL.cpp | 5 +++++ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/library/Core.cpp b/library/Core.cpp index 032e2b0be..1d4f52a56 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -1459,12 +1459,9 @@ void Core::fatal (std::string output) con.print("\n"); } fprintf(stderr, "%s\n", out.str().c_str()); -#ifndef LINUX_BUILD - out << "Check file stderr.log for details\n"; - MessageBox(0,out.str().c_str(),"DFHack error!", MB_OK | MB_ICONERROR); -#else + out << "Check file stderr.log for details.\n"; std::cout << "DFHack fatal error: " << out.str() << std::endl; -#endif + DFSDL::DFSDL_ShowSimpleMessageBox(0x10 /* SDL_MESSAGEBOX_ERROR */, "DFHack error!", out.str().c_str(), NULL); bool is_headless = bool(getenv("DFHACK_HEADLESS")); if (is_headless) @@ -1506,6 +1503,12 @@ bool Core::InitMainThread() { std::cerr << "DFHack build: " << Version::git_description() << "\n" << "Starting with working directory: " << Filesystem::getcwd() << std::endl; + std::cerr << "Binding to SDL.\n"; + if (!DFSDL::init(con)) { + fatal("cannot bind SDL libraries"); + return false; + } + // find out what we are... #ifdef LINUX_BUILD const char * path = "hack/symbols.xml"; @@ -1692,11 +1695,6 @@ bool Core::InitSimulationThread() return false; } - std::cerr << "Binding to SDL.\n"; - if (!DFSDL::init(con)) { - fatal("cannot bind SDL libraries"); - return false; - } if (DFSteam::init(con)) { std::cerr << "Found Steam.\n"; DFSteam::launchSteamDFHackIfNecessary(con); diff --git a/library/include/modules/DFSDL.h b/library/include/modules/DFSDL.h index b70255ec8..c96147dfb 100644 --- a/library/include/modules/DFSDL.h +++ b/library/include/modules/DFSDL.h @@ -6,6 +6,7 @@ struct SDL_Surface; struct SDL_Rect; struct SDL_PixelFormat; +struct SDL_Window; union SDL_Event; namespace DFHack @@ -50,6 +51,7 @@ DFHACK_EXPORT int DFSDL_PushEvent(SDL_Event *event); DFHACK_EXPORT void DFSDL_free(void *ptr); DFHACK_EXPORT SDL_PixelFormat* DFSDL_AllocFormat(uint32_t pixel_format); DFHACK_EXPORT SDL_Surface* DFSDL_CreateRGBSurfaceWithFormat(uint32_t flags, int width, int height, int depth, uint32_t format); +DFHACK_EXPORT int DFSDL_ShowSimpleMessageBox(uint32_t flags, const char *title, const char *message, SDL_Window *window); // submitted and returned text is UTF-8 // see wrapper functions below for cp-437 variants diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp index 398a9c8b2..4d8bb3be5 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -43,6 +43,7 @@ char * (*g_SDL_GetClipboardText)(); void (*g_SDL_free)(void *); SDL_PixelFormat* (*g_SDL_AllocFormat)(uint32_t pixel_format) = nullptr; SDL_Surface* (*g_SDL_CreateRGBSurfaceWithFormat)(uint32_t flags, int width, int height, int depth, uint32_t format) = nullptr; +int (*g_SDL_ShowSimpleMessageBox)(uint32_t flags, const char *title, const char *message, SDL_Window *window) = nullptr; bool DFSDL::init(color_ostream &out) { for (auto &lib_str : SDL_LIBS) { @@ -85,6 +86,7 @@ bool DFSDL::init(color_ostream &out) { bind(g_sdl_handle, SDL_free); bind(g_sdl_handle, SDL_AllocFormat); bind(g_sdl_handle, SDL_CreateRGBSurfaceWithFormat); + bind(g_sdl_handle, SDL_ShowSimpleMessageBox); #undef bind DEBUG(dfsdl,out).print("sdl successfully loaded\n"); @@ -159,6 +161,9 @@ SDL_Surface* DFSDL::DFSDL_CreateRGBSurfaceWithFormat(uint32_t flags, int width, return g_SDL_CreateRGBSurfaceWithFormat(flags, width, height, depth, format); } +int DFSDL::DFSDL_ShowSimpleMessageBox(uint32_t flags, const char *title, const char *message, SDL_Window *window) { + return g_SDL_ShowSimpleMessageBox(flags, title, message, window); +} DFHACK_EXPORT std::string DFHack::getClipboardTextCp437() { if (!g_sdl_handle || g_SDL_HasClipboardText() != SDL_TRUE) From 3af118dce985a97668b41e4108431b6dc42e22db Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 21 Sep 2023 01:18:56 -0400 Subject: [PATCH 571/851] Check that SDL_ShowSimpleMessageBox has been bound first This function can be called before DFSDL is initialized --- library/modules/DFSDL.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/modules/DFSDL.cpp b/library/modules/DFSDL.cpp index 4d8bb3be5..dec43a1c5 100644 --- a/library/modules/DFSDL.cpp +++ b/library/modules/DFSDL.cpp @@ -162,6 +162,8 @@ SDL_Surface* DFSDL::DFSDL_CreateRGBSurfaceWithFormat(uint32_t flags, int width, } int DFSDL::DFSDL_ShowSimpleMessageBox(uint32_t flags, const char *title, const char *message, SDL_Window *window) { + if (!g_SDL_ShowSimpleMessageBox) + return -1; return g_SDL_ShowSimpleMessageBox(flags, title, message, window); } From 6f45e347affe753d5c1015b32ed3cfc8cf0c92aa Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 22 Sep 2023 12:14:41 +0100 Subject: [PATCH 572/851] digtype now doesn't designate hidden tiles for digging, instead only designating visible tiles in 'auto' mode (also changed MapCache* to unique_ptr) --- plugins/dig.cpp | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/plugins/dig.cpp b/plugins/dig.cpp index 879d0dd52..307a1f221 100644 --- a/plugins/dig.cpp +++ b/plugins/dig.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "Core.h" #include "Console.h" @@ -1072,14 +1073,13 @@ command_result digv (color_ostream &out, vector & parameters) con.printerr("I won't dig the borders. That would be cheating!\n"); return CR_FAILURE; } - MapExtras::MapCache * MCache = new MapExtras::MapCache; + std::unique_ptr MCache = std::make_unique(); df::tile_designation des = MCache->designationAt(xy); df::tiletype tt = MCache->tiletypeAt(xy); int16_t veinmat = MCache->veinMaterialAt(xy); if( veinmat == -1 ) { con.printerr("This tile is not a vein.\n"); - delete MCache; return CR_FAILURE; } con.print("%d/%d/%d tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole); @@ -1192,7 +1192,6 @@ command_result digv (color_ostream &out, vector & parameters) } } MCache->WriteAll(); - delete MCache; return CR_OK; } @@ -1259,7 +1258,7 @@ command_result digl (color_ostream &out, vector & parameters) con.printerr("I won't dig the borders. That would be cheating!\n"); return CR_FAILURE; } - MapExtras::MapCache * MCache = new MapExtras::MapCache; + std::unique_ptr MCache = std::make_unique(); df::tile_designation des = MCache->designationAt(xy); df::tiletype tt = MCache->tiletypeAt(xy); int16_t veinmat = MCache->veinMaterialAt(xy); @@ -1267,7 +1266,6 @@ command_result digl (color_ostream &out, vector & parameters) if( veinmat != -1 ) { con.printerr("This is a vein. Use digv instead!\n"); - delete MCache; return CR_FAILURE; } con.print("%d/%d/%d tiletype: %d, basemat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, basemat, des.whole); @@ -1408,7 +1406,6 @@ command_result digl (color_ostream &out, vector & parameters) } } MCache->WriteAll(); - delete MCache; return CR_OK; } @@ -1462,14 +1459,21 @@ command_result digtype (color_ostream &out, vector & parameters) return CR_FAILURE; } DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz); - MapExtras::MapCache * mCache = new MapExtras::MapCache; + std::unique_ptr mCache = std::make_unique(); df::tile_designation baseDes = mCache->designationAt(xy); + + if (baseDes.bits.hidden) { + out.printerr("Cursor is pointing at a hidden tile. Point the cursor at a visible tile"); + return CR_FAILURE; + } + + df::tile_occupancy baseOcc = mCache->occupancyAt(xy); + df::tiletype tt = mCache->tiletypeAt(xy); int16_t veinmat = mCache->veinMaterialAt(xy); if( veinmat == -1 ) { out.printerr("This tile is not a vein.\n"); - delete mCache; return CR_FAILURE; } out.print("(%d,%d,%d) tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, baseDes.whole); @@ -1486,6 +1490,8 @@ command_result digtype (color_ostream &out, vector & parameters) } } + baseOcc.bits.dig_auto = true; + for( uint32_t z = 0; z < zMax; z++ ) { for( uint32_t x = 1; x < tileXMax-1; x++ ) @@ -1506,18 +1512,22 @@ command_result digtype (color_ostream &out, vector & parameters) if ( !mCache->testCoord(current) ) { out.printerr("testCoord failed at (%d,%d,%d)\n", x, y, z); - delete mCache; return CR_FAILURE; } df::tile_designation designation = mCache->designationAt(current); + + if (designation.bits.hidden) continue; + + df::tile_occupancy occupancy = mCache->occupancyAt(current); designation.bits.dig = baseDes.bits.dig; - mCache->setDesignationAt(current, designation,priority); + occupancy.bits.dig_auto = baseOcc.bits.dig_auto; + mCache->setDesignationAt(current, designation, priority); + mCache->setOccupancyAt(current, occupancy); } } } mCache->WriteAll(); - delete mCache; return CR_OK; } From b7fcf035bcd22932a0e16f4efcea323bbd52f9ad Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 22 Sep 2023 12:18:38 +0100 Subject: [PATCH 573/851] Stopped setting auto-dig on non-default dig designations as auto-dig doesn't work for anything except for the standard 'mine' designation --- plugins/dig.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/dig.cpp b/plugins/dig.cpp index 307a1f221..7b0edf7dd 100644 --- a/plugins/dig.cpp +++ b/plugins/dig.cpp @@ -1489,8 +1489,10 @@ command_result digtype (color_ostream &out, vector & parameters) baseDes.bits.dig = tile_dig_designation::Default; } } - - baseOcc.bits.dig_auto = true; + // Auto dig only works on default dig designation. Setting dig_auto for any other designation + // prevents dwarves from digging that tile at all. + if (baseDes.bits.dig == tile_dig_designation::Default) baseOcc.bits.dig_auto = true; + else baseOcc.bits.dig_auto = false; for( uint32_t z = 0; z < zMax; z++ ) { From 2083bab2e956b1fe0b21342658619e9b0dc4b433 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 22 Sep 2023 12:41:41 +0100 Subject: [PATCH 574/851] added a +z option to digtype --- docs/plugins/dig.rst | 7 ++++--- plugins/dig.cpp | 6 +++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index 77b3137ae..d6b6451a6 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -143,9 +143,10 @@ Designation options: ``clear`` Clear any designations. -You can also pass a ``-z`` option, which restricts designations to the current -z-level and down. This is useful when you don't want to designate tiles on the -same z-levels as your carefully dug fort above. +You can also pass a ``-z`` and/or a ``+z``` option, which restricts designations to the +current z-level and down/up. This is useful when you don't want to designate tiles on the +same z-levels as your carefully dug fort above/below. To dig only at the current z-level, +pass in both. digexp ------ diff --git a/plugins/dig.cpp b/plugins/dig.cpp index 7b0edf7dd..7a92a0851 100644 --- a/plugins/dig.cpp +++ b/plugins/dig.cpp @@ -1424,6 +1424,8 @@ command_result digtype (color_ostream &out, vector & parameters) uint32_t xMax,yMax,zMax; Maps::getSize(xMax,yMax,zMax); + uint32_t zMin = 0; + int32_t targetDigType = -1; for (string parameter : parameters) { if ( parameter == "clear" ) @@ -1442,6 +1444,8 @@ command_result digtype (color_ostream &out, vector & parameters) targetDigType = tile_dig_designation::UpStair; else if ( parameter == "-z" ) zMax = *window_z + 1; + else if ( parameter == "+z") + zMin = *window_z; else { out.printerr("Invalid parameter: '%s'.\n", parameter.c_str()); @@ -1494,7 +1498,7 @@ command_result digtype (color_ostream &out, vector & parameters) if (baseDes.bits.dig == tile_dig_designation::Default) baseOcc.bits.dig_auto = true; else baseOcc.bits.dig_auto = false; - for( uint32_t z = 0; z < zMax; z++ ) + for( uint32_t z = zMin; z < zMax; z++ ) { for( uint32_t x = 1; x < tileXMax-1; x++ ) { From 6fe0fb5bf92ec68abb5cc54867cb17324f273f70 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 22 Sep 2023 12:45:33 +0100 Subject: [PATCH 575/851] removed trailing whitespace --- plugins/dig.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/dig.cpp b/plugins/dig.cpp index 7a92a0851..1379bc3db 100644 --- a/plugins/dig.cpp +++ b/plugins/dig.cpp @@ -1496,7 +1496,7 @@ command_result digtype (color_ostream &out, vector & parameters) // Auto dig only works on default dig designation. Setting dig_auto for any other designation // prevents dwarves from digging that tile at all. if (baseDes.bits.dig == tile_dig_designation::Default) baseOcc.bits.dig_auto = true; - else baseOcc.bits.dig_auto = false; + else baseOcc.bits.dig_auto = false; for( uint32_t z = zMin; z < zMax; z++ ) { From 3fc289cefadcde4ebca15d08991d3ff1cef27a1c Mon Sep 17 00:00:00 2001 From: Mikhail Panov Date: Fri, 22 Sep 2023 16:26:23 +0300 Subject: [PATCH 576/851] Added single order recheck option to orders recheck. Sorting by material and job type consider frequency as a higher priority. --- plugins/orders.cpp | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/plugins/orders.cpp b/plugins/orders.cpp index 4b93cff2d..0bb89a0bc 100644 --- a/plugins/orders.cpp +++ b/plugins/orders.cpp @@ -67,6 +67,7 @@ static command_result orders_sort_command(color_ostream & out); static command_result orders_sort_type_command(color_ostream & out); static command_result orders_sort_material_command(color_ostream & out); static command_result orders_recheck_command(color_ostream & out); +static command_result orders_recheck_current_command(color_ostream & out); static command_result orders_command(color_ostream & out, std::vector & parameters) { @@ -129,6 +130,14 @@ static command_result orders_command(color_ostream & out, std::vectorfrequency != b->frequency) + { + return compare_freq(a, b); + } + // Determine if only one order has reaction_name bool a_has_reaction_name = !a->reaction_name.empty(); bool b_has_reaction_name = !b->reaction_name.empty(); @@ -1077,8 +1092,8 @@ static bool compare_type(df::manager_order *a, df::manager_order *b) } } - // Fall back to freq sort - return compare_freq(a, b); + // By default orders are the same + return false; } static command_result orders_sort_type_command(color_ostream & out) @@ -1102,6 +1117,12 @@ static bool compare_material(df::manager_order *a, df::manager_order *b) // Goal: Sort orders to easily find them in the list and to see dupclicated orders. // Sorting by materials + // Divide orders by frequency first + if (a->frequency != b->frequency) + { + return compare_freq(a, b); + } + // Determine if only one of the orders has mat_type bool a_has_material = (a->mat_type != -1 || a->mat_index != -1); bool b_has_material = (b->mat_type != -1 || b->mat_index != -1); @@ -1169,3 +1190,17 @@ static command_result orders_recheck_command(color_ostream & out) } return CR_OK; } + +static command_result orders_recheck_current_command(color_ostream & out) +{ + if (game->main_interface.info.work_orders.conditions.open) + { + game->main_interface.info.work_orders.conditions.wq.status.active = false; + } + else + { + out << COLOR_LIGHTRED << "Order conditions is not open" << std::endl; + return CR_FAILURE; + } + return CR_OK; +} From a500233e0baf78ab28b89150baf92babcaef6509 Mon Sep 17 00:00:00 2001 From: Mikhail Panov Date: Fri, 22 Sep 2023 18:29:45 +0300 Subject: [PATCH 577/851] Moved onde order recheck to orders plugin. --- plugins/lua/orders.lua | 84 ++++++++++++++++++++++++++++++++++++++++++ plugins/orders.cpp | 3 ++ 2 files changed, 87 insertions(+) diff --git a/plugins/lua/orders.lua b/plugins/lua/orders.lua index b50c28694..1dd7e8160 100644 --- a/plugins/lua/orders.lua +++ b/plugins/lua/orders.lua @@ -190,7 +190,91 @@ function OrdersOverlay:render(dc) OrdersOverlay.super.render(self, dc) end +-- Resets the selected work order to the `Checking` state + +local function set_current_inactive() + local scrConditions = df.global.game.main_interface.info.work_orders.conditions + if scrConditions.open then + dfhack.run_command('orders', 'recheck', 'this') + else + qerror("Order conditions is not open") + end +end + +local function is_current_active() + local scrConditions = df.global.game.main_interface.info.work_orders.conditions + local order = scrConditions.wq + return order.status.active +end + +-- ------------------- +-- RecheckOverlay +-- + +local focusString = 'dwarfmode/Info/WORK_ORDERS/Conditions' + +RecheckOverlay = defclass(RecheckOverlay, overlay.OverlayWidget) +RecheckOverlay.ATTRS{ + default_pos={x=6,y=8}, + default_enabled=true, + viewscreens=focusString, + -- width is the sum of lengths of `[` + `Ctrl+A` + `: ` + button.label + `]` + frame={w=1 + 6 + 2 + 16 + 1, h=3}, +} + +local function areTabsInTwoRows() + -- get the tile above the order status icon + local pen = dfhack.screen.readTile(7, 7, false) + -- in graphics mode, `0` when one row, something else when two (`67` aka 'C' from "Creatures") + -- in ASCII mode, `32` aka ' ' when one row, something else when two (`196` aka '-' from tab frame's top) + return (pen.ch ~= 0 and pen.ch ~= 32) +end + +function RecheckOverlay:updateTextButtonFrame() + local twoRows = areTabsInTwoRows() + if (self._twoRows == twoRows) then return false end + + self._twoRows = twoRows + local frame = twoRows + and {b=0, l=0, r=0, h=1} + or {t=0, l=0, r=0, h=1} + self.subviews.button.frame = frame + + return true +end + +function RecheckOverlay:init() + self:addviews{ + widgets.TextButton{ + view_id = 'button', + -- frame={t=0, l=0, r=0, h=1}, -- is set in `updateTextButtonFrame()` + label='request re-check', + key='CUSTOM_CTRL_A', + on_activate=set_current_inactive, + enabled=is_current_active, + }, + } + + self:updateTextButtonFrame() +end + +function RecheckOverlay:onRenderBody(dc) + if (self.frame_rect.y1 == 7) then + -- only apply this logic if the overlay is on the same row as + -- originally thought: just above the order status icon + + if self:updateTextButtonFrame() then + self:updateLayout() + end + end + + RecheckOverlay.super.onRenderBody(self, dc) +end + +-- ------------------- + OVERLAY_WIDGETS = { + recheck=RecheckOverlay, overlay=OrdersOverlay, } diff --git a/plugins/orders.cpp b/plugins/orders.cpp index 0bb89a0bc..bfbe03480 100644 --- a/plugins/orders.cpp +++ b/plugins/orders.cpp @@ -10,6 +10,7 @@ #include "json/json.h" #include "df/building.h" +#include "df/gamest.h" #include "df/historical_figure.h" #include "df/itemdef_ammost.h" #include "df/itemdef_armorst.h" @@ -36,6 +37,8 @@ using namespace DFHack; using namespace df::enums; +using df::global::game; + DFHACK_PLUGIN("orders"); REQUIRE_GLOBAL(world); From a236722a752ebd665ae75ee26ff89fd1ef1a504e Mon Sep 17 00:00:00 2001 From: Mikhail Panov Date: Fri, 22 Sep 2023 18:37:14 +0300 Subject: [PATCH 578/851] Changed hotkeys + orders.cpp compilation error fix. --- plugins/lua/orders.lua | 4 ++-- plugins/orders.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/lua/orders.lua b/plugins/lua/orders.lua index 1dd7e8160..c84dfa5f7 100644 --- a/plugins/lua/orders.lua +++ b/plugins/lua/orders.lua @@ -129,14 +129,14 @@ function OrdersOverlay:init() widgets.HotkeyLabel{ frame={t=1, l=30}, label='sort by type', - key='CUSTOM_CTRL_T', + key='CUSTOM_CTRL_J', auto_width=true, on_activate=do_sort_type, }, widgets.HotkeyLabel{ frame={t=0, l=52}, label='sort by mat', - key='CUSTOM_CTRL_M', + key='CUSTOM_CTRL_T', auto_width=true, on_activate=do_sort_mat, }, diff --git a/plugins/orders.cpp b/plugins/orders.cpp index bfbe03480..77e8d5fa8 100644 --- a/plugins/orders.cpp +++ b/plugins/orders.cpp @@ -1198,7 +1198,7 @@ static command_result orders_recheck_current_command(color_ostream & out) { if (game->main_interface.info.work_orders.conditions.open) { - game->main_interface.info.work_orders.conditions.wq.status.active = false; + game->main_interface.info.work_orders.conditions.wq->status.bits.active = false; } else { From 8a424de7ffb90f868c3f67112637137fdeeab3d7 Mon Sep 17 00:00:00 2001 From: Mikhail Panov Date: Fri, 22 Sep 2023 19:04:49 +0300 Subject: [PATCH 579/851] Updated orders.rst --- docs/plugins/orders.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/plugins/orders.rst b/docs/plugins/orders.rst index 351456e2e..9bf220a06 100644 --- a/docs/plugins/orders.rst +++ b/docs/plugins/orders.rst @@ -17,8 +17,13 @@ Usage manager orders. It will not clear the orders that already exist. ``orders clear`` Deletes all manager orders in the current embark. -``orders recheck`` - Invalidates manager orders forcing material conditions recheck. +``orders recheck [this]`` + Sets the status to ``Checking`` (from ``Active``) of all work orders or one + currently viewed if 'this' option is passed. Work order conditions screen + should be open in this case. This makes the manager reevaluate its conditions. + This is especially useful for an order that had its conditions met when it + was started, but the requisite items have since disappeared and the workorder + is now generating job cancellation spam. ``orders sort`` Sorts current manager orders by repeat frequency so repeating orders don't prevent one-time orders from ever being completed. The sorting order is: From 303ce1fdc3005ccbef47fa415713243241e3b6bf Mon Sep 17 00:00:00 2001 From: donhth <> Date: Sat, 23 Sep 2023 15:54:46 -0400 Subject: [PATCH 580/851] re-enable tubefill. --- plugins/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index b96606284..bb2794011 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -167,7 +167,7 @@ if(BUILD_SUPPORTED) dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(title-folder title-folder.cpp) #dfhack_plugin(trackstop trackstop.cpp) - #dfhack_plugin(tubefill tubefill.cpp) + dfhack_plugin(tubefill tubefill.cpp) #add_subdirectory(tweak) dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua) dfhack_plugin(work-now work-now.cpp) From 6f26650255c2f8ecc887e20a79f46d3a966e6401 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Fri, 1 Sep 2023 18:12:59 +0300 Subject: [PATCH 581/851] reserved texpos range --- docs/dev/Lua API.rst | 12 ++- library/LuaApi.cpp | 9 +- library/include/modules/Textures.h | 10 +- library/lua/gui/textures.lua | 22 ++-- library/modules/Textures.cpp | 118 +++++++++++++++++--- plugins/lua/hotkeys.lua | 168 +++++++++++++++-------------- plugins/pathable.cpp | 2 +- 7 files changed, 222 insertions(+), 119 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 4f182d132..9199130fe 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2595,10 +2595,12 @@ The ``textures`` module solves this problem by providing a stable handle instead raw ``texpos``. When we need to draw a particular tile, we can look up the current ``texpos`` value via the handle. -* ``loadTileset(file, tile_px_w, tile_px_h)`` +* ``loadTileset(file, tile_px_w, tile_px_h, reserved?)`` Loads a tileset from the image ``file`` with give tile dimensions in pixels. The image will be sliced in row major order. Returns an array of ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). Example usage:: @@ -2611,18 +2613,22 @@ raw ``texpos``. When we need to draw a particular tile, we can look up the curre get the ``texpos`` for your texture. ``texpos`` can change when game textures are reset, but the handle will be the same. -* ``createTile(pixels, tile_px_w, tile_px_h)`` +* ``createTile(pixels, tile_px_w, tile_px_h, reserved?)`` Create and register a new texture with the given tile dimensions and an array of ``pixels`` in row major order. Each pixel is an integer representing color in packed RBGA format (for example, #0022FF11). Returns a ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). -* ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h)`` +* ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h, reserved?)`` Create and register a new texture with the given texture dimensions and an array of ``pixels`` in row major order. Then slice it into tiles with the given tile dimensions. Each pixel is an integer representing color in packed RBGA format (for example #0022FF11). Returns an array of ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). * ``deleteHandle(handle)`` diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index f792cff90..5faec6d88 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1760,7 +1760,8 @@ static int textures_loadTileset(lua_State *state) std::string file = luaL_checkstring(state, 1); auto tile_w = luaL_checkint(state, 2); auto tile_h = luaL_checkint(state, 3); - auto handles = Textures::loadTileset(file, tile_w, tile_h); + bool reserved = lua_isboolean(state, 4) ? lua_toboolean(state, 4) : false; + auto handles = Textures::loadTileset(file, tile_w, tile_h, reserved); Lua::PushVector(state, handles); return 1; } @@ -1798,7 +1799,8 @@ static int textures_createTile(lua_State *state) Lua::GetVector(state, pixels); auto tile_w = luaL_checkint(state, 2); auto tile_h = luaL_checkint(state, 3); - auto handle = Textures::createTile(pixels, tile_w, tile_h); + bool reserved = lua_isboolean(state, 4) ? lua_toboolean(state, 4) : false; + auto handle = Textures::createTile(pixels, tile_w, tile_h, reserved); Lua::Push(state, handle); return 1; } @@ -1811,7 +1813,8 @@ static int textures_createTileset(lua_State *state) auto texture_h = luaL_checkint(state, 3); auto tile_w = luaL_checkint(state, 4); auto tile_h = luaL_checkint(state, 5); - auto handles = Textures::createTileset(pixels, texture_w, texture_h, tile_w, tile_h); + bool reserved = lua_isboolean(state, 6) ? lua_toboolean(state, 6) : false; + auto handles = Textures::createTileset(pixels, texture_w, texture_h, tile_w, tile_h, reserved); Lua::PushVector(state, handles); return 1; } diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 5b238a4fd..b820c3332 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -26,7 +26,7 @@ const uint32_t TILE_HEIGHT_PX = 12; * Load texture and get handle. * Keep it to obtain valid texpos. */ -DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); +DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface, bool reserved = false); /** * Load tileset from image file. @@ -34,7 +34,8 @@ DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); */ DFHACK_EXPORT std::vector loadTileset(const std::string& file, int tile_px_w = TILE_WIDTH_PX, - int tile_px_h = TILE_HEIGHT_PX); + int tile_px_h = TILE_HEIGHT_PX, + bool reserved = false); /** * Get texpos by handle. @@ -53,7 +54,7 @@ DFHACK_EXPORT void deleteHandle(TexposHandle handle); * Register this texture and return TexposHandle. */ DFHACK_EXPORT TexposHandle createTile(std::vector& pixels, int tile_px_w = TILE_WIDTH_PX, - int tile_px_h = TILE_HEIGHT_PX); + int tile_px_h = TILE_HEIGHT_PX, bool reserved = false); /** * Create new textures as tileset with RGBA32 format and pixels as data in row major order. @@ -62,7 +63,8 @@ DFHACK_EXPORT TexposHandle createTile(std::vector& pixels, int tile_px DFHACK_EXPORT std::vector createTileset(std::vector& pixels, int texture_px_w, int texture_px_h, int tile_px_w = TILE_WIDTH_PX, - int tile_px_h = TILE_HEIGHT_PX); + int tile_px_h = TILE_HEIGHT_PX, + bool reserved = false); /** * Call this on DFHack init just once to setup interposed handlers and diff --git a/library/lua/gui/textures.lua b/library/lua/gui/textures.lua index 6557b6e02..6dac234e0 100644 --- a/library/lua/gui/textures.lua +++ b/library/lua/gui/textures.lua @@ -6,18 +6,18 @@ local _ENV = mkmodule('gui.textures') -- Preloaded DFHack Assets. -- Use this handles if you need to get dfhack standard textures. ----@type table +---@type table local texpos_handles = { - green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), - red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12), - icons = dfhack.textures.loadTileset('hack/data/art/icons.png', 8, 12), - on_off = dfhack.textures.loadTileset('hack/data/art/on-off.png', 8, 12), - control_panel = dfhack.textures.loadTileset('hack/data/art/control-panel.png', 8, 12), - border_thin = dfhack.textures.loadTileset('hack/data/art/border-thin.png', 8, 12), - border_medium = dfhack.textures.loadTileset('hack/data/art/border-medium.png', 8, 12), - border_bold = dfhack.textures.loadTileset('hack/data/art/border-bold.png', 8, 12), - border_panel = dfhack.textures.loadTileset('hack/data/art/border-panel.png', 8, 12), - border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), + green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12, true), + red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12, true), + icons = dfhack.textures.loadTileset('hack/data/art/icons.png', 8, 12, true), + on_off = dfhack.textures.loadTileset('hack/data/art/on-off.png', 8, 12, true), + control_panel = dfhack.textures.loadTileset('hack/data/art/control-panel.png', 8, 12, true), + border_thin = dfhack.textures.loadTileset('hack/data/art/border-thin.png', 8, 12, true), + border_medium = dfhack.textures.loadTileset('hack/data/art/border-medium.png', 8, 12, true), + border_bold = dfhack.textures.loadTileset('hack/data/art/border-bold.png', 8, 12, true), + border_panel = dfhack.textures.loadTileset('hack/data/art/border-panel.png', 8, 12, true), + border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12, true), } -- Get valid texpos for preloaded texture in tileset diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index c957bd878..e52445f18 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -29,8 +30,30 @@ DBG_DECLARE(core, textures, DebugCategory::LINFO); } static std::unordered_map g_handle_to_texpos; +static std::unordered_map g_handle_to_reserved_texpos; static std::unordered_map g_handle_to_surface; +static std::unordered_map> g_tileset_to_handles; static std::mutex g_adding_mutex; +static std::atomic loading_state = false; + +struct Reserved { + static void init(int32_t start) { + reserved_range.start = start; + reserved_range.end = start + Reserved::size; + reserved_range.current = start; + } + static long get_new_texpos() { + if (reserved_range.current == reserved_range.end) + return -1; + current = reserved_range.current; + reserved_range.current++; + return current; + } + static const int32_t size = 10000; // size of reserved texpos buffer + inline static int32_t start = -1; + inline static int32_t end = -1; + inline static long current = -1; +} reserved_range; // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set @@ -71,6 +94,12 @@ static long add_texture(SDL_Surface* surface) { return texpos; } +// register surface in texture raws to specific texpos, returns a texpos +static void insert_texture(SDL_Surface* surface, long texpos) { + std::lock_guard lg_add_texture(g_adding_mutex); + enabler->textures.raws[texpos] = surface; +} + // delete surface from texture raws static void delete_texture(long texpos) { std::lock_guard lg_add_texture(g_adding_mutex); @@ -94,7 +123,8 @@ SDL_Surface* create_texture(std::vector& pixels, int texture_px_w, int // convert single surface into tiles according w/h // register tiles in texture raws and return handles -std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int tile_px_h) { +std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int tile_px_h, + bool reserved) { std::vector handles{}; if (!surface) return handles; @@ -109,7 +139,7 @@ std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int surface->format->Bmask, surface->format->Amask); SDL_Rect vp{tile_px_w * x, tile_px_h * y, tile_px_w, tile_px_h}; DFSDL_UpperBlit(surface, &vp, tile, NULL); - auto handle = Textures::loadTexture(tile); + auto handle = Textures::loadTexture(tile, reserved); handles.push_back(handle); } } @@ -118,22 +148,38 @@ std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int return handles; } -TexposHandle Textures::loadTexture(SDL_Surface* surface) { +TexposHandle Textures::loadTexture(SDL_Surface* surface, bool reserved) { if (!surface || !enabler) return 0; // should be some error, i guess + if (loading_state) { + ERR(textures).printerr("unable to load texture during game loading\n"); + return 0; + } auto handle = reinterpret_cast(surface); g_handle_to_surface.emplace(handle, surface); surface->refcount++; // prevent destruct on next FreeSurface by game - auto texpos = add_texture(surface); - g_handle_to_texpos.emplace(handle, texpos); + if (reserved) { + auto texpos = reserved_range.get_new_texpos(); + if (texpos == -1) { + ERR(textures).printerr("reserved range limit has been reached, use dynamic range\n"); + return 0; + } + insert_texture(surface, texpos); + g_handle_to_reserved_texpos.emplace(handle, texpos); + } else { + auto texpos = add_texture(surface); + g_handle_to_texpos.emplace(handle, texpos); + } return handle; } std::vector Textures::loadTileset(const std::string& file, int tile_px_w, - int tile_px_h) { + int tile_px_h, bool reserved) { if (!enabler) return std::vector{}; + if (g_tileset_to_handles.contains(file)) + return g_tileset_to_handles[file]; SDL_Surface* surface = DFIMG_Load(file.c_str()); if (!surface) { @@ -142,10 +188,12 @@ std::vector Textures::loadTileset(const std::string& file, int til } surface = canonicalize_format(surface); - auto handles = slice_tileset(surface, tile_px_w, tile_px_h); + auto handles = slice_tileset(surface, tile_px_w, tile_px_h, reserved); - DEBUG(textures).print("loaded %zd textures from '%s'\n", handles.size(), file.c_str()); + DEBUG(textures).print("loaded %zd textures from '%s' to %s range\n", handles.size(), + file.c_str(), reserved ? "reserved" : "dynamic"); + g_tileset_to_handles[file] = handles; return handles; } @@ -153,10 +201,15 @@ long Textures::getTexposByHandle(TexposHandle handle) { if (!handle || !enabler) return -1; + if (g_handle_to_reserved_texpos.contains(handle)) + return g_handle_to_reserved_texpos[handle]; if (g_handle_to_texpos.contains(handle)) return g_handle_to_texpos[handle]; - if (g_handle_to_surface.contains(handle)) { + if (loading_state) { + ERR(textures).printerr("unable reinit texture from dynamic range during loading\n"); + return -1; + } g_handle_to_surface[handle]->refcount++; // prevent destruct on next FreeSurface by game auto texpos = add_texture(g_handle_to_surface[handle]); g_handle_to_texpos.emplace(handle, texpos); @@ -166,22 +219,24 @@ long Textures::getTexposByHandle(TexposHandle handle) { return -1; } -TexposHandle Textures::createTile(std::vector& pixels, int tile_px_w, int tile_px_h) { +TexposHandle Textures::createTile(std::vector& pixels, int tile_px_w, int tile_px_h, + bool reserved) { if (!enabler) return 0; auto texture = create_texture(pixels, tile_px_w, tile_px_h); - auto handle = Textures::loadTexture(texture); + auto handle = Textures::loadTexture(texture, reserved); return handle; } std::vector Textures::createTileset(std::vector& pixels, int texture_px_w, - int texture_px_h, int tile_px_w, int tile_px_h) { + int texture_px_h, int tile_px_w, int tile_px_h, + bool reserved) { if (!enabler) return std::vector{}; auto texture = create_texture(pixels, texture_px_w, texture_px_h); - auto handles = slice_tileset(texture, tile_px_w, tile_px_h); + auto handles = slice_tileset(texture, tile_px_w, tile_px_h, reserved); return handles; } @@ -192,6 +247,8 @@ void Textures::deleteHandle(TexposHandle handle) { auto texpos = Textures::getTexposByHandle(handle); if (texpos > 0) delete_texture(texpos); + if (g_handle_to_reserved_texpos.contains(handle)) + g_handle_to_reserved_texpos.erase(handle); if (g_handle_to_texpos.contains(handle)) g_handle_to_texpos.erase(handle); if (g_handle_to_surface.contains(handle)) { @@ -207,7 +264,18 @@ static void reset_texpos() { g_handle_to_texpos.clear(); } +static void reset_reserved_texpos() { + DEBUG(textures).print("resetting reserved texture mappings\n"); + g_handle_to_reserved_texpos.clear(); +} + +static void reset_tilesets() { + DEBUG(textures).print("resetting tileset to handle mappings\n"); + g_tileset_to_handles.clear(); +} + static void reset_surface() { + DEBUG(textures).print("deleting cached surfaces\n"); for (auto& entry : g_handle_to_surface) { DFSDL_FreeSurface(entry.second); } @@ -220,7 +288,9 @@ struct tracking_stage_new_region : df::viewscreen_new_regionst { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_raw_load_stage != this->raw_load_stage) { - TRACE(textures).print("raw_load_stage %d -> %d\n", this->m_raw_load_stage, this->raw_load_stage); + TRACE(textures).print("raw_load_stage %d -> %d\n", this->m_raw_load_stage, + this->raw_load_stage); + loading_state = this->raw_load_stage >= 0 && this->raw_load_stage < 3 ? true : false; this->m_raw_load_stage = this->raw_load_stage; if (this->m_raw_load_stage == 1) reset_texpos(); @@ -240,6 +310,7 @@ struct tracking_stage_adopt_region : df::viewscreen_adopt_regionst { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); + loading_state = this->cur_step >= 0 && this->cur_step < 3 ? true : false; this->m_cur_step = this->cur_step; if (this->m_cur_step == 1) reset_texpos(); @@ -259,6 +330,7 @@ struct tracking_stage_load_region : df::viewscreen_loadgamest { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); + loading_state = this->cur_step >= 0 && this->cur_step < 3 ? true : false; this->m_cur_step = this->cur_step; if (this->m_cur_step == 1) reset_texpos(); @@ -278,6 +350,7 @@ struct tracking_stage_new_arena : df::viewscreen_new_arenast { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); + loading_state = this->cur_step >= 0 && this->cur_step < 3 ? true : false; this->m_cur_step = this->cur_step; if (this->m_cur_step == 0) reset_texpos(); @@ -304,12 +377,25 @@ static void uninstall_reset_point() { INTERPOSE_HOOK(tracking_stage_new_arena, logic).remove(); } +static void reserve_static_range() { + reserved_range.init(enabler->textures.init_texture_size); + auto dummy_surface = + DFSDL_CreateRGBSurfaceWithFormat(0, 0, 0, 32, SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32); + for (int32_t i = 0; i < Reserved::size; i++) { + add_texture(dummy_surface); + } + enabler->textures.init_texture_size += Reserved::size; +} + void Textures::init(color_ostream& out) { if (!enabler) return; + reserve_static_range(); install_reset_point(); - DEBUG(textures, out).print("dynamic texture loading ready"); + DEBUG(textures, out) + .print("dynamic texture loading ready, reserved range %d-%d\n", reserved_range.start, + reserved_range.end); } void Textures::cleanup() { @@ -317,6 +403,8 @@ void Textures::cleanup() { return; reset_texpos(); + reset_reserved_texpos(); + reset_tilesets(); reset_surface(); uninstall_reset_point(); } diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index fae138353..4169d439a 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -5,8 +5,8 @@ local helpdb = require('helpdb') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') -local logo_textures = dfhack.textures.loadTileset('hack/data/art/logo.png', 8, 12) -local logo_hovered_textures = dfhack.textures.loadTileset('hack/data/art/logo_hovered.png', 8, 12) +local logo_textures = dfhack.textures.loadTileset('hack/data/art/logo.png', 8, 12, true) +local logo_hovered_textures = dfhack.textures.loadTileset('hack/data/art/logo_hovered.png', 8, 12, true) local function get_command(cmdline) local first_word = cmdline:trim():split(' +')[1] @@ -17,8 +17,8 @@ end function should_hide_armok(cmdline) local command = get_command(cmdline) return dfhack.getHideArmokTools() and - helpdb.is_entry(command) and - helpdb.get_entry_tags(command).armok + helpdb.is_entry(command) and + helpdb.get_entry_tags(command).armok end -- ----------------- -- @@ -26,11 +26,11 @@ end -- ----------------- -- HotspotMenuWidget = defclass(HotspotMenuWidget, overlay.OverlayWidget) -HotspotMenuWidget.ATTRS{ - default_pos={x=5,y=1}, - default_enabled=true, - version=2, - viewscreens={ +HotspotMenuWidget.ATTRS { + default_pos = { x = 5, y = 1 }, + default_enabled = true, + version = 2, + viewscreens = { 'adopt_region', 'choose_game_type', -- 'choose_start_site', -- conflicts with vanilla panel layouts @@ -48,51 +48,51 @@ HotspotMenuWidget.ATTRS{ 'update_region', 'world' }, - frame={w=4, h=3} + frame = { w = 4, h = 3 } } function HotspotMenuWidget:init() local to_pen = dfhack.pen.parse local function tp(idx, ch) - return to_pen{ - tile=function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end, - ch=ch, - fg=COLOR_GREY, + return to_pen { + tile = function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end, + ch = ch, + fg = COLOR_GREY, } end local function tph(idx, ch) - return to_pen{ - tile=function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, - ch=ch, - fg=COLOR_WHITE, + return to_pen { + tile = function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, + ch = ch, + fg = COLOR_WHITE, } end local function get_tile_token(idx, ch) return { - tile=tp(idx, ch), - htile=tph(idx, ch), - width=1, + tile = tp(idx, ch), + htile = tph(idx, ch), + width = 1, } end - self:addviews{ - widgets.Label{ - text={ + self:addviews { + widgets.Label { + text = { get_tile_token(1, '!'), get_tile_token(2, 'D'), get_tile_token(3, 'F'), get_tile_token(4, '!'), NEWLINE, get_tile_token(5, '!'), get_tile_token(6, 'H'), get_tile_token(7, 'a'), get_tile_token(8, '!'), NEWLINE, get_tile_token(9, '!'), get_tile_token(10, 'c'), get_tile_token(11, 'k'), get_tile_token(12, '!'), }, - on_click=function() dfhack.run_command('hotkeys') end, + on_click = function() dfhack.run_command('hotkeys') end, }, } end function HotspotMenuWidget:overlay_trigger() - return MenuScreen{hotspot=self}:show() + return MenuScreen { hotspot = self }:show() end -- register the menu hotspot with the overlay -OVERLAY_WIDGETS = {menu=HotspotMenuWidget} +OVERLAY_WIDGETS = { menu = HotspotMenuWidget } -- ---- -- -- Menu -- @@ -103,15 +103,15 @@ local MAX_LIST_WIDTH = 45 local MAX_LIST_HEIGHT = 15 Menu = defclass(Menu, widgets.Panel) -Menu.ATTRS{ - hotspot=DEFAULT_NIL, +Menu.ATTRS { + hotspot = DEFAULT_NIL, } -- get a map from the binding string to a list of hotkey strings that all -- point to that binding local function get_bindings_to_hotkeys(hotkeys, bindings) local bindings_to_hotkeys = {} - for _,hotkey in ipairs(hotkeys) do + for _, hotkey in ipairs(hotkeys) do local binding = bindings[hotkey] table.insert(ensure_key(bindings_to_hotkeys, binding), hotkey) end @@ -126,17 +126,17 @@ local function get_choices(hotkeys, bindings, is_inverted) local bindings_to_hotkeys = get_bindings_to_hotkeys(hotkeys, bindings) -- build list choices - for _,hotkey in ipairs(hotkeys) do + for _, hotkey in ipairs(hotkeys) do local command = bindings[hotkey] if seen[command] then goto continue end seen[command] = true local hk_width, tokens = 0, {} - for _,hk in ipairs(bindings_to_hotkeys[command]) do + for _, hk in ipairs(bindings_to_hotkeys[command]) do if hk_width ~= 0 then table.insert(tokens, ', ') hk_width = hk_width + 2 end - table.insert(tokens, {text=hk, pen=COLOR_LIGHTGREEN}) + table.insert(tokens, { text = hk, pen = COLOR_LIGHTGREEN }) hk_width = hk_width + #hk end local command_str = command @@ -144,16 +144,20 @@ local function get_choices(hotkeys, bindings, is_inverted) local max_command_len = MAX_LIST_WIDTH - hk_width - LIST_BUFFER command_str = command:sub(1, max_command_len - 3) .. '...' end - table.insert(tokens, 1, {text=command_str}) - local choice = {icon=ARROW, command=command, text=tokens, - hk_width=hk_width} + table.insert(tokens, 1, { text = command_str }) + local choice = { + icon = ARROW, + command = command, + text = tokens, + hk_width = hk_width + } max_width = math.max(max_width, hk_width + #command_str + LIST_BUFFER) table.insert(choices, is_inverted and 1 or #choices + 1, choice) ::continue:: end -- adjust width of command fields so the hotkey tokens are right justified - for _,choice in ipairs(choices) do + for _, choice in ipairs(choices) do local command_token = choice.text[1] command_token.width = max_width - choice.hk_width - (LIST_BUFFER - 1) end @@ -164,17 +168,17 @@ end function Menu:init() local hotkeys, bindings = getHotkeys() if #hotkeys == 0 then - hotkeys = {''} - bindings = {['']='gui/launcher'} + hotkeys = { '' } + bindings = { [''] = 'gui/launcher' } end local is_inverted = not not self.hotspot.frame.b - local choices,list_width = get_choices(hotkeys, bindings, is_inverted) + local choices, list_width = get_choices(hotkeys, bindings, is_inverted) list_width = math.max(35, list_width) local list_frame = copyall(self.hotspot.frame) - local list_widget_frame = {h=math.min(#choices, MAX_LIST_HEIGHT)} + local list_widget_frame = { h = math.min(#choices, MAX_LIST_HEIGHT) } local quickstart_frame = {} list_frame.w = list_width + 2 list_frame.h = list_widget_frame.h + 4 @@ -193,51 +197,51 @@ function Menu:init() list_frame.r = math.max(0, list_frame.r + 5) end - local help_frame = {w=list_frame.w, l=list_frame.l, r=list_frame.r} + local help_frame = { w = list_frame.w, l = list_frame.l, r = list_frame.r } if list_frame.t then help_frame.t = list_frame.t + list_frame.h else help_frame.b = list_frame.b + list_frame.h end - self:addviews{ - widgets.Panel{ - view_id='list_panel', - frame=list_frame, - frame_style=gui.PANEL_FRAME, - frame_background=gui.CLEAR_PEN, - subviews={ - widgets.List{ - view_id='list', - frame=list_widget_frame, - choices=choices, - icon_width=2, - on_select=self:callback('onSelect'), - on_submit=self:callback('onSubmit'), - on_submit2=self:callback('onSubmit2'), + self:addviews { + widgets.Panel { + view_id = 'list_panel', + frame = list_frame, + frame_style = gui.PANEL_FRAME, + frame_background = gui.CLEAR_PEN, + subviews = { + widgets.List { + view_id = 'list', + frame = list_widget_frame, + choices = choices, + icon_width = 2, + on_select = self:callback('onSelect'), + on_submit = self:callback('onSubmit'), + on_submit2 = self:callback('onSubmit2'), }, - widgets.Panel{frame={h=1}}, - widgets.HotkeyLabel{ - frame=quickstart_frame, - label='Quickstart guide', - key='STRING_A063', - on_activate=function() - self:onSubmit(nil, {command='quickstart-guide'}) + widgets.Panel { frame = { h = 1 } }, + widgets.HotkeyLabel { + frame = quickstart_frame, + label = 'Quickstart guide', + key = 'STRING_A063', + on_activate = function() + self:onSubmit(nil, { command = 'quickstart-guide' }) end, }, }, }, - widgets.ResizingPanel{ - view_id='help_panel', - autoarrange_subviews=true, - frame=help_frame, - frame_style=gui.PANEL_FRAME, - frame_background=gui.CLEAR_PEN, - subviews={ - widgets.WrappedLabel{ - view_id='help', - text_to_wrap='', - scroll_keys={}, + widgets.ResizingPanel { + view_id = 'help_panel', + autoarrange_subviews = true, + frame = help_frame, + frame_style = gui.PANEL_FRAME, + frame_background = gui.CLEAR_PEN, + subviews = { + widgets.WrappedLabel { + view_id = 'help', + text_to_wrap = '', + scroll_keys = {}, }, }, }, @@ -252,7 +256,7 @@ function Menu:onSelect(_, choice) if not choice or #self.subviews == 0 then return end 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' + helpdb.get_entry_short_help(command) or 'Command not found' self.subviews.help_panel:updateLayout() end @@ -302,7 +306,7 @@ end function Menu:getMouseFramePos() return self.subviews.list_panel:getMouseFramePos() or - self.subviews.help_panel:getMouseFramePos() + self.subviews.help_panel:getMouseFramePos() end function Menu:onRenderBody(dc) @@ -324,14 +328,14 @@ end MenuScreen = defclass(MenuScreen, gui.ZScreen) MenuScreen.ATTRS { - focus_path='hotkeys/menu', - initial_pause=false, - hotspot=DEFAULT_NIL, + focus_path = 'hotkeys/menu', + initial_pause = false, + hotspot = DEFAULT_NIL, } function MenuScreen:init() - self:addviews{ - Menu{hotspot=self.hotspot}, + self:addviews { + Menu { hotspot = self.hotspot }, } end diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 12852a894..be6537d32 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -36,7 +36,7 @@ namespace DFHack { static std::vector textures; DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { - textures = Textures::loadTileset("hack/data/art/pathable.png", 32, 32); + textures = Textures::loadTileset("hack/data/art/pathable.png", 32, 32, true); return CR_OK; } From 5b34ac63e19599b0a2494e57cbd8761bd9737e03 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Fri, 1 Sep 2023 18:31:19 +0300 Subject: [PATCH 582/851] fix for gcc --- library/modules/Textures.cpp | 44 +++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index e52445f18..bdb1e815a 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -29,6 +29,27 @@ namespace DFHack { DBG_DECLARE(core, textures, DebugCategory::LINFO); } +struct ReservedRange { + void init(int32_t start) { + this->start = start; + this->end = start + ReservedRange::size; + this->current = start; + } + long get_new_texpos() { + if (this->current == this->end) + return -1; + current = this->current; + this->current++; + return current; + } + + static const int32_t size = 10000; // size of reserved texpos buffer + int32_t start = -1; + int32_t end = -1; + long current = -1; +}; + +static ReservedRange reserved_range{}; static std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_reserved_texpos; static std::unordered_map g_handle_to_surface; @@ -36,25 +57,6 @@ static std::unordered_map> g_tileset_to_h static std::mutex g_adding_mutex; static std::atomic loading_state = false; -struct Reserved { - static void init(int32_t start) { - reserved_range.start = start; - reserved_range.end = start + Reserved::size; - reserved_range.current = start; - } - static long get_new_texpos() { - if (reserved_range.current == reserved_range.end) - return -1; - current = reserved_range.current; - reserved_range.current++; - return current; - } - static const int32_t size = 10000; // size of reserved texpos buffer - inline static int32_t start = -1; - inline static int32_t end = -1; - inline static long current = -1; -} reserved_range; - // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set // and the source surface didn't already have an alpha channel. @@ -381,10 +383,10 @@ static void reserve_static_range() { reserved_range.init(enabler->textures.init_texture_size); auto dummy_surface = DFSDL_CreateRGBSurfaceWithFormat(0, 0, 0, 32, SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32); - for (int32_t i = 0; i < Reserved::size; i++) { + for (int32_t i = 0; i < ReservedRange::size; i++) { add_texture(dummy_surface); } - enabler->textures.init_texture_size += Reserved::size; + enabler->textures.init_texture_size += ReservedRange::size; } void Textures::init(color_ostream& out) { From 469a97f78189a2f0bf86ffa7253da47df4cdf475 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sat, 2 Sep 2023 08:38:33 +0300 Subject: [PATCH 583/851] review --- docs/dev/Lua API.rst | 5 +++ library/modules/Textures.cpp | 76 +++++++++++++++++++++++++++++------- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 9199130fe..dc1722bf4 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2594,6 +2594,11 @@ invalidates the ``texpos`` value that used to point to that texture. The ``textures`` module solves this problem by providing a stable handle instead of a raw ``texpos``. When we need to draw a particular tile, we can look up the current ``texpos`` value via the handle. +Texture module can register textures in two ways: to reserved and dynamic ranges. +Reserved range is a limit buffer in a game texture vector, that will never be wiped. +It is good for static assets, which need to be loaded at the very beginning and will be used during the process running. +In other cases, it is better to use dynamic range. +If reserved range buffer limit has been reached, dynamic range will be used by default. * ``loadTileset(file, tile_px_w, tile_px_h, reserved?)`` diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index bdb1e815a..a2810dd20 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -34,6 +35,7 @@ struct ReservedRange { this->start = start; this->end = start + ReservedRange::size; this->current = start; + this->is_installed = true; } long get_new_texpos() { if (this->current == this->end) @@ -47,6 +49,7 @@ struct ReservedRange { int32_t start = -1; int32_t end = -1; long current = -1; + bool is_installed = false; }; static ReservedRange reserved_range{}; @@ -54,6 +57,7 @@ static std::unordered_map g_handle_to_texpos; static std::unordered_map g_handle_to_reserved_texpos; static std::unordered_map g_handle_to_surface; static std::unordered_map> g_tileset_to_handles; +static std::vector g_delayed_regs; static std::mutex g_adding_mutex; static std::atomic loading_state = false; @@ -134,6 +138,12 @@ std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int int dimx = surface->w / tile_px_w; int dimy = surface->h / tile_px_h; + if (reserved && (dimx * dimy > reserved_range.end - reserved_range.current)) { + WARN(textures).print( + "there is not enough space in reserved range for whole tileset, using dynamic range\n"); + reserved = false; + } + for (int y = 0; y < dimy; y++) { for (int x = 0; x < dimx; x++) { SDL_Surface* tile = DFSDL_CreateRGBSurface( @@ -153,26 +163,35 @@ std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int TexposHandle Textures::loadTexture(SDL_Surface* surface, bool reserved) { if (!surface || !enabler) return 0; // should be some error, i guess - if (loading_state) { - ERR(textures).printerr("unable to load texture during game loading\n"); - return 0; - } + if (loading_state) + reserved = true; // use reserved range during loading for all textures auto handle = reinterpret_cast(surface); g_handle_to_surface.emplace(handle, surface); surface->refcount++; // prevent destruct on next FreeSurface by game - if (reserved) { + + if (reserved && reserved_range.is_installed) { auto texpos = reserved_range.get_new_texpos(); - if (texpos == -1) { + if (texpos != -1) { + insert_texture(surface, texpos); + g_handle_to_reserved_texpos.emplace(handle, texpos); + return handle; + } + + if (loading_state) { // if we in loading state and reserved range is full -> error ERR(textures).printerr("reserved range limit has been reached, use dynamic range\n"); return 0; } - insert_texture(surface, texpos); - g_handle_to_reserved_texpos.emplace(handle, texpos); + } + + // if we here in loading state = true, then it should be dynamic range -> delay reg + if (loading_state) { + g_delayed_regs.push_back(handle); } else { auto texpos = add_texture(surface); g_handle_to_texpos.emplace(handle, texpos); } + return handle; } @@ -192,10 +211,9 @@ std::vector Textures::loadTileset(const std::string& file, int til surface = canonicalize_format(surface); auto handles = slice_tileset(surface, tile_px_w, tile_px_h, reserved); - DEBUG(textures).print("loaded %zd textures from '%s' to %s range\n", handles.size(), - file.c_str(), reserved ? "reserved" : "dynamic"); - + DEBUG(textures).print("loaded %zd textures from '%s'\n", handles.size(), file.c_str()); g_tileset_to_handles[file] = handles; + return handles; } @@ -207,12 +225,14 @@ long Textures::getTexposByHandle(TexposHandle handle) { return g_handle_to_reserved_texpos[handle]; if (g_handle_to_texpos.contains(handle)) return g_handle_to_texpos[handle]; + if (std::find(g_delayed_regs.begin(), g_delayed_regs.end(), handle) != g_delayed_regs.end()) + return 0; if (g_handle_to_surface.contains(handle)) { - if (loading_state) { - ERR(textures).printerr("unable reinit texture from dynamic range during loading\n"); - return -1; - } g_handle_to_surface[handle]->refcount++; // prevent destruct on next FreeSurface by game + if (loading_state) { // reinit dor dynamic range during loading -> delayed + g_delayed_regs.push_back(handle); + return 0; + } auto texpos = add_texture(g_handle_to_surface[handle]); g_handle_to_texpos.emplace(handle, texpos); return texpos; @@ -284,6 +304,15 @@ static void reset_surface() { g_handle_to_surface.clear(); } +static void register_delayed_handles() { + DEBUG(textures).print("register delayed handles, size %zd\n", g_delayed_regs.size()); + for (auto& handle : g_delayed_regs) { + auto texpos = add_texture(g_handle_to_surface[handle]); + g_handle_to_texpos.emplace(handle, texpos); + } + g_delayed_regs.clear(); +} + // reset point on New Game struct tracking_stage_new_region : df::viewscreen_new_regionst { typedef df::viewscreen_new_regionst interpose_base; @@ -292,7 +321,10 @@ struct tracking_stage_new_region : df::viewscreen_new_regionst { if (this->m_raw_load_stage != this->raw_load_stage) { TRACE(textures).print("raw_load_stage %d -> %d\n", this->m_raw_load_stage, this->raw_load_stage); + bool tmp_state = loading_state; loading_state = this->raw_load_stage >= 0 && this->raw_load_stage < 3 ? true : false; + if (tmp_state != loading_state && !loading_state) + register_delayed_handles(); this->m_raw_load_stage = this->raw_load_stage; if (this->m_raw_load_stage == 1) reset_texpos(); @@ -312,7 +344,10 @@ struct tracking_stage_adopt_region : df::viewscreen_adopt_regionst { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); + bool tmp_state = loading_state; loading_state = this->cur_step >= 0 && this->cur_step < 3 ? true : false; + if (tmp_state != loading_state && !loading_state) + register_delayed_handles(); this->m_cur_step = this->cur_step; if (this->m_cur_step == 1) reset_texpos(); @@ -332,7 +367,10 @@ struct tracking_stage_load_region : df::viewscreen_loadgamest { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); + bool tmp_state = loading_state; loading_state = this->cur_step >= 0 && this->cur_step < 3 ? true : false; + if (tmp_state != loading_state && !loading_state) + register_delayed_handles(); this->m_cur_step = this->cur_step; if (this->m_cur_step == 1) reset_texpos(); @@ -352,7 +390,10 @@ struct tracking_stage_new_arena : df::viewscreen_new_arenast { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); + bool tmp_state = loading_state; loading_state = this->cur_step >= 0 && this->cur_step < 3 ? true : false; + if (tmp_state != loading_state && !loading_state) + register_delayed_handles(); this->m_cur_step = this->cur_step; if (this->m_cur_step == 0) reset_texpos(); @@ -380,6 +421,11 @@ static void uninstall_reset_point() { } static void reserve_static_range() { + if (static_cast(enabler->textures.init_texture_size) != enabler->textures.raws.size()) { + WARN(textures).print( + "reserved range can't be installed! all textures will be loaded to dynamic range!"); + return; + } reserved_range.init(enabler->textures.init_texture_size); auto dummy_surface = DFSDL_CreateRGBSurfaceWithFormat(0, 0, 0, 32, SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32); From 033a849de2580485daa66458502e4a87eb296190 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sat, 2 Sep 2023 08:40:24 +0300 Subject: [PATCH 584/851] Apply suggestions from code review Co-authored-by: Myk --- docs/dev/Lua API.rst | 6 +++--- library/modules/Textures.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index dc1722bf4..1cba8284e 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2600,7 +2600,7 @@ It is good for static assets, which need to be loaded at the very beginning and In other cases, it is better to use dynamic range. If reserved range buffer limit has been reached, dynamic range will be used by default. -* ``loadTileset(file, tile_px_w, tile_px_h, reserved?)`` +* ``loadTileset(file, tile_px_w, tile_px_h[, reserved])`` Loads a tileset from the image ``file`` with give tile dimensions in pixels. The image will be sliced in row major order. Returns an array of ``TexposHandle``. @@ -2618,7 +2618,7 @@ If reserved range buffer limit has been reached, dynamic range will be used by d get the ``texpos`` for your texture. ``texpos`` can change when game textures are reset, but the handle will be the same. -* ``createTile(pixels, tile_px_w, tile_px_h, reserved?)`` +* ``createTile(pixels, tile_px_w, tile_px_h[, reserved])`` Create and register a new texture with the given tile dimensions and an array of ``pixels`` in row major order. Each pixel is an integer representing color in packed @@ -2626,7 +2626,7 @@ If reserved range buffer limit has been reached, dynamic range will be used by d ``reserved`` is optional boolean argument, which indicates texpos range. ``true`` - reserved, ``false`` - dynamic (default). -* ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h, reserved?)`` +* ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h[, reserved])`` Create and register a new texture with the given texture dimensions and an array of ``pixels`` in row major order. Then slice it into tiles with the given tile diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index a2810dd20..291b5343c 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -100,7 +100,7 @@ static long add_texture(SDL_Surface* surface) { return texpos; } -// register surface in texture raws to specific texpos, returns a texpos +// register surface in texture raws to specific texpos static void insert_texture(SDL_Surface* surface, long texpos) { std::lock_guard lg_add_texture(g_adding_mutex); enabler->textures.raws[texpos] = surface; From 770402a2928e576b78235a36f247cca3b98463b9 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sat, 2 Sep 2023 11:05:28 +0300 Subject: [PATCH 585/851] erase from delayed when deleteHandle() --- library/modules/Textures.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 291b5343c..5ece05193 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -273,6 +273,9 @@ void Textures::deleteHandle(TexposHandle handle) { g_handle_to_reserved_texpos.erase(handle); if (g_handle_to_texpos.contains(handle)) g_handle_to_texpos.erase(handle); + if (auto it = std::find(g_delayed_regs.begin(), g_delayed_regs.end(), handle); + it != g_delayed_regs.end()) + g_delayed_regs.erase(it); if (g_handle_to_surface.contains(handle)) { auto surface = g_handle_to_surface[handle]; while (surface->refcount) From 25cc778fce4e02784ec41aeffc46293a4093a23a Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 10 Sep 2023 11:17:24 +0300 Subject: [PATCH 586/851] review refactor --- library/modules/Textures.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 5ece05193..c8dc33c84 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -40,9 +40,7 @@ struct ReservedRange { long get_new_texpos() { if (this->current == this->end) return -1; - current = this->current; - this->current++; - return current; + return this->current++; } static const int32_t size = 10000; // size of reserved texpos buffer From bd4d831582e852bd36d2005d8a5ae7ca2fe5131e Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 10 Sep 2023 14:50:03 +0300 Subject: [PATCH 587/851] add flag for dummy & resolve conflicts --- library/modules/Textures.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index c8dc33c84..b03821907 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -200,6 +200,9 @@ std::vector Textures::loadTileset(const std::string& file, int til if (g_tileset_to_handles.contains(file)) return g_tileset_to_handles[file]; + if (!enabler) + return std::vector{}; + SDL_Surface* surface = DFIMG_Load(file.c_str()); if (!surface) { ERR(textures).printerr("unable to load textures from '%s'\n", file.c_str()); @@ -428,8 +431,8 @@ static void reserve_static_range() { return; } reserved_range.init(enabler->textures.init_texture_size); - auto dummy_surface = - DFSDL_CreateRGBSurfaceWithFormat(0, 0, 0, 32, SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32); + auto dummy_surface = DFSDL_CreateRGBSurfaceWithFormat( + SDL_DONTFREE, 0, 0, 32, SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32); for (int32_t i = 0; i < ReservedRange::size; i++) { add_texture(dummy_surface); } From d2bc834fa960fd35d69f9a2ee252bebbe78f93c0 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Mon, 11 Sep 2023 07:35:27 +0300 Subject: [PATCH 588/851] fix exception on close, dummy surface refcount --- library/modules/Textures.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index b03821907..016a2193e 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -58,6 +58,7 @@ static std::unordered_map> g_tileset_to_h static std::vector g_delayed_regs; static std::mutex g_adding_mutex; static std::atomic loading_state = false; +static SDL_Surface* dummy_surface = NULL; // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set @@ -173,6 +174,7 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface, bool reserved) { if (texpos != -1) { insert_texture(surface, texpos); g_handle_to_reserved_texpos.emplace(handle, texpos); + dummy_surface->refcount--; return handle; } @@ -431,8 +433,9 @@ static void reserve_static_range() { return; } reserved_range.init(enabler->textures.init_texture_size); - auto dummy_surface = DFSDL_CreateRGBSurfaceWithFormat( - SDL_DONTFREE, 0, 0, 32, SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32); + dummy_surface = + DFSDL_CreateRGBSurfaceWithFormat(0, 0, 0, 32, SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32); + dummy_surface->refcount += ReservedRange::size; for (int32_t i = 0; i < ReservedRange::size; i++) { add_texture(dummy_surface); } From f4348095a33f66ad5ada8338a9bad1083253370c Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 24 Sep 2023 09:43:28 +0300 Subject: [PATCH 589/851] upstream --- plugins/lua/hotkeys.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 4169d439a..30407a8fa 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -177,6 +177,8 @@ function Menu:init() list_width = math.max(35, list_width) + list_width = math.max(35, list_width) + local list_frame = copyall(self.hotspot.frame) local list_widget_frame = { h = math.min(#choices, MAX_LIST_HEIGHT) } local quickstart_frame = {} From 9cdfe36aeabea0317665fa6e57eeb54009c4755e Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 16 Sep 2023 05:50:53 -0500 Subject: [PATCH 590/851] reenable `spectate` by request from the community --- docs/changelog.txt | 1 + plugins/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 044cb1ca4..42793d524 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -52,6 +52,7 @@ Template for new versions: # Future ## New Tools +- `spectate`: automatically follow productive dwarves (returned to availability) ## New Features diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index b96606284..a9421f88d 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -158,7 +158,7 @@ if(BUILD_SUPPORTED) #dfhack_plugin(siege-engine siege-engine.cpp LINK_LIBRARIES lua) dfhack_plugin(sort sort.cpp LINK_LIBRARIES lua) #dfhack_plugin(steam-engine steam-engine.cpp) - #add_subdirectory(spectate) + add_subdirectory(spectate) #dfhack_plugin(stockflow stockflow.cpp LINK_LIBRARIES lua) add_subdirectory(stockpiles) #dfhack_plugin(stocks stocks.cpp) From ae67ec05dec9d9f3b818def9616b7f5d340bcecc Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 24 Sep 2023 13:01:31 +0300 Subject: [PATCH 591/851] remove doubled check --- build/ALL_BUILD.vcxproj | 533 +++++++++ build/ALL_BUILD.vcxproj.filters | 8 + build/Continuous.vcxproj | 145 +++ build/Continuous.vcxproj.filters | 17 + build/Experimental.vcxproj | 145 +++ build/Experimental.vcxproj.filters | 17 + build/INSTALL.vcxproj | 126 +++ build/INSTALL.vcxproj.filters | 13 + build/Nightly.vcxproj | 145 +++ build/Nightly.vcxproj.filters | 17 + build/NightlyMemoryCheck.vcxproj | 145 +++ build/NightlyMemoryCheck.vcxproj.filters | 17 + build/PACKAGE.vcxproj | 132 +++ build/PACKAGE.vcxproj.filters | 13 + build/RUN_TESTS.vcxproj | 118 ++ build/RUN_TESTS.vcxproj.filters | 13 + build/ZERO_CHECK.vcxproj | 105 ++ build/ZERO_CHECK.vcxproj.filters | 13 + build/dfhack.sln | 1295 ++++++++++++++++++++++ library/modules/Textures.cpp | 3 - 20 files changed, 3017 insertions(+), 3 deletions(-) create mode 100644 build/ALL_BUILD.vcxproj create mode 100644 build/ALL_BUILD.vcxproj.filters create mode 100644 build/Continuous.vcxproj create mode 100644 build/Continuous.vcxproj.filters create mode 100644 build/Experimental.vcxproj create mode 100644 build/Experimental.vcxproj.filters create mode 100644 build/INSTALL.vcxproj create mode 100644 build/INSTALL.vcxproj.filters create mode 100644 build/Nightly.vcxproj create mode 100644 build/Nightly.vcxproj.filters create mode 100644 build/NightlyMemoryCheck.vcxproj create mode 100644 build/NightlyMemoryCheck.vcxproj.filters create mode 100644 build/PACKAGE.vcxproj create mode 100644 build/PACKAGE.vcxproj.filters create mode 100644 build/RUN_TESTS.vcxproj create mode 100644 build/RUN_TESTS.vcxproj.filters create mode 100644 build/ZERO_CHECK.vcxproj create mode 100644 build/ZERO_CHECK.vcxproj.filters create mode 100644 build/dfhack.sln diff --git a/build/ALL_BUILD.vcxproj b/build/ALL_BUILD.vcxproj new file mode 100644 index 000000000..eefddc34c --- /dev/null +++ b/build/ALL_BUILD.vcxproj @@ -0,0 +1,533 @@ + + + + x64 + + + + Release + x64 + + + RelWithDebInfo + x64 + + + + {40EA859D-1269-313F-A313-AA32B87C8935} + 10.0.22000.0 + Win32Proj + x64 + ALL_BUILD + NoUpgrade + + + + Utility + MultiByte + v143 + + + Utility + MultiByte + v143 + + + + + + + + + + <_ProjectFileVersion>10.0.20506.1 + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + Always + Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp + false + Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp + false + + + + + + + {31277AF8-10A2-3494-B123-559421E08C26} + ZERO_CHECK + false + Never + + + {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA} + 3dveins + false + Never + + + {14C478D6-D815-378F-81D1-B53BBD6CBE9A} + RemoteFortressReader + false + Never + + + {3A2B0858-3B92-3598-B679-2A437C1286E0} + add-spatter + false + Never + + + {27ECEB5C-C396-32BE-93E6-4D4801692191} + autobutcher + false + Never + + + {5F63101D-75FE-31BE-9D25-6641FBBFF959} + autochop + false + Never + + + {7D67495E-4C92-37BE-BEF8-174CA37ADD21} + autoclothing + false + Never + + + {6152D284-A720-3556-A60A-7C13C89205AD} + autodump + false + Never + + + {4049FF1D-8A65-3021-B550-0DE0E63F9577} + autofarm + false + Never + + + {8CE562EE-798E-3C1B-975C-F49C6B5C84ED} + autolabor + false + Never + + + {961FD68A-49A7-3F16-9F96-16AC8236D3A3} + autonestbox + false + Never + + + {D3C67352-8290-3C4E-9F23-93DDE051AA37} + autoslab + false + Never + + + {A0486456-80E4-3492-940E-6652FF2B45B9} + binpatch + + + {386966C3-DC46-3936-AD44-35E2470C6A28} + blueprint + false + Never + + + {02D9B109-1602-3567-80C0-3BF354675829} + buildingplan + false + Never + + + {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA} + changeitem + false + Never + + + {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515} + changelayer + false + Never + + + {76B00654-E15A-3E4F-8C41-DDC63A14246A} + changevein + false + Never + + + {D7DF31C2-3247-31BA-A745-DF4095334504} + channel-safely + false + Never + + + {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204} + cleanconst + false + Never + + + {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5} + cleaners + false + Never + + + {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB} + cleanowned + false + Never + + + {BAABB124-4999-3462-AF35-16DB3C974D7C} + confirm + false + Never + + + {6F451C91-A082-3981-83D5-65844ED16BDA} + createitem + false + Never + + + {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80} + cursecheck + false + Never + + + {AB8FA0F9-1482-31F8-87E2-E3C7BB178053} + cxxrandom + false + Never + + + {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212} + debug + false + Never + + + {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20} + deramp + false + Never + + + {5347E62F-7AEB-3B7C-B480-161A35974C9E} + design + false + Never + + + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + dfhack + + + {136AD85C-398C-329A-84AC-AD4481963950} + dfhack-client + + + {78DBE964-AC8C-3264-903B-2B102B46D476} + dfhack-run + + + {5DC5A20B-821C-3008-A247-B08677276F56} + dfhack-version + + + {D3A6760C-34FD-3EE2-B9CC-24647168DC6A} + dig + false + Never + + + {AFC95A6A-BDBB-35E2-9381-253284E1112D} + dig-now + false + Never + + + {0AED7AC4-8C48-3205-AF43-3D536A60D815} + dwarfvet + false + Never + + + {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96} + eventful + false + Never + + + {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} + expat + + + {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7} + fastdwarf + false + Never + + + {47842A81-7497-313E-B466-C60AE89334CB} + faststart + false + Never + + + {25303A98-8EE4-3355-8C68-CFA8B4116EF0} + filltraffic + false + Never + + + {A80E6C37-1E31-3DDC-A4FE-B21553E580DB} + flows + false + Never + + + {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA} + getplants + false + Never + + + {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD} + hotkeys + false + Never + + + {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B} + lair + false + Never + + + {21572060-CA28-355B-A508-5675A4A2FAB3} + liquids + false + Never + + + {F1206958-458C-3F18-84D9-3EEE07B73862} + logistics + false + Never + + + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + lua + + + {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3} + luasocket + false + Never + + + {419297F2-C54C-3C4B-91AB-7B119D09E730} + misery + false + Never + + + {8F94C6B8-42CE-329C-B6A9-3E13C04350CF} + nestboxes + false + Never + + + {7FF993D7-A6D3-37CC-AE69-2906ECD89E03} + orders + false + Never + + + {374D8559-CBBF-3F24-BEE1-8B11A184B7F8} + overlay + false + Never + + + {4E197970-E280-3B04-AD7D-E52DC551E902} + pathable + false + Never + + + {4E6C8BD2-2434-31DC-BDD2-8788D2547403} + probe + false + Never + + + {37629CF4-1B6A-312A-89B7-CF11593F51A4} + prospector + false + Never + + + {8D195538-264D-3C39-AB9A-653DA8A6F56E} + protobuf + + + {9302E53B-085D-3577-A3E2-EB51A51D084C} + protobuf-lite + + + {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} + protoc + + + {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} + protoc-bin + + + {E36DC20B-AE7A-3449-B308-C932B9DD4290} + regrass + false + Never + + + {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121} + reveal + false + Never + + + {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3} + seedwatch + false + Never + + + {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2} + showmood + false + Never + + + {C080819A-4275-3D2A-84DE-7C21EDAE2BBA} + sort + false + Never + + + {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F} + stockpiles + false + Never + + + {6579683E-AB4A-3B40-A145-1952047837D2} + strangemood + false + Never + + + {2FE38842-BDF7-3A93-9D06-1C9814B6B11B} + tailor + false + Never + + + {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C} + tiletypes + false + Never + + + {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4} + work-now + false + Never + + + {C884F97B-4C5C-3457-AF4D-BB4C05670662} + workflow + false + Never + + + {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D} + xlsxio_read_STATIC + + + {796760C3-71E4-32AD-A9C4-B984AFC97106} + xlsxio_write_STATIC + + + {8054C91C-5221-314F-96C5-8FEC57BBEED1} + xlsxreader + false + Never + + + {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} + zip + + + {3B9F42C2-0060-329E-B123-7DEF1E91617D} + zone + false + Never + + + + + + \ No newline at end of file diff --git a/build/ALL_BUILD.vcxproj.filters b/build/ALL_BUILD.vcxproj.filters new file mode 100644 index 000000000..a80df604e --- /dev/null +++ b/build/ALL_BUILD.vcxproj.filters @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/build/Continuous.vcxproj b/build/Continuous.vcxproj new file mode 100644 index 000000000..63a376abe --- /dev/null +++ b/build/Continuous.vcxproj @@ -0,0 +1,145 @@ + + + + x64 + + + + Release + x64 + + + RelWithDebInfo + x64 + + + + {D7C70C41-500D-35F8-A992-1351DDDCDA0C} + 10.0.22000.0 + Win32Proj + x64 + Continuous + NoUpgrade + + + + Utility + MultiByte + v143 + + + Utility + MultiByte + v143 + + + + + + + + + + <_ProjectFileVersion>10.0.20506.1 + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + + setlocal +"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Continuous +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\Continuous + false + false + + setlocal +"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Continuous +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\Continuous + false + false + + + + + Always + Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp + false + Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp + false + + + + + + + + + {31277AF8-10A2-3494-B123-559421E08C26} + ZERO_CHECK + false + Never + + + + + + \ No newline at end of file diff --git a/build/Continuous.vcxproj.filters b/build/Continuous.vcxproj.filters new file mode 100644 index 000000000..a7314dd00 --- /dev/null +++ b/build/Continuous.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + CMake Rules + + + + + + + + + {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} + + + diff --git a/build/Experimental.vcxproj b/build/Experimental.vcxproj new file mode 100644 index 000000000..396a79388 --- /dev/null +++ b/build/Experimental.vcxproj @@ -0,0 +1,145 @@ + + + + x64 + + + + Release + x64 + + + RelWithDebInfo + x64 + + + + {474F765F-548E-3AAB-8D5B-66CF364BE4B2} + 10.0.22000.0 + Win32Proj + x64 + Experimental + NoUpgrade + + + + Utility + MultiByte + v143 + + + Utility + MultiByte + v143 + + + + + + + + + + <_ProjectFileVersion>10.0.20506.1 + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + + setlocal +"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Experimental +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\Experimental + false + false + + setlocal +"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Experimental +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\Experimental + false + false + + + + + Always + Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp + false + Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp + false + + + + + + + + + {31277AF8-10A2-3494-B123-559421E08C26} + ZERO_CHECK + false + Never + + + + + + \ No newline at end of file diff --git a/build/Experimental.vcxproj.filters b/build/Experimental.vcxproj.filters new file mode 100644 index 000000000..8622c11e8 --- /dev/null +++ b/build/Experimental.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + CMake Rules + + + + + + + + + {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} + + + diff --git a/build/INSTALL.vcxproj b/build/INSTALL.vcxproj new file mode 100644 index 000000000..fcc0e5dd0 --- /dev/null +++ b/build/INSTALL.vcxproj @@ -0,0 +1,126 @@ + + + + x64 + + + + Release + x64 + + + RelWithDebInfo + x64 + + + + {07ADCCA9-7D16-3F3D-AB6F-1BDA83D4E943} + 10.0.22000.0 + Win32Proj + x64 + INSTALL + NoUpgrade + + + + Utility + MultiByte + v143 + + + Utility + MultiByte + v143 + + + + + + + + + + <_ProjectFileVersion>10.0.20506.1 + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + Always + + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -DBUILD_TYPE=$(Configuration) -P cmake_install.cmake +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + + + + + Always + + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -DBUILD_TYPE=$(Configuration) -P cmake_install.cmake +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + + + + + + setlocal +cd . +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\INSTALL_force + false + false + + setlocal +cd . +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\INSTALL_force + false + false + + + + + {31277AF8-10A2-3494-B123-559421E08C26} + ZERO_CHECK + false + Never + + + {40EA859D-1269-313F-A313-AA32B87C8935} + ALL_BUILD + false + Never + + + + + + \ No newline at end of file diff --git a/build/INSTALL.vcxproj.filters b/build/INSTALL.vcxproj.filters new file mode 100644 index 000000000..1d3583629 --- /dev/null +++ b/build/INSTALL.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + CMake Rules + + + + + {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} + + + diff --git a/build/Nightly.vcxproj b/build/Nightly.vcxproj new file mode 100644 index 000000000..ff59ec296 --- /dev/null +++ b/build/Nightly.vcxproj @@ -0,0 +1,145 @@ + + + + x64 + + + + Release + x64 + + + RelWithDebInfo + x64 + + + + {246A2207-0D75-3894-8E4E-785344D8ABF4} + 10.0.22000.0 + Win32Proj + x64 + Nightly + NoUpgrade + + + + Utility + MultiByte + v143 + + + Utility + MultiByte + v143 + + + + + + + + + + <_ProjectFileVersion>10.0.20506.1 + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + + setlocal +"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Nightly +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\Nightly + false + false + + setlocal +"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Nightly +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\Nightly + false + false + + + + + Always + Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp + false + Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp + false + + + + + + + + + {31277AF8-10A2-3494-B123-559421E08C26} + ZERO_CHECK + false + Never + + + + + + \ No newline at end of file diff --git a/build/Nightly.vcxproj.filters b/build/Nightly.vcxproj.filters new file mode 100644 index 000000000..cf94569d8 --- /dev/null +++ b/build/Nightly.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + CMake Rules + + + + + + + + + {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} + + + diff --git a/build/NightlyMemoryCheck.vcxproj b/build/NightlyMemoryCheck.vcxproj new file mode 100644 index 000000000..260a79e55 --- /dev/null +++ b/build/NightlyMemoryCheck.vcxproj @@ -0,0 +1,145 @@ + + + + x64 + + + + Release + x64 + + + RelWithDebInfo + x64 + + + + {93318712-66D7-31F1-B537-E229E2FD9AF0} + 10.0.22000.0 + Win32Proj + x64 + NightlyMemoryCheck + NoUpgrade + + + + Utility + MultiByte + v143 + + + Utility + MultiByte + v143 + + + + + + + + + + <_ProjectFileVersion>10.0.20506.1 + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + + setlocal +"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D NightlyMemoryCheck +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\NightlyMemoryCheck + false + false + + setlocal +"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D NightlyMemoryCheck +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\NightlyMemoryCheck + false + false + + + + + Always + Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp + false + Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp + false + + + + + + + + + {31277AF8-10A2-3494-B123-559421E08C26} + ZERO_CHECK + false + Never + + + + + + \ No newline at end of file diff --git a/build/NightlyMemoryCheck.vcxproj.filters b/build/NightlyMemoryCheck.vcxproj.filters new file mode 100644 index 000000000..a4b92fdc7 --- /dev/null +++ b/build/NightlyMemoryCheck.vcxproj.filters @@ -0,0 +1,17 @@ + + + + + CMake Rules + + + + + + + + + {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} + + + diff --git a/build/PACKAGE.vcxproj b/build/PACKAGE.vcxproj new file mode 100644 index 000000000..67c1c92dc --- /dev/null +++ b/build/PACKAGE.vcxproj @@ -0,0 +1,132 @@ + + + + x64 + + + + Release + x64 + + + RelWithDebInfo + x64 + + + + {F20BBC06-43D9-375A-A5A9-E717817CF640} + 10.0.22000.0 + Win32Proj + x64 + PACKAGE + NoUpgrade + + + + Utility + MultiByte + v143 + + + Utility + MultiByte + v143 + + + + + + + + + + <_ProjectFileVersion>10.0.20506.1 + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + + setlocal +cd E:\programming\cplus\dfhack\build +if %errorlevel% neq 0 goto :cmEnd +E: +if %errorlevel% neq 0 goto :cmEnd +"C:\Program Files\CMake\bin\cpack.exe" -C $(Configuration) --config ./CPackConfig.cmake +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + + + + + + setlocal +cd E:\programming\cplus\dfhack\build +if %errorlevel% neq 0 goto :cmEnd +E: +if %errorlevel% neq 0 goto :cmEnd +"C:\Program Files\CMake\bin\cpack.exe" -C $(Configuration) --config ./CPackConfig.cmake +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + + + + + + setlocal +cd . +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\PACKAGE_force + false + false + + setlocal +cd . +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\PACKAGE_force + false + false + + + + + {31277AF8-10A2-3494-B123-559421E08C26} + ZERO_CHECK + false + Never + + + {40EA859D-1269-313F-A313-AA32B87C8935} + ALL_BUILD + false + Never + + + + + + \ No newline at end of file diff --git a/build/PACKAGE.vcxproj.filters b/build/PACKAGE.vcxproj.filters new file mode 100644 index 000000000..8c2a983bf --- /dev/null +++ b/build/PACKAGE.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + CMake Rules + + + + + {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} + + + diff --git a/build/RUN_TESTS.vcxproj b/build/RUN_TESTS.vcxproj new file mode 100644 index 000000000..197f2baf3 --- /dev/null +++ b/build/RUN_TESTS.vcxproj @@ -0,0 +1,118 @@ + + + + x64 + + + + Release + x64 + + + RelWithDebInfo + x64 + + + + {45641EBC-7207-3F33-8572-930EA9BD4C6B} + 10.0.22000.0 + Win32Proj + x64 + RUN_TESTS + NoUpgrade + + + + Utility + MultiByte + v143 + + + Utility + MultiByte + v143 + + + + + + + + + + <_ProjectFileVersion>10.0.20506.1 + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + + setlocal +"C:\Program Files\CMake\bin\ctest.exe" --force-new-ctest-process -C $(Configuration) +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + + + + + + setlocal +"C:\Program Files\CMake\bin\ctest.exe" --force-new-ctest-process -C $(Configuration) +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + + + + + + setlocal +cd . +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\RUN_TESTS_force + false + false + + setlocal +cd . +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + %(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\RUN_TESTS_force + false + false + + + + + {31277AF8-10A2-3494-B123-559421E08C26} + ZERO_CHECK + false + Never + + + + + + \ No newline at end of file diff --git a/build/RUN_TESTS.vcxproj.filters b/build/RUN_TESTS.vcxproj.filters new file mode 100644 index 000000000..9b4c15921 --- /dev/null +++ b/build/RUN_TESTS.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + CMake Rules + + + + + {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} + + + diff --git a/build/ZERO_CHECK.vcxproj b/build/ZERO_CHECK.vcxproj new file mode 100644 index 000000000..c71698f74 --- /dev/null +++ b/build/ZERO_CHECK.vcxproj @@ -0,0 +1,105 @@ + + + + x64 + + + + Release + x64 + + + RelWithDebInfo + x64 + + + + {31277AF8-10A2-3494-B123-559421E08C26} + 10.0.22000.0 + Win32Proj + x64 + ZERO_CHECK + NoUpgrade + + + + Utility + MultiByte + v143 + + + Utility + MultiByte + v143 + + + + + + + + + + <_ProjectFileVersion>10.0.20506.1 + $(Platform)\$(Configuration)\$(ProjectName)\ + $(Platform)\$(Configuration)\$(ProjectName)\ + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) + $(ProjectDir)/$(IntDir) + %(Filename).h + %(Filename).tlb + %(Filename)_i.c + %(Filename)_p.c + + + + + Always + Checking Build System + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-list CMakeFiles/generate.stamp.list --vs-solution-file E:/programming/cplus/dfhack/build/dfhack.sln +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\BasicConfigVersion-AnyNewerVersion.cmake.in;C:\Program Files\CMake\share\cmake-3.22\Modules\BasicConfigVersion-SameMajorVersion.cmake.in;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCheckCompilerFlagCommonPatterns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakePackageConfigHelpers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCCompilerFlag.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCSourceRuns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSymbolExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckFunctionExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFile.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFileCXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckLibraryExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckStructHasMember.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckSymbolExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckTypeSize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\GNUInstallDirs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckCompilerFlag.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceRuns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\TestBigEndian.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\WriteBasicConfigVersionFile.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\CMakeLists.txt;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;E:\programming\cplus\dfhack\data\CMakeLists.txt;E:\programming\cplus\dfhack\depends\CMakeLists.txt;E:\programming\cplus\dfhack\depends\clsocket\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\cmake\JoinPaths.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\PreventInBuildInstalls.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\PreventInSourceBuilds.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\pkg-config\jsoncpp.pc.in;E:\programming\cplus\dfhack\depends\jsoncpp-sub\src\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\src\lib_json\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\version.in;E:\programming\cplus\dfhack\depends\libexpat\expat\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libexpat\expat\Changes;E:\programming\cplus\dfhack\depends\libexpat\expat\ConfigureChecks.cmake;E:\programming\cplus\dfhack\depends\libexpat\expat\cmake\expat-config.cmake.in;E:\programming\cplus\dfhack\depends\libexpat\expat\expat_config.h.cmake;E:\programming\cplus\dfhack\depends\libzip\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libzip\cmake-config.h.in;E:\programming\cplus\dfhack\depends\libzip\cmake-zipconf.h.in;E:\programming\cplus\dfhack\depends\libzip\cmake\Dist.cmake;E:\programming\cplus\dfhack\depends\libzip\lib\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libzip\libzip-config.cmake.in;E:\programming\cplus\dfhack\depends\libzip\libzip.pc.in;E:\programming\cplus\dfhack\depends\libzip\regress\nihtest.conf.in;E:\programming\cplus\dfhack\depends\libzip\regress\runtest.in;E:\programming\cplus\dfhack\depends\lodepng\CMakeLists.txt;E:\programming\cplus\dfhack\depends\lua\CMakeLists.txt;E:\programming\cplus\dfhack\depends\md5\CMakeLists.txt;E:\programming\cplus\dfhack\depends\protobuf\CMakeLists.txt;E:\programming\cplus\dfhack\depends\protobuf\config.h.in;E:\programming\cplus\dfhack\depends\tinyxml\CMakeLists.txt;E:\programming\cplus\dfhack\depends\tthread\CMakeLists.txt;E:\programming\cplus\dfhack\depends\xlsxio\CMakeLists.txt;E:\programming\cplus\dfhack\library\CMakeLists.txt;E:\programming\cplus\dfhack\library\git-describe.cmake.in;E:\programming\cplus\dfhack\library\xml\CMakeLists.txt;E:\programming\cplus\dfhack\library\xml\tools\CMakeLists.txt;E:\programming\cplus\dfhack\package\windows\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\Plugins.cmake;E:\programming\cplus\dfhack\plugins\autolabor\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\buildingplan\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\channel-safely\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\external\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\remotefortressreader\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\stockpiles\CMakeLists.txt;E:\programming\cplus\dfhack\scripts\CMakeLists.txt;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\lodepng\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\lua\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\md5\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\protobuf\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\tinyxml\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\tthread\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\src\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\src\lib_json\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\include\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\clsocket\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libexpat\expat\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libzip\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libzip\lib\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\xlsxio\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\xml\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\xml\tools\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\autolabor\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\buildingplan\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\channel-safely\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\remotefortressreader\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\stockpiles\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\external\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\data\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\scripts\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\package\windows\CMakeFiles\generate.stamp + false + Checking Build System + setlocal +"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-list CMakeFiles/generate.stamp.list --vs-solution-file E:/programming/cplus/dfhack/build/dfhack.sln +if %errorlevel% neq 0 goto :cmEnd +:cmEnd +endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone +:cmErrorLevel +exit /b %1 +:cmDone +if %errorlevel% neq 0 goto :VCEnd + C:\Program Files\CMake\share\cmake-3.22\Modules\BasicConfigVersion-AnyNewerVersion.cmake.in;C:\Program Files\CMake\share\cmake-3.22\Modules\BasicConfigVersion-SameMajorVersion.cmake.in;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCheckCompilerFlagCommonPatterns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakePackageConfigHelpers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCCompilerFlag.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCSourceRuns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSymbolExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckFunctionExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFile.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFileCXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckLibraryExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckStructHasMember.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckSymbolExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckTypeSize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\GNUInstallDirs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckCompilerFlag.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceRuns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\TestBigEndian.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\WriteBasicConfigVersionFile.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\CMakeLists.txt;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;E:\programming\cplus\dfhack\data\CMakeLists.txt;E:\programming\cplus\dfhack\depends\CMakeLists.txt;E:\programming\cplus\dfhack\depends\clsocket\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\cmake\JoinPaths.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\PreventInBuildInstalls.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\PreventInSourceBuilds.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\pkg-config\jsoncpp.pc.in;E:\programming\cplus\dfhack\depends\jsoncpp-sub\src\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\src\lib_json\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\version.in;E:\programming\cplus\dfhack\depends\libexpat\expat\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libexpat\expat\Changes;E:\programming\cplus\dfhack\depends\libexpat\expat\ConfigureChecks.cmake;E:\programming\cplus\dfhack\depends\libexpat\expat\cmake\expat-config.cmake.in;E:\programming\cplus\dfhack\depends\libexpat\expat\expat_config.h.cmake;E:\programming\cplus\dfhack\depends\libzip\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libzip\cmake-config.h.in;E:\programming\cplus\dfhack\depends\libzip\cmake-zipconf.h.in;E:\programming\cplus\dfhack\depends\libzip\cmake\Dist.cmake;E:\programming\cplus\dfhack\depends\libzip\lib\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libzip\libzip-config.cmake.in;E:\programming\cplus\dfhack\depends\libzip\libzip.pc.in;E:\programming\cplus\dfhack\depends\libzip\regress\nihtest.conf.in;E:\programming\cplus\dfhack\depends\libzip\regress\runtest.in;E:\programming\cplus\dfhack\depends\lodepng\CMakeLists.txt;E:\programming\cplus\dfhack\depends\lua\CMakeLists.txt;E:\programming\cplus\dfhack\depends\md5\CMakeLists.txt;E:\programming\cplus\dfhack\depends\protobuf\CMakeLists.txt;E:\programming\cplus\dfhack\depends\protobuf\config.h.in;E:\programming\cplus\dfhack\depends\tinyxml\CMakeLists.txt;E:\programming\cplus\dfhack\depends\tthread\CMakeLists.txt;E:\programming\cplus\dfhack\depends\xlsxio\CMakeLists.txt;E:\programming\cplus\dfhack\library\CMakeLists.txt;E:\programming\cplus\dfhack\library\git-describe.cmake.in;E:\programming\cplus\dfhack\library\xml\CMakeLists.txt;E:\programming\cplus\dfhack\library\xml\tools\CMakeLists.txt;E:\programming\cplus\dfhack\package\windows\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\Plugins.cmake;E:\programming\cplus\dfhack\plugins\autolabor\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\buildingplan\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\channel-safely\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\external\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\remotefortressreader\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\stockpiles\CMakeLists.txt;E:\programming\cplus\dfhack\scripts\CMakeLists.txt;%(AdditionalInputs) + E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\lodepng\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\lua\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\md5\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\protobuf\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\tinyxml\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\tthread\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\src\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\src\lib_json\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\include\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\clsocket\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libexpat\expat\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libzip\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libzip\lib\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\xlsxio\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\xml\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\xml\tools\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\autolabor\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\buildingplan\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\channel-safely\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\remotefortressreader\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\stockpiles\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\external\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\data\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\scripts\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\package\windows\CMakeFiles\generate.stamp + false + + + + + + + + + + \ No newline at end of file diff --git a/build/ZERO_CHECK.vcxproj.filters b/build/ZERO_CHECK.vcxproj.filters new file mode 100644 index 000000000..2c79705a5 --- /dev/null +++ b/build/ZERO_CHECK.vcxproj.filters @@ -0,0 +1,13 @@ + + + + + CMake Rules + + + + + {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} + + + diff --git a/build/dfhack.sln b/build/dfhack.sln new file mode 100644 index 000000000..83a916c71 --- /dev/null +++ b/build/dfhack.sln @@ -0,0 +1,1295 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CMakePredefinedTargets", "CMakePredefinedTargets", "{28D9607F-8931-375B-9273-9E20D2F6347F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CTestDashboardTargets", "CTestDashboardTargets", "{068CE9B1-E6DD-3864-AC38-93F10EF27A17}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Depends", "Depends", "{D8D353CC-1D2C-3A83-8EA0-A85D6CF14722}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{25456F37-E968-3921-80E5-1C0E141753B6}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ALL_BUILD", "ALL_BUILD.vcxproj", "{40EA859D-1269-313F-A313-AA32B87C8935}" + ProjectSection(ProjectDependencies) = postProject + {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA} = {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA} + {14C478D6-D815-378F-81D1-B53BBD6CBE9A} = {14C478D6-D815-378F-81D1-B53BBD6CBE9A} + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {3A2B0858-3B92-3598-B679-2A437C1286E0} = {3A2B0858-3B92-3598-B679-2A437C1286E0} + {27ECEB5C-C396-32BE-93E6-4D4801692191} = {27ECEB5C-C396-32BE-93E6-4D4801692191} + {5F63101D-75FE-31BE-9D25-6641FBBFF959} = {5F63101D-75FE-31BE-9D25-6641FBBFF959} + {7D67495E-4C92-37BE-BEF8-174CA37ADD21} = {7D67495E-4C92-37BE-BEF8-174CA37ADD21} + {6152D284-A720-3556-A60A-7C13C89205AD} = {6152D284-A720-3556-A60A-7C13C89205AD} + {4049FF1D-8A65-3021-B550-0DE0E63F9577} = {4049FF1D-8A65-3021-B550-0DE0E63F9577} + {8CE562EE-798E-3C1B-975C-F49C6B5C84ED} = {8CE562EE-798E-3C1B-975C-F49C6B5C84ED} + {961FD68A-49A7-3F16-9F96-16AC8236D3A3} = {961FD68A-49A7-3F16-9F96-16AC8236D3A3} + {D3C67352-8290-3C4E-9F23-93DDE051AA37} = {D3C67352-8290-3C4E-9F23-93DDE051AA37} + {A0486456-80E4-3492-940E-6652FF2B45B9} = {A0486456-80E4-3492-940E-6652FF2B45B9} + {386966C3-DC46-3936-AD44-35E2470C6A28} = {386966C3-DC46-3936-AD44-35E2470C6A28} + {02D9B109-1602-3567-80C0-3BF354675829} = {02D9B109-1602-3567-80C0-3BF354675829} + {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA} = {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA} + {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515} = {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515} + {76B00654-E15A-3E4F-8C41-DDC63A14246A} = {76B00654-E15A-3E4F-8C41-DDC63A14246A} + {D7DF31C2-3247-31BA-A745-DF4095334504} = {D7DF31C2-3247-31BA-A745-DF4095334504} + {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204} = {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204} + {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5} = {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5} + {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB} = {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB} + {BAABB124-4999-3462-AF35-16DB3C974D7C} = {BAABB124-4999-3462-AF35-16DB3C974D7C} + {6F451C91-A082-3981-83D5-65844ED16BDA} = {6F451C91-A082-3981-83D5-65844ED16BDA} + {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80} = {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80} + {AB8FA0F9-1482-31F8-87E2-E3C7BB178053} = {AB8FA0F9-1482-31F8-87E2-E3C7BB178053} + {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212} = {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212} + {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20} = {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20} + {5347E62F-7AEB-3B7C-B480-161A35974C9E} = {5347E62F-7AEB-3B7C-B480-161A35974C9E} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {136AD85C-398C-329A-84AC-AD4481963950} = {136AD85C-398C-329A-84AC-AD4481963950} + {78DBE964-AC8C-3264-903B-2B102B46D476} = {78DBE964-AC8C-3264-903B-2B102B46D476} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {D3A6760C-34FD-3EE2-B9CC-24647168DC6A} = {D3A6760C-34FD-3EE2-B9CC-24647168DC6A} + {AFC95A6A-BDBB-35E2-9381-253284E1112D} = {AFC95A6A-BDBB-35E2-9381-253284E1112D} + {0AED7AC4-8C48-3205-AF43-3D536A60D815} = {0AED7AC4-8C48-3205-AF43-3D536A60D815} + {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96} = {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96} + {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} = {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} + {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7} = {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7} + {47842A81-7497-313E-B466-C60AE89334CB} = {47842A81-7497-313E-B466-C60AE89334CB} + {25303A98-8EE4-3355-8C68-CFA8B4116EF0} = {25303A98-8EE4-3355-8C68-CFA8B4116EF0} + {A80E6C37-1E31-3DDC-A4FE-B21553E580DB} = {A80E6C37-1E31-3DDC-A4FE-B21553E580DB} + {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA} = {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA} + {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD} = {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD} + {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B} = {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B} + {21572060-CA28-355B-A508-5675A4A2FAB3} = {21572060-CA28-355B-A508-5675A4A2FAB3} + {F1206958-458C-3F18-84D9-3EEE07B73862} = {F1206958-458C-3F18-84D9-3EEE07B73862} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3} = {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3} + {419297F2-C54C-3C4B-91AB-7B119D09E730} = {419297F2-C54C-3C4B-91AB-7B119D09E730} + {8F94C6B8-42CE-329C-B6A9-3E13C04350CF} = {8F94C6B8-42CE-329C-B6A9-3E13C04350CF} + {7FF993D7-A6D3-37CC-AE69-2906ECD89E03} = {7FF993D7-A6D3-37CC-AE69-2906ECD89E03} + {374D8559-CBBF-3F24-BEE1-8B11A184B7F8} = {374D8559-CBBF-3F24-BEE1-8B11A184B7F8} + {4E197970-E280-3B04-AD7D-E52DC551E902} = {4E197970-E280-3B04-AD7D-E52DC551E902} + {4E6C8BD2-2434-31DC-BDD2-8788D2547403} = {4E6C8BD2-2434-31DC-BDD2-8788D2547403} + {37629CF4-1B6A-312A-89B7-CF11593F51A4} = {37629CF4-1B6A-312A-89B7-CF11593F51A4} + {8D195538-264D-3C39-AB9A-653DA8A6F56E} = {8D195538-264D-3C39-AB9A-653DA8A6F56E} + {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} + {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} = {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} + {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} + {E36DC20B-AE7A-3449-B308-C932B9DD4290} = {E36DC20B-AE7A-3449-B308-C932B9DD4290} + {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121} = {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121} + {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3} = {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3} + {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2} = {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2} + {C080819A-4275-3D2A-84DE-7C21EDAE2BBA} = {C080819A-4275-3D2A-84DE-7C21EDAE2BBA} + {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F} = {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F} + {6579683E-AB4A-3B40-A145-1952047837D2} = {6579683E-AB4A-3B40-A145-1952047837D2} + {2FE38842-BDF7-3A93-9D06-1C9814B6B11B} = {2FE38842-BDF7-3A93-9D06-1C9814B6B11B} + {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C} = {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C} + {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4} = {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4} + {C884F97B-4C5C-3457-AF4D-BB4C05670662} = {C884F97B-4C5C-3457-AF4D-BB4C05670662} + {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D} = {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D} + {796760C3-71E4-32AD-A9C4-B984AFC97106} = {796760C3-71E4-32AD-A9C4-B984AFC97106} + {8054C91C-5221-314F-96C5-8FEC57BBEED1} = {8054C91C-5221-314F-96C5-8FEC57BBEED1} + {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} = {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} + {3B9F42C2-0060-329E-B123-7DEF1E91617D} = {3B9F42C2-0060-329E-B123-7DEF1E91617D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "3dveins", "plugins\3dveins.vcxproj", "{B10F83BD-77CE-3CC2-A4D0-2B412287DFEA}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous", "Continuous.vcxproj", "{D7C70C41-500D-35F8-A992-1351DDDCDA0C}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Experimental", "Experimental.vcxproj", "{474F765F-548E-3AAB-8D5B-66CF364BE4B2}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "INSTALL", "INSTALL.vcxproj", "{07ADCCA9-7D16-3F3D-AB6F-1BDA83D4E943}" + ProjectSection(ProjectDependencies) = postProject + {40EA859D-1269-313F-A313-AA32B87C8935} = {40EA859D-1269-313F-A313-AA32B87C8935} + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Nightly", "Nightly.vcxproj", "{246A2207-0D75-3894-8E4E-785344D8ABF4}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NightlyMemoryCheck", "NightlyMemoryCheck.vcxproj", "{93318712-66D7-31F1-B537-E229E2FD9AF0}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PACKAGE", "PACKAGE.vcxproj", "{F20BBC06-43D9-375A-A5A9-E717817CF640}" + ProjectSection(ProjectDependencies) = postProject + {40EA859D-1269-313F-A313-AA32B87C8935} = {40EA859D-1269-313F-A313-AA32B87C8935} + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RUN_TESTS", "RUN_TESTS.vcxproj", "{45641EBC-7207-3F33-8572-930EA9BD4C6B}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RemoteFortressReader", "plugins\remotefortressreader\RemoteFortressReader.vcxproj", "{14C478D6-D815-378F-81D1-B53BBD6CBE9A}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {69CB13F6-E5DD-3AC2-AF47-08A452514760} = {69CB13F6-E5DD-3AC2-AF47-08A452514760} + {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "ZERO_CHECK.vcxproj", "{31277AF8-10A2-3494-B123-559421E08C26}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "add-spatter", "plugins\add-spatter.vcxproj", "{3A2B0858-3B92-3598-B679-2A437C1286E0}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autobutcher", "plugins\autobutcher.vcxproj", "{27ECEB5C-C396-32BE-93E6-4D4801692191}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autochop", "plugins\autochop.vcxproj", "{5F63101D-75FE-31BE-9D25-6641FBBFF959}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autoclothing", "plugins\autoclothing.vcxproj", "{7D67495E-4C92-37BE-BEF8-174CA37ADD21}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autodump", "plugins\autodump.vcxproj", "{6152D284-A720-3556-A60A-7C13C89205AD}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autofarm", "plugins\autofarm.vcxproj", "{4049FF1D-8A65-3021-B550-0DE0E63F9577}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autolabor", "plugins\autolabor\autolabor.vcxproj", "{8CE562EE-798E-3C1B-975C-F49C6B5C84ED}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autonestbox", "plugins\autonestbox.vcxproj", "{961FD68A-49A7-3F16-9F96-16AC8236D3A3}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autoslab", "plugins\autoslab.vcxproj", "{D3C67352-8290-3C4E-9F23-93DDE051AA37}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "binpatch", "library\binpatch.vcxproj", "{A0486456-80E4-3492-940E-6652FF2B45B9}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {111D1A41-5C7F-397A-A62C-B19B0AEB044B} = {111D1A41-5C7F-397A-A62C-B19B0AEB044B} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blueprint", "plugins\blueprint.vcxproj", "{386966C3-DC46-3936-AD44-35E2470C6A28}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "buildingplan", "plugins\buildingplan\buildingplan.vcxproj", "{02D9B109-1602-3567-80C0-3BF354675829}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "changeitem", "plugins\changeitem.vcxproj", "{B6B32914-FA20-3991-AEDE-3FFA75FDF7DA}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "changelayer", "plugins\changelayer.vcxproj", "{C153A10F-47F2-3FF1-A27D-0CE7AA4B1515}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "changevein", "plugins\changevein.vcxproj", "{76B00654-E15A-3E4F-8C41-DDC63A14246A}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "channel-safely", "plugins\channel-safely\channel-safely.vcxproj", "{D7DF31C2-3247-31BA-A745-DF4095334504}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cleanconst", "plugins\cleanconst.vcxproj", "{2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cleaners", "plugins\cleaners.vcxproj", "{099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cleanowned", "plugins\cleanowned.vcxproj", "{D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "clsocket", "depends\clsocket\clsocket.vcxproj", "{39BD79E1-6088-33F3-AD4A-74F0E0EE785C}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "confirm", "plugins\confirm.vcxproj", "{BAABB124-4999-3462-AF35-16DB3C974D7C}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "createitem", "plugins\createitem.vcxproj", "{6F451C91-A082-3981-83D5-65844ED16BDA}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cursecheck", "plugins\cursecheck.vcxproj", "{C143DDD8-9AB8-368F-ACE4-BA4F7651DA80}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cxxrandom", "plugins\cxxrandom.vcxproj", "{AB8FA0F9-1482-31F8-87E2-E3C7BB178053}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "debug", "plugins\debug.vcxproj", "{CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {CD9E5829-45CA-308D-9ED7-C2C38139D69E} = {CD9E5829-45CA-308D-9ED7-C2C38139D69E} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "deramp", "plugins\deramp.vcxproj", "{E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "design", "plugins\design.vcxproj", "{5347E62F-7AEB-3B7C-B480-161A35974C9E}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack", "library\dfhack.vcxproj", "{6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} = {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} + {111D1A41-5C7F-397A-A62C-B19B0AEB044B} = {111D1A41-5C7F-397A-A62C-B19B0AEB044B} + {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7} = {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7} + {19F34DB6-1C4F-36FD-A7A8-8E5077651209} = {19F34DB6-1C4F-36FD-A7A8-8E5077651209} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE} = {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE} + {A294D3AD-91C7-32D9-B361-D399900843E5} = {A294D3AD-91C7-32D9-B361-D399900843E5} + {CD9E5829-45CA-308D-9ED7-C2C38139D69E} = {CD9E5829-45CA-308D-9ED7-C2C38139D69E} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-client", "library\dfhack-client.vcxproj", "{136AD85C-398C-329A-84AC-AD4481963950}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} = {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {CD9E5829-45CA-308D-9ED7-C2C38139D69E} = {CD9E5829-45CA-308D-9ED7-C2C38139D69E} + {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-lodepng", "depends\lodepng\dfhack-lodepng.vcxproj", "{8DB90A0E-6076-3C07-B890-7E5E886009EC}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-md5", "depends\md5\dfhack-md5.vcxproj", "{111D1A41-5C7F-397A-A62C-B19B0AEB044B}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-run", "library\dfhack-run.vcxproj", "{78DBE964-AC8C-3264-903B-2B102B46D476}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} = {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} + {136AD85C-398C-329A-84AC-AD4481963950} = {136AD85C-398C-329A-84AC-AD4481963950} + {CD9E5829-45CA-308D-9ED7-C2C38139D69E} = {CD9E5829-45CA-308D-9ED7-C2C38139D69E} + {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-tinythread", "depends\tthread\dfhack-tinythread.vcxproj", "{D3A713C3-480C-3DF0-95FA-8B80D95DF8F7}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-tinyxml", "depends\tinyxml\dfhack-tinyxml.vcxproj", "{19F34DB6-1C4F-36FD-A7A8-8E5077651209}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-version", "library\dfhack-version.vcxproj", "{5DC5A20B-821C-3008-A247-B08677276F56}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dig", "plugins\dig.vcxproj", "{D3A6760C-34FD-3EE2-B9CC-24647168DC6A}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dig-now", "plugins\dig-now.vcxproj", "{AFC95A6A-BDBB-35E2-9381-253284E1112D}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dist", "depends\libzip\dist.vcxproj", "{24F97336-D35B-3FBA-BEF8-64B2D5845D3F}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "distcheck", "depends\libzip\distcheck.vcxproj", "{86289ECD-3E29-3E01-93B2-829B5666A809}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {24F97336-D35B-3FBA-BEF8-64B2D5845D3F} = {24F97336-D35B-3FBA-BEF8-64B2D5845D3F} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dwarfvet", "plugins\dwarfvet.vcxproj", "{0AED7AC4-8C48-3205-AF43-3D536A60D815}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eventful", "plugins\eventful.vcxproj", "{D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "expat", "depends\libexpat\expat\expat.vcxproj", "{BA32E800-D5FA-3F4E-B91B-763CD4FE389C}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fastdwarf", "plugins\fastdwarf.vcxproj", "{894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "faststart", "plugins\faststart.vcxproj", "{47842A81-7497-313E-B466-C60AE89334CB}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "filltraffic", "plugins\filltraffic.vcxproj", "{25303A98-8EE4-3355-8C68-CFA8B4116EF0}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flows", "plugins\flows.vcxproj", "{A80E6C37-1E31-3DDC-A4FE-B21553E580DB}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate_headers", "library\generate_headers.vcxproj", "{F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate_proto", "plugins\generate_proto.vcxproj", "{0AE42C92-16FF-3E69-B468-111535996095}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate_proto_RemoteFortressReader", "plugins\remotefortressreader\generate_proto_RemoteFortressReader.vcxproj", "{69CB13F6-E5DD-3AC2-AF47-08A452514760}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate_proto_core", "library\generate_proto_core.vcxproj", "{A294D3AD-91C7-32D9-B361-D399900843E5}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate_proto_stockpiles", "plugins\stockpiles\generate_proto_stockpiles.vcxproj", "{73A57BCF-3487-35DC-B448-FD328037CDF3}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getplants", "plugins\getplants.vcxproj", "{E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hotkeys", "plugins\hotkeys.vcxproj", "{6F10CAC8-6D9F-357E-B574-5EC901BF4EAD}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jsoncpp_static", "depends\jsoncpp-sub\src\lib_json\jsoncpp_static.vcxproj", "{CD9E5829-45CA-308D-9ED7-C2C38139D69E}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lair", "plugins\lair.vcxproj", "{DA8EE8E6-6AE0-3DA6-AED9-316977621A0B}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liquids", "plugins\liquids.vcxproj", "{21572060-CA28-355B-A508-5675A4A2FAB3}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logistics", "plugins\logistics.vcxproj", "{F1206958-458C-3F18-84D9-3EEE07B73862}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lua", "depends\lua\lua.vcxproj", "{6CA1FA88-B709-340C-8366-DCE4C1D1FB32}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luasocket", "plugins\luasocket.vcxproj", "{4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} = {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7} = {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "misery", "plugins\misery.vcxproj", "{419297F2-C54C-3C4B-91AB-7B119D09E730}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nestboxes", "plugins\nestboxes.vcxproj", "{8F94C6B8-42CE-329C-B6A9-3E13C04350CF}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "orders", "plugins\orders.vcxproj", "{7FF993D7-A6D3-37CC-AE69-2906ECD89E03}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {CD9E5829-45CA-308D-9ED7-C2C38139D69E} = {CD9E5829-45CA-308D-9ED7-C2C38139D69E} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "overlay", "plugins\overlay.vcxproj", "{374D8559-CBBF-3F24-BEE1-8B11A184B7F8}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pathable", "plugins\pathable.vcxproj", "{4E197970-E280-3B04-AD7D-E52DC551E902}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "probe", "plugins\probe.vcxproj", "{4E6C8BD2-2434-31DC-BDD2-8788D2547403}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "prospector", "plugins\prospector.vcxproj", "{37629CF4-1B6A-312A-89B7-CF11593F51A4}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protobuf", "depends\protobuf\protobuf.vcxproj", "{8D195538-264D-3C39-AB9A-653DA8A6F56E}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protobuf-lite", "depends\protobuf\protobuf-lite.vcxproj", "{9302E53B-085D-3577-A3E2-EB51A51D084C}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protoc", "depends\protobuf\protoc.vcxproj", "{1C17AAAA-9E99-32C1-9FF6-E88C054A2646}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {8D195538-264D-3C39-AB9A-653DA8A6F56E} = {8D195538-264D-3C39-AB9A-653DA8A6F56E} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protoc-bin", "depends\protobuf\protoc-bin.vcxproj", "{74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {8D195538-264D-3C39-AB9A-653DA8A6F56E} = {8D195538-264D-3C39-AB9A-653DA8A6F56E} + {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} = {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regrass", "plugins\regrass.vcxproj", "{E36DC20B-AE7A-3449-B308-C932B9DD4290}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reveal", "plugins\reveal.vcxproj", "{C831208B-D7C3-3DD6-9F16-0EA8A5FF3121}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "seedwatch", "plugins\seedwatch.vcxproj", "{7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "showmood", "plugins\showmood.vcxproj", "{E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sort", "plugins\sort.vcxproj", "{C080819A-4275-3D2A-84DE-7C21EDAE2BBA}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stockpiles", "plugins\stockpiles\stockpiles.vcxproj", "{7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {73A57BCF-3487-35DC-B448-FD328037CDF3} = {73A57BCF-3487-35DC-B448-FD328037CDF3} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strangemood", "plugins\strangemood.vcxproj", "{6579683E-AB4A-3B40-A145-1952047837D2}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tailor", "plugins\tailor.vcxproj", "{2FE38842-BDF7-3A93-9D06-1C9814B6B11B}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tiletypes", "plugins\tiletypes.vcxproj", "{B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "work-now", "plugins\work-now.vcxproj", "{2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "workflow", "plugins\workflow.vcxproj", "{C884F97B-4C5C-3457-AF4D-BB4C05670662}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xlsxio_read_STATIC", "depends\xlsxio\xlsxio_read_STATIC.vcxproj", "{85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} = {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} + {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} = {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xlsxio_write_STATIC", "depends\xlsxio\xlsxio_write_STATIC.vcxproj", "{796760C3-71E4-32AD-A9C4-B984AFC97106}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} = {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xlsxreader", "plugins\xlsxreader.vcxproj", "{8054C91C-5221-314F-96C5-8FEC57BBEED1}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} = {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D} = {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D} + {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} = {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zip", "depends\libzip\lib\zip.vcxproj", "{744BEFA7-C931-39C8-A1B4-1A9A88901B1D}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zone", "plugins\zone.vcxproj", "{3B9F42C2-0060-329E-B123-7DEF1E91617D}" + ProjectSection(ProjectDependencies) = postProject + {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} + {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} + {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|x64 = Release|x64 + RelWithDebInfo|x64 = RelWithDebInfo|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {40EA859D-1269-313F-A313-AA32B87C8935}.Release|x64.ActiveCfg = Release|x64 + {40EA859D-1269-313F-A313-AA32B87C8935}.Release|x64.Build.0 = Release|x64 + {40EA859D-1269-313F-A313-AA32B87C8935}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {40EA859D-1269-313F-A313-AA32B87C8935}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA}.Release|x64.ActiveCfg = Release|x64 + {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA}.Release|x64.Build.0 = Release|x64 + {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {D7C70C41-500D-35F8-A992-1351DDDCDA0C}.Release|x64.ActiveCfg = Release|x64 + {D7C70C41-500D-35F8-A992-1351DDDCDA0C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {474F765F-548E-3AAB-8D5B-66CF364BE4B2}.Release|x64.ActiveCfg = Release|x64 + {474F765F-548E-3AAB-8D5B-66CF364BE4B2}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {07ADCCA9-7D16-3F3D-AB6F-1BDA83D4E943}.Release|x64.ActiveCfg = Release|x64 + {07ADCCA9-7D16-3F3D-AB6F-1BDA83D4E943}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {246A2207-0D75-3894-8E4E-785344D8ABF4}.Release|x64.ActiveCfg = Release|x64 + {246A2207-0D75-3894-8E4E-785344D8ABF4}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {93318712-66D7-31F1-B537-E229E2FD9AF0}.Release|x64.ActiveCfg = Release|x64 + {93318712-66D7-31F1-B537-E229E2FD9AF0}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {F20BBC06-43D9-375A-A5A9-E717817CF640}.Release|x64.ActiveCfg = Release|x64 + {F20BBC06-43D9-375A-A5A9-E717817CF640}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {45641EBC-7207-3F33-8572-930EA9BD4C6B}.Release|x64.ActiveCfg = Release|x64 + {45641EBC-7207-3F33-8572-930EA9BD4C6B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {14C478D6-D815-378F-81D1-B53BBD6CBE9A}.Release|x64.ActiveCfg = Release|x64 + {14C478D6-D815-378F-81D1-B53BBD6CBE9A}.Release|x64.Build.0 = Release|x64 + {14C478D6-D815-378F-81D1-B53BBD6CBE9A}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {14C478D6-D815-378F-81D1-B53BBD6CBE9A}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {31277AF8-10A2-3494-B123-559421E08C26}.Release|x64.ActiveCfg = Release|x64 + {31277AF8-10A2-3494-B123-559421E08C26}.Release|x64.Build.0 = Release|x64 + {31277AF8-10A2-3494-B123-559421E08C26}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {31277AF8-10A2-3494-B123-559421E08C26}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {3A2B0858-3B92-3598-B679-2A437C1286E0}.Release|x64.ActiveCfg = Release|x64 + {3A2B0858-3B92-3598-B679-2A437C1286E0}.Release|x64.Build.0 = Release|x64 + {3A2B0858-3B92-3598-B679-2A437C1286E0}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {3A2B0858-3B92-3598-B679-2A437C1286E0}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {27ECEB5C-C396-32BE-93E6-4D4801692191}.Release|x64.ActiveCfg = Release|x64 + {27ECEB5C-C396-32BE-93E6-4D4801692191}.Release|x64.Build.0 = Release|x64 + {27ECEB5C-C396-32BE-93E6-4D4801692191}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {27ECEB5C-C396-32BE-93E6-4D4801692191}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {5F63101D-75FE-31BE-9D25-6641FBBFF959}.Release|x64.ActiveCfg = Release|x64 + {5F63101D-75FE-31BE-9D25-6641FBBFF959}.Release|x64.Build.0 = Release|x64 + {5F63101D-75FE-31BE-9D25-6641FBBFF959}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {5F63101D-75FE-31BE-9D25-6641FBBFF959}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {7D67495E-4C92-37BE-BEF8-174CA37ADD21}.Release|x64.ActiveCfg = Release|x64 + {7D67495E-4C92-37BE-BEF8-174CA37ADD21}.Release|x64.Build.0 = Release|x64 + {7D67495E-4C92-37BE-BEF8-174CA37ADD21}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {7D67495E-4C92-37BE-BEF8-174CA37ADD21}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {6152D284-A720-3556-A60A-7C13C89205AD}.Release|x64.ActiveCfg = Release|x64 + {6152D284-A720-3556-A60A-7C13C89205AD}.Release|x64.Build.0 = Release|x64 + {6152D284-A720-3556-A60A-7C13C89205AD}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {6152D284-A720-3556-A60A-7C13C89205AD}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {4049FF1D-8A65-3021-B550-0DE0E63F9577}.Release|x64.ActiveCfg = Release|x64 + {4049FF1D-8A65-3021-B550-0DE0E63F9577}.Release|x64.Build.0 = Release|x64 + {4049FF1D-8A65-3021-B550-0DE0E63F9577}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {4049FF1D-8A65-3021-B550-0DE0E63F9577}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {8CE562EE-798E-3C1B-975C-F49C6B5C84ED}.Release|x64.ActiveCfg = Release|x64 + {8CE562EE-798E-3C1B-975C-F49C6B5C84ED}.Release|x64.Build.0 = Release|x64 + {8CE562EE-798E-3C1B-975C-F49C6B5C84ED}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {8CE562EE-798E-3C1B-975C-F49C6B5C84ED}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {961FD68A-49A7-3F16-9F96-16AC8236D3A3}.Release|x64.ActiveCfg = Release|x64 + {961FD68A-49A7-3F16-9F96-16AC8236D3A3}.Release|x64.Build.0 = Release|x64 + {961FD68A-49A7-3F16-9F96-16AC8236D3A3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {961FD68A-49A7-3F16-9F96-16AC8236D3A3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {D3C67352-8290-3C4E-9F23-93DDE051AA37}.Release|x64.ActiveCfg = Release|x64 + {D3C67352-8290-3C4E-9F23-93DDE051AA37}.Release|x64.Build.0 = Release|x64 + {D3C67352-8290-3C4E-9F23-93DDE051AA37}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {D3C67352-8290-3C4E-9F23-93DDE051AA37}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {A0486456-80E4-3492-940E-6652FF2B45B9}.Release|x64.ActiveCfg = Release|x64 + {A0486456-80E4-3492-940E-6652FF2B45B9}.Release|x64.Build.0 = Release|x64 + {A0486456-80E4-3492-940E-6652FF2B45B9}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {A0486456-80E4-3492-940E-6652FF2B45B9}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {386966C3-DC46-3936-AD44-35E2470C6A28}.Release|x64.ActiveCfg = Release|x64 + {386966C3-DC46-3936-AD44-35E2470C6A28}.Release|x64.Build.0 = Release|x64 + {386966C3-DC46-3936-AD44-35E2470C6A28}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {386966C3-DC46-3936-AD44-35E2470C6A28}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {02D9B109-1602-3567-80C0-3BF354675829}.Release|x64.ActiveCfg = Release|x64 + {02D9B109-1602-3567-80C0-3BF354675829}.Release|x64.Build.0 = Release|x64 + {02D9B109-1602-3567-80C0-3BF354675829}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {02D9B109-1602-3567-80C0-3BF354675829}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA}.Release|x64.ActiveCfg = Release|x64 + {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA}.Release|x64.Build.0 = Release|x64 + {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515}.Release|x64.ActiveCfg = Release|x64 + {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515}.Release|x64.Build.0 = Release|x64 + {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {76B00654-E15A-3E4F-8C41-DDC63A14246A}.Release|x64.ActiveCfg = Release|x64 + {76B00654-E15A-3E4F-8C41-DDC63A14246A}.Release|x64.Build.0 = Release|x64 + {76B00654-E15A-3E4F-8C41-DDC63A14246A}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {76B00654-E15A-3E4F-8C41-DDC63A14246A}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {D7DF31C2-3247-31BA-A745-DF4095334504}.Release|x64.ActiveCfg = Release|x64 + {D7DF31C2-3247-31BA-A745-DF4095334504}.Release|x64.Build.0 = Release|x64 + {D7DF31C2-3247-31BA-A745-DF4095334504}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {D7DF31C2-3247-31BA-A745-DF4095334504}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204}.Release|x64.ActiveCfg = Release|x64 + {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204}.Release|x64.Build.0 = Release|x64 + {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5}.Release|x64.ActiveCfg = Release|x64 + {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5}.Release|x64.Build.0 = Release|x64 + {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB}.Release|x64.ActiveCfg = Release|x64 + {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB}.Release|x64.Build.0 = Release|x64 + {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {39BD79E1-6088-33F3-AD4A-74F0E0EE785C}.Release|x64.ActiveCfg = Release|x64 + {39BD79E1-6088-33F3-AD4A-74F0E0EE785C}.Release|x64.Build.0 = Release|x64 + {39BD79E1-6088-33F3-AD4A-74F0E0EE785C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {39BD79E1-6088-33F3-AD4A-74F0E0EE785C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {BAABB124-4999-3462-AF35-16DB3C974D7C}.Release|x64.ActiveCfg = Release|x64 + {BAABB124-4999-3462-AF35-16DB3C974D7C}.Release|x64.Build.0 = Release|x64 + {BAABB124-4999-3462-AF35-16DB3C974D7C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {BAABB124-4999-3462-AF35-16DB3C974D7C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {6F451C91-A082-3981-83D5-65844ED16BDA}.Release|x64.ActiveCfg = Release|x64 + {6F451C91-A082-3981-83D5-65844ED16BDA}.Release|x64.Build.0 = Release|x64 + {6F451C91-A082-3981-83D5-65844ED16BDA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {6F451C91-A082-3981-83D5-65844ED16BDA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80}.Release|x64.ActiveCfg = Release|x64 + {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80}.Release|x64.Build.0 = Release|x64 + {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {AB8FA0F9-1482-31F8-87E2-E3C7BB178053}.Release|x64.ActiveCfg = Release|x64 + {AB8FA0F9-1482-31F8-87E2-E3C7BB178053}.Release|x64.Build.0 = Release|x64 + {AB8FA0F9-1482-31F8-87E2-E3C7BB178053}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {AB8FA0F9-1482-31F8-87E2-E3C7BB178053}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212}.Release|x64.ActiveCfg = Release|x64 + {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212}.Release|x64.Build.0 = Release|x64 + {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20}.Release|x64.ActiveCfg = Release|x64 + {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20}.Release|x64.Build.0 = Release|x64 + {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {5347E62F-7AEB-3B7C-B480-161A35974C9E}.Release|x64.ActiveCfg = Release|x64 + {5347E62F-7AEB-3B7C-B480-161A35974C9E}.Release|x64.Build.0 = Release|x64 + {5347E62F-7AEB-3B7C-B480-161A35974C9E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {5347E62F-7AEB-3B7C-B480-161A35974C9E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62}.Release|x64.ActiveCfg = Release|x64 + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62}.Release|x64.Build.0 = Release|x64 + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {136AD85C-398C-329A-84AC-AD4481963950}.Release|x64.ActiveCfg = Release|x64 + {136AD85C-398C-329A-84AC-AD4481963950}.Release|x64.Build.0 = Release|x64 + {136AD85C-398C-329A-84AC-AD4481963950}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {136AD85C-398C-329A-84AC-AD4481963950}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {8DB90A0E-6076-3C07-B890-7E5E886009EC}.Release|x64.ActiveCfg = Release|x64 + {8DB90A0E-6076-3C07-B890-7E5E886009EC}.Release|x64.Build.0 = Release|x64 + {8DB90A0E-6076-3C07-B890-7E5E886009EC}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {8DB90A0E-6076-3C07-B890-7E5E886009EC}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {111D1A41-5C7F-397A-A62C-B19B0AEB044B}.Release|x64.ActiveCfg = Release|x64 + {111D1A41-5C7F-397A-A62C-B19B0AEB044B}.Release|x64.Build.0 = Release|x64 + {111D1A41-5C7F-397A-A62C-B19B0AEB044B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {111D1A41-5C7F-397A-A62C-B19B0AEB044B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {78DBE964-AC8C-3264-903B-2B102B46D476}.Release|x64.ActiveCfg = Release|x64 + {78DBE964-AC8C-3264-903B-2B102B46D476}.Release|x64.Build.0 = Release|x64 + {78DBE964-AC8C-3264-903B-2B102B46D476}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {78DBE964-AC8C-3264-903B-2B102B46D476}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7}.Release|x64.ActiveCfg = Release|x64 + {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7}.Release|x64.Build.0 = Release|x64 + {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {19F34DB6-1C4F-36FD-A7A8-8E5077651209}.Release|x64.ActiveCfg = Release|x64 + {19F34DB6-1C4F-36FD-A7A8-8E5077651209}.Release|x64.Build.0 = Release|x64 + {19F34DB6-1C4F-36FD-A7A8-8E5077651209}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {19F34DB6-1C4F-36FD-A7A8-8E5077651209}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {5DC5A20B-821C-3008-A247-B08677276F56}.Release|x64.ActiveCfg = Release|x64 + {5DC5A20B-821C-3008-A247-B08677276F56}.Release|x64.Build.0 = Release|x64 + {5DC5A20B-821C-3008-A247-B08677276F56}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {5DC5A20B-821C-3008-A247-B08677276F56}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {D3A6760C-34FD-3EE2-B9CC-24647168DC6A}.Release|x64.ActiveCfg = Release|x64 + {D3A6760C-34FD-3EE2-B9CC-24647168DC6A}.Release|x64.Build.0 = Release|x64 + {D3A6760C-34FD-3EE2-B9CC-24647168DC6A}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {D3A6760C-34FD-3EE2-B9CC-24647168DC6A}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {AFC95A6A-BDBB-35E2-9381-253284E1112D}.Release|x64.ActiveCfg = Release|x64 + {AFC95A6A-BDBB-35E2-9381-253284E1112D}.Release|x64.Build.0 = Release|x64 + {AFC95A6A-BDBB-35E2-9381-253284E1112D}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {AFC95A6A-BDBB-35E2-9381-253284E1112D}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {24F97336-D35B-3FBA-BEF8-64B2D5845D3F}.Release|x64.ActiveCfg = Release|x64 + {24F97336-D35B-3FBA-BEF8-64B2D5845D3F}.Release|x64.Build.0 = Release|x64 + {24F97336-D35B-3FBA-BEF8-64B2D5845D3F}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {24F97336-D35B-3FBA-BEF8-64B2D5845D3F}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {86289ECD-3E29-3E01-93B2-829B5666A809}.Release|x64.ActiveCfg = Release|x64 + {86289ECD-3E29-3E01-93B2-829B5666A809}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {0AED7AC4-8C48-3205-AF43-3D536A60D815}.Release|x64.ActiveCfg = Release|x64 + {0AED7AC4-8C48-3205-AF43-3D536A60D815}.Release|x64.Build.0 = Release|x64 + {0AED7AC4-8C48-3205-AF43-3D536A60D815}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {0AED7AC4-8C48-3205-AF43-3D536A60D815}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96}.Release|x64.ActiveCfg = Release|x64 + {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96}.Release|x64.Build.0 = Release|x64 + {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {BA32E800-D5FA-3F4E-B91B-763CD4FE389C}.Release|x64.ActiveCfg = Release|x64 + {BA32E800-D5FA-3F4E-B91B-763CD4FE389C}.Release|x64.Build.0 = Release|x64 + {BA32E800-D5FA-3F4E-B91B-763CD4FE389C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {BA32E800-D5FA-3F4E-B91B-763CD4FE389C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7}.Release|x64.ActiveCfg = Release|x64 + {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7}.Release|x64.Build.0 = Release|x64 + {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {47842A81-7497-313E-B466-C60AE89334CB}.Release|x64.ActiveCfg = Release|x64 + {47842A81-7497-313E-B466-C60AE89334CB}.Release|x64.Build.0 = Release|x64 + {47842A81-7497-313E-B466-C60AE89334CB}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {47842A81-7497-313E-B466-C60AE89334CB}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {25303A98-8EE4-3355-8C68-CFA8B4116EF0}.Release|x64.ActiveCfg = Release|x64 + {25303A98-8EE4-3355-8C68-CFA8B4116EF0}.Release|x64.Build.0 = Release|x64 + {25303A98-8EE4-3355-8C68-CFA8B4116EF0}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {25303A98-8EE4-3355-8C68-CFA8B4116EF0}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {A80E6C37-1E31-3DDC-A4FE-B21553E580DB}.Release|x64.ActiveCfg = Release|x64 + {A80E6C37-1E31-3DDC-A4FE-B21553E580DB}.Release|x64.Build.0 = Release|x64 + {A80E6C37-1E31-3DDC-A4FE-B21553E580DB}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {A80E6C37-1E31-3DDC-A4FE-B21553E580DB}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE}.Release|x64.ActiveCfg = Release|x64 + {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE}.Release|x64.Build.0 = Release|x64 + {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {0AE42C92-16FF-3E69-B468-111535996095}.Release|x64.ActiveCfg = Release|x64 + {0AE42C92-16FF-3E69-B468-111535996095}.Release|x64.Build.0 = Release|x64 + {0AE42C92-16FF-3E69-B468-111535996095}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {0AE42C92-16FF-3E69-B468-111535996095}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {69CB13F6-E5DD-3AC2-AF47-08A452514760}.Release|x64.ActiveCfg = Release|x64 + {69CB13F6-E5DD-3AC2-AF47-08A452514760}.Release|x64.Build.0 = Release|x64 + {69CB13F6-E5DD-3AC2-AF47-08A452514760}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {69CB13F6-E5DD-3AC2-AF47-08A452514760}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {A294D3AD-91C7-32D9-B361-D399900843E5}.Release|x64.ActiveCfg = Release|x64 + {A294D3AD-91C7-32D9-B361-D399900843E5}.Release|x64.Build.0 = Release|x64 + {A294D3AD-91C7-32D9-B361-D399900843E5}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {A294D3AD-91C7-32D9-B361-D399900843E5}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {73A57BCF-3487-35DC-B448-FD328037CDF3}.Release|x64.ActiveCfg = Release|x64 + {73A57BCF-3487-35DC-B448-FD328037CDF3}.Release|x64.Build.0 = Release|x64 + {73A57BCF-3487-35DC-B448-FD328037CDF3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {73A57BCF-3487-35DC-B448-FD328037CDF3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA}.Release|x64.ActiveCfg = Release|x64 + {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA}.Release|x64.Build.0 = Release|x64 + {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD}.Release|x64.ActiveCfg = Release|x64 + {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD}.Release|x64.Build.0 = Release|x64 + {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {CD9E5829-45CA-308D-9ED7-C2C38139D69E}.Release|x64.ActiveCfg = Release|x64 + {CD9E5829-45CA-308D-9ED7-C2C38139D69E}.Release|x64.Build.0 = Release|x64 + {CD9E5829-45CA-308D-9ED7-C2C38139D69E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {CD9E5829-45CA-308D-9ED7-C2C38139D69E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B}.Release|x64.ActiveCfg = Release|x64 + {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B}.Release|x64.Build.0 = Release|x64 + {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {21572060-CA28-355B-A508-5675A4A2FAB3}.Release|x64.ActiveCfg = Release|x64 + {21572060-CA28-355B-A508-5675A4A2FAB3}.Release|x64.Build.0 = Release|x64 + {21572060-CA28-355B-A508-5675A4A2FAB3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {21572060-CA28-355B-A508-5675A4A2FAB3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {F1206958-458C-3F18-84D9-3EEE07B73862}.Release|x64.ActiveCfg = Release|x64 + {F1206958-458C-3F18-84D9-3EEE07B73862}.Release|x64.Build.0 = Release|x64 + {F1206958-458C-3F18-84D9-3EEE07B73862}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {F1206958-458C-3F18-84D9-3EEE07B73862}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32}.Release|x64.ActiveCfg = Release|x64 + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32}.Release|x64.Build.0 = Release|x64 + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3}.Release|x64.ActiveCfg = Release|x64 + {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3}.Release|x64.Build.0 = Release|x64 + {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {419297F2-C54C-3C4B-91AB-7B119D09E730}.Release|x64.ActiveCfg = Release|x64 + {419297F2-C54C-3C4B-91AB-7B119D09E730}.Release|x64.Build.0 = Release|x64 + {419297F2-C54C-3C4B-91AB-7B119D09E730}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {419297F2-C54C-3C4B-91AB-7B119D09E730}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {8F94C6B8-42CE-329C-B6A9-3E13C04350CF}.Release|x64.ActiveCfg = Release|x64 + {8F94C6B8-42CE-329C-B6A9-3E13C04350CF}.Release|x64.Build.0 = Release|x64 + {8F94C6B8-42CE-329C-B6A9-3E13C04350CF}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {8F94C6B8-42CE-329C-B6A9-3E13C04350CF}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {7FF993D7-A6D3-37CC-AE69-2906ECD89E03}.Release|x64.ActiveCfg = Release|x64 + {7FF993D7-A6D3-37CC-AE69-2906ECD89E03}.Release|x64.Build.0 = Release|x64 + {7FF993D7-A6D3-37CC-AE69-2906ECD89E03}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {7FF993D7-A6D3-37CC-AE69-2906ECD89E03}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {374D8559-CBBF-3F24-BEE1-8B11A184B7F8}.Release|x64.ActiveCfg = Release|x64 + {374D8559-CBBF-3F24-BEE1-8B11A184B7F8}.Release|x64.Build.0 = Release|x64 + {374D8559-CBBF-3F24-BEE1-8B11A184B7F8}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {374D8559-CBBF-3F24-BEE1-8B11A184B7F8}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {4E197970-E280-3B04-AD7D-E52DC551E902}.Release|x64.ActiveCfg = Release|x64 + {4E197970-E280-3B04-AD7D-E52DC551E902}.Release|x64.Build.0 = Release|x64 + {4E197970-E280-3B04-AD7D-E52DC551E902}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {4E197970-E280-3B04-AD7D-E52DC551E902}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {4E6C8BD2-2434-31DC-BDD2-8788D2547403}.Release|x64.ActiveCfg = Release|x64 + {4E6C8BD2-2434-31DC-BDD2-8788D2547403}.Release|x64.Build.0 = Release|x64 + {4E6C8BD2-2434-31DC-BDD2-8788D2547403}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {4E6C8BD2-2434-31DC-BDD2-8788D2547403}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {37629CF4-1B6A-312A-89B7-CF11593F51A4}.Release|x64.ActiveCfg = Release|x64 + {37629CF4-1B6A-312A-89B7-CF11593F51A4}.Release|x64.Build.0 = Release|x64 + {37629CF4-1B6A-312A-89B7-CF11593F51A4}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {37629CF4-1B6A-312A-89B7-CF11593F51A4}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {8D195538-264D-3C39-AB9A-653DA8A6F56E}.Release|x64.ActiveCfg = Release|x64 + {8D195538-264D-3C39-AB9A-653DA8A6F56E}.Release|x64.Build.0 = Release|x64 + {8D195538-264D-3C39-AB9A-653DA8A6F56E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {8D195538-264D-3C39-AB9A-653DA8A6F56E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {9302E53B-085D-3577-A3E2-EB51A51D084C}.Release|x64.ActiveCfg = Release|x64 + {9302E53B-085D-3577-A3E2-EB51A51D084C}.Release|x64.Build.0 = Release|x64 + {9302E53B-085D-3577-A3E2-EB51A51D084C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {9302E53B-085D-3577-A3E2-EB51A51D084C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {1C17AAAA-9E99-32C1-9FF6-E88C054A2646}.Release|x64.ActiveCfg = Release|x64 + {1C17AAAA-9E99-32C1-9FF6-E88C054A2646}.Release|x64.Build.0 = Release|x64 + {1C17AAAA-9E99-32C1-9FF6-E88C054A2646}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {1C17AAAA-9E99-32C1-9FF6-E88C054A2646}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7}.Release|x64.ActiveCfg = Release|x64 + {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7}.Release|x64.Build.0 = Release|x64 + {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {E36DC20B-AE7A-3449-B308-C932B9DD4290}.Release|x64.ActiveCfg = Release|x64 + {E36DC20B-AE7A-3449-B308-C932B9DD4290}.Release|x64.Build.0 = Release|x64 + {E36DC20B-AE7A-3449-B308-C932B9DD4290}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {E36DC20B-AE7A-3449-B308-C932B9DD4290}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121}.Release|x64.ActiveCfg = Release|x64 + {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121}.Release|x64.Build.0 = Release|x64 + {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3}.Release|x64.ActiveCfg = Release|x64 + {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3}.Release|x64.Build.0 = Release|x64 + {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2}.Release|x64.ActiveCfg = Release|x64 + {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2}.Release|x64.Build.0 = Release|x64 + {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {C080819A-4275-3D2A-84DE-7C21EDAE2BBA}.Release|x64.ActiveCfg = Release|x64 + {C080819A-4275-3D2A-84DE-7C21EDAE2BBA}.Release|x64.Build.0 = Release|x64 + {C080819A-4275-3D2A-84DE-7C21EDAE2BBA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {C080819A-4275-3D2A-84DE-7C21EDAE2BBA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F}.Release|x64.ActiveCfg = Release|x64 + {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F}.Release|x64.Build.0 = Release|x64 + {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {6579683E-AB4A-3B40-A145-1952047837D2}.Release|x64.ActiveCfg = Release|x64 + {6579683E-AB4A-3B40-A145-1952047837D2}.Release|x64.Build.0 = Release|x64 + {6579683E-AB4A-3B40-A145-1952047837D2}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {6579683E-AB4A-3B40-A145-1952047837D2}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {2FE38842-BDF7-3A93-9D06-1C9814B6B11B}.Release|x64.ActiveCfg = Release|x64 + {2FE38842-BDF7-3A93-9D06-1C9814B6B11B}.Release|x64.Build.0 = Release|x64 + {2FE38842-BDF7-3A93-9D06-1C9814B6B11B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {2FE38842-BDF7-3A93-9D06-1C9814B6B11B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C}.Release|x64.ActiveCfg = Release|x64 + {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C}.Release|x64.Build.0 = Release|x64 + {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4}.Release|x64.ActiveCfg = Release|x64 + {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4}.Release|x64.Build.0 = Release|x64 + {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {C884F97B-4C5C-3457-AF4D-BB4C05670662}.Release|x64.ActiveCfg = Release|x64 + {C884F97B-4C5C-3457-AF4D-BB4C05670662}.Release|x64.Build.0 = Release|x64 + {C884F97B-4C5C-3457-AF4D-BB4C05670662}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {C884F97B-4C5C-3457-AF4D-BB4C05670662}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D}.Release|x64.ActiveCfg = Release|x64 + {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D}.Release|x64.Build.0 = Release|x64 + {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {796760C3-71E4-32AD-A9C4-B984AFC97106}.Release|x64.ActiveCfg = Release|x64 + {796760C3-71E4-32AD-A9C4-B984AFC97106}.Release|x64.Build.0 = Release|x64 + {796760C3-71E4-32AD-A9C4-B984AFC97106}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {796760C3-71E4-32AD-A9C4-B984AFC97106}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {8054C91C-5221-314F-96C5-8FEC57BBEED1}.Release|x64.ActiveCfg = Release|x64 + {8054C91C-5221-314F-96C5-8FEC57BBEED1}.Release|x64.Build.0 = Release|x64 + {8054C91C-5221-314F-96C5-8FEC57BBEED1}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {8054C91C-5221-314F-96C5-8FEC57BBEED1}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {744BEFA7-C931-39C8-A1B4-1A9A88901B1D}.Release|x64.ActiveCfg = Release|x64 + {744BEFA7-C931-39C8-A1B4-1A9A88901B1D}.Release|x64.Build.0 = Release|x64 + {744BEFA7-C931-39C8-A1B4-1A9A88901B1D}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {744BEFA7-C931-39C8-A1B4-1A9A88901B1D}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + {3B9F42C2-0060-329E-B123-7DEF1E91617D}.Release|x64.ActiveCfg = Release|x64 + {3B9F42C2-0060-329E-B123-7DEF1E91617D}.Release|x64.Build.0 = Release|x64 + {3B9F42C2-0060-329E-B123-7DEF1E91617D}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 + {3B9F42C2-0060-329E-B123-7DEF1E91617D}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {40EA859D-1269-313F-A313-AA32B87C8935} = {28D9607F-8931-375B-9273-9E20D2F6347F} + {07ADCCA9-7D16-3F3D-AB6F-1BDA83D4E943} = {28D9607F-8931-375B-9273-9E20D2F6347F} + {F20BBC06-43D9-375A-A5A9-E717817CF640} = {28D9607F-8931-375B-9273-9E20D2F6347F} + {45641EBC-7207-3F33-8572-930EA9BD4C6B} = {28D9607F-8931-375B-9273-9E20D2F6347F} + {31277AF8-10A2-3494-B123-559421E08C26} = {28D9607F-8931-375B-9273-9E20D2F6347F} + {D7C70C41-500D-35F8-A992-1351DDDCDA0C} = {068CE9B1-E6DD-3864-AC38-93F10EF27A17} + {474F765F-548E-3AAB-8D5B-66CF364BE4B2} = {068CE9B1-E6DD-3864-AC38-93F10EF27A17} + {246A2207-0D75-3894-8E4E-785344D8ABF4} = {068CE9B1-E6DD-3864-AC38-93F10EF27A17} + {93318712-66D7-31F1-B537-E229E2FD9AF0} = {068CE9B1-E6DD-3864-AC38-93F10EF27A17} + {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} + {8DB90A0E-6076-3C07-B890-7E5E886009EC} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} + {111D1A41-5C7F-397A-A62C-B19B0AEB044B} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} + {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} + {19F34DB6-1C4F-36FD-A7A8-8E5077651209} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} + {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} + {8D195538-264D-3C39-AB9A-653DA8A6F56E} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} + {9302E53B-085D-3577-A3E2-EB51A51D084C} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} + {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} + {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} + {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA} = {25456F37-E968-3921-80E5-1C0E141753B6} + {14C478D6-D815-378F-81D1-B53BBD6CBE9A} = {25456F37-E968-3921-80E5-1C0E141753B6} + {3A2B0858-3B92-3598-B679-2A437C1286E0} = {25456F37-E968-3921-80E5-1C0E141753B6} + {27ECEB5C-C396-32BE-93E6-4D4801692191} = {25456F37-E968-3921-80E5-1C0E141753B6} + {5F63101D-75FE-31BE-9D25-6641FBBFF959} = {25456F37-E968-3921-80E5-1C0E141753B6} + {7D67495E-4C92-37BE-BEF8-174CA37ADD21} = {25456F37-E968-3921-80E5-1C0E141753B6} + {6152D284-A720-3556-A60A-7C13C89205AD} = {25456F37-E968-3921-80E5-1C0E141753B6} + {4049FF1D-8A65-3021-B550-0DE0E63F9577} = {25456F37-E968-3921-80E5-1C0E141753B6} + {8CE562EE-798E-3C1B-975C-F49C6B5C84ED} = {25456F37-E968-3921-80E5-1C0E141753B6} + {961FD68A-49A7-3F16-9F96-16AC8236D3A3} = {25456F37-E968-3921-80E5-1C0E141753B6} + {D3C67352-8290-3C4E-9F23-93DDE051AA37} = {25456F37-E968-3921-80E5-1C0E141753B6} + {386966C3-DC46-3936-AD44-35E2470C6A28} = {25456F37-E968-3921-80E5-1C0E141753B6} + {02D9B109-1602-3567-80C0-3BF354675829} = {25456F37-E968-3921-80E5-1C0E141753B6} + {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA} = {25456F37-E968-3921-80E5-1C0E141753B6} + {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515} = {25456F37-E968-3921-80E5-1C0E141753B6} + {76B00654-E15A-3E4F-8C41-DDC63A14246A} = {25456F37-E968-3921-80E5-1C0E141753B6} + {D7DF31C2-3247-31BA-A745-DF4095334504} = {25456F37-E968-3921-80E5-1C0E141753B6} + {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204} = {25456F37-E968-3921-80E5-1C0E141753B6} + {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5} = {25456F37-E968-3921-80E5-1C0E141753B6} + {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB} = {25456F37-E968-3921-80E5-1C0E141753B6} + {BAABB124-4999-3462-AF35-16DB3C974D7C} = {25456F37-E968-3921-80E5-1C0E141753B6} + {6F451C91-A082-3981-83D5-65844ED16BDA} = {25456F37-E968-3921-80E5-1C0E141753B6} + {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80} = {25456F37-E968-3921-80E5-1C0E141753B6} + {AB8FA0F9-1482-31F8-87E2-E3C7BB178053} = {25456F37-E968-3921-80E5-1C0E141753B6} + {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212} = {25456F37-E968-3921-80E5-1C0E141753B6} + {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20} = {25456F37-E968-3921-80E5-1C0E141753B6} + {5347E62F-7AEB-3B7C-B480-161A35974C9E} = {25456F37-E968-3921-80E5-1C0E141753B6} + {D3A6760C-34FD-3EE2-B9CC-24647168DC6A} = {25456F37-E968-3921-80E5-1C0E141753B6} + {AFC95A6A-BDBB-35E2-9381-253284E1112D} = {25456F37-E968-3921-80E5-1C0E141753B6} + {0AED7AC4-8C48-3205-AF43-3D536A60D815} = {25456F37-E968-3921-80E5-1C0E141753B6} + {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96} = {25456F37-E968-3921-80E5-1C0E141753B6} + {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7} = {25456F37-E968-3921-80E5-1C0E141753B6} + {47842A81-7497-313E-B466-C60AE89334CB} = {25456F37-E968-3921-80E5-1C0E141753B6} + {25303A98-8EE4-3355-8C68-CFA8B4116EF0} = {25456F37-E968-3921-80E5-1C0E141753B6} + {A80E6C37-1E31-3DDC-A4FE-B21553E580DB} = {25456F37-E968-3921-80E5-1C0E141753B6} + {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA} = {25456F37-E968-3921-80E5-1C0E141753B6} + {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD} = {25456F37-E968-3921-80E5-1C0E141753B6} + {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B} = {25456F37-E968-3921-80E5-1C0E141753B6} + {21572060-CA28-355B-A508-5675A4A2FAB3} = {25456F37-E968-3921-80E5-1C0E141753B6} + {F1206958-458C-3F18-84D9-3EEE07B73862} = {25456F37-E968-3921-80E5-1C0E141753B6} + {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3} = {25456F37-E968-3921-80E5-1C0E141753B6} + {419297F2-C54C-3C4B-91AB-7B119D09E730} = {25456F37-E968-3921-80E5-1C0E141753B6} + {8F94C6B8-42CE-329C-B6A9-3E13C04350CF} = {25456F37-E968-3921-80E5-1C0E141753B6} + {7FF993D7-A6D3-37CC-AE69-2906ECD89E03} = {25456F37-E968-3921-80E5-1C0E141753B6} + {374D8559-CBBF-3F24-BEE1-8B11A184B7F8} = {25456F37-E968-3921-80E5-1C0E141753B6} + {4E197970-E280-3B04-AD7D-E52DC551E902} = {25456F37-E968-3921-80E5-1C0E141753B6} + {4E6C8BD2-2434-31DC-BDD2-8788D2547403} = {25456F37-E968-3921-80E5-1C0E141753B6} + {37629CF4-1B6A-312A-89B7-CF11593F51A4} = {25456F37-E968-3921-80E5-1C0E141753B6} + {E36DC20B-AE7A-3449-B308-C932B9DD4290} = {25456F37-E968-3921-80E5-1C0E141753B6} + {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121} = {25456F37-E968-3921-80E5-1C0E141753B6} + {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3} = {25456F37-E968-3921-80E5-1C0E141753B6} + {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2} = {25456F37-E968-3921-80E5-1C0E141753B6} + {C080819A-4275-3D2A-84DE-7C21EDAE2BBA} = {25456F37-E968-3921-80E5-1C0E141753B6} + {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F} = {25456F37-E968-3921-80E5-1C0E141753B6} + {6579683E-AB4A-3B40-A145-1952047837D2} = {25456F37-E968-3921-80E5-1C0E141753B6} + {2FE38842-BDF7-3A93-9D06-1C9814B6B11B} = {25456F37-E968-3921-80E5-1C0E141753B6} + {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C} = {25456F37-E968-3921-80E5-1C0E141753B6} + {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4} = {25456F37-E968-3921-80E5-1C0E141753B6} + {C884F97B-4C5C-3457-AF4D-BB4C05670662} = {25456F37-E968-3921-80E5-1C0E141753B6} + {8054C91C-5221-314F-96C5-8FEC57BBEED1} = {25456F37-E968-3921-80E5-1C0E141753B6} + {3B9F42C2-0060-329E-B123-7DEF1E91617D} = {25456F37-E968-3921-80E5-1C0E141753B6} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {97344453-ACD8-397F-8291-084632F194C3} + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 016a2193e..8b485a3a6 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -197,11 +197,8 @@ TexposHandle Textures::loadTexture(SDL_Surface* surface, bool reserved) { std::vector Textures::loadTileset(const std::string& file, int tile_px_w, int tile_px_h, bool reserved) { - if (!enabler) - return std::vector{}; if (g_tileset_to_handles.contains(file)) return g_tileset_to_handles[file]; - if (!enabler) return std::vector{}; From 7e4fe646054f99a3baeb4992fdc4875c19a7fb06 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 24 Sep 2023 13:10:48 +0300 Subject: [PATCH 592/851] oops --- build/ALL_BUILD.vcxproj | 533 --------- build/ALL_BUILD.vcxproj.filters | 8 - build/Continuous.vcxproj | 145 --- build/Continuous.vcxproj.filters | 17 - build/Experimental.vcxproj | 145 --- build/Experimental.vcxproj.filters | 17 - build/INSTALL.vcxproj | 126 --- build/INSTALL.vcxproj.filters | 13 - build/Nightly.vcxproj | 145 --- build/Nightly.vcxproj.filters | 17 - build/NightlyMemoryCheck.vcxproj | 145 --- build/NightlyMemoryCheck.vcxproj.filters | 17 - build/PACKAGE.vcxproj | 132 --- build/PACKAGE.vcxproj.filters | 13 - build/RUN_TESTS.vcxproj | 118 -- build/RUN_TESTS.vcxproj.filters | 13 - build/ZERO_CHECK.vcxproj | 105 -- build/ZERO_CHECK.vcxproj.filters | 13 - build/dfhack.sln | 1295 ---------------------- 19 files changed, 3017 deletions(-) delete mode 100644 build/ALL_BUILD.vcxproj delete mode 100644 build/ALL_BUILD.vcxproj.filters delete mode 100644 build/Continuous.vcxproj delete mode 100644 build/Continuous.vcxproj.filters delete mode 100644 build/Experimental.vcxproj delete mode 100644 build/Experimental.vcxproj.filters delete mode 100644 build/INSTALL.vcxproj delete mode 100644 build/INSTALL.vcxproj.filters delete mode 100644 build/Nightly.vcxproj delete mode 100644 build/Nightly.vcxproj.filters delete mode 100644 build/NightlyMemoryCheck.vcxproj delete mode 100644 build/NightlyMemoryCheck.vcxproj.filters delete mode 100644 build/PACKAGE.vcxproj delete mode 100644 build/PACKAGE.vcxproj.filters delete mode 100644 build/RUN_TESTS.vcxproj delete mode 100644 build/RUN_TESTS.vcxproj.filters delete mode 100644 build/ZERO_CHECK.vcxproj delete mode 100644 build/ZERO_CHECK.vcxproj.filters delete mode 100644 build/dfhack.sln diff --git a/build/ALL_BUILD.vcxproj b/build/ALL_BUILD.vcxproj deleted file mode 100644 index eefddc34c..000000000 --- a/build/ALL_BUILD.vcxproj +++ /dev/null @@ -1,533 +0,0 @@ - - - - x64 - - - - Release - x64 - - - RelWithDebInfo - x64 - - - - {40EA859D-1269-313F-A313-AA32B87C8935} - 10.0.22000.0 - Win32Proj - x64 - ALL_BUILD - NoUpgrade - - - - Utility - MultiByte - v143 - - - Utility - MultiByte - v143 - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - $(Platform)\$(Configuration)\$(ProjectName)\ - $(Platform)\$(Configuration)\$(ProjectName)\ - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - Always - Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp - false - Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp - false - - - - - - - {31277AF8-10A2-3494-B123-559421E08C26} - ZERO_CHECK - false - Never - - - {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA} - 3dveins - false - Never - - - {14C478D6-D815-378F-81D1-B53BBD6CBE9A} - RemoteFortressReader - false - Never - - - {3A2B0858-3B92-3598-B679-2A437C1286E0} - add-spatter - false - Never - - - {27ECEB5C-C396-32BE-93E6-4D4801692191} - autobutcher - false - Never - - - {5F63101D-75FE-31BE-9D25-6641FBBFF959} - autochop - false - Never - - - {7D67495E-4C92-37BE-BEF8-174CA37ADD21} - autoclothing - false - Never - - - {6152D284-A720-3556-A60A-7C13C89205AD} - autodump - false - Never - - - {4049FF1D-8A65-3021-B550-0DE0E63F9577} - autofarm - false - Never - - - {8CE562EE-798E-3C1B-975C-F49C6B5C84ED} - autolabor - false - Never - - - {961FD68A-49A7-3F16-9F96-16AC8236D3A3} - autonestbox - false - Never - - - {D3C67352-8290-3C4E-9F23-93DDE051AA37} - autoslab - false - Never - - - {A0486456-80E4-3492-940E-6652FF2B45B9} - binpatch - - - {386966C3-DC46-3936-AD44-35E2470C6A28} - blueprint - false - Never - - - {02D9B109-1602-3567-80C0-3BF354675829} - buildingplan - false - Never - - - {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA} - changeitem - false - Never - - - {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515} - changelayer - false - Never - - - {76B00654-E15A-3E4F-8C41-DDC63A14246A} - changevein - false - Never - - - {D7DF31C2-3247-31BA-A745-DF4095334504} - channel-safely - false - Never - - - {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204} - cleanconst - false - Never - - - {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5} - cleaners - false - Never - - - {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB} - cleanowned - false - Never - - - {BAABB124-4999-3462-AF35-16DB3C974D7C} - confirm - false - Never - - - {6F451C91-A082-3981-83D5-65844ED16BDA} - createitem - false - Never - - - {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80} - cursecheck - false - Never - - - {AB8FA0F9-1482-31F8-87E2-E3C7BB178053} - cxxrandom - false - Never - - - {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212} - debug - false - Never - - - {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20} - deramp - false - Never - - - {5347E62F-7AEB-3B7C-B480-161A35974C9E} - design - false - Never - - - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - dfhack - - - {136AD85C-398C-329A-84AC-AD4481963950} - dfhack-client - - - {78DBE964-AC8C-3264-903B-2B102B46D476} - dfhack-run - - - {5DC5A20B-821C-3008-A247-B08677276F56} - dfhack-version - - - {D3A6760C-34FD-3EE2-B9CC-24647168DC6A} - dig - false - Never - - - {AFC95A6A-BDBB-35E2-9381-253284E1112D} - dig-now - false - Never - - - {0AED7AC4-8C48-3205-AF43-3D536A60D815} - dwarfvet - false - Never - - - {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96} - eventful - false - Never - - - {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} - expat - - - {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7} - fastdwarf - false - Never - - - {47842A81-7497-313E-B466-C60AE89334CB} - faststart - false - Never - - - {25303A98-8EE4-3355-8C68-CFA8B4116EF0} - filltraffic - false - Never - - - {A80E6C37-1E31-3DDC-A4FE-B21553E580DB} - flows - false - Never - - - {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA} - getplants - false - Never - - - {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD} - hotkeys - false - Never - - - {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B} - lair - false - Never - - - {21572060-CA28-355B-A508-5675A4A2FAB3} - liquids - false - Never - - - {F1206958-458C-3F18-84D9-3EEE07B73862} - logistics - false - Never - - - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - lua - - - {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3} - luasocket - false - Never - - - {419297F2-C54C-3C4B-91AB-7B119D09E730} - misery - false - Never - - - {8F94C6B8-42CE-329C-B6A9-3E13C04350CF} - nestboxes - false - Never - - - {7FF993D7-A6D3-37CC-AE69-2906ECD89E03} - orders - false - Never - - - {374D8559-CBBF-3F24-BEE1-8B11A184B7F8} - overlay - false - Never - - - {4E197970-E280-3B04-AD7D-E52DC551E902} - pathable - false - Never - - - {4E6C8BD2-2434-31DC-BDD2-8788D2547403} - probe - false - Never - - - {37629CF4-1B6A-312A-89B7-CF11593F51A4} - prospector - false - Never - - - {8D195538-264D-3C39-AB9A-653DA8A6F56E} - protobuf - - - {9302E53B-085D-3577-A3E2-EB51A51D084C} - protobuf-lite - - - {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} - protoc - - - {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} - protoc-bin - - - {E36DC20B-AE7A-3449-B308-C932B9DD4290} - regrass - false - Never - - - {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121} - reveal - false - Never - - - {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3} - seedwatch - false - Never - - - {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2} - showmood - false - Never - - - {C080819A-4275-3D2A-84DE-7C21EDAE2BBA} - sort - false - Never - - - {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F} - stockpiles - false - Never - - - {6579683E-AB4A-3B40-A145-1952047837D2} - strangemood - false - Never - - - {2FE38842-BDF7-3A93-9D06-1C9814B6B11B} - tailor - false - Never - - - {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C} - tiletypes - false - Never - - - {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4} - work-now - false - Never - - - {C884F97B-4C5C-3457-AF4D-BB4C05670662} - workflow - false - Never - - - {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D} - xlsxio_read_STATIC - - - {796760C3-71E4-32AD-A9C4-B984AFC97106} - xlsxio_write_STATIC - - - {8054C91C-5221-314F-96C5-8FEC57BBEED1} - xlsxreader - false - Never - - - {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} - zip - - - {3B9F42C2-0060-329E-B123-7DEF1E91617D} - zone - false - Never - - - - - - \ No newline at end of file diff --git a/build/ALL_BUILD.vcxproj.filters b/build/ALL_BUILD.vcxproj.filters deleted file mode 100644 index a80df604e..000000000 --- a/build/ALL_BUILD.vcxproj.filters +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/build/Continuous.vcxproj b/build/Continuous.vcxproj deleted file mode 100644 index 63a376abe..000000000 --- a/build/Continuous.vcxproj +++ /dev/null @@ -1,145 +0,0 @@ - - - - x64 - - - - Release - x64 - - - RelWithDebInfo - x64 - - - - {D7C70C41-500D-35F8-A992-1351DDDCDA0C} - 10.0.22000.0 - Win32Proj - x64 - Continuous - NoUpgrade - - - - Utility - MultiByte - v143 - - - Utility - MultiByte - v143 - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - $(Platform)\$(Configuration)\$(ProjectName)\ - $(Platform)\$(Configuration)\$(ProjectName)\ - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - - setlocal -"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Continuous -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\Continuous - false - false - - setlocal -"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Continuous -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\Continuous - false - false - - - - - Always - Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp - false - Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp - false - - - - - - - - - {31277AF8-10A2-3494-B123-559421E08C26} - ZERO_CHECK - false - Never - - - - - - \ No newline at end of file diff --git a/build/Continuous.vcxproj.filters b/build/Continuous.vcxproj.filters deleted file mode 100644 index a7314dd00..000000000 --- a/build/Continuous.vcxproj.filters +++ /dev/null @@ -1,17 +0,0 @@ - - - - - CMake Rules - - - - - - - - - {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} - - - diff --git a/build/Experimental.vcxproj b/build/Experimental.vcxproj deleted file mode 100644 index 396a79388..000000000 --- a/build/Experimental.vcxproj +++ /dev/null @@ -1,145 +0,0 @@ - - - - x64 - - - - Release - x64 - - - RelWithDebInfo - x64 - - - - {474F765F-548E-3AAB-8D5B-66CF364BE4B2} - 10.0.22000.0 - Win32Proj - x64 - Experimental - NoUpgrade - - - - Utility - MultiByte - v143 - - - Utility - MultiByte - v143 - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - $(Platform)\$(Configuration)\$(ProjectName)\ - $(Platform)\$(Configuration)\$(ProjectName)\ - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - - setlocal -"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Experimental -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\Experimental - false - false - - setlocal -"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Experimental -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\Experimental - false - false - - - - - Always - Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp - false - Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp - false - - - - - - - - - {31277AF8-10A2-3494-B123-559421E08C26} - ZERO_CHECK - false - Never - - - - - - \ No newline at end of file diff --git a/build/Experimental.vcxproj.filters b/build/Experimental.vcxproj.filters deleted file mode 100644 index 8622c11e8..000000000 --- a/build/Experimental.vcxproj.filters +++ /dev/null @@ -1,17 +0,0 @@ - - - - - CMake Rules - - - - - - - - - {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} - - - diff --git a/build/INSTALL.vcxproj b/build/INSTALL.vcxproj deleted file mode 100644 index fcc0e5dd0..000000000 --- a/build/INSTALL.vcxproj +++ /dev/null @@ -1,126 +0,0 @@ - - - - x64 - - - - Release - x64 - - - RelWithDebInfo - x64 - - - - {07ADCCA9-7D16-3F3D-AB6F-1BDA83D4E943} - 10.0.22000.0 - Win32Proj - x64 - INSTALL - NoUpgrade - - - - Utility - MultiByte - v143 - - - Utility - MultiByte - v143 - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - $(Platform)\$(Configuration)\$(ProjectName)\ - $(Platform)\$(Configuration)\$(ProjectName)\ - - - - Always - - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -DBUILD_TYPE=$(Configuration) -P cmake_install.cmake -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - - - - - Always - - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -DBUILD_TYPE=$(Configuration) -P cmake_install.cmake -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - - - - - - setlocal -cd . -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\INSTALL_force - false - false - - setlocal -cd . -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\INSTALL_force - false - false - - - - - {31277AF8-10A2-3494-B123-559421E08C26} - ZERO_CHECK - false - Never - - - {40EA859D-1269-313F-A313-AA32B87C8935} - ALL_BUILD - false - Never - - - - - - \ No newline at end of file diff --git a/build/INSTALL.vcxproj.filters b/build/INSTALL.vcxproj.filters deleted file mode 100644 index 1d3583629..000000000 --- a/build/INSTALL.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - CMake Rules - - - - - {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} - - - diff --git a/build/Nightly.vcxproj b/build/Nightly.vcxproj deleted file mode 100644 index ff59ec296..000000000 --- a/build/Nightly.vcxproj +++ /dev/null @@ -1,145 +0,0 @@ - - - - x64 - - - - Release - x64 - - - RelWithDebInfo - x64 - - - - {246A2207-0D75-3894-8E4E-785344D8ABF4} - 10.0.22000.0 - Win32Proj - x64 - Nightly - NoUpgrade - - - - Utility - MultiByte - v143 - - - Utility - MultiByte - v143 - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - $(Platform)\$(Configuration)\$(ProjectName)\ - $(Platform)\$(Configuration)\$(ProjectName)\ - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - - setlocal -"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Nightly -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\Nightly - false - false - - setlocal -"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D Nightly -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\Nightly - false - false - - - - - Always - Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp - false - Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp - false - - - - - - - - - {31277AF8-10A2-3494-B123-559421E08C26} - ZERO_CHECK - false - Never - - - - - - \ No newline at end of file diff --git a/build/Nightly.vcxproj.filters b/build/Nightly.vcxproj.filters deleted file mode 100644 index cf94569d8..000000000 --- a/build/Nightly.vcxproj.filters +++ /dev/null @@ -1,17 +0,0 @@ - - - - - CMake Rules - - - - - - - - - {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} - - - diff --git a/build/NightlyMemoryCheck.vcxproj b/build/NightlyMemoryCheck.vcxproj deleted file mode 100644 index 260a79e55..000000000 --- a/build/NightlyMemoryCheck.vcxproj +++ /dev/null @@ -1,145 +0,0 @@ - - - - x64 - - - - Release - x64 - - - RelWithDebInfo - x64 - - - - {93318712-66D7-31F1-B537-E229E2FD9AF0} - 10.0.22000.0 - Win32Proj - x64 - NightlyMemoryCheck - NoUpgrade - - - - Utility - MultiByte - v143 - - - Utility - MultiByte - v143 - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - $(Platform)\$(Configuration)\$(ProjectName)\ - $(Platform)\$(Configuration)\$(ProjectName)\ - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - - setlocal -"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D NightlyMemoryCheck -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\NightlyMemoryCheck - false - false - - setlocal -"C:\Program Files\CMake\bin\ctest.exe" -C $(Configuration) -D NightlyMemoryCheck -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\NightlyMemoryCheck - false - false - - - - - Always - Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp - false - Building Custom Rule E:/programming/cplus/dfhack/CMakeLists.txt - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-file E:/programming/cplus/dfhack/build/CMakeFiles/generate.stamp -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp - false - - - - - - - - - {31277AF8-10A2-3494-B123-559421E08C26} - ZERO_CHECK - false - Never - - - - - - \ No newline at end of file diff --git a/build/NightlyMemoryCheck.vcxproj.filters b/build/NightlyMemoryCheck.vcxproj.filters deleted file mode 100644 index a4b92fdc7..000000000 --- a/build/NightlyMemoryCheck.vcxproj.filters +++ /dev/null @@ -1,17 +0,0 @@ - - - - - CMake Rules - - - - - - - - - {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} - - - diff --git a/build/PACKAGE.vcxproj b/build/PACKAGE.vcxproj deleted file mode 100644 index 67c1c92dc..000000000 --- a/build/PACKAGE.vcxproj +++ /dev/null @@ -1,132 +0,0 @@ - - - - x64 - - - - Release - x64 - - - RelWithDebInfo - x64 - - - - {F20BBC06-43D9-375A-A5A9-E717817CF640} - 10.0.22000.0 - Win32Proj - x64 - PACKAGE - NoUpgrade - - - - Utility - MultiByte - v143 - - - Utility - MultiByte - v143 - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - $(Platform)\$(Configuration)\$(ProjectName)\ - $(Platform)\$(Configuration)\$(ProjectName)\ - - - - - setlocal -cd E:\programming\cplus\dfhack\build -if %errorlevel% neq 0 goto :cmEnd -E: -if %errorlevel% neq 0 goto :cmEnd -"C:\Program Files\CMake\bin\cpack.exe" -C $(Configuration) --config ./CPackConfig.cmake -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - - - - - - setlocal -cd E:\programming\cplus\dfhack\build -if %errorlevel% neq 0 goto :cmEnd -E: -if %errorlevel% neq 0 goto :cmEnd -"C:\Program Files\CMake\bin\cpack.exe" -C $(Configuration) --config ./CPackConfig.cmake -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - - - - - - setlocal -cd . -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\PACKAGE_force - false - false - - setlocal -cd . -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\PACKAGE_force - false - false - - - - - {31277AF8-10A2-3494-B123-559421E08C26} - ZERO_CHECK - false - Never - - - {40EA859D-1269-313F-A313-AA32B87C8935} - ALL_BUILD - false - Never - - - - - - \ No newline at end of file diff --git a/build/PACKAGE.vcxproj.filters b/build/PACKAGE.vcxproj.filters deleted file mode 100644 index 8c2a983bf..000000000 --- a/build/PACKAGE.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - CMake Rules - - - - - {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} - - - diff --git a/build/RUN_TESTS.vcxproj b/build/RUN_TESTS.vcxproj deleted file mode 100644 index 197f2baf3..000000000 --- a/build/RUN_TESTS.vcxproj +++ /dev/null @@ -1,118 +0,0 @@ - - - - x64 - - - - Release - x64 - - - RelWithDebInfo - x64 - - - - {45641EBC-7207-3F33-8572-930EA9BD4C6B} - 10.0.22000.0 - Win32Proj - x64 - RUN_TESTS - NoUpgrade - - - - Utility - MultiByte - v143 - - - Utility - MultiByte - v143 - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - $(Platform)\$(Configuration)\$(ProjectName)\ - $(Platform)\$(Configuration)\$(ProjectName)\ - - - - - setlocal -"C:\Program Files\CMake\bin\ctest.exe" --force-new-ctest-process -C $(Configuration) -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - - - - - - setlocal -"C:\Program Files\CMake\bin\ctest.exe" --force-new-ctest-process -C $(Configuration) -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - - - - - - setlocal -cd . -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\RUN_TESTS_force - false - false - - setlocal -cd . -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - %(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\RUN_TESTS_force - false - false - - - - - {31277AF8-10A2-3494-B123-559421E08C26} - ZERO_CHECK - false - Never - - - - - - \ No newline at end of file diff --git a/build/RUN_TESTS.vcxproj.filters b/build/RUN_TESTS.vcxproj.filters deleted file mode 100644 index 9b4c15921..000000000 --- a/build/RUN_TESTS.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - CMake Rules - - - - - {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} - - - diff --git a/build/ZERO_CHECK.vcxproj b/build/ZERO_CHECK.vcxproj deleted file mode 100644 index c71698f74..000000000 --- a/build/ZERO_CHECK.vcxproj +++ /dev/null @@ -1,105 +0,0 @@ - - - - x64 - - - - Release - x64 - - - RelWithDebInfo - x64 - - - - {31277AF8-10A2-3494-B123-559421E08C26} - 10.0.22000.0 - Win32Proj - x64 - ZERO_CHECK - NoUpgrade - - - - Utility - MultiByte - v143 - - - Utility - MultiByte - v143 - - - - - - - - - - <_ProjectFileVersion>10.0.20506.1 - $(Platform)\$(Configuration)\$(ProjectName)\ - $(Platform)\$(Configuration)\$(ProjectName)\ - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - E:\programming\cplus\dfhack\depends\zlib\include;E:\programming\cplus\dfhack\depends\SDL2\SDL2-2.26.2\include;E:\programming\cplus\dfhack\depends\protobuf;E:\programming\cplus\dfhack\depends\lua\include;E:\programming\cplus\dfhack\depends\md5;E:\programming\cplus\dfhack\depends\tinyxml;E:\programming\cplus\dfhack\depends\lodepng;E:\programming\cplus\dfhack\depends\tthread;E:\programming\cplus\dfhack\depends\clsocket\src;E:\programming\cplus\dfhack\depends\xlsxio\include;%(AdditionalIncludeDirectories) - $(ProjectDir)/$(IntDir) - %(Filename).h - %(Filename).tlb - %(Filename)_i.c - %(Filename)_p.c - - - - - Always - Checking Build System - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-list CMakeFiles/generate.stamp.list --vs-solution-file E:/programming/cplus/dfhack/build/dfhack.sln -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\BasicConfigVersion-AnyNewerVersion.cmake.in;C:\Program Files\CMake\share\cmake-3.22\Modules\BasicConfigVersion-SameMajorVersion.cmake.in;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCheckCompilerFlagCommonPatterns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakePackageConfigHelpers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCCompilerFlag.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCSourceRuns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSymbolExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckFunctionExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFile.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFileCXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckLibraryExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckStructHasMember.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckSymbolExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckTypeSize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\GNUInstallDirs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckCompilerFlag.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceRuns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\TestBigEndian.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\WriteBasicConfigVersionFile.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\CMakeLists.txt;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;E:\programming\cplus\dfhack\data\CMakeLists.txt;E:\programming\cplus\dfhack\depends\CMakeLists.txt;E:\programming\cplus\dfhack\depends\clsocket\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\cmake\JoinPaths.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\PreventInBuildInstalls.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\PreventInSourceBuilds.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\pkg-config\jsoncpp.pc.in;E:\programming\cplus\dfhack\depends\jsoncpp-sub\src\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\src\lib_json\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\version.in;E:\programming\cplus\dfhack\depends\libexpat\expat\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libexpat\expat\Changes;E:\programming\cplus\dfhack\depends\libexpat\expat\ConfigureChecks.cmake;E:\programming\cplus\dfhack\depends\libexpat\expat\cmake\expat-config.cmake.in;E:\programming\cplus\dfhack\depends\libexpat\expat\expat_config.h.cmake;E:\programming\cplus\dfhack\depends\libzip\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libzip\cmake-config.h.in;E:\programming\cplus\dfhack\depends\libzip\cmake-zipconf.h.in;E:\programming\cplus\dfhack\depends\libzip\cmake\Dist.cmake;E:\programming\cplus\dfhack\depends\libzip\lib\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libzip\libzip-config.cmake.in;E:\programming\cplus\dfhack\depends\libzip\libzip.pc.in;E:\programming\cplus\dfhack\depends\libzip\regress\nihtest.conf.in;E:\programming\cplus\dfhack\depends\libzip\regress\runtest.in;E:\programming\cplus\dfhack\depends\lodepng\CMakeLists.txt;E:\programming\cplus\dfhack\depends\lua\CMakeLists.txt;E:\programming\cplus\dfhack\depends\md5\CMakeLists.txt;E:\programming\cplus\dfhack\depends\protobuf\CMakeLists.txt;E:\programming\cplus\dfhack\depends\protobuf\config.h.in;E:\programming\cplus\dfhack\depends\tinyxml\CMakeLists.txt;E:\programming\cplus\dfhack\depends\tthread\CMakeLists.txt;E:\programming\cplus\dfhack\depends\xlsxio\CMakeLists.txt;E:\programming\cplus\dfhack\library\CMakeLists.txt;E:\programming\cplus\dfhack\library\git-describe.cmake.in;E:\programming\cplus\dfhack\library\xml\CMakeLists.txt;E:\programming\cplus\dfhack\library\xml\tools\CMakeLists.txt;E:\programming\cplus\dfhack\package\windows\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\Plugins.cmake;E:\programming\cplus\dfhack\plugins\autolabor\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\buildingplan\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\channel-safely\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\external\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\remotefortressreader\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\stockpiles\CMakeLists.txt;E:\programming\cplus\dfhack\scripts\CMakeLists.txt;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\lodepng\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\lua\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\md5\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\protobuf\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\tinyxml\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\tthread\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\src\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\src\lib_json\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\include\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\clsocket\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libexpat\expat\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libzip\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libzip\lib\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\xlsxio\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\xml\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\xml\tools\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\autolabor\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\buildingplan\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\channel-safely\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\remotefortressreader\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\stockpiles\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\external\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\data\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\scripts\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\package\windows\CMakeFiles\generate.stamp - false - Checking Build System - setlocal -"C:\Program Files\CMake\bin\cmake.exe" -SE:/programming/cplus/dfhack -BE:/programming/cplus/dfhack/build --check-stamp-list CMakeFiles/generate.stamp.list --vs-solution-file E:/programming/cplus/dfhack/build/dfhack.sln -if %errorlevel% neq 0 goto :cmEnd -:cmEnd -endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone -:cmErrorLevel -exit /b %1 -:cmDone -if %errorlevel% neq 0 goto :VCEnd - C:\Program Files\CMake\share\cmake-3.22\Modules\BasicConfigVersion-AnyNewerVersion.cmake.in;C:\Program Files\CMake\share\cmake-3.22\Modules\BasicConfigVersion-SameMajorVersion.cmake.in;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCXXInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCheckCompilerFlagCommonPatterns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeCommonLanguageInclude.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeGenericSystem.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeInitializeConfigs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeLanguageInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakePackageConfigHelpers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeRCInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInformation.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CMakeSystemSpecificInitialize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPack.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CPackComponent.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTest.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestTargets.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CTestUseLaunchers.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCCompilerFlag.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCSourceRuns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckCXXSymbolExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckFunctionExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFile.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFileCXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckIncludeFiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckLibraryExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckStructHasMember.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckSymbolExists.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\CheckTypeSize.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\CMakeCommonCompilerMacros.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Compiler\MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\DartConfiguration.tcl.in;C:\Program Files\CMake\share\cmake-3.22\Modules\FindCygwin.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindGit.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindMsys.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageHandleStandardArgs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPackageMessage.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindPerl.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\FindZLIB.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\GNUInstallDirs.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckCompilerFlag.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceCompiles.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Internal\CheckSourceRuns.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-C.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC-CXX.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows-MSVC.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\Windows.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\Platform\WindowsPaths.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\SelectLibraryConfigurations.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\TestBigEndian.cmake;C:\Program Files\CMake\share\cmake-3.22\Modules\WriteBasicConfigVersionFile.cmake;C:\Program Files\CMake\share\cmake-3.22\Templates\CPackConfig.cmake.in;E:\programming\cplus\dfhack\CMake\DownloadFile.cmake;E:\programming\cplus\dfhack\CMakeLists.txt;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeCXXCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeRCCompiler.cmake;E:\programming\cplus\dfhack\build\CMakeFiles\3.22.1\CMakeSystem.cmake;E:\programming\cplus\dfhack\data\CMakeLists.txt;E:\programming\cplus\dfhack\depends\CMakeLists.txt;E:\programming\cplus\dfhack\depends\clsocket\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\cmake\JoinPaths.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\PreventInBuildInstalls.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\include\PreventInSourceBuilds.cmake;E:\programming\cplus\dfhack\depends\jsoncpp-sub\pkg-config\jsoncpp.pc.in;E:\programming\cplus\dfhack\depends\jsoncpp-sub\src\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\src\lib_json\CMakeLists.txt;E:\programming\cplus\dfhack\depends\jsoncpp-sub\version.in;E:\programming\cplus\dfhack\depends\libexpat\expat\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libexpat\expat\Changes;E:\programming\cplus\dfhack\depends\libexpat\expat\ConfigureChecks.cmake;E:\programming\cplus\dfhack\depends\libexpat\expat\cmake\expat-config.cmake.in;E:\programming\cplus\dfhack\depends\libexpat\expat\expat_config.h.cmake;E:\programming\cplus\dfhack\depends\libzip\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libzip\cmake-config.h.in;E:\programming\cplus\dfhack\depends\libzip\cmake-zipconf.h.in;E:\programming\cplus\dfhack\depends\libzip\cmake\Dist.cmake;E:\programming\cplus\dfhack\depends\libzip\lib\CMakeLists.txt;E:\programming\cplus\dfhack\depends\libzip\libzip-config.cmake.in;E:\programming\cplus\dfhack\depends\libzip\libzip.pc.in;E:\programming\cplus\dfhack\depends\libzip\regress\nihtest.conf.in;E:\programming\cplus\dfhack\depends\libzip\regress\runtest.in;E:\programming\cplus\dfhack\depends\lodepng\CMakeLists.txt;E:\programming\cplus\dfhack\depends\lua\CMakeLists.txt;E:\programming\cplus\dfhack\depends\md5\CMakeLists.txt;E:\programming\cplus\dfhack\depends\protobuf\CMakeLists.txt;E:\programming\cplus\dfhack\depends\protobuf\config.h.in;E:\programming\cplus\dfhack\depends\tinyxml\CMakeLists.txt;E:\programming\cplus\dfhack\depends\tthread\CMakeLists.txt;E:\programming\cplus\dfhack\depends\xlsxio\CMakeLists.txt;E:\programming\cplus\dfhack\library\CMakeLists.txt;E:\programming\cplus\dfhack\library\git-describe.cmake.in;E:\programming\cplus\dfhack\library\xml\CMakeLists.txt;E:\programming\cplus\dfhack\library\xml\tools\CMakeLists.txt;E:\programming\cplus\dfhack\package\windows\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\Plugins.cmake;E:\programming\cplus\dfhack\plugins\autolabor\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\buildingplan\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\channel-safely\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\external\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\remotefortressreader\CMakeLists.txt;E:\programming\cplus\dfhack\plugins\stockpiles\CMakeLists.txt;E:\programming\cplus\dfhack\scripts\CMakeLists.txt;%(AdditionalInputs) - E:\programming\cplus\dfhack\build\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\lodepng\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\lua\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\md5\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\protobuf\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\tinyxml\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\tthread\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\src\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\src\lib_json\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\jsoncpp-sub\include\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\clsocket\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libexpat\expat\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libzip\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\libzip\lib\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\depends\xlsxio\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\xml\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\library\xml\tools\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\autolabor\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\buildingplan\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\channel-safely\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\remotefortressreader\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\stockpiles\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\plugins\external\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\data\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\scripts\CMakeFiles\generate.stamp;E:\programming\cplus\dfhack\build\package\windows\CMakeFiles\generate.stamp - false - - - - - - - - - - \ No newline at end of file diff --git a/build/ZERO_CHECK.vcxproj.filters b/build/ZERO_CHECK.vcxproj.filters deleted file mode 100644 index 2c79705a5..000000000 --- a/build/ZERO_CHECK.vcxproj.filters +++ /dev/null @@ -1,13 +0,0 @@ - - - - - CMake Rules - - - - - {AFAB5955-3E8F-3466-BF00-9CBF4FE558A1} - - - diff --git a/build/dfhack.sln b/build/dfhack.sln deleted file mode 100644 index 83a916c71..000000000 --- a/build/dfhack.sln +++ /dev/null @@ -1,1295 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CMakePredefinedTargets", "CMakePredefinedTargets", "{28D9607F-8931-375B-9273-9E20D2F6347F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CTestDashboardTargets", "CTestDashboardTargets", "{068CE9B1-E6DD-3864-AC38-93F10EF27A17}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Depends", "Depends", "{D8D353CC-1D2C-3A83-8EA0-A85D6CF14722}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{25456F37-E968-3921-80E5-1C0E141753B6}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ALL_BUILD", "ALL_BUILD.vcxproj", "{40EA859D-1269-313F-A313-AA32B87C8935}" - ProjectSection(ProjectDependencies) = postProject - {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA} = {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA} - {14C478D6-D815-378F-81D1-B53BBD6CBE9A} = {14C478D6-D815-378F-81D1-B53BBD6CBE9A} - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {3A2B0858-3B92-3598-B679-2A437C1286E0} = {3A2B0858-3B92-3598-B679-2A437C1286E0} - {27ECEB5C-C396-32BE-93E6-4D4801692191} = {27ECEB5C-C396-32BE-93E6-4D4801692191} - {5F63101D-75FE-31BE-9D25-6641FBBFF959} = {5F63101D-75FE-31BE-9D25-6641FBBFF959} - {7D67495E-4C92-37BE-BEF8-174CA37ADD21} = {7D67495E-4C92-37BE-BEF8-174CA37ADD21} - {6152D284-A720-3556-A60A-7C13C89205AD} = {6152D284-A720-3556-A60A-7C13C89205AD} - {4049FF1D-8A65-3021-B550-0DE0E63F9577} = {4049FF1D-8A65-3021-B550-0DE0E63F9577} - {8CE562EE-798E-3C1B-975C-F49C6B5C84ED} = {8CE562EE-798E-3C1B-975C-F49C6B5C84ED} - {961FD68A-49A7-3F16-9F96-16AC8236D3A3} = {961FD68A-49A7-3F16-9F96-16AC8236D3A3} - {D3C67352-8290-3C4E-9F23-93DDE051AA37} = {D3C67352-8290-3C4E-9F23-93DDE051AA37} - {A0486456-80E4-3492-940E-6652FF2B45B9} = {A0486456-80E4-3492-940E-6652FF2B45B9} - {386966C3-DC46-3936-AD44-35E2470C6A28} = {386966C3-DC46-3936-AD44-35E2470C6A28} - {02D9B109-1602-3567-80C0-3BF354675829} = {02D9B109-1602-3567-80C0-3BF354675829} - {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA} = {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA} - {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515} = {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515} - {76B00654-E15A-3E4F-8C41-DDC63A14246A} = {76B00654-E15A-3E4F-8C41-DDC63A14246A} - {D7DF31C2-3247-31BA-A745-DF4095334504} = {D7DF31C2-3247-31BA-A745-DF4095334504} - {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204} = {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204} - {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5} = {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5} - {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB} = {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB} - {BAABB124-4999-3462-AF35-16DB3C974D7C} = {BAABB124-4999-3462-AF35-16DB3C974D7C} - {6F451C91-A082-3981-83D5-65844ED16BDA} = {6F451C91-A082-3981-83D5-65844ED16BDA} - {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80} = {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80} - {AB8FA0F9-1482-31F8-87E2-E3C7BB178053} = {AB8FA0F9-1482-31F8-87E2-E3C7BB178053} - {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212} = {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212} - {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20} = {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20} - {5347E62F-7AEB-3B7C-B480-161A35974C9E} = {5347E62F-7AEB-3B7C-B480-161A35974C9E} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {136AD85C-398C-329A-84AC-AD4481963950} = {136AD85C-398C-329A-84AC-AD4481963950} - {78DBE964-AC8C-3264-903B-2B102B46D476} = {78DBE964-AC8C-3264-903B-2B102B46D476} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {D3A6760C-34FD-3EE2-B9CC-24647168DC6A} = {D3A6760C-34FD-3EE2-B9CC-24647168DC6A} - {AFC95A6A-BDBB-35E2-9381-253284E1112D} = {AFC95A6A-BDBB-35E2-9381-253284E1112D} - {0AED7AC4-8C48-3205-AF43-3D536A60D815} = {0AED7AC4-8C48-3205-AF43-3D536A60D815} - {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96} = {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96} - {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} = {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} - {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7} = {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7} - {47842A81-7497-313E-B466-C60AE89334CB} = {47842A81-7497-313E-B466-C60AE89334CB} - {25303A98-8EE4-3355-8C68-CFA8B4116EF0} = {25303A98-8EE4-3355-8C68-CFA8B4116EF0} - {A80E6C37-1E31-3DDC-A4FE-B21553E580DB} = {A80E6C37-1E31-3DDC-A4FE-B21553E580DB} - {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA} = {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA} - {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD} = {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD} - {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B} = {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B} - {21572060-CA28-355B-A508-5675A4A2FAB3} = {21572060-CA28-355B-A508-5675A4A2FAB3} - {F1206958-458C-3F18-84D9-3EEE07B73862} = {F1206958-458C-3F18-84D9-3EEE07B73862} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3} = {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3} - {419297F2-C54C-3C4B-91AB-7B119D09E730} = {419297F2-C54C-3C4B-91AB-7B119D09E730} - {8F94C6B8-42CE-329C-B6A9-3E13C04350CF} = {8F94C6B8-42CE-329C-B6A9-3E13C04350CF} - {7FF993D7-A6D3-37CC-AE69-2906ECD89E03} = {7FF993D7-A6D3-37CC-AE69-2906ECD89E03} - {374D8559-CBBF-3F24-BEE1-8B11A184B7F8} = {374D8559-CBBF-3F24-BEE1-8B11A184B7F8} - {4E197970-E280-3B04-AD7D-E52DC551E902} = {4E197970-E280-3B04-AD7D-E52DC551E902} - {4E6C8BD2-2434-31DC-BDD2-8788D2547403} = {4E6C8BD2-2434-31DC-BDD2-8788D2547403} - {37629CF4-1B6A-312A-89B7-CF11593F51A4} = {37629CF4-1B6A-312A-89B7-CF11593F51A4} - {8D195538-264D-3C39-AB9A-653DA8A6F56E} = {8D195538-264D-3C39-AB9A-653DA8A6F56E} - {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} - {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} = {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} - {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} - {E36DC20B-AE7A-3449-B308-C932B9DD4290} = {E36DC20B-AE7A-3449-B308-C932B9DD4290} - {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121} = {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121} - {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3} = {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3} - {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2} = {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2} - {C080819A-4275-3D2A-84DE-7C21EDAE2BBA} = {C080819A-4275-3D2A-84DE-7C21EDAE2BBA} - {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F} = {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F} - {6579683E-AB4A-3B40-A145-1952047837D2} = {6579683E-AB4A-3B40-A145-1952047837D2} - {2FE38842-BDF7-3A93-9D06-1C9814B6B11B} = {2FE38842-BDF7-3A93-9D06-1C9814B6B11B} - {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C} = {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C} - {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4} = {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4} - {C884F97B-4C5C-3457-AF4D-BB4C05670662} = {C884F97B-4C5C-3457-AF4D-BB4C05670662} - {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D} = {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D} - {796760C3-71E4-32AD-A9C4-B984AFC97106} = {796760C3-71E4-32AD-A9C4-B984AFC97106} - {8054C91C-5221-314F-96C5-8FEC57BBEED1} = {8054C91C-5221-314F-96C5-8FEC57BBEED1} - {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} = {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} - {3B9F42C2-0060-329E-B123-7DEF1E91617D} = {3B9F42C2-0060-329E-B123-7DEF1E91617D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "3dveins", "plugins\3dveins.vcxproj", "{B10F83BD-77CE-3CC2-A4D0-2B412287DFEA}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Continuous", "Continuous.vcxproj", "{D7C70C41-500D-35F8-A992-1351DDDCDA0C}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Experimental", "Experimental.vcxproj", "{474F765F-548E-3AAB-8D5B-66CF364BE4B2}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "INSTALL", "INSTALL.vcxproj", "{07ADCCA9-7D16-3F3D-AB6F-1BDA83D4E943}" - ProjectSection(ProjectDependencies) = postProject - {40EA859D-1269-313F-A313-AA32B87C8935} = {40EA859D-1269-313F-A313-AA32B87C8935} - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Nightly", "Nightly.vcxproj", "{246A2207-0D75-3894-8E4E-785344D8ABF4}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NightlyMemoryCheck", "NightlyMemoryCheck.vcxproj", "{93318712-66D7-31F1-B537-E229E2FD9AF0}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PACKAGE", "PACKAGE.vcxproj", "{F20BBC06-43D9-375A-A5A9-E717817CF640}" - ProjectSection(ProjectDependencies) = postProject - {40EA859D-1269-313F-A313-AA32B87C8935} = {40EA859D-1269-313F-A313-AA32B87C8935} - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RUN_TESTS", "RUN_TESTS.vcxproj", "{45641EBC-7207-3F33-8572-930EA9BD4C6B}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RemoteFortressReader", "plugins\remotefortressreader\RemoteFortressReader.vcxproj", "{14C478D6-D815-378F-81D1-B53BBD6CBE9A}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {69CB13F6-E5DD-3AC2-AF47-08A452514760} = {69CB13F6-E5DD-3AC2-AF47-08A452514760} - {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZERO_CHECK", "ZERO_CHECK.vcxproj", "{31277AF8-10A2-3494-B123-559421E08C26}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "add-spatter", "plugins\add-spatter.vcxproj", "{3A2B0858-3B92-3598-B679-2A437C1286E0}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autobutcher", "plugins\autobutcher.vcxproj", "{27ECEB5C-C396-32BE-93E6-4D4801692191}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autochop", "plugins\autochop.vcxproj", "{5F63101D-75FE-31BE-9D25-6641FBBFF959}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autoclothing", "plugins\autoclothing.vcxproj", "{7D67495E-4C92-37BE-BEF8-174CA37ADD21}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autodump", "plugins\autodump.vcxproj", "{6152D284-A720-3556-A60A-7C13C89205AD}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autofarm", "plugins\autofarm.vcxproj", "{4049FF1D-8A65-3021-B550-0DE0E63F9577}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autolabor", "plugins\autolabor\autolabor.vcxproj", "{8CE562EE-798E-3C1B-975C-F49C6B5C84ED}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autonestbox", "plugins\autonestbox.vcxproj", "{961FD68A-49A7-3F16-9F96-16AC8236D3A3}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "autoslab", "plugins\autoslab.vcxproj", "{D3C67352-8290-3C4E-9F23-93DDE051AA37}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "binpatch", "library\binpatch.vcxproj", "{A0486456-80E4-3492-940E-6652FF2B45B9}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {111D1A41-5C7F-397A-A62C-B19B0AEB044B} = {111D1A41-5C7F-397A-A62C-B19B0AEB044B} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blueprint", "plugins\blueprint.vcxproj", "{386966C3-DC46-3936-AD44-35E2470C6A28}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "buildingplan", "plugins\buildingplan\buildingplan.vcxproj", "{02D9B109-1602-3567-80C0-3BF354675829}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "changeitem", "plugins\changeitem.vcxproj", "{B6B32914-FA20-3991-AEDE-3FFA75FDF7DA}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "changelayer", "plugins\changelayer.vcxproj", "{C153A10F-47F2-3FF1-A27D-0CE7AA4B1515}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "changevein", "plugins\changevein.vcxproj", "{76B00654-E15A-3E4F-8C41-DDC63A14246A}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "channel-safely", "plugins\channel-safely\channel-safely.vcxproj", "{D7DF31C2-3247-31BA-A745-DF4095334504}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cleanconst", "plugins\cleanconst.vcxproj", "{2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cleaners", "plugins\cleaners.vcxproj", "{099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cleanowned", "plugins\cleanowned.vcxproj", "{D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "clsocket", "depends\clsocket\clsocket.vcxproj", "{39BD79E1-6088-33F3-AD4A-74F0E0EE785C}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "confirm", "plugins\confirm.vcxproj", "{BAABB124-4999-3462-AF35-16DB3C974D7C}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "createitem", "plugins\createitem.vcxproj", "{6F451C91-A082-3981-83D5-65844ED16BDA}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cursecheck", "plugins\cursecheck.vcxproj", "{C143DDD8-9AB8-368F-ACE4-BA4F7651DA80}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cxxrandom", "plugins\cxxrandom.vcxproj", "{AB8FA0F9-1482-31F8-87E2-E3C7BB178053}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "debug", "plugins\debug.vcxproj", "{CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {CD9E5829-45CA-308D-9ED7-C2C38139D69E} = {CD9E5829-45CA-308D-9ED7-C2C38139D69E} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "deramp", "plugins\deramp.vcxproj", "{E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "design", "plugins\design.vcxproj", "{5347E62F-7AEB-3B7C-B480-161A35974C9E}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack", "library\dfhack.vcxproj", "{6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} = {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} - {111D1A41-5C7F-397A-A62C-B19B0AEB044B} = {111D1A41-5C7F-397A-A62C-B19B0AEB044B} - {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7} = {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7} - {19F34DB6-1C4F-36FD-A7A8-8E5077651209} = {19F34DB6-1C4F-36FD-A7A8-8E5077651209} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE} = {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE} - {A294D3AD-91C7-32D9-B361-D399900843E5} = {A294D3AD-91C7-32D9-B361-D399900843E5} - {CD9E5829-45CA-308D-9ED7-C2C38139D69E} = {CD9E5829-45CA-308D-9ED7-C2C38139D69E} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-client", "library\dfhack-client.vcxproj", "{136AD85C-398C-329A-84AC-AD4481963950}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} = {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {CD9E5829-45CA-308D-9ED7-C2C38139D69E} = {CD9E5829-45CA-308D-9ED7-C2C38139D69E} - {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-lodepng", "depends\lodepng\dfhack-lodepng.vcxproj", "{8DB90A0E-6076-3C07-B890-7E5E886009EC}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-md5", "depends\md5\dfhack-md5.vcxproj", "{111D1A41-5C7F-397A-A62C-B19B0AEB044B}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-run", "library\dfhack-run.vcxproj", "{78DBE964-AC8C-3264-903B-2B102B46D476}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} = {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} - {136AD85C-398C-329A-84AC-AD4481963950} = {136AD85C-398C-329A-84AC-AD4481963950} - {CD9E5829-45CA-308D-9ED7-C2C38139D69E} = {CD9E5829-45CA-308D-9ED7-C2C38139D69E} - {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-tinythread", "depends\tthread\dfhack-tinythread.vcxproj", "{D3A713C3-480C-3DF0-95FA-8B80D95DF8F7}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-tinyxml", "depends\tinyxml\dfhack-tinyxml.vcxproj", "{19F34DB6-1C4F-36FD-A7A8-8E5077651209}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfhack-version", "library\dfhack-version.vcxproj", "{5DC5A20B-821C-3008-A247-B08677276F56}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dig", "plugins\dig.vcxproj", "{D3A6760C-34FD-3EE2-B9CC-24647168DC6A}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dig-now", "plugins\dig-now.vcxproj", "{AFC95A6A-BDBB-35E2-9381-253284E1112D}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dist", "depends\libzip\dist.vcxproj", "{24F97336-D35B-3FBA-BEF8-64B2D5845D3F}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "distcheck", "depends\libzip\distcheck.vcxproj", "{86289ECD-3E29-3E01-93B2-829B5666A809}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {24F97336-D35B-3FBA-BEF8-64B2D5845D3F} = {24F97336-D35B-3FBA-BEF8-64B2D5845D3F} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dwarfvet", "plugins\dwarfvet.vcxproj", "{0AED7AC4-8C48-3205-AF43-3D536A60D815}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eventful", "plugins\eventful.vcxproj", "{D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "expat", "depends\libexpat\expat\expat.vcxproj", "{BA32E800-D5FA-3F4E-B91B-763CD4FE389C}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fastdwarf", "plugins\fastdwarf.vcxproj", "{894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "faststart", "plugins\faststart.vcxproj", "{47842A81-7497-313E-B466-C60AE89334CB}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "filltraffic", "plugins\filltraffic.vcxproj", "{25303A98-8EE4-3355-8C68-CFA8B4116EF0}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flows", "plugins\flows.vcxproj", "{A80E6C37-1E31-3DDC-A4FE-B21553E580DB}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate_headers", "library\generate_headers.vcxproj", "{F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate_proto", "plugins\generate_proto.vcxproj", "{0AE42C92-16FF-3E69-B468-111535996095}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate_proto_RemoteFortressReader", "plugins\remotefortressreader\generate_proto_RemoteFortressReader.vcxproj", "{69CB13F6-E5DD-3AC2-AF47-08A452514760}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate_proto_core", "library\generate_proto_core.vcxproj", "{A294D3AD-91C7-32D9-B361-D399900843E5}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generate_proto_stockpiles", "plugins\stockpiles\generate_proto_stockpiles.vcxproj", "{73A57BCF-3487-35DC-B448-FD328037CDF3}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getplants", "plugins\getplants.vcxproj", "{E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hotkeys", "plugins\hotkeys.vcxproj", "{6F10CAC8-6D9F-357E-B574-5EC901BF4EAD}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jsoncpp_static", "depends\jsoncpp-sub\src\lib_json\jsoncpp_static.vcxproj", "{CD9E5829-45CA-308D-9ED7-C2C38139D69E}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lair", "plugins\lair.vcxproj", "{DA8EE8E6-6AE0-3DA6-AED9-316977621A0B}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "liquids", "plugins\liquids.vcxproj", "{21572060-CA28-355B-A508-5675A4A2FAB3}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logistics", "plugins\logistics.vcxproj", "{F1206958-458C-3F18-84D9-3EEE07B73862}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lua", "depends\lua\lua.vcxproj", "{6CA1FA88-B709-340C-8366-DCE4C1D1FB32}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luasocket", "plugins\luasocket.vcxproj", "{4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} = {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7} = {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "misery", "plugins\misery.vcxproj", "{419297F2-C54C-3C4B-91AB-7B119D09E730}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nestboxes", "plugins\nestboxes.vcxproj", "{8F94C6B8-42CE-329C-B6A9-3E13C04350CF}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "orders", "plugins\orders.vcxproj", "{7FF993D7-A6D3-37CC-AE69-2906ECD89E03}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {CD9E5829-45CA-308D-9ED7-C2C38139D69E} = {CD9E5829-45CA-308D-9ED7-C2C38139D69E} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "overlay", "plugins\overlay.vcxproj", "{374D8559-CBBF-3F24-BEE1-8B11A184B7F8}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pathable", "plugins\pathable.vcxproj", "{4E197970-E280-3B04-AD7D-E52DC551E902}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "probe", "plugins\probe.vcxproj", "{4E6C8BD2-2434-31DC-BDD2-8788D2547403}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "prospector", "plugins\prospector.vcxproj", "{37629CF4-1B6A-312A-89B7-CF11593F51A4}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protobuf", "depends\protobuf\protobuf.vcxproj", "{8D195538-264D-3C39-AB9A-653DA8A6F56E}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protobuf-lite", "depends\protobuf\protobuf-lite.vcxproj", "{9302E53B-085D-3577-A3E2-EB51A51D084C}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protoc", "depends\protobuf\protoc.vcxproj", "{1C17AAAA-9E99-32C1-9FF6-E88C054A2646}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {8D195538-264D-3C39-AB9A-653DA8A6F56E} = {8D195538-264D-3C39-AB9A-653DA8A6F56E} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "protoc-bin", "depends\protobuf\protoc-bin.vcxproj", "{74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {8D195538-264D-3C39-AB9A-653DA8A6F56E} = {8D195538-264D-3C39-AB9A-653DA8A6F56E} - {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} = {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "regrass", "plugins\regrass.vcxproj", "{E36DC20B-AE7A-3449-B308-C932B9DD4290}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "reveal", "plugins\reveal.vcxproj", "{C831208B-D7C3-3DD6-9F16-0EA8A5FF3121}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "seedwatch", "plugins\seedwatch.vcxproj", "{7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "showmood", "plugins\showmood.vcxproj", "{E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sort", "plugins\sort.vcxproj", "{C080819A-4275-3D2A-84DE-7C21EDAE2BBA}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stockpiles", "plugins\stockpiles\stockpiles.vcxproj", "{7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {73A57BCF-3487-35DC-B448-FD328037CDF3} = {73A57BCF-3487-35DC-B448-FD328037CDF3} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - {9302E53B-085D-3577-A3E2-EB51A51D084C} = {9302E53B-085D-3577-A3E2-EB51A51D084C} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "strangemood", "plugins\strangemood.vcxproj", "{6579683E-AB4A-3B40-A145-1952047837D2}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tailor", "plugins\tailor.vcxproj", "{2FE38842-BDF7-3A93-9D06-1C9814B6B11B}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tiletypes", "plugins\tiletypes.vcxproj", "{B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "work-now", "plugins\work-now.vcxproj", "{2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "workflow", "plugins\workflow.vcxproj", "{C884F97B-4C5C-3457-AF4D-BB4C05670662}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xlsxio_read_STATIC", "depends\xlsxio\xlsxio_read_STATIC.vcxproj", "{85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} = {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} - {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} = {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xlsxio_write_STATIC", "depends\xlsxio\xlsxio_write_STATIC.vcxproj", "{796760C3-71E4-32AD-A9C4-B984AFC97106}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} = {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xlsxreader", "plugins\xlsxreader.vcxproj", "{8054C91C-5221-314F-96C5-8FEC57BBEED1}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} = {BA32E800-D5FA-3F4E-B91B-763CD4FE389C} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D} = {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D} - {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} = {744BEFA7-C931-39C8-A1B4-1A9A88901B1D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zip", "depends\libzip\lib\zip.vcxproj", "{744BEFA7-C931-39C8-A1B4-1A9A88901B1D}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zone", "plugins\zone.vcxproj", "{3B9F42C2-0060-329E-B123-7DEF1E91617D}" - ProjectSection(ProjectDependencies) = postProject - {31277AF8-10A2-3494-B123-559421E08C26} = {31277AF8-10A2-3494-B123-559421E08C26} - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} = {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62} - {5DC5A20B-821C-3008-A247-B08677276F56} = {5DC5A20B-821C-3008-A247-B08677276F56} - {0AE42C92-16FF-3E69-B468-111535996095} = {0AE42C92-16FF-3E69-B468-111535996095} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Release|x64 = Release|x64 - RelWithDebInfo|x64 = RelWithDebInfo|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {40EA859D-1269-313F-A313-AA32B87C8935}.Release|x64.ActiveCfg = Release|x64 - {40EA859D-1269-313F-A313-AA32B87C8935}.Release|x64.Build.0 = Release|x64 - {40EA859D-1269-313F-A313-AA32B87C8935}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {40EA859D-1269-313F-A313-AA32B87C8935}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA}.Release|x64.ActiveCfg = Release|x64 - {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA}.Release|x64.Build.0 = Release|x64 - {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {D7C70C41-500D-35F8-A992-1351DDDCDA0C}.Release|x64.ActiveCfg = Release|x64 - {D7C70C41-500D-35F8-A992-1351DDDCDA0C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {474F765F-548E-3AAB-8D5B-66CF364BE4B2}.Release|x64.ActiveCfg = Release|x64 - {474F765F-548E-3AAB-8D5B-66CF364BE4B2}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {07ADCCA9-7D16-3F3D-AB6F-1BDA83D4E943}.Release|x64.ActiveCfg = Release|x64 - {07ADCCA9-7D16-3F3D-AB6F-1BDA83D4E943}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {246A2207-0D75-3894-8E4E-785344D8ABF4}.Release|x64.ActiveCfg = Release|x64 - {246A2207-0D75-3894-8E4E-785344D8ABF4}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {93318712-66D7-31F1-B537-E229E2FD9AF0}.Release|x64.ActiveCfg = Release|x64 - {93318712-66D7-31F1-B537-E229E2FD9AF0}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {F20BBC06-43D9-375A-A5A9-E717817CF640}.Release|x64.ActiveCfg = Release|x64 - {F20BBC06-43D9-375A-A5A9-E717817CF640}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {45641EBC-7207-3F33-8572-930EA9BD4C6B}.Release|x64.ActiveCfg = Release|x64 - {45641EBC-7207-3F33-8572-930EA9BD4C6B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {14C478D6-D815-378F-81D1-B53BBD6CBE9A}.Release|x64.ActiveCfg = Release|x64 - {14C478D6-D815-378F-81D1-B53BBD6CBE9A}.Release|x64.Build.0 = Release|x64 - {14C478D6-D815-378F-81D1-B53BBD6CBE9A}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {14C478D6-D815-378F-81D1-B53BBD6CBE9A}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {31277AF8-10A2-3494-B123-559421E08C26}.Release|x64.ActiveCfg = Release|x64 - {31277AF8-10A2-3494-B123-559421E08C26}.Release|x64.Build.0 = Release|x64 - {31277AF8-10A2-3494-B123-559421E08C26}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {31277AF8-10A2-3494-B123-559421E08C26}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {3A2B0858-3B92-3598-B679-2A437C1286E0}.Release|x64.ActiveCfg = Release|x64 - {3A2B0858-3B92-3598-B679-2A437C1286E0}.Release|x64.Build.0 = Release|x64 - {3A2B0858-3B92-3598-B679-2A437C1286E0}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {3A2B0858-3B92-3598-B679-2A437C1286E0}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {27ECEB5C-C396-32BE-93E6-4D4801692191}.Release|x64.ActiveCfg = Release|x64 - {27ECEB5C-C396-32BE-93E6-4D4801692191}.Release|x64.Build.0 = Release|x64 - {27ECEB5C-C396-32BE-93E6-4D4801692191}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {27ECEB5C-C396-32BE-93E6-4D4801692191}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {5F63101D-75FE-31BE-9D25-6641FBBFF959}.Release|x64.ActiveCfg = Release|x64 - {5F63101D-75FE-31BE-9D25-6641FBBFF959}.Release|x64.Build.0 = Release|x64 - {5F63101D-75FE-31BE-9D25-6641FBBFF959}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {5F63101D-75FE-31BE-9D25-6641FBBFF959}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {7D67495E-4C92-37BE-BEF8-174CA37ADD21}.Release|x64.ActiveCfg = Release|x64 - {7D67495E-4C92-37BE-BEF8-174CA37ADD21}.Release|x64.Build.0 = Release|x64 - {7D67495E-4C92-37BE-BEF8-174CA37ADD21}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {7D67495E-4C92-37BE-BEF8-174CA37ADD21}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {6152D284-A720-3556-A60A-7C13C89205AD}.Release|x64.ActiveCfg = Release|x64 - {6152D284-A720-3556-A60A-7C13C89205AD}.Release|x64.Build.0 = Release|x64 - {6152D284-A720-3556-A60A-7C13C89205AD}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {6152D284-A720-3556-A60A-7C13C89205AD}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {4049FF1D-8A65-3021-B550-0DE0E63F9577}.Release|x64.ActiveCfg = Release|x64 - {4049FF1D-8A65-3021-B550-0DE0E63F9577}.Release|x64.Build.0 = Release|x64 - {4049FF1D-8A65-3021-B550-0DE0E63F9577}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {4049FF1D-8A65-3021-B550-0DE0E63F9577}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {8CE562EE-798E-3C1B-975C-F49C6B5C84ED}.Release|x64.ActiveCfg = Release|x64 - {8CE562EE-798E-3C1B-975C-F49C6B5C84ED}.Release|x64.Build.0 = Release|x64 - {8CE562EE-798E-3C1B-975C-F49C6B5C84ED}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {8CE562EE-798E-3C1B-975C-F49C6B5C84ED}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {961FD68A-49A7-3F16-9F96-16AC8236D3A3}.Release|x64.ActiveCfg = Release|x64 - {961FD68A-49A7-3F16-9F96-16AC8236D3A3}.Release|x64.Build.0 = Release|x64 - {961FD68A-49A7-3F16-9F96-16AC8236D3A3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {961FD68A-49A7-3F16-9F96-16AC8236D3A3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {D3C67352-8290-3C4E-9F23-93DDE051AA37}.Release|x64.ActiveCfg = Release|x64 - {D3C67352-8290-3C4E-9F23-93DDE051AA37}.Release|x64.Build.0 = Release|x64 - {D3C67352-8290-3C4E-9F23-93DDE051AA37}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {D3C67352-8290-3C4E-9F23-93DDE051AA37}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {A0486456-80E4-3492-940E-6652FF2B45B9}.Release|x64.ActiveCfg = Release|x64 - {A0486456-80E4-3492-940E-6652FF2B45B9}.Release|x64.Build.0 = Release|x64 - {A0486456-80E4-3492-940E-6652FF2B45B9}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {A0486456-80E4-3492-940E-6652FF2B45B9}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {386966C3-DC46-3936-AD44-35E2470C6A28}.Release|x64.ActiveCfg = Release|x64 - {386966C3-DC46-3936-AD44-35E2470C6A28}.Release|x64.Build.0 = Release|x64 - {386966C3-DC46-3936-AD44-35E2470C6A28}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {386966C3-DC46-3936-AD44-35E2470C6A28}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {02D9B109-1602-3567-80C0-3BF354675829}.Release|x64.ActiveCfg = Release|x64 - {02D9B109-1602-3567-80C0-3BF354675829}.Release|x64.Build.0 = Release|x64 - {02D9B109-1602-3567-80C0-3BF354675829}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {02D9B109-1602-3567-80C0-3BF354675829}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA}.Release|x64.ActiveCfg = Release|x64 - {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA}.Release|x64.Build.0 = Release|x64 - {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515}.Release|x64.ActiveCfg = Release|x64 - {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515}.Release|x64.Build.0 = Release|x64 - {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {76B00654-E15A-3E4F-8C41-DDC63A14246A}.Release|x64.ActiveCfg = Release|x64 - {76B00654-E15A-3E4F-8C41-DDC63A14246A}.Release|x64.Build.0 = Release|x64 - {76B00654-E15A-3E4F-8C41-DDC63A14246A}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {76B00654-E15A-3E4F-8C41-DDC63A14246A}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {D7DF31C2-3247-31BA-A745-DF4095334504}.Release|x64.ActiveCfg = Release|x64 - {D7DF31C2-3247-31BA-A745-DF4095334504}.Release|x64.Build.0 = Release|x64 - {D7DF31C2-3247-31BA-A745-DF4095334504}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {D7DF31C2-3247-31BA-A745-DF4095334504}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204}.Release|x64.ActiveCfg = Release|x64 - {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204}.Release|x64.Build.0 = Release|x64 - {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5}.Release|x64.ActiveCfg = Release|x64 - {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5}.Release|x64.Build.0 = Release|x64 - {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB}.Release|x64.ActiveCfg = Release|x64 - {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB}.Release|x64.Build.0 = Release|x64 - {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {39BD79E1-6088-33F3-AD4A-74F0E0EE785C}.Release|x64.ActiveCfg = Release|x64 - {39BD79E1-6088-33F3-AD4A-74F0E0EE785C}.Release|x64.Build.0 = Release|x64 - {39BD79E1-6088-33F3-AD4A-74F0E0EE785C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {39BD79E1-6088-33F3-AD4A-74F0E0EE785C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {BAABB124-4999-3462-AF35-16DB3C974D7C}.Release|x64.ActiveCfg = Release|x64 - {BAABB124-4999-3462-AF35-16DB3C974D7C}.Release|x64.Build.0 = Release|x64 - {BAABB124-4999-3462-AF35-16DB3C974D7C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {BAABB124-4999-3462-AF35-16DB3C974D7C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {6F451C91-A082-3981-83D5-65844ED16BDA}.Release|x64.ActiveCfg = Release|x64 - {6F451C91-A082-3981-83D5-65844ED16BDA}.Release|x64.Build.0 = Release|x64 - {6F451C91-A082-3981-83D5-65844ED16BDA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {6F451C91-A082-3981-83D5-65844ED16BDA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80}.Release|x64.ActiveCfg = Release|x64 - {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80}.Release|x64.Build.0 = Release|x64 - {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {AB8FA0F9-1482-31F8-87E2-E3C7BB178053}.Release|x64.ActiveCfg = Release|x64 - {AB8FA0F9-1482-31F8-87E2-E3C7BB178053}.Release|x64.Build.0 = Release|x64 - {AB8FA0F9-1482-31F8-87E2-E3C7BB178053}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {AB8FA0F9-1482-31F8-87E2-E3C7BB178053}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212}.Release|x64.ActiveCfg = Release|x64 - {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212}.Release|x64.Build.0 = Release|x64 - {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20}.Release|x64.ActiveCfg = Release|x64 - {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20}.Release|x64.Build.0 = Release|x64 - {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {5347E62F-7AEB-3B7C-B480-161A35974C9E}.Release|x64.ActiveCfg = Release|x64 - {5347E62F-7AEB-3B7C-B480-161A35974C9E}.Release|x64.Build.0 = Release|x64 - {5347E62F-7AEB-3B7C-B480-161A35974C9E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {5347E62F-7AEB-3B7C-B480-161A35974C9E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62}.Release|x64.ActiveCfg = Release|x64 - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62}.Release|x64.Build.0 = Release|x64 - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {6DA5B761-FD24-3B41-9DCA-C7B11FDEBC62}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {136AD85C-398C-329A-84AC-AD4481963950}.Release|x64.ActiveCfg = Release|x64 - {136AD85C-398C-329A-84AC-AD4481963950}.Release|x64.Build.0 = Release|x64 - {136AD85C-398C-329A-84AC-AD4481963950}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {136AD85C-398C-329A-84AC-AD4481963950}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {8DB90A0E-6076-3C07-B890-7E5E886009EC}.Release|x64.ActiveCfg = Release|x64 - {8DB90A0E-6076-3C07-B890-7E5E886009EC}.Release|x64.Build.0 = Release|x64 - {8DB90A0E-6076-3C07-B890-7E5E886009EC}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {8DB90A0E-6076-3C07-B890-7E5E886009EC}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {111D1A41-5C7F-397A-A62C-B19B0AEB044B}.Release|x64.ActiveCfg = Release|x64 - {111D1A41-5C7F-397A-A62C-B19B0AEB044B}.Release|x64.Build.0 = Release|x64 - {111D1A41-5C7F-397A-A62C-B19B0AEB044B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {111D1A41-5C7F-397A-A62C-B19B0AEB044B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {78DBE964-AC8C-3264-903B-2B102B46D476}.Release|x64.ActiveCfg = Release|x64 - {78DBE964-AC8C-3264-903B-2B102B46D476}.Release|x64.Build.0 = Release|x64 - {78DBE964-AC8C-3264-903B-2B102B46D476}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {78DBE964-AC8C-3264-903B-2B102B46D476}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7}.Release|x64.ActiveCfg = Release|x64 - {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7}.Release|x64.Build.0 = Release|x64 - {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {19F34DB6-1C4F-36FD-A7A8-8E5077651209}.Release|x64.ActiveCfg = Release|x64 - {19F34DB6-1C4F-36FD-A7A8-8E5077651209}.Release|x64.Build.0 = Release|x64 - {19F34DB6-1C4F-36FD-A7A8-8E5077651209}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {19F34DB6-1C4F-36FD-A7A8-8E5077651209}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {5DC5A20B-821C-3008-A247-B08677276F56}.Release|x64.ActiveCfg = Release|x64 - {5DC5A20B-821C-3008-A247-B08677276F56}.Release|x64.Build.0 = Release|x64 - {5DC5A20B-821C-3008-A247-B08677276F56}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {5DC5A20B-821C-3008-A247-B08677276F56}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {D3A6760C-34FD-3EE2-B9CC-24647168DC6A}.Release|x64.ActiveCfg = Release|x64 - {D3A6760C-34FD-3EE2-B9CC-24647168DC6A}.Release|x64.Build.0 = Release|x64 - {D3A6760C-34FD-3EE2-B9CC-24647168DC6A}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {D3A6760C-34FD-3EE2-B9CC-24647168DC6A}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {AFC95A6A-BDBB-35E2-9381-253284E1112D}.Release|x64.ActiveCfg = Release|x64 - {AFC95A6A-BDBB-35E2-9381-253284E1112D}.Release|x64.Build.0 = Release|x64 - {AFC95A6A-BDBB-35E2-9381-253284E1112D}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {AFC95A6A-BDBB-35E2-9381-253284E1112D}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {24F97336-D35B-3FBA-BEF8-64B2D5845D3F}.Release|x64.ActiveCfg = Release|x64 - {24F97336-D35B-3FBA-BEF8-64B2D5845D3F}.Release|x64.Build.0 = Release|x64 - {24F97336-D35B-3FBA-BEF8-64B2D5845D3F}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {24F97336-D35B-3FBA-BEF8-64B2D5845D3F}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {86289ECD-3E29-3E01-93B2-829B5666A809}.Release|x64.ActiveCfg = Release|x64 - {86289ECD-3E29-3E01-93B2-829B5666A809}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {0AED7AC4-8C48-3205-AF43-3D536A60D815}.Release|x64.ActiveCfg = Release|x64 - {0AED7AC4-8C48-3205-AF43-3D536A60D815}.Release|x64.Build.0 = Release|x64 - {0AED7AC4-8C48-3205-AF43-3D536A60D815}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {0AED7AC4-8C48-3205-AF43-3D536A60D815}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96}.Release|x64.ActiveCfg = Release|x64 - {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96}.Release|x64.Build.0 = Release|x64 - {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {BA32E800-D5FA-3F4E-B91B-763CD4FE389C}.Release|x64.ActiveCfg = Release|x64 - {BA32E800-D5FA-3F4E-B91B-763CD4FE389C}.Release|x64.Build.0 = Release|x64 - {BA32E800-D5FA-3F4E-B91B-763CD4FE389C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {BA32E800-D5FA-3F4E-B91B-763CD4FE389C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7}.Release|x64.ActiveCfg = Release|x64 - {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7}.Release|x64.Build.0 = Release|x64 - {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {47842A81-7497-313E-B466-C60AE89334CB}.Release|x64.ActiveCfg = Release|x64 - {47842A81-7497-313E-B466-C60AE89334CB}.Release|x64.Build.0 = Release|x64 - {47842A81-7497-313E-B466-C60AE89334CB}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {47842A81-7497-313E-B466-C60AE89334CB}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {25303A98-8EE4-3355-8C68-CFA8B4116EF0}.Release|x64.ActiveCfg = Release|x64 - {25303A98-8EE4-3355-8C68-CFA8B4116EF0}.Release|x64.Build.0 = Release|x64 - {25303A98-8EE4-3355-8C68-CFA8B4116EF0}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {25303A98-8EE4-3355-8C68-CFA8B4116EF0}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {A80E6C37-1E31-3DDC-A4FE-B21553E580DB}.Release|x64.ActiveCfg = Release|x64 - {A80E6C37-1E31-3DDC-A4FE-B21553E580DB}.Release|x64.Build.0 = Release|x64 - {A80E6C37-1E31-3DDC-A4FE-B21553E580DB}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {A80E6C37-1E31-3DDC-A4FE-B21553E580DB}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE}.Release|x64.ActiveCfg = Release|x64 - {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE}.Release|x64.Build.0 = Release|x64 - {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {F2136CA7-D3F2-3A3E-8D32-FE5A5E55E1EE}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {0AE42C92-16FF-3E69-B468-111535996095}.Release|x64.ActiveCfg = Release|x64 - {0AE42C92-16FF-3E69-B468-111535996095}.Release|x64.Build.0 = Release|x64 - {0AE42C92-16FF-3E69-B468-111535996095}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {0AE42C92-16FF-3E69-B468-111535996095}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {69CB13F6-E5DD-3AC2-AF47-08A452514760}.Release|x64.ActiveCfg = Release|x64 - {69CB13F6-E5DD-3AC2-AF47-08A452514760}.Release|x64.Build.0 = Release|x64 - {69CB13F6-E5DD-3AC2-AF47-08A452514760}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {69CB13F6-E5DD-3AC2-AF47-08A452514760}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {A294D3AD-91C7-32D9-B361-D399900843E5}.Release|x64.ActiveCfg = Release|x64 - {A294D3AD-91C7-32D9-B361-D399900843E5}.Release|x64.Build.0 = Release|x64 - {A294D3AD-91C7-32D9-B361-D399900843E5}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {A294D3AD-91C7-32D9-B361-D399900843E5}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {73A57BCF-3487-35DC-B448-FD328037CDF3}.Release|x64.ActiveCfg = Release|x64 - {73A57BCF-3487-35DC-B448-FD328037CDF3}.Release|x64.Build.0 = Release|x64 - {73A57BCF-3487-35DC-B448-FD328037CDF3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {73A57BCF-3487-35DC-B448-FD328037CDF3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA}.Release|x64.ActiveCfg = Release|x64 - {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA}.Release|x64.Build.0 = Release|x64 - {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD}.Release|x64.ActiveCfg = Release|x64 - {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD}.Release|x64.Build.0 = Release|x64 - {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {CD9E5829-45CA-308D-9ED7-C2C38139D69E}.Release|x64.ActiveCfg = Release|x64 - {CD9E5829-45CA-308D-9ED7-C2C38139D69E}.Release|x64.Build.0 = Release|x64 - {CD9E5829-45CA-308D-9ED7-C2C38139D69E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {CD9E5829-45CA-308D-9ED7-C2C38139D69E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B}.Release|x64.ActiveCfg = Release|x64 - {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B}.Release|x64.Build.0 = Release|x64 - {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {21572060-CA28-355B-A508-5675A4A2FAB3}.Release|x64.ActiveCfg = Release|x64 - {21572060-CA28-355B-A508-5675A4A2FAB3}.Release|x64.Build.0 = Release|x64 - {21572060-CA28-355B-A508-5675A4A2FAB3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {21572060-CA28-355B-A508-5675A4A2FAB3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {F1206958-458C-3F18-84D9-3EEE07B73862}.Release|x64.ActiveCfg = Release|x64 - {F1206958-458C-3F18-84D9-3EEE07B73862}.Release|x64.Build.0 = Release|x64 - {F1206958-458C-3F18-84D9-3EEE07B73862}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {F1206958-458C-3F18-84D9-3EEE07B73862}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32}.Release|x64.ActiveCfg = Release|x64 - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32}.Release|x64.Build.0 = Release|x64 - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3}.Release|x64.ActiveCfg = Release|x64 - {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3}.Release|x64.Build.0 = Release|x64 - {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {419297F2-C54C-3C4B-91AB-7B119D09E730}.Release|x64.ActiveCfg = Release|x64 - {419297F2-C54C-3C4B-91AB-7B119D09E730}.Release|x64.Build.0 = Release|x64 - {419297F2-C54C-3C4B-91AB-7B119D09E730}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {419297F2-C54C-3C4B-91AB-7B119D09E730}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {8F94C6B8-42CE-329C-B6A9-3E13C04350CF}.Release|x64.ActiveCfg = Release|x64 - {8F94C6B8-42CE-329C-B6A9-3E13C04350CF}.Release|x64.Build.0 = Release|x64 - {8F94C6B8-42CE-329C-B6A9-3E13C04350CF}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {8F94C6B8-42CE-329C-B6A9-3E13C04350CF}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {7FF993D7-A6D3-37CC-AE69-2906ECD89E03}.Release|x64.ActiveCfg = Release|x64 - {7FF993D7-A6D3-37CC-AE69-2906ECD89E03}.Release|x64.Build.0 = Release|x64 - {7FF993D7-A6D3-37CC-AE69-2906ECD89E03}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {7FF993D7-A6D3-37CC-AE69-2906ECD89E03}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {374D8559-CBBF-3F24-BEE1-8B11A184B7F8}.Release|x64.ActiveCfg = Release|x64 - {374D8559-CBBF-3F24-BEE1-8B11A184B7F8}.Release|x64.Build.0 = Release|x64 - {374D8559-CBBF-3F24-BEE1-8B11A184B7F8}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {374D8559-CBBF-3F24-BEE1-8B11A184B7F8}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {4E197970-E280-3B04-AD7D-E52DC551E902}.Release|x64.ActiveCfg = Release|x64 - {4E197970-E280-3B04-AD7D-E52DC551E902}.Release|x64.Build.0 = Release|x64 - {4E197970-E280-3B04-AD7D-E52DC551E902}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {4E197970-E280-3B04-AD7D-E52DC551E902}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {4E6C8BD2-2434-31DC-BDD2-8788D2547403}.Release|x64.ActiveCfg = Release|x64 - {4E6C8BD2-2434-31DC-BDD2-8788D2547403}.Release|x64.Build.0 = Release|x64 - {4E6C8BD2-2434-31DC-BDD2-8788D2547403}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {4E6C8BD2-2434-31DC-BDD2-8788D2547403}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {37629CF4-1B6A-312A-89B7-CF11593F51A4}.Release|x64.ActiveCfg = Release|x64 - {37629CF4-1B6A-312A-89B7-CF11593F51A4}.Release|x64.Build.0 = Release|x64 - {37629CF4-1B6A-312A-89B7-CF11593F51A4}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {37629CF4-1B6A-312A-89B7-CF11593F51A4}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {8D195538-264D-3C39-AB9A-653DA8A6F56E}.Release|x64.ActiveCfg = Release|x64 - {8D195538-264D-3C39-AB9A-653DA8A6F56E}.Release|x64.Build.0 = Release|x64 - {8D195538-264D-3C39-AB9A-653DA8A6F56E}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {8D195538-264D-3C39-AB9A-653DA8A6F56E}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {9302E53B-085D-3577-A3E2-EB51A51D084C}.Release|x64.ActiveCfg = Release|x64 - {9302E53B-085D-3577-A3E2-EB51A51D084C}.Release|x64.Build.0 = Release|x64 - {9302E53B-085D-3577-A3E2-EB51A51D084C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {9302E53B-085D-3577-A3E2-EB51A51D084C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {1C17AAAA-9E99-32C1-9FF6-E88C054A2646}.Release|x64.ActiveCfg = Release|x64 - {1C17AAAA-9E99-32C1-9FF6-E88C054A2646}.Release|x64.Build.0 = Release|x64 - {1C17AAAA-9E99-32C1-9FF6-E88C054A2646}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {1C17AAAA-9E99-32C1-9FF6-E88C054A2646}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7}.Release|x64.ActiveCfg = Release|x64 - {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7}.Release|x64.Build.0 = Release|x64 - {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {E36DC20B-AE7A-3449-B308-C932B9DD4290}.Release|x64.ActiveCfg = Release|x64 - {E36DC20B-AE7A-3449-B308-C932B9DD4290}.Release|x64.Build.0 = Release|x64 - {E36DC20B-AE7A-3449-B308-C932B9DD4290}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {E36DC20B-AE7A-3449-B308-C932B9DD4290}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121}.Release|x64.ActiveCfg = Release|x64 - {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121}.Release|x64.Build.0 = Release|x64 - {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3}.Release|x64.ActiveCfg = Release|x64 - {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3}.Release|x64.Build.0 = Release|x64 - {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2}.Release|x64.ActiveCfg = Release|x64 - {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2}.Release|x64.Build.0 = Release|x64 - {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {C080819A-4275-3D2A-84DE-7C21EDAE2BBA}.Release|x64.ActiveCfg = Release|x64 - {C080819A-4275-3D2A-84DE-7C21EDAE2BBA}.Release|x64.Build.0 = Release|x64 - {C080819A-4275-3D2A-84DE-7C21EDAE2BBA}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {C080819A-4275-3D2A-84DE-7C21EDAE2BBA}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F}.Release|x64.ActiveCfg = Release|x64 - {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F}.Release|x64.Build.0 = Release|x64 - {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {6579683E-AB4A-3B40-A145-1952047837D2}.Release|x64.ActiveCfg = Release|x64 - {6579683E-AB4A-3B40-A145-1952047837D2}.Release|x64.Build.0 = Release|x64 - {6579683E-AB4A-3B40-A145-1952047837D2}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {6579683E-AB4A-3B40-A145-1952047837D2}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {2FE38842-BDF7-3A93-9D06-1C9814B6B11B}.Release|x64.ActiveCfg = Release|x64 - {2FE38842-BDF7-3A93-9D06-1C9814B6B11B}.Release|x64.Build.0 = Release|x64 - {2FE38842-BDF7-3A93-9D06-1C9814B6B11B}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {2FE38842-BDF7-3A93-9D06-1C9814B6B11B}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C}.Release|x64.ActiveCfg = Release|x64 - {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C}.Release|x64.Build.0 = Release|x64 - {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4}.Release|x64.ActiveCfg = Release|x64 - {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4}.Release|x64.Build.0 = Release|x64 - {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {C884F97B-4C5C-3457-AF4D-BB4C05670662}.Release|x64.ActiveCfg = Release|x64 - {C884F97B-4C5C-3457-AF4D-BB4C05670662}.Release|x64.Build.0 = Release|x64 - {C884F97B-4C5C-3457-AF4D-BB4C05670662}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {C884F97B-4C5C-3457-AF4D-BB4C05670662}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D}.Release|x64.ActiveCfg = Release|x64 - {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D}.Release|x64.Build.0 = Release|x64 - {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {85B6988E-9C0B-3B6E-B35A-2AD1ABB5588D}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {796760C3-71E4-32AD-A9C4-B984AFC97106}.Release|x64.ActiveCfg = Release|x64 - {796760C3-71E4-32AD-A9C4-B984AFC97106}.Release|x64.Build.0 = Release|x64 - {796760C3-71E4-32AD-A9C4-B984AFC97106}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {796760C3-71E4-32AD-A9C4-B984AFC97106}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {8054C91C-5221-314F-96C5-8FEC57BBEED1}.Release|x64.ActiveCfg = Release|x64 - {8054C91C-5221-314F-96C5-8FEC57BBEED1}.Release|x64.Build.0 = Release|x64 - {8054C91C-5221-314F-96C5-8FEC57BBEED1}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {8054C91C-5221-314F-96C5-8FEC57BBEED1}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {744BEFA7-C931-39C8-A1B4-1A9A88901B1D}.Release|x64.ActiveCfg = Release|x64 - {744BEFA7-C931-39C8-A1B4-1A9A88901B1D}.Release|x64.Build.0 = Release|x64 - {744BEFA7-C931-39C8-A1B4-1A9A88901B1D}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {744BEFA7-C931-39C8-A1B4-1A9A88901B1D}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - {3B9F42C2-0060-329E-B123-7DEF1E91617D}.Release|x64.ActiveCfg = Release|x64 - {3B9F42C2-0060-329E-B123-7DEF1E91617D}.Release|x64.Build.0 = Release|x64 - {3B9F42C2-0060-329E-B123-7DEF1E91617D}.RelWithDebInfo|x64.ActiveCfg = RelWithDebInfo|x64 - {3B9F42C2-0060-329E-B123-7DEF1E91617D}.RelWithDebInfo|x64.Build.0 = RelWithDebInfo|x64 - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {40EA859D-1269-313F-A313-AA32B87C8935} = {28D9607F-8931-375B-9273-9E20D2F6347F} - {07ADCCA9-7D16-3F3D-AB6F-1BDA83D4E943} = {28D9607F-8931-375B-9273-9E20D2F6347F} - {F20BBC06-43D9-375A-A5A9-E717817CF640} = {28D9607F-8931-375B-9273-9E20D2F6347F} - {45641EBC-7207-3F33-8572-930EA9BD4C6B} = {28D9607F-8931-375B-9273-9E20D2F6347F} - {31277AF8-10A2-3494-B123-559421E08C26} = {28D9607F-8931-375B-9273-9E20D2F6347F} - {D7C70C41-500D-35F8-A992-1351DDDCDA0C} = {068CE9B1-E6DD-3864-AC38-93F10EF27A17} - {474F765F-548E-3AAB-8D5B-66CF364BE4B2} = {068CE9B1-E6DD-3864-AC38-93F10EF27A17} - {246A2207-0D75-3894-8E4E-785344D8ABF4} = {068CE9B1-E6DD-3864-AC38-93F10EF27A17} - {93318712-66D7-31F1-B537-E229E2FD9AF0} = {068CE9B1-E6DD-3864-AC38-93F10EF27A17} - {39BD79E1-6088-33F3-AD4A-74F0E0EE785C} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} - {8DB90A0E-6076-3C07-B890-7E5E886009EC} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} - {111D1A41-5C7F-397A-A62C-B19B0AEB044B} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} - {D3A713C3-480C-3DF0-95FA-8B80D95DF8F7} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} - {19F34DB6-1C4F-36FD-A7A8-8E5077651209} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} - {6CA1FA88-B709-340C-8366-DCE4C1D1FB32} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} - {8D195538-264D-3C39-AB9A-653DA8A6F56E} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} - {9302E53B-085D-3577-A3E2-EB51A51D084C} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} - {1C17AAAA-9E99-32C1-9FF6-E88C054A2646} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} - {74CBC9D0-87DE-34DC-AA46-FD7DD2A990E7} = {D8D353CC-1D2C-3A83-8EA0-A85D6CF14722} - {B10F83BD-77CE-3CC2-A4D0-2B412287DFEA} = {25456F37-E968-3921-80E5-1C0E141753B6} - {14C478D6-D815-378F-81D1-B53BBD6CBE9A} = {25456F37-E968-3921-80E5-1C0E141753B6} - {3A2B0858-3B92-3598-B679-2A437C1286E0} = {25456F37-E968-3921-80E5-1C0E141753B6} - {27ECEB5C-C396-32BE-93E6-4D4801692191} = {25456F37-E968-3921-80E5-1C0E141753B6} - {5F63101D-75FE-31BE-9D25-6641FBBFF959} = {25456F37-E968-3921-80E5-1C0E141753B6} - {7D67495E-4C92-37BE-BEF8-174CA37ADD21} = {25456F37-E968-3921-80E5-1C0E141753B6} - {6152D284-A720-3556-A60A-7C13C89205AD} = {25456F37-E968-3921-80E5-1C0E141753B6} - {4049FF1D-8A65-3021-B550-0DE0E63F9577} = {25456F37-E968-3921-80E5-1C0E141753B6} - {8CE562EE-798E-3C1B-975C-F49C6B5C84ED} = {25456F37-E968-3921-80E5-1C0E141753B6} - {961FD68A-49A7-3F16-9F96-16AC8236D3A3} = {25456F37-E968-3921-80E5-1C0E141753B6} - {D3C67352-8290-3C4E-9F23-93DDE051AA37} = {25456F37-E968-3921-80E5-1C0E141753B6} - {386966C3-DC46-3936-AD44-35E2470C6A28} = {25456F37-E968-3921-80E5-1C0E141753B6} - {02D9B109-1602-3567-80C0-3BF354675829} = {25456F37-E968-3921-80E5-1C0E141753B6} - {B6B32914-FA20-3991-AEDE-3FFA75FDF7DA} = {25456F37-E968-3921-80E5-1C0E141753B6} - {C153A10F-47F2-3FF1-A27D-0CE7AA4B1515} = {25456F37-E968-3921-80E5-1C0E141753B6} - {76B00654-E15A-3E4F-8C41-DDC63A14246A} = {25456F37-E968-3921-80E5-1C0E141753B6} - {D7DF31C2-3247-31BA-A745-DF4095334504} = {25456F37-E968-3921-80E5-1C0E141753B6} - {2B9B4415-E1BD-33F7-95FD-7DFA4F7B2204} = {25456F37-E968-3921-80E5-1C0E141753B6} - {099D780E-7F06-3EAA-98A8-2A9C7BBA3FD5} = {25456F37-E968-3921-80E5-1C0E141753B6} - {D65A7A3A-0A4D-361D-B093-CB7BF60BC5DB} = {25456F37-E968-3921-80E5-1C0E141753B6} - {BAABB124-4999-3462-AF35-16DB3C974D7C} = {25456F37-E968-3921-80E5-1C0E141753B6} - {6F451C91-A082-3981-83D5-65844ED16BDA} = {25456F37-E968-3921-80E5-1C0E141753B6} - {C143DDD8-9AB8-368F-ACE4-BA4F7651DA80} = {25456F37-E968-3921-80E5-1C0E141753B6} - {AB8FA0F9-1482-31F8-87E2-E3C7BB178053} = {25456F37-E968-3921-80E5-1C0E141753B6} - {CFC3621A-1CB4-3FC2-B1B7-FD3E6AC9B212} = {25456F37-E968-3921-80E5-1C0E141753B6} - {E3A6CF18-2D4A-3541-97FD-EA36D6A9DC20} = {25456F37-E968-3921-80E5-1C0E141753B6} - {5347E62F-7AEB-3B7C-B480-161A35974C9E} = {25456F37-E968-3921-80E5-1C0E141753B6} - {D3A6760C-34FD-3EE2-B9CC-24647168DC6A} = {25456F37-E968-3921-80E5-1C0E141753B6} - {AFC95A6A-BDBB-35E2-9381-253284E1112D} = {25456F37-E968-3921-80E5-1C0E141753B6} - {0AED7AC4-8C48-3205-AF43-3D536A60D815} = {25456F37-E968-3921-80E5-1C0E141753B6} - {D46EA8E6-D149-35E8-B2C3-A4FD5AE72B96} = {25456F37-E968-3921-80E5-1C0E141753B6} - {894B02CD-77FD-3B32-8A23-AFE5DFEFD7A7} = {25456F37-E968-3921-80E5-1C0E141753B6} - {47842A81-7497-313E-B466-C60AE89334CB} = {25456F37-E968-3921-80E5-1C0E141753B6} - {25303A98-8EE4-3355-8C68-CFA8B4116EF0} = {25456F37-E968-3921-80E5-1C0E141753B6} - {A80E6C37-1E31-3DDC-A4FE-B21553E580DB} = {25456F37-E968-3921-80E5-1C0E141753B6} - {E6EA4F63-3C22-3D4C-A201-F9E90BBB7FCA} = {25456F37-E968-3921-80E5-1C0E141753B6} - {6F10CAC8-6D9F-357E-B574-5EC901BF4EAD} = {25456F37-E968-3921-80E5-1C0E141753B6} - {DA8EE8E6-6AE0-3DA6-AED9-316977621A0B} = {25456F37-E968-3921-80E5-1C0E141753B6} - {21572060-CA28-355B-A508-5675A4A2FAB3} = {25456F37-E968-3921-80E5-1C0E141753B6} - {F1206958-458C-3F18-84D9-3EEE07B73862} = {25456F37-E968-3921-80E5-1C0E141753B6} - {4BEF77D9-B9D4-33A2-950A-48EB5CE10FB3} = {25456F37-E968-3921-80E5-1C0E141753B6} - {419297F2-C54C-3C4B-91AB-7B119D09E730} = {25456F37-E968-3921-80E5-1C0E141753B6} - {8F94C6B8-42CE-329C-B6A9-3E13C04350CF} = {25456F37-E968-3921-80E5-1C0E141753B6} - {7FF993D7-A6D3-37CC-AE69-2906ECD89E03} = {25456F37-E968-3921-80E5-1C0E141753B6} - {374D8559-CBBF-3F24-BEE1-8B11A184B7F8} = {25456F37-E968-3921-80E5-1C0E141753B6} - {4E197970-E280-3B04-AD7D-E52DC551E902} = {25456F37-E968-3921-80E5-1C0E141753B6} - {4E6C8BD2-2434-31DC-BDD2-8788D2547403} = {25456F37-E968-3921-80E5-1C0E141753B6} - {37629CF4-1B6A-312A-89B7-CF11593F51A4} = {25456F37-E968-3921-80E5-1C0E141753B6} - {E36DC20B-AE7A-3449-B308-C932B9DD4290} = {25456F37-E968-3921-80E5-1C0E141753B6} - {C831208B-D7C3-3DD6-9F16-0EA8A5FF3121} = {25456F37-E968-3921-80E5-1C0E141753B6} - {7B31A6BF-105F-3E5D-8FEF-1B9B86D51ED3} = {25456F37-E968-3921-80E5-1C0E141753B6} - {E1C04F8B-70DF-31A7-B06F-BD5CEDBA17C2} = {25456F37-E968-3921-80E5-1C0E141753B6} - {C080819A-4275-3D2A-84DE-7C21EDAE2BBA} = {25456F37-E968-3921-80E5-1C0E141753B6} - {7EE9C0CE-18BB-36A8-BE3E-EEE7F673B97F} = {25456F37-E968-3921-80E5-1C0E141753B6} - {6579683E-AB4A-3B40-A145-1952047837D2} = {25456F37-E968-3921-80E5-1C0E141753B6} - {2FE38842-BDF7-3A93-9D06-1C9814B6B11B} = {25456F37-E968-3921-80E5-1C0E141753B6} - {B8FB6F36-01B4-37A3-84F1-0E364DCA8F1C} = {25456F37-E968-3921-80E5-1C0E141753B6} - {2E73B9B9-ADD5-3FD1-8BCB-FD6A829934B4} = {25456F37-E968-3921-80E5-1C0E141753B6} - {C884F97B-4C5C-3457-AF4D-BB4C05670662} = {25456F37-E968-3921-80E5-1C0E141753B6} - {8054C91C-5221-314F-96C5-8FEC57BBEED1} = {25456F37-E968-3921-80E5-1C0E141753B6} - {3B9F42C2-0060-329E-B123-7DEF1E91617D} = {25456F37-E968-3921-80E5-1C0E141753B6} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {97344453-ACD8-397F-8291-084632F194C3} - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal From 9f4f14d0257c889396e6612031c87e3d1191fe8d Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 24 Sep 2023 13:18:58 +0300 Subject: [PATCH 593/851] put back unformatted hotkeys --- plugins/lua/hotkeys.lua | 168 +++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 87 deletions(-) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 30407a8fa..7173bed80 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -17,8 +17,8 @@ end function should_hide_armok(cmdline) local command = get_command(cmdline) return dfhack.getHideArmokTools() and - helpdb.is_entry(command) and - helpdb.get_entry_tags(command).armok + helpdb.is_entry(command) and + helpdb.get_entry_tags(command).armok end -- ----------------- -- @@ -26,11 +26,11 @@ end -- ----------------- -- HotspotMenuWidget = defclass(HotspotMenuWidget, overlay.OverlayWidget) -HotspotMenuWidget.ATTRS { - default_pos = { x = 5, y = 1 }, - default_enabled = true, - version = 2, - viewscreens = { +HotspotMenuWidget.ATTRS{ + default_pos={x=5,y=1}, + default_enabled=true, + version=2, + viewscreens={ 'adopt_region', 'choose_game_type', -- 'choose_start_site', -- conflicts with vanilla panel layouts @@ -48,51 +48,51 @@ HotspotMenuWidget.ATTRS { 'update_region', 'world' }, - frame = { w = 4, h = 3 } + frame={w=4, h=3} } function HotspotMenuWidget:init() local to_pen = dfhack.pen.parse local function tp(idx, ch) - return to_pen { - tile = function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end, - ch = ch, - fg = COLOR_GREY, + return to_pen{ + tile=function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end, + ch=ch, + fg=COLOR_GREY, } end local function tph(idx, ch) - return to_pen { - tile = function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, - ch = ch, - fg = COLOR_WHITE, + return to_pen{ + tile=function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, + ch=ch, + fg=COLOR_WHITE, } end local function get_tile_token(idx, ch) return { - tile = tp(idx, ch), - htile = tph(idx, ch), - width = 1, + tile=tp(idx, ch), + htile=tph(idx, ch), + width=1, } end - self:addviews { - widgets.Label { - text = { + self:addviews{ + widgets.Label{ + text={ get_tile_token(1, '!'), get_tile_token(2, 'D'), get_tile_token(3, 'F'), get_tile_token(4, '!'), NEWLINE, get_tile_token(5, '!'), get_tile_token(6, 'H'), get_tile_token(7, 'a'), get_tile_token(8, '!'), NEWLINE, get_tile_token(9, '!'), get_tile_token(10, 'c'), get_tile_token(11, 'k'), get_tile_token(12, '!'), }, - on_click = function() dfhack.run_command('hotkeys') end, + on_click=function() dfhack.run_command('hotkeys') end, }, } end function HotspotMenuWidget:overlay_trigger() - return MenuScreen { hotspot = self }:show() + return MenuScreen{hotspot=self}:show() end -- register the menu hotspot with the overlay -OVERLAY_WIDGETS = { menu = HotspotMenuWidget } +OVERLAY_WIDGETS = {menu=HotspotMenuWidget} -- ---- -- -- Menu -- @@ -103,15 +103,15 @@ local MAX_LIST_WIDTH = 45 local MAX_LIST_HEIGHT = 15 Menu = defclass(Menu, widgets.Panel) -Menu.ATTRS { - hotspot = DEFAULT_NIL, +Menu.ATTRS{ + hotspot=DEFAULT_NIL, } -- get a map from the binding string to a list of hotkey strings that all -- point to that binding local function get_bindings_to_hotkeys(hotkeys, bindings) local bindings_to_hotkeys = {} - for _, hotkey in ipairs(hotkeys) do + for _,hotkey in ipairs(hotkeys) do local binding = bindings[hotkey] table.insert(ensure_key(bindings_to_hotkeys, binding), hotkey) end @@ -126,17 +126,17 @@ local function get_choices(hotkeys, bindings, is_inverted) local bindings_to_hotkeys = get_bindings_to_hotkeys(hotkeys, bindings) -- build list choices - for _, hotkey in ipairs(hotkeys) do + for _,hotkey in ipairs(hotkeys) do local command = bindings[hotkey] if seen[command] then goto continue end seen[command] = true local hk_width, tokens = 0, {} - for _, hk in ipairs(bindings_to_hotkeys[command]) do + for _,hk in ipairs(bindings_to_hotkeys[command]) do if hk_width ~= 0 then table.insert(tokens, ', ') hk_width = hk_width + 2 end - table.insert(tokens, { text = hk, pen = COLOR_LIGHTGREEN }) + table.insert(tokens, {text=hk, pen=COLOR_LIGHTGREEN}) hk_width = hk_width + #hk end local command_str = command @@ -144,20 +144,16 @@ local function get_choices(hotkeys, bindings, is_inverted) local max_command_len = MAX_LIST_WIDTH - hk_width - LIST_BUFFER command_str = command:sub(1, max_command_len - 3) .. '...' end - table.insert(tokens, 1, { text = command_str }) - local choice = { - icon = ARROW, - command = command, - text = tokens, - hk_width = hk_width - } + table.insert(tokens, 1, {text=command_str}) + local choice = {icon=ARROW, command=command, text=tokens, + hk_width=hk_width} max_width = math.max(max_width, hk_width + #command_str + LIST_BUFFER) table.insert(choices, is_inverted and 1 or #choices + 1, choice) ::continue:: end -- adjust width of command fields so the hotkey tokens are right justified - for _, choice in ipairs(choices) do + for _,choice in ipairs(choices) do local command_token = choice.text[1] command_token.width = max_width - choice.hk_width - (LIST_BUFFER - 1) end @@ -168,19 +164,17 @@ end function Menu:init() local hotkeys, bindings = getHotkeys() if #hotkeys == 0 then - hotkeys = { '' } - bindings = { [''] = 'gui/launcher' } + hotkeys = {''} + bindings = {['']='gui/launcher'} end local is_inverted = not not self.hotspot.frame.b - local choices, list_width = get_choices(hotkeys, bindings, is_inverted) - - list_width = math.max(35, list_width) + local choices,list_width = get_choices(hotkeys, bindings, is_inverted) list_width = math.max(35, list_width) local list_frame = copyall(self.hotspot.frame) - local list_widget_frame = { h = math.min(#choices, MAX_LIST_HEIGHT) } + local list_widget_frame = {h=math.min(#choices, MAX_LIST_HEIGHT)} local quickstart_frame = {} list_frame.w = list_width + 2 list_frame.h = list_widget_frame.h + 4 @@ -199,51 +193,51 @@ function Menu:init() list_frame.r = math.max(0, list_frame.r + 5) end - local help_frame = { w = list_frame.w, l = list_frame.l, r = list_frame.r } + local help_frame = {w=list_frame.w, l=list_frame.l, r=list_frame.r} if list_frame.t then help_frame.t = list_frame.t + list_frame.h else help_frame.b = list_frame.b + list_frame.h end - self:addviews { - widgets.Panel { - view_id = 'list_panel', - frame = list_frame, - frame_style = gui.PANEL_FRAME, - frame_background = gui.CLEAR_PEN, - subviews = { - widgets.List { - view_id = 'list', - frame = list_widget_frame, - choices = choices, - icon_width = 2, - on_select = self:callback('onSelect'), - on_submit = self:callback('onSubmit'), - on_submit2 = self:callback('onSubmit2'), + self:addviews{ + widgets.Panel{ + view_id='list_panel', + frame=list_frame, + frame_style=gui.PANEL_FRAME, + frame_background=gui.CLEAR_PEN, + subviews={ + widgets.List{ + view_id='list', + frame=list_widget_frame, + choices=choices, + icon_width=2, + on_select=self:callback('onSelect'), + on_submit=self:callback('onSubmit'), + on_submit2=self:callback('onSubmit2'), }, - widgets.Panel { frame = { h = 1 } }, - widgets.HotkeyLabel { - frame = quickstart_frame, - label = 'Quickstart guide', - key = 'STRING_A063', - on_activate = function() - self:onSubmit(nil, { command = 'quickstart-guide' }) + widgets.Panel{frame={h=1}}, + widgets.HotkeyLabel{ + frame=quickstart_frame, + label='Quickstart guide', + key='STRING_A063', + on_activate=function() + self:onSubmit(nil, {command='quickstart-guide'}) end, }, }, }, - widgets.ResizingPanel { - view_id = 'help_panel', - autoarrange_subviews = true, - frame = help_frame, - frame_style = gui.PANEL_FRAME, - frame_background = gui.CLEAR_PEN, - subviews = { - widgets.WrappedLabel { - view_id = 'help', - text_to_wrap = '', - scroll_keys = {}, + widgets.ResizingPanel{ + view_id='help_panel', + autoarrange_subviews=true, + frame=help_frame, + frame_style=gui.PANEL_FRAME, + frame_background=gui.CLEAR_PEN, + subviews={ + widgets.WrappedLabel{ + view_id='help', + text_to_wrap='', + scroll_keys={}, }, }, }, @@ -258,7 +252,7 @@ function Menu:onSelect(_, choice) if not choice or #self.subviews == 0 then return end 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' + helpdb.get_entry_short_help(command) or 'Command not found' self.subviews.help_panel:updateLayout() end @@ -308,7 +302,7 @@ end function Menu:getMouseFramePos() return self.subviews.list_panel:getMouseFramePos() or - self.subviews.help_panel:getMouseFramePos() + self.subviews.help_panel:getMouseFramePos() end function Menu:onRenderBody(dc) @@ -330,14 +324,14 @@ end MenuScreen = defclass(MenuScreen, gui.ZScreen) MenuScreen.ATTRS { - focus_path = 'hotkeys/menu', - initial_pause = false, - hotspot = DEFAULT_NIL, + focus_path='hotkeys/menu', + initial_pause=false, + hotspot=DEFAULT_NIL, } function MenuScreen:init() - self:addviews { - Menu { hotspot = self.hotspot }, + self:addviews{ + Menu{hotspot=self.hotspot}, } end @@ -345,4 +339,4 @@ function MenuScreen:onDismiss() cleanupHotkeys() end -return _ENV +return _ENV \ No newline at end of file From bb5e178756dd73f6075ff69cb743ca1990a92b21 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 24 Sep 2023 13:19:48 +0300 Subject: [PATCH 594/851] fix eof --- plugins/lua/hotkeys.lua | 166 ++++++++++++++++++++-------------------- 1 file changed, 85 insertions(+), 81 deletions(-) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 7173bed80..4169d439a 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -17,8 +17,8 @@ end function should_hide_armok(cmdline) local command = get_command(cmdline) return dfhack.getHideArmokTools() and - helpdb.is_entry(command) and - helpdb.get_entry_tags(command).armok + helpdb.is_entry(command) and + helpdb.get_entry_tags(command).armok end -- ----------------- -- @@ -26,11 +26,11 @@ end -- ----------------- -- HotspotMenuWidget = defclass(HotspotMenuWidget, overlay.OverlayWidget) -HotspotMenuWidget.ATTRS{ - default_pos={x=5,y=1}, - default_enabled=true, - version=2, - viewscreens={ +HotspotMenuWidget.ATTRS { + default_pos = { x = 5, y = 1 }, + default_enabled = true, + version = 2, + viewscreens = { 'adopt_region', 'choose_game_type', -- 'choose_start_site', -- conflicts with vanilla panel layouts @@ -48,51 +48,51 @@ HotspotMenuWidget.ATTRS{ 'update_region', 'world' }, - frame={w=4, h=3} + frame = { w = 4, h = 3 } } function HotspotMenuWidget:init() local to_pen = dfhack.pen.parse local function tp(idx, ch) - return to_pen{ - tile=function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end, - ch=ch, - fg=COLOR_GREY, + return to_pen { + tile = function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end, + ch = ch, + fg = COLOR_GREY, } end local function tph(idx, ch) - return to_pen{ - tile=function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, - ch=ch, - fg=COLOR_WHITE, + return to_pen { + tile = function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, + ch = ch, + fg = COLOR_WHITE, } end local function get_tile_token(idx, ch) return { - tile=tp(idx, ch), - htile=tph(idx, ch), - width=1, + tile = tp(idx, ch), + htile = tph(idx, ch), + width = 1, } end - self:addviews{ - widgets.Label{ - text={ + self:addviews { + widgets.Label { + text = { get_tile_token(1, '!'), get_tile_token(2, 'D'), get_tile_token(3, 'F'), get_tile_token(4, '!'), NEWLINE, get_tile_token(5, '!'), get_tile_token(6, 'H'), get_tile_token(7, 'a'), get_tile_token(8, '!'), NEWLINE, get_tile_token(9, '!'), get_tile_token(10, 'c'), get_tile_token(11, 'k'), get_tile_token(12, '!'), }, - on_click=function() dfhack.run_command('hotkeys') end, + on_click = function() dfhack.run_command('hotkeys') end, }, } end function HotspotMenuWidget:overlay_trigger() - return MenuScreen{hotspot=self}:show() + return MenuScreen { hotspot = self }:show() end -- register the menu hotspot with the overlay -OVERLAY_WIDGETS = {menu=HotspotMenuWidget} +OVERLAY_WIDGETS = { menu = HotspotMenuWidget } -- ---- -- -- Menu -- @@ -103,15 +103,15 @@ local MAX_LIST_WIDTH = 45 local MAX_LIST_HEIGHT = 15 Menu = defclass(Menu, widgets.Panel) -Menu.ATTRS{ - hotspot=DEFAULT_NIL, +Menu.ATTRS { + hotspot = DEFAULT_NIL, } -- get a map from the binding string to a list of hotkey strings that all -- point to that binding local function get_bindings_to_hotkeys(hotkeys, bindings) local bindings_to_hotkeys = {} - for _,hotkey in ipairs(hotkeys) do + for _, hotkey in ipairs(hotkeys) do local binding = bindings[hotkey] table.insert(ensure_key(bindings_to_hotkeys, binding), hotkey) end @@ -126,17 +126,17 @@ local function get_choices(hotkeys, bindings, is_inverted) local bindings_to_hotkeys = get_bindings_to_hotkeys(hotkeys, bindings) -- build list choices - for _,hotkey in ipairs(hotkeys) do + for _, hotkey in ipairs(hotkeys) do local command = bindings[hotkey] if seen[command] then goto continue end seen[command] = true local hk_width, tokens = 0, {} - for _,hk in ipairs(bindings_to_hotkeys[command]) do + for _, hk in ipairs(bindings_to_hotkeys[command]) do if hk_width ~= 0 then table.insert(tokens, ', ') hk_width = hk_width + 2 end - table.insert(tokens, {text=hk, pen=COLOR_LIGHTGREEN}) + table.insert(tokens, { text = hk, pen = COLOR_LIGHTGREEN }) hk_width = hk_width + #hk end local command_str = command @@ -144,16 +144,20 @@ local function get_choices(hotkeys, bindings, is_inverted) local max_command_len = MAX_LIST_WIDTH - hk_width - LIST_BUFFER command_str = command:sub(1, max_command_len - 3) .. '...' end - table.insert(tokens, 1, {text=command_str}) - local choice = {icon=ARROW, command=command, text=tokens, - hk_width=hk_width} + table.insert(tokens, 1, { text = command_str }) + local choice = { + icon = ARROW, + command = command, + text = tokens, + hk_width = hk_width + } max_width = math.max(max_width, hk_width + #command_str + LIST_BUFFER) table.insert(choices, is_inverted and 1 or #choices + 1, choice) ::continue:: end -- adjust width of command fields so the hotkey tokens are right justified - for _,choice in ipairs(choices) do + for _, choice in ipairs(choices) do local command_token = choice.text[1] command_token.width = max_width - choice.hk_width - (LIST_BUFFER - 1) end @@ -164,17 +168,17 @@ end function Menu:init() local hotkeys, bindings = getHotkeys() if #hotkeys == 0 then - hotkeys = {''} - bindings = {['']='gui/launcher'} + hotkeys = { '' } + bindings = { [''] = 'gui/launcher' } end local is_inverted = not not self.hotspot.frame.b - local choices,list_width = get_choices(hotkeys, bindings, is_inverted) + local choices, list_width = get_choices(hotkeys, bindings, is_inverted) list_width = math.max(35, list_width) local list_frame = copyall(self.hotspot.frame) - local list_widget_frame = {h=math.min(#choices, MAX_LIST_HEIGHT)} + local list_widget_frame = { h = math.min(#choices, MAX_LIST_HEIGHT) } local quickstart_frame = {} list_frame.w = list_width + 2 list_frame.h = list_widget_frame.h + 4 @@ -193,51 +197,51 @@ function Menu:init() list_frame.r = math.max(0, list_frame.r + 5) end - local help_frame = {w=list_frame.w, l=list_frame.l, r=list_frame.r} + local help_frame = { w = list_frame.w, l = list_frame.l, r = list_frame.r } if list_frame.t then help_frame.t = list_frame.t + list_frame.h else help_frame.b = list_frame.b + list_frame.h end - self:addviews{ - widgets.Panel{ - view_id='list_panel', - frame=list_frame, - frame_style=gui.PANEL_FRAME, - frame_background=gui.CLEAR_PEN, - subviews={ - widgets.List{ - view_id='list', - frame=list_widget_frame, - choices=choices, - icon_width=2, - on_select=self:callback('onSelect'), - on_submit=self:callback('onSubmit'), - on_submit2=self:callback('onSubmit2'), + self:addviews { + widgets.Panel { + view_id = 'list_panel', + frame = list_frame, + frame_style = gui.PANEL_FRAME, + frame_background = gui.CLEAR_PEN, + subviews = { + widgets.List { + view_id = 'list', + frame = list_widget_frame, + choices = choices, + icon_width = 2, + on_select = self:callback('onSelect'), + on_submit = self:callback('onSubmit'), + on_submit2 = self:callback('onSubmit2'), }, - widgets.Panel{frame={h=1}}, - widgets.HotkeyLabel{ - frame=quickstart_frame, - label='Quickstart guide', - key='STRING_A063', - on_activate=function() - self:onSubmit(nil, {command='quickstart-guide'}) + widgets.Panel { frame = { h = 1 } }, + widgets.HotkeyLabel { + frame = quickstart_frame, + label = 'Quickstart guide', + key = 'STRING_A063', + on_activate = function() + self:onSubmit(nil, { command = 'quickstart-guide' }) end, }, }, }, - widgets.ResizingPanel{ - view_id='help_panel', - autoarrange_subviews=true, - frame=help_frame, - frame_style=gui.PANEL_FRAME, - frame_background=gui.CLEAR_PEN, - subviews={ - widgets.WrappedLabel{ - view_id='help', - text_to_wrap='', - scroll_keys={}, + widgets.ResizingPanel { + view_id = 'help_panel', + autoarrange_subviews = true, + frame = help_frame, + frame_style = gui.PANEL_FRAME, + frame_background = gui.CLEAR_PEN, + subviews = { + widgets.WrappedLabel { + view_id = 'help', + text_to_wrap = '', + scroll_keys = {}, }, }, }, @@ -252,7 +256,7 @@ function Menu:onSelect(_, choice) if not choice or #self.subviews == 0 then return end 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' + helpdb.get_entry_short_help(command) or 'Command not found' self.subviews.help_panel:updateLayout() end @@ -302,7 +306,7 @@ end function Menu:getMouseFramePos() return self.subviews.list_panel:getMouseFramePos() or - self.subviews.help_panel:getMouseFramePos() + self.subviews.help_panel:getMouseFramePos() end function Menu:onRenderBody(dc) @@ -324,14 +328,14 @@ end MenuScreen = defclass(MenuScreen, gui.ZScreen) MenuScreen.ATTRS { - focus_path='hotkeys/menu', - initial_pause=false, - hotspot=DEFAULT_NIL, + focus_path = 'hotkeys/menu', + initial_pause = false, + hotspot = DEFAULT_NIL, } function MenuScreen:init() - self:addviews{ - Menu{hotspot=self.hotspot}, + self:addviews { + Menu { hotspot = self.hotspot }, } end @@ -339,4 +343,4 @@ function MenuScreen:onDismiss() cleanupHotkeys() end -return _ENV \ No newline at end of file +return _ENV From be26449ef77fe8538c793762d34510df0207798f Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Sun, 24 Sep 2023 13:22:20 +0300 Subject: [PATCH 595/851] ugh --- plugins/lua/hotkeys.lua | 164 ++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 84 deletions(-) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 4169d439a..8eff17aae 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -17,8 +17,8 @@ end function should_hide_armok(cmdline) local command = get_command(cmdline) return dfhack.getHideArmokTools() and - helpdb.is_entry(command) and - helpdb.get_entry_tags(command).armok + helpdb.is_entry(command) and + helpdb.get_entry_tags(command).armok end -- ----------------- -- @@ -26,11 +26,11 @@ end -- ----------------- -- HotspotMenuWidget = defclass(HotspotMenuWidget, overlay.OverlayWidget) -HotspotMenuWidget.ATTRS { - default_pos = { x = 5, y = 1 }, - default_enabled = true, - version = 2, - viewscreens = { +HotspotMenuWidget.ATTRS{ + default_pos={x=5,y=1}, + default_enabled=true, + version=2, + viewscreens={ 'adopt_region', 'choose_game_type', -- 'choose_start_site', -- conflicts with vanilla panel layouts @@ -48,51 +48,51 @@ HotspotMenuWidget.ATTRS { 'update_region', 'world' }, - frame = { w = 4, h = 3 } + frame={w=4, h=3} } function HotspotMenuWidget:init() local to_pen = dfhack.pen.parse local function tp(idx, ch) - return to_pen { - tile = function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end, - ch = ch, - fg = COLOR_GREY, + return to_pen{ + tile=function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end, + ch=ch, + fg=COLOR_GREY, } end local function tph(idx, ch) - return to_pen { - tile = function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, - ch = ch, - fg = COLOR_WHITE, + return to_pen{ + tile=function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, + ch=ch, + fg=COLOR_WHITE, } end local function get_tile_token(idx, ch) return { - tile = tp(idx, ch), - htile = tph(idx, ch), - width = 1, + tile=tp(idx, ch), + htile=tph(idx, ch), + width=1, } end - self:addviews { - widgets.Label { - text = { + self:addviews{ + widgets.Label{ + text={ get_tile_token(1, '!'), get_tile_token(2, 'D'), get_tile_token(3, 'F'), get_tile_token(4, '!'), NEWLINE, get_tile_token(5, '!'), get_tile_token(6, 'H'), get_tile_token(7, 'a'), get_tile_token(8, '!'), NEWLINE, get_tile_token(9, '!'), get_tile_token(10, 'c'), get_tile_token(11, 'k'), get_tile_token(12, '!'), }, - on_click = function() dfhack.run_command('hotkeys') end, + on_click=function() dfhack.run_command('hotkeys') end, }, } end function HotspotMenuWidget:overlay_trigger() - return MenuScreen { hotspot = self }:show() + return MenuScreen{hotspot=self}:show() end -- register the menu hotspot with the overlay -OVERLAY_WIDGETS = { menu = HotspotMenuWidget } +OVERLAY_WIDGETS = {menu=HotspotMenuWidget} -- ---- -- -- Menu -- @@ -103,15 +103,15 @@ local MAX_LIST_WIDTH = 45 local MAX_LIST_HEIGHT = 15 Menu = defclass(Menu, widgets.Panel) -Menu.ATTRS { - hotspot = DEFAULT_NIL, +Menu.ATTRS{ + hotspot=DEFAULT_NIL, } -- get a map from the binding string to a list of hotkey strings that all -- point to that binding local function get_bindings_to_hotkeys(hotkeys, bindings) local bindings_to_hotkeys = {} - for _, hotkey in ipairs(hotkeys) do + for _,hotkey in ipairs(hotkeys) do local binding = bindings[hotkey] table.insert(ensure_key(bindings_to_hotkeys, binding), hotkey) end @@ -126,17 +126,17 @@ local function get_choices(hotkeys, bindings, is_inverted) local bindings_to_hotkeys = get_bindings_to_hotkeys(hotkeys, bindings) -- build list choices - for _, hotkey in ipairs(hotkeys) do + for _,hotkey in ipairs(hotkeys) do local command = bindings[hotkey] if seen[command] then goto continue end seen[command] = true local hk_width, tokens = 0, {} - for _, hk in ipairs(bindings_to_hotkeys[command]) do + for _,hk in ipairs(bindings_to_hotkeys[command]) do if hk_width ~= 0 then table.insert(tokens, ', ') hk_width = hk_width + 2 end - table.insert(tokens, { text = hk, pen = COLOR_LIGHTGREEN }) + table.insert(tokens, {text=hk, pen=COLOR_LIGHTGREEN}) hk_width = hk_width + #hk end local command_str = command @@ -144,20 +144,16 @@ local function get_choices(hotkeys, bindings, is_inverted) local max_command_len = MAX_LIST_WIDTH - hk_width - LIST_BUFFER command_str = command:sub(1, max_command_len - 3) .. '...' end - table.insert(tokens, 1, { text = command_str }) - local choice = { - icon = ARROW, - command = command, - text = tokens, - hk_width = hk_width - } + table.insert(tokens, 1, {text=command_str}) + local choice = {icon=ARROW, command=command, text=tokens, + hk_width=hk_width} max_width = math.max(max_width, hk_width + #command_str + LIST_BUFFER) table.insert(choices, is_inverted and 1 or #choices + 1, choice) ::continue:: end -- adjust width of command fields so the hotkey tokens are right justified - for _, choice in ipairs(choices) do + for _,choice in ipairs(choices) do local command_token = choice.text[1] command_token.width = max_width - choice.hk_width - (LIST_BUFFER - 1) end @@ -168,17 +164,17 @@ end function Menu:init() local hotkeys, bindings = getHotkeys() if #hotkeys == 0 then - hotkeys = { '' } - bindings = { [''] = 'gui/launcher' } + hotkeys = {''} + bindings = {['']='gui/launcher'} end local is_inverted = not not self.hotspot.frame.b - local choices, list_width = get_choices(hotkeys, bindings, is_inverted) + local choices,list_width = get_choices(hotkeys, bindings, is_inverted) list_width = math.max(35, list_width) local list_frame = copyall(self.hotspot.frame) - local list_widget_frame = { h = math.min(#choices, MAX_LIST_HEIGHT) } + local list_widget_frame = {h=math.min(#choices, MAX_LIST_HEIGHT)} local quickstart_frame = {} list_frame.w = list_width + 2 list_frame.h = list_widget_frame.h + 4 @@ -197,51 +193,51 @@ function Menu:init() list_frame.r = math.max(0, list_frame.r + 5) end - local help_frame = { w = list_frame.w, l = list_frame.l, r = list_frame.r } + local help_frame = {w=list_frame.w, l=list_frame.l, r=list_frame.r} if list_frame.t then help_frame.t = list_frame.t + list_frame.h else help_frame.b = list_frame.b + list_frame.h end - self:addviews { - widgets.Panel { - view_id = 'list_panel', - frame = list_frame, - frame_style = gui.PANEL_FRAME, - frame_background = gui.CLEAR_PEN, - subviews = { - widgets.List { - view_id = 'list', - frame = list_widget_frame, - choices = choices, - icon_width = 2, - on_select = self:callback('onSelect'), - on_submit = self:callback('onSubmit'), - on_submit2 = self:callback('onSubmit2'), + self:addviews{ + widgets.Panel{ + view_id='list_panel', + frame=list_frame, + frame_style=gui.PANEL_FRAME, + frame_background=gui.CLEAR_PEN, + subviews={ + widgets.List{ + view_id='list', + frame=list_widget_frame, + choices=choices, + icon_width=2, + on_select=self:callback('onSelect'), + on_submit=self:callback('onSubmit'), + on_submit2=self:callback('onSubmit2'), }, - widgets.Panel { frame = { h = 1 } }, - widgets.HotkeyLabel { - frame = quickstart_frame, - label = 'Quickstart guide', - key = 'STRING_A063', - on_activate = function() - self:onSubmit(nil, { command = 'quickstart-guide' }) + widgets.Panel{frame={h=1}}, + widgets.HotkeyLabel{ + frame=quickstart_frame, + label='Quickstart guide', + key='STRING_A063', + on_activate=function() + self:onSubmit(nil, {command='quickstart-guide'}) end, }, }, }, - widgets.ResizingPanel { - view_id = 'help_panel', - autoarrange_subviews = true, - frame = help_frame, - frame_style = gui.PANEL_FRAME, - frame_background = gui.CLEAR_PEN, - subviews = { - widgets.WrappedLabel { - view_id = 'help', - text_to_wrap = '', - scroll_keys = {}, + widgets.ResizingPanel{ + view_id='help_panel', + autoarrange_subviews=true, + frame=help_frame, + frame_style=gui.PANEL_FRAME, + frame_background=gui.CLEAR_PEN, + subviews={ + widgets.WrappedLabel{ + view_id='help', + text_to_wrap='', + scroll_keys={}, }, }, }, @@ -256,7 +252,7 @@ function Menu:onSelect(_, choice) if not choice or #self.subviews == 0 then return end 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' + helpdb.get_entry_short_help(command) or 'Command not found' self.subviews.help_panel:updateLayout() end @@ -306,7 +302,7 @@ end function Menu:getMouseFramePos() return self.subviews.list_panel:getMouseFramePos() or - self.subviews.help_panel:getMouseFramePos() + self.subviews.help_panel:getMouseFramePos() end function Menu:onRenderBody(dc) @@ -328,14 +324,14 @@ end MenuScreen = defclass(MenuScreen, gui.ZScreen) MenuScreen.ATTRS { - focus_path = 'hotkeys/menu', - initial_pause = false, - hotspot = DEFAULT_NIL, + focus_path='hotkeys/menu', + initial_pause=false, + hotspot=DEFAULT_NIL, } function MenuScreen:init() - self:addviews { - Menu { hotspot = self.hotspot }, + self:addviews{ + Menu{hotspot=self.hotspot}, } end From b22ca57f50d6c3446af6e3cea5375305a3ea9065 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sun, 24 Sep 2023 12:15:46 +0100 Subject: [PATCH 596/851] added previous 'hidden' and 'no-auto' functionality as options, and adjusted how z-level options are specified --- docs/plugins/dig.rst | 25 +++++++++++++++++-------- plugins/dig.cpp | 21 +++++++++++++++------ 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index d6b6451a6..9cb3cc505 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -50,7 +50,7 @@ Usage Designate circles. The diameter is the number of tiles across the center of the circle that you want to dig. See the `digcircle`_ section below for options. -``digtype [] [-p] [-z]`` +``digtype [] [-p] [--zup|-u] [--zdown|-zu] [--cur-zlevel|-z] [--hidden|-h] [--no-auto|-a]`` Designate all vein tiles of the same type as the selected tile. See the `digtype`_ section below for options. ``digexp [] [] [-p]`` @@ -119,9 +119,11 @@ the last selected parameters. digtype ------- -For every tile on the map of the same vein type as the selected tile, this -command designates it to have the same designation as the selected tile. If the -selected tile has no designation, they will be dig designated. +For every tile on the map of the same vein type as the selected tile, this command +designates it to have the same designation as the selected tile. If the selected +tile has no designation, they will be dig designated. By default, only designates +visible tiles, and in the case of dig designation, applies automatic mining to them +(designates uncovered neighbouring tiles of the same type to be dug). If an argument is given, the designation of the selected tile is ignored, and all appropriate tiles are set to the specified designation. @@ -143,10 +145,17 @@ Designation options: ``clear`` Clear any designations. -You can also pass a ``-z`` and/or a ``+z``` option, which restricts designations to the -current z-level and down/up. This is useful when you don't want to designate tiles on the -same z-levels as your carefully dug fort above/below. To dig only at the current z-level, -pass in both. +Other options: +``--zdown`` or ``-d`` + Only designates tiles on the cursor's z-level and below +``--zup`` or ``-u`` + Only designates tiles on the cursor's z-level and above +``--cur-zlevel`` or ``-z`` + Only designates tiles on the same z-level as the cursor +``--hidden`` or ``-h`` + Allows designation of hidden tiles, and using a hidden tile as the "palette" +``--no-auto`` or ``-a`` + No automatic mining mode designation - useful if you want to avoid dwarves digging where you don't want them digexp ------ diff --git a/plugins/dig.cpp b/plugins/dig.cpp index 1379bc3db..836f48e9d 100644 --- a/plugins/dig.cpp +++ b/plugins/dig.cpp @@ -1425,6 +1425,9 @@ command_result digtype (color_ostream &out, vector & parameters) Maps::getSize(xMax,yMax,zMax); uint32_t zMin = 0; + + bool hidden = false; + bool automine = true; int32_t targetDigType = -1; for (string parameter : parameters) { @@ -1442,10 +1445,16 @@ command_result digtype (color_ostream &out, vector & parameters) targetDigType = tile_dig_designation::DownStair; else if ( parameter == "up" ) targetDigType = tile_dig_designation::UpStair; - else if ( parameter == "-z" ) + else if ( parameter == "-z" || parameter == "--cur-zlevel" ) + {zMax = *window_z + 1; zMin = *window_z;} + else if ( parameter == "--zdown" || parameter == "-d") zMax = *window_z + 1; - else if ( parameter == "+z") + else if ( parameter == "--zup" || parameter == "-u") zMin = *window_z; + else if ( parameter == "--hidden" || parameter == "-h") + hidden = true; + else if ( parameter == "--no-auto" || parameter == "-a" ) + automine = false; else { out.printerr("Invalid parameter: '%s'.\n", parameter.c_str()); @@ -1466,8 +1475,8 @@ command_result digtype (color_ostream &out, vector & parameters) std::unique_ptr mCache = std::make_unique(); df::tile_designation baseDes = mCache->designationAt(xy); - if (baseDes.bits.hidden) { - out.printerr("Cursor is pointing at a hidden tile. Point the cursor at a visible tile"); + if (baseDes.bits.hidden && !hidden) { + out.printerr("Cursor is pointing at a hidden tile. Point the cursor at a visible tile when using the --hidden option.\n"); return CR_FAILURE; } @@ -1495,7 +1504,7 @@ command_result digtype (color_ostream &out, vector & parameters) } // Auto dig only works on default dig designation. Setting dig_auto for any other designation // prevents dwarves from digging that tile at all. - if (baseDes.bits.dig == tile_dig_designation::Default) baseOcc.bits.dig_auto = true; + if (baseDes.bits.dig == tile_dig_designation::Default && automine) baseOcc.bits.dig_auto = true; else baseOcc.bits.dig_auto = false; for( uint32_t z = zMin; z < zMax; z++ ) @@ -1523,7 +1532,7 @@ command_result digtype (color_ostream &out, vector & parameters) df::tile_designation designation = mCache->designationAt(current); - if (designation.bits.hidden) continue; + if (designation.bits.hidden && !hidden) continue; df::tile_occupancy occupancy = mCache->occupancyAt(current); designation.bits.dig = baseDes.bits.dig; From ff03fc1f2d085e981b52a89c1f552649584e3c2b Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sun, 24 Sep 2023 12:17:50 +0100 Subject: [PATCH 597/851] trailing whitespace removed --- plugins/dig.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/dig.cpp b/plugins/dig.cpp index 836f48e9d..7be7b815f 100644 --- a/plugins/dig.cpp +++ b/plugins/dig.cpp @@ -1421,11 +1421,10 @@ command_result digtype (color_ostream &out, vector & parameters) return CR_FAILURE; } + uint32_t zMin = 0; uint32_t xMax,yMax,zMax; Maps::getSize(xMax,yMax,zMax); - uint32_t zMin = 0; - bool hidden = false; bool automine = true; From dff9edb26bc3affa85a0835ff6c117a2e65264e5 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sun, 24 Sep 2023 12:20:55 +0100 Subject: [PATCH 598/851] dig doc unexpected indentation fixed --- docs/plugins/dig.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index 9cb3cc505..91951434e 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -147,15 +147,15 @@ Designation options: Other options: ``--zdown`` or ``-d`` - Only designates tiles on the cursor's z-level and below + Only designates tiles on the cursor's z-level and below. ``--zup`` or ``-u`` - Only designates tiles on the cursor's z-level and above + Only designates tiles on the cursor's z-level and above. ``--cur-zlevel`` or ``-z`` - Only designates tiles on the same z-level as the cursor + Only designates tiles on the same z-level as the cursor. ``--hidden`` or ``-h`` - Allows designation of hidden tiles, and using a hidden tile as the "palette" + Allows designation of hidden tiles, and using a hidden tile as the "palette". ``--no-auto`` or ``-a`` - No automatic mining mode designation - useful if you want to avoid dwarves digging where you don't want them + No automatic mining mode designation - useful if you want to avoid dwarves digging where you don't want them. digexp ------ From 15ede64d9b0f3d614c5176596452d9c693e7d21d Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sun, 24 Sep 2023 12:23:25 +0100 Subject: [PATCH 599/851] dig doc unexpected indentation actually fixed --- docs/plugins/dig.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index 91951434e..dd69a5f04 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -146,15 +146,15 @@ Designation options: Clear any designations. Other options: -``--zdown`` or ``-d`` +``--zdown``, ``-d`` Only designates tiles on the cursor's z-level and below. -``--zup`` or ``-u`` +``--zup``, ``-u`` Only designates tiles on the cursor's z-level and above. -``--cur-zlevel`` or ``-z`` +``--cur-zlevel``, ``-z`` Only designates tiles on the same z-level as the cursor. -``--hidden`` or ``-h`` +``--hidden``, ``-h`` Allows designation of hidden tiles, and using a hidden tile as the "palette". -``--no-auto`` or ``-a`` +``--no-auto``, ``-a`` No automatic mining mode designation - useful if you want to avoid dwarves digging where you don't want them. digexp From 437f96f3c03e7cecab8732f203a9c3e72d839aeb Mon Sep 17 00:00:00 2001 From: donhth <> Date: Sun, 24 Sep 2023 07:30:31 -0400 Subject: [PATCH 600/851] add changelog entry, remove unavailable tag for tubefill --- docs/changelog.txt | 2 ++ docs/plugins/tubefill.rst | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 044cb1ca4..eb54766f2 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -53,6 +53,8 @@ Template for new versions: ## New Tools +- `tubefill`: (reinstated) replenishes mined-out adamantine + ## New Features ## Fixes diff --git a/docs/plugins/tubefill.rst b/docs/plugins/tubefill.rst index a8684c765..80282f6d9 100644 --- a/docs/plugins/tubefill.rst +++ b/docs/plugins/tubefill.rst @@ -3,7 +3,7 @@ tubefill .. dfhack-tool:: :summary: Replenishes mined-out adamantine. - :tags: unavailable fort armok map + :tags: fort armok map Veins that were originally hollow will be left alone. From 26dd4e1f787ff80cad1345bc8d1430d18bed1b03 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sun, 24 Sep 2023 12:30:32 +0100 Subject: [PATCH 601/851] dig doc unexpected indentation actually fixed fr this time --- docs/plugins/dig.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index dd69a5f04..b098d5ac1 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -146,6 +146,7 @@ Designation options: Clear any designations. Other options: + ``--zdown``, ``-d`` Only designates tiles on the cursor's z-level and below. ``--zup``, ``-u`` From 7d9dad4688df1639f3ecfc8e6c23d9d77bf06e4c Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sun, 24 Sep 2023 20:51:30 +0100 Subject: [PATCH 602/851] dig - doc rewording and added change to changelog --- docs/changelog.txt | 1 + docs/plugins/dig.rst | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 044cb1ca4..74522451d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,6 +58,7 @@ Template for new versions: ## Fixes ## Misc Improvements +- `dig`: `digtype` command now has options to choose between designating only visible tiles or hidden tiles, as well as "auto" dig mode. Z-level options adjusted to allow choosing z-levels above, below, or the same as the cursor. ## Documentation diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index b098d5ac1..8d5c99536 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -154,7 +154,7 @@ Other options: ``--cur-zlevel``, ``-z`` Only designates tiles on the same z-level as the cursor. ``--hidden``, ``-h`` - Allows designation of hidden tiles, and using a hidden tile as the "palette". + Allows designation of hidden tiles, and picking a hidden tile as the target type. ``--no-auto``, ``-a`` No automatic mining mode designation - useful if you want to avoid dwarves digging where you don't want them. From d7d142c61604ffb070269d4fc7bf167c8989eecc Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sun, 24 Sep 2023 21:13:04 +0100 Subject: [PATCH 603/851] Authors.rst master-spike added --- docs/about/Authors.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/about/Authors.rst b/docs/about/Authors.rst index e81649d8d..27b896f89 100644 --- a/docs/about/Authors.rst +++ b/docs/about/Authors.rst @@ -139,6 +139,7 @@ moversti moversti mrrho mrrho Murad Beybalaev Erquint Myk Taylor myk002 +Najeeb Al-Shabibi master-spike napagokc napagokc Neil Little nmlittle Nick Rart nickrart comestible From 0559af9f1343d5c5be04c03ed26770406f60b6e8 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sun, 24 Sep 2023 19:10:46 -0500 Subject: [PATCH 604/851] autolabor: fix #3812 make sure autolabor resets the work detail bypass flag whenever autolabor is unloaded for _any_ reason i tested `disable autolabor`, `unload autolabor`, and unloading a fort with autolabor enabled; in all cases the work detail bypass flag was cleared as desired closes #3812 --- docs/changelog.txt | 1 + plugins/autolabor/autolabor.cpp | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 74522451d..638c01459 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -56,6 +56,7 @@ Template for new versions: ## New Features ## Fixes +- `autolabor`: now unconditionally clears ``game.external_flag`` when unloading a fort or the plugin ## Misc Improvements - `dig`: `digtype` command now has options to choose between designating only visible tiles or hidden tiles, as well as "auto" dig mode. Z-level options adjusted to allow choosing z-levels above, below, or the same as the cursor. diff --git a/plugins/autolabor/autolabor.cpp b/plugins/autolabor/autolabor.cpp index 72bb4d84e..8be035214 100644 --- a/plugins/autolabor/autolabor.cpp +++ b/plugins/autolabor/autolabor.cpp @@ -305,6 +305,7 @@ static void cleanup_state() { enable_autolabor = false; labor_infos.clear(); + game->external_flag &= ~1; // reinstate DF's work detail system } static void reset_labor(df::unit_labor labor) @@ -326,6 +327,8 @@ static void init_state() if (!enable_autolabor) return; + game->external_flag |= 1; // bypass DF's work detail system + auto cfg_haulpct = World::GetPersistentData("autolabor/haulpct"); if (cfg_haulpct.isValid()) { @@ -413,8 +416,17 @@ static void enable_plugin(color_ostream &out) cleanup_state(); init_state(); +} + +static void disable_plugin(color_ostream& out) +{ + if (config.isValid()) + setOptionEnabled(CF_ENABLED, false); - game->external_flag |= 1; // shut down DF's work detail system + enable_autolabor = false; + out << "Disabling autolabor." << std::endl; + + cleanup_state(); } DFhackCExport command_result plugin_init ( color_ostream &out, std::vector &commands) @@ -1081,12 +1093,7 @@ DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable ) } else if(!enable && enable_autolabor) { - enable_autolabor = false; - setOptionEnabled(CF_ENABLED, false); - - game->external_flag &= ~1; // reenable DF's work detail system - - out << "Autolabor is disabled." << std::endl; + disable_plugin(out); } return CR_OK; From a721fee8cdf25606ee0b15be1fc184dd1c118533 Mon Sep 17 00:00:00 2001 From: Myk Date: Sun, 24 Sep 2023 17:21:28 -0700 Subject: [PATCH 605/851] Update docs/changelog.txt --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 638c01459..9efb86430 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -56,7 +56,7 @@ Template for new versions: ## New Features ## Fixes -- `autolabor`: now unconditionally clears ``game.external_flag`` when unloading a fort or the plugin +- `autolabor`: now unconditionally re-enables vanilla work details when the fort or the plugin is unloaded ## Misc Improvements - `dig`: `digtype` command now has options to choose between designating only visible tiles or hidden tiles, as well as "auto" dig mode. Z-level options adjusted to allow choosing z-levels above, below, or the same as the cursor. From 33cc0c5d0f975d039d6e497335306c9e80b7e471 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sun, 24 Sep 2023 19:36:46 -0500 Subject: [PATCH 606/851] spectate: remove unavailable tag --- docs/plugins/spectate.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/spectate.rst b/docs/plugins/spectate.rst index 95ce852ae..f54d68142 100644 --- a/docs/plugins/spectate.rst +++ b/docs/plugins/spectate.rst @@ -3,7 +3,7 @@ spectate .. dfhack-tool:: :summary: Automatically follow productive dwarves. - :tags: unavailable fort interface + :tags: fort interface Usage ----- From 7e21d384ab4002d4dcf85c85e807ffb3daf42c09 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 25 Sep 2023 07:13:23 +0000 Subject: [PATCH 607/851] 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 041493b22..e6d83ccae 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 041493b221e0799c106abeac1f86df4535ab80d3 +Subproject commit e6d83ccaee5b5a3c663b56046ae55a7389742da8 diff --git a/scripts b/scripts index e0591830b..0ed4052ac 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit e0591830b72cdfaec5c9bdb1bf713a74fe744788 +Subproject commit 0ed4052ac9049151657e22831996800d0d3104bb From fd31d9eb03a51d6d8382b3212eeb7c5ed6f42adf Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 15:07:05 -0700 Subject: [PATCH 608/851] enable fortress mode tests in CI --- ci/test.lua | 56 ++++++++++++++++++++++++++++++----------- test/plugins/orders.lua | 2 +- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index ac0e5718d..807572a70 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -189,39 +189,67 @@ local function ensure_title_screen() dfhack.gui.getCurFocus(true)[1])) end -local function is_fortress(focus_string) - focus_string = focus_string or dfhack.gui.getCurFocus(true) - return focus_string == 'dwarfmode/Default' +local function is_fortress() + return dfhack.gui.matchFocusString('dwarfmode/Default') +end + +local function click_top_title_button(scr) + local sw, sh = dfhack.screen.getWindowSize() + df.global.gps.mouse_x = sw // 2 + df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x + if sh < 60 then + df.global.gps.mouse_y = 23 + else + df.global.gps.mouse_y = (sh // 2) + 1 + end + df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y + df.global.enabler.tracking_on = 1 + df.global.enabler.mouse_lbut = 1 + df.global.enabler.mouse_lbut_down = 1 + dfhack.screen._doSimulateInput(scr, {}) +end + +local function load_first_save(scr) + if #scr.savegame_header == 0 then + qerror('no savegames available to load') + end + scr.mode = 2 + click_top_title_button(scr) + delay() + click_top_title_button(scr) + delay() end -- Requires that a fortress game is already loaded or is ready to be loaded via --- the "Continue Playing" option in the title screen. Otherwise the function +-- the "Continue active game" option in the title screen. Otherwise the function -- will time out and/or exit with error. local function ensure_fortress(config) - local focus_string = dfhack.gui.getCurFocus(true) for screen_timeout = 1,10 do - if is_fortress(focus_string) then + if is_fortress() then print('Loaded fortress map') -- pause the game (if it's not already paused) dfhack.gui.resetDwarfmodeView(true) return end - local scr = dfhack.gui.getCurViewscreen(true) - if focus_string == 'title' or - focus_string == 'dfhack/lua/load_screen' then + local scr = dfhack.gui.getDFViewscreen(true) + if dfhack.gui.matchFocusString('title') then + -- TODO: reinstate loading of a specified save dir; for now + -- just load the first possible save, which will at least let us + -- run fortress tests in CI -- qerror()'s on falure - dfhack.run_script('load-save', config.save_dir) - elseif focus_string ~= 'loadgame' then + -- dfhack.run_script('load-save', config.save_dir) + load_first_save(scr) + elseif dfhack.gui.matchFocusString('loadgame') then -- if we're not actively loading a game, hope we're in -- a screen where hitting ESC will get us to the game map -- or the title screen scr:feed_key(df.interface_key.LEAVESCREEN) end -- wait for current screen to change - local prev_focus_string = focus_string + local prev_focus_string = dfhack.gui.getCurFocus(true)[1] for frame_timeout = 1,100 do delay(10) - focus_string = dfhack.gui.getCurFocus(true) + local focus_string = dfhack.gui.getCurFocus(true)[1] if focus_string ~= prev_focus_string then goto next_screen end @@ -236,7 +264,7 @@ local function ensure_fortress(config) ::next_screen:: end qerror(string.format('Could not load fortress (timed out at %s)', - focus_string)) + table.concat(dfhack.gui.getCurFocus(), ' '))) end local MODES = { diff --git a/test/plugins/orders.lua b/test/plugins/orders.lua index c5fae8eb2..d851adb02 100644 --- a/test/plugins/orders.lua +++ b/test/plugins/orders.lua @@ -1,5 +1,5 @@ config.mode = 'fortress' ---config.target = 'orders' +config.target = 'orders' local FILE_PATH_PATTERN = 'dfhack-config/orders/%s.json' From b9a6d39b60027ddbe6efc37542b13a7227ed9f37 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 16:00:19 -0700 Subject: [PATCH 609/851] enable testing on Linux --- .github/workflows/test.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 40b30cd13..e0576dbf7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -67,15 +67,14 @@ jobs: compiler: msvc plugins: "default" config: "empty" - # TODO: uncomment once we have a linux build we can download from bay12 - # - os: ubuntu - # compiler: gcc-10 - # plugins: "default" - # config: "default" - # - os: ubuntu - # compiler: gcc-12 - # plugins: "all" - # config: "default" + - os: ubuntu + compiler: gcc-10 + plugins: "default" + config: "default" + - os: ubuntu + compiler: gcc-12 + plugins: "all" + config: "default" steps: - name: Set env shell: bash From 621d36fd3a28074aeb53a9c36430308ad0a2a1da Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 16:16:21 -0700 Subject: [PATCH 610/851] tighen up screen matching --- ci/test.lua | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index 807572a70..5860ef5ea 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -175,6 +175,9 @@ local function ensure_title_screen() prev_ms = now_ms end end + if df.viewscreen_dwarfmodest:is_instance(dfhack.gui.getDFViewscreen(true)) then + qerror('Cannot reach title screen from loaded fort') + end for i = 1, 100 do local scr = dfhack.gui.getCurViewscreen() if is_title_screen(scr) then @@ -193,6 +196,18 @@ local function is_fortress() return dfhack.gui.matchFocusString('dwarfmode/Default') end +-- error out if we're not running in a CI environment +-- the tests may corrupt saves, and we don't want to unexpectedly ruin a real player save +-- this heuristic is not perfect, but it should be able to detect most cases +local function ensure_ci_save(scr) + if #scr.savegame_header ~= 1 + or #scr.savegame_header_world ~= 1 + or not string.find(scr.savegame_header[0].fort_name, 'Dream') + then + qerror('Unexpected test save in slot 0; please manually load a fort for testing. note that tests may corrupt the game!') + end +end + local function click_top_title_button(scr) local sw, sh = dfhack.screen.getWindowSize() df.global.gps.mouse_x = sw // 2 @@ -232,14 +247,15 @@ local function ensure_fortress(config) return end local scr = dfhack.gui.getDFViewscreen(true) - if dfhack.gui.matchFocusString('title') then + if dfhack.gui.matchFocusString('title/Default') then -- TODO: reinstate loading of a specified save dir; for now -- just load the first possible save, which will at least let us -- run fortress tests in CI -- qerror()'s on falure -- dfhack.run_script('load-save', config.save_dir) + ensure_ci_save(scr) load_first_save(scr) - elseif dfhack.gui.matchFocusString('loadgame') then + elseif not dfhack.gui.matchFocusString('loadgame') then -- if we're not actively loading a game, hope we're in -- a screen where hitting ESC will get us to the game map -- or the title screen From 4ffa78c96c336c900801fe0d1fd88a1dfbd0342a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 16:23:30 -0700 Subject: [PATCH 611/851] fix DF extraction on Linux --- ci/download-df.sh | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ci/download-df.sh b/ci/download-df.sh index 12e9a41e3..399b75714 100755 --- a/ci/download-df.sh +++ b/ci/download-df.sh @@ -18,7 +18,7 @@ elif test "$OS_TARGET" = "ubuntu"; then WGET=wget df_url="${df_url}_linux.tar.bz2" df_archive_name="df.tar.bz2" - df_extract_cmd="tar -x -j --strip-components=1 -f" + df_extract_cmd="tar -x -j -C ${DF_FOLDER} -f" else echo "Unhandled OS target: ${OS_TARGET}" exit 1 @@ -29,22 +29,25 @@ if ! $WGET -v "$df_url" -O "$df_archive_name"; then exit 1 fi +md5sum "$df_archive_name" + save_url="https://dffd.bay12games.com/download.php?id=15434&f=dreamfort.7z" save_archive_name="test_save.7z" -save_extract_cmd="7z x -oDF/save" +save_extract_cmd="7z x -o${DF_FOLDER}/save" if ! $WGET -v "$save_url" -O "$save_archive_name"; then echo "Failed to download test save from $save_url" exit 1 fi +md5sum "$save_archive_name" + echo Extracting +mkdir -p ${DF_FOLDER} $df_extract_cmd "$df_archive_name" $save_extract_cmd "$save_archive_name" -mv DF/save/* DF/save/region1 +mv ${DF_FOLDER}/save/* ${DF_FOLDER}/save/region1 echo Done ls -l - -md5sum "$df_archive_name" "$save_archive_name" From 92b35e32cb7330e10e8661181854110353a0cc44 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 17:01:06 -0700 Subject: [PATCH 612/851] wait for initial load when transitioning states --- ci/test.lua | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index 5860ef5ea..06dee5a75 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -151,18 +151,14 @@ end test_envvars.require = clean_require test_envvars.reqscript = clean_reqscript -local function is_title_screen(scr) - scr = scr or dfhack.gui.getCurViewscreen() - return df.viewscreen_titlest:is_instance(scr) +local function is_title_screen() + return dfhack.gui.matchFocusString('title/Default') end --- This only handles pre-fortress-load screens. It will time out if the player --- has already loaded a fortress or is in any screen that can't get to the title --- screen by sending ESC keys. -local function ensure_title_screen() +local function wait_for_game_load() local start_ms = dfhack.getTickCount() local prev_ms = start_ms - while df.viewscreen_initial_prepst:is_instance(dfhack.gui.getCurViewscreen()) do + while df.viewscreen_initial_prepst:is_instance(dfhack.gui.getDFViewscreen()) do delay(10) -- wait up to 1 minute for the game to load and show the title screen local now_ms = dfhack.getTickCount() @@ -175,12 +171,19 @@ local function ensure_title_screen() prev_ms = now_ms end end +end + +-- This only handles pre-fortress-load screens. It will time out if the player +-- has already loaded a fortress or is in any screen that can't get to the title +-- screen by sending ESC keys. +local function ensure_title_screen() + wait_for_game_load() if df.viewscreen_dwarfmodest:is_instance(dfhack.gui.getDFViewscreen(true)) then qerror('Cannot reach title screen from loaded fort') end for i = 1, 100 do local scr = dfhack.gui.getCurViewscreen() - if is_title_screen(scr) then + if is_title_screen() then print('Found title screen') return end @@ -239,15 +242,17 @@ end -- the "Continue active game" option in the title screen. Otherwise the function -- will time out and/or exit with error. local function ensure_fortress(config) + wait_for_game_load() for screen_timeout = 1,10 do if is_fortress() then - print('Loaded fortress map') + print('Fortress map is loaded') -- pause the game (if it's not already paused) dfhack.gui.resetDwarfmodeView(true) return end local scr = dfhack.gui.getDFViewscreen(true) if dfhack.gui.matchFocusString('title/Default') then + print('Attempting to load the test fortress') -- TODO: reinstate loading of a specified save dir; for now -- just load the first possible save, which will at least let us -- run fortress tests in CI From 8b3a3d4ebbbec670bffc712c1753d948cb28aad7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 17:05:08 -0700 Subject: [PATCH 613/851] reduce tries to one so we don't lose stdout other option: save stdout after every run and concatenate at the end --- ci/run-tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/run-tests.py b/ci/run-tests.py index 3d646a2f7..257359324 100755 --- a/ci/run-tests.py +++ b/ci/run-tests.py @@ -31,7 +31,7 @@ if args.test_dir is not None: if not os.path.isdir(args.test_dir): print('ERROR: invalid test folder: %r' % args.test_dir) -MAX_TRIES = 5 +MAX_TRIES = 1 dfhack = 'Dwarf Fortress.exe' if sys.platform == 'win32' else './dfhack' test_status_file = 'test_status.json' From 32bd04f83e3498e1134d290283ece53e76d1c00b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 17:16:13 -0700 Subject: [PATCH 614/851] install SDL2 on Linux for DF --- .github/workflows/test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e0576dbf7..fb7bcce7d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -79,6 +79,11 @@ jobs: - name: Set env shell: bash run: echo "DF_FOLDER=DF" >> $GITHUB_ENV + - name: Install dependencies + if: matrix.os == 'ubuntu' + run: | + sudo apt-get update + sudo apt-get install libsdl2-dev libsdl2-image-dev - name: Clone DFHack uses: actions/checkout@v3 with: From 0d7f9a401f7670d6e866de3096813ea0529421be Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 17:54:10 -0700 Subject: [PATCH 615/851] output where we're clicking for debugging --- ci/test.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/test.lua b/ci/test.lua index 06dee5a75..57ed13124 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -220,6 +220,7 @@ local function click_top_title_button(scr) else df.global.gps.mouse_y = (sh // 2) + 1 end + print(('simulating click at screen coordinates %d, %d'):format(df.global.gps.mouse_x, df.global.gps.mouse_y)) df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y df.global.enabler.tracking_on = 1 df.global.enabler.mouse_lbut = 1 From b3fdaa54c558e9ff72bd8bf51c973e5b09c07e9d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 22:00:03 -0700 Subject: [PATCH 616/851] install non-dev libs; start X server --- .github/workflows/test.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fb7bcce7d..d36ff49d4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -83,7 +83,9 @@ jobs: if: matrix.os == 'ubuntu' run: | sudo apt-get update - sudo apt-get install libsdl2-dev libsdl2-image-dev + sudo apt-get install \ + libsdl2-2.0-0 \ + libsdl2-image-2.0-0 - name: Clone DFHack uses: actions/checkout@v3 with: @@ -121,8 +123,13 @@ jobs: - name: Install DFHack shell: bash run: tar xjf test-${{ matrix.compiler }}.tar.bz2 -C ${{ env.DF_FOLDER }} + - name: Start X server + if: matrix.os == 'ubuntu' + run: Xvfb :0 -screen 0 1600x1200x32 & - name: Run lua tests timeout-minutes: 10 + env: + DISPLAY: :0 run: python ci/run-tests.py --keep-status "${{ env.DF_FOLDER }}" - name: Check RPC interface run: python ci/check-rpc.py "${{ env.DF_FOLDER }}/dfhack-rpc.txt" From e8f0de4078efbbdec0150823e8418d6006bfb9b4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 22:00:15 -0700 Subject: [PATCH 617/851] print screen dims --- ci/test.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/test.lua b/ci/test.lua index 57ed13124..34fcd97a6 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -213,6 +213,7 @@ end local function click_top_title_button(scr) local sw, sh = dfhack.screen.getWindowSize() + print(('screen dimensions: %d, %d'):format(sw. sh)) df.global.gps.mouse_x = sw // 2 df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x if sh < 60 then From 8dc5f8e86b23746aea2912b02039f2de30a7d636 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 23:23:49 -0700 Subject: [PATCH 618/851] fix screen depth and print syntax --- .github/workflows/test.yml | 2 +- ci/test.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d36ff49d4..fa59c5f2e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -125,7 +125,7 @@ jobs: run: tar xjf test-${{ matrix.compiler }}.tar.bz2 -C ${{ env.DF_FOLDER }} - name: Start X server if: matrix.os == 'ubuntu' - run: Xvfb :0 -screen 0 1600x1200x32 & + run: Xvfb :0 -screen 0 1600x1200x24 & - name: Run lua tests timeout-minutes: 10 env: diff --git a/ci/test.lua b/ci/test.lua index 34fcd97a6..193b89ce8 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -213,7 +213,7 @@ end local function click_top_title_button(scr) local sw, sh = dfhack.screen.getWindowSize() - print(('screen dimensions: %d, %d'):format(sw. sh)) + print(('screen dimensions: %d, %d'):format(sw, sh)) df.global.gps.mouse_x = sw // 2 df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x if sh < 60 then From 989415cef08b420d6e19e8f81b9a7fd1d641baac Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 24 Sep 2023 23:45:43 -0700 Subject: [PATCH 619/851] use gui.simulateInput --- ci/test.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci/test.lua b/ci/test.lua index 193b89ce8..dc814da19 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -2,6 +2,7 @@ --@ module = true local expect = require('test_util.expect') +local gui = require('gui') local helpdb = require('helpdb') local json = require('json') local mock = require('test_util.mock') @@ -226,7 +227,7 @@ local function click_top_title_button(scr) df.global.enabler.tracking_on = 1 df.global.enabler.mouse_lbut = 1 df.global.enabler.mouse_lbut_down = 1 - dfhack.screen._doSimulateInput(scr, {}) + gui.simulateInput(scr, '_MOUSE_L') end local function load_first_save(scr) From 9cd90589822cbc6bc2adee1e90b543293b27adcc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 25 Sep 2023 00:04:29 -0700 Subject: [PATCH 620/851] set a TERM var --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fa59c5f2e..6255219e6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -130,6 +130,7 @@ jobs: timeout-minutes: 10 env: DISPLAY: :0 + TERM: xterm-256color run: python ci/run-tests.py --keep-status "${{ env.DF_FOLDER }}" - name: Check RPC interface run: python ci/check-rpc.py "${{ env.DF_FOLDER }}/dfhack-rpc.txt" From 0c1d73cfe63bd86e1061ae22eabe42619636a61a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 25 Sep 2023 00:04:41 -0700 Subject: [PATCH 621/851] adjust settings to v50 norms --- ci/run-tests.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/ci/run-tests.py b/ci/run-tests.py index 257359324..f43c7efd4 100755 --- a/ci/run-tests.py +++ b/ci/run-tests.py @@ -65,14 +65,12 @@ if not os.path.exists(init_txt_path): shutil.copyfile(init_txt_path, init_txt_path + '.orig') with open(init_txt_path) as f: init_contents = f.read() -init_contents = change_setting(init_contents, 'INTRO', 'NO') init_contents = change_setting(init_contents, 'SOUND', 'NO') init_contents = change_setting(init_contents, 'WINDOWED', 'YES') -init_contents = change_setting(init_contents, 'WINDOWEDX', '80') -init_contents = change_setting(init_contents, 'WINDOWEDY', '25') -init_contents = change_setting(init_contents, 'FPS', 'YES') -if args.headless: - init_contents = change_setting(init_contents, 'PRINT_MODE', 'TEXT') +init_contents = change_setting(init_contents, 'WINDOWEDX', '1200') +init_contents = change_setting(init_contents, 'WINDOWEDY', '800') +#if args.headless: +# init_contents = change_setting(init_contents, 'PRINT_MODE', 'TEXT') init_path = 'dfhack-config/init' if not os.path.isdir('hack/init'): From cc49c07870d2585b0ec625354cb2020cb0193c23 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 25 Sep 2023 12:07:39 -0700 Subject: [PATCH 622/851] click on buttons to drive the UI --- ci/test.lua | 69 +++++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index dc814da19..3b5b041ba 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -156,19 +156,18 @@ local function is_title_screen() return dfhack.gui.matchFocusString('title/Default') end -local function wait_for_game_load() +local function wait_for(ms, desc, predicate) local start_ms = dfhack.getTickCount() local prev_ms = start_ms - while df.viewscreen_initial_prepst:is_instance(dfhack.gui.getDFViewscreen()) do + while not predicate() do delay(10) - -- wait up to 1 minute for the game to load and show the title screen local now_ms = dfhack.getTickCount() - if now_ms - start_ms > 60000 then - qerror(('Could not find title screen (timed out at %s)'):format( - dfhack.gui.getCurFocus(true)[1])) + if now_ms - start_ms > ms then + qerror(('%s took too long (timed out at %s)'):format( + desc, dfhack.gui.getCurFocus(true)[1])) end if now_ms - prev_ms > 1000 then - print('Waiting for game to load and show title screen...') + print(('Waiting for %s...'):format(desc)) prev_ms = now_ms end end @@ -178,7 +177,6 @@ end -- has already loaded a fortress or is in any screen that can't get to the title -- screen by sending ESC keys. local function ensure_title_screen() - wait_for_game_load() if df.viewscreen_dwarfmodest:is_instance(dfhack.gui.getDFViewscreen(true)) then qerror('Cannot reach title screen from loaded fort') end @@ -208,21 +206,21 @@ local function ensure_ci_save(scr) or #scr.savegame_header_world ~= 1 or not string.find(scr.savegame_header[0].fort_name, 'Dream') then - qerror('Unexpected test save in slot 0; please manually load a fort for testing. note that tests may corrupt the game!') + qerror('Unexpected test save in slot 0; please manually load a fort for ' .. + 'running fortress mode tests. note that tests may alter or corrupt the ' .. + 'fort! Do not save after running tests.') end end local function click_top_title_button(scr) local sw, sh = dfhack.screen.getWindowSize() - print(('screen dimensions: %d, %d'):format(sw, sh)) df.global.gps.mouse_x = sw // 2 df.global.gps.precise_mouse_x = df.global.gps.mouse_x * df.global.gps.tile_pixel_x if sh < 60 then - df.global.gps.mouse_y = 23 + df.global.gps.mouse_y = 25 else - df.global.gps.mouse_y = (sh // 2) + 1 + df.global.gps.mouse_y = (sh // 2) + 3 end - print(('simulating click at screen coordinates %d, %d'):format(df.global.gps.mouse_x, df.global.gps.mouse_y)) df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y df.global.enabler.tracking_on = 1 df.global.enabler.mouse_lbut = 1 @@ -234,18 +232,25 @@ local function load_first_save(scr) if #scr.savegame_header == 0 then qerror('no savegames available to load') end - scr.mode = 2 + click_top_title_button(scr) - delay() + wait_for(1000, 'world list', function() + return scr.mode == 2 + end) click_top_title_button(scr) - delay() + wait_for(1000, 'savegame list', function() + return scr.mode == 3 + end) + click_top_title_button(scr) + wait_for(1000, 'loadgame progress bar', function() + return dfhack.gui.matchFocusString('loadgame') + end) end -- Requires that a fortress game is already loaded or is ready to be loaded via -- the "Continue active game" option in the title screen. Otherwise the function -- will time out and/or exit with error. local function ensure_fortress(config) - wait_for_game_load() for screen_timeout = 1,10 do if is_fortress() then print('Fortress map is loaded') @@ -253,8 +258,8 @@ local function ensure_fortress(config) dfhack.gui.resetDwarfmodeView(true) return end - local scr = dfhack.gui.getDFViewscreen(true) - if dfhack.gui.matchFocusString('title/Default') then + local scr = dfhack.gui.getCurViewscreen() + if dfhack.gui.matchFocusString('title/Default', scr) then print('Attempting to load the test fortress') -- TODO: reinstate loading of a specified save dir; for now -- just load the first possible save, which will at least let us @@ -263,29 +268,17 @@ local function ensure_fortress(config) -- dfhack.run_script('load-save', config.save_dir) ensure_ci_save(scr) load_first_save(scr) - elseif not dfhack.gui.matchFocusString('loadgame') then + elseif not dfhack.gui.matchFocusString('loadgame', scr) then -- if we're not actively loading a game, hope we're in -- a screen where hitting ESC will get us to the game map -- or the title screen scr:feed_key(df.interface_key.LEAVESCREEN) end -- wait for current screen to change - local prev_focus_string = dfhack.gui.getCurFocus(true)[1] - for frame_timeout = 1,100 do - delay(10) - local focus_string = dfhack.gui.getCurFocus(true)[1] - if focus_string ~= prev_focus_string then - goto next_screen - end - if frame_timeout % 10 == 0 then - print(string.format( - 'Loading fortress (currently at screen: %s)', - focus_string)) - end - end - print('Timed out waiting for screen to change') - break - ::next_screen:: + local prev_focus_string = dfhack.gui.getCurFocus()[1] + wait_for(60000, 'screen change', function() + return dfhack.gui.getCurFocus()[1] ~= prev_focus_string + end) end qerror(string.format('Could not load fortress (timed out at %s)', table.concat(dfhack.gui.getCurFocus(), ' '))) @@ -630,6 +623,10 @@ local function filter_tests(tests, config) end local function run_tests(tests, status, counts, config) + wait_for(60000, 'game load', function() + local scr = dfhack.gui.getDFViewscreen() + return not df.viewscreen_initial_prepst:is_instance(scr) + end) print(('Running %d tests'):format(#tests)) local start_ms = dfhack.getTickCount() local num_skipped = 0 From 30e3b695a17b215a9c10a11c51d29a91ac74f189 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 25 Sep 2023 17:34:38 -0700 Subject: [PATCH 623/851] skip crashing tests and mark them as failed --- ci/run-tests.py | 2 +- ci/test.lua | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ci/run-tests.py b/ci/run-tests.py index f43c7efd4..13eeb099c 100755 --- a/ci/run-tests.py +++ b/ci/run-tests.py @@ -31,7 +31,7 @@ if args.test_dir is not None: if not os.path.isdir(args.test_dir): print('ERROR: invalid test folder: %r' % args.test_dir) -MAX_TRIES = 1 +MAX_TRIES = 5 dfhack = 'Dwarf Fortress.exe' if sys.platform == 'win32' else './dfhack' test_status_file = 'test_status.json' diff --git a/ci/test.lua b/ci/test.lua index 3b5b041ba..372d8f262 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -645,12 +645,13 @@ local function run_tests(tests, status, counts, config) goto skip end end + -- pre-emptively mark the test as failed in case we induce a crash + status[test.full_name] = TestStatus.FAILED + save_test_status(status) if run_test(test, status, counts) then status[test.full_name] = TestStatus.PASSED - else - status[test.full_name] = TestStatus.FAILED + save_test_status(status) end - save_test_status(status) ::skip:: end local elapsed_ms = dfhack.getTickCount() - start_ms From 83137378332e02601b9ff4e267fca538b67eaae3 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 26 Sep 2023 07:13:08 +0000 Subject: [PATCH 624/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 0ed4052ac..a8aacf9b3 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 0ed4052ac9049151657e22831996800d0d3104bb +Subproject commit a8aacf9b3e8d71c338f8d087792ee8aa39a85220 From 932f3324d3efb09d160008b59bf25842cfa76b2a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 26 Sep 2023 03:45:15 -0700 Subject: [PATCH 625/851] add detailed focus strings for setupdwarfgame --- library/modules/Gui.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 9eee284ac..58763262f 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -87,6 +87,7 @@ using namespace DFHack; #include "df/viewscreen_dwarfmodest.h" #include "df/viewscreen_legendsst.h" #include "df/viewscreen_new_regionst.h" +#include "df/viewscreen_setupdwarfgamest.h" #include "df/viewscreen_titlest.h" #include "df/world.h" @@ -174,6 +175,45 @@ DEFINE_GET_FOCUS_STRING_HANDLER(new_region) focusStrings.push_back(baseFocus); } +DEFINE_GET_FOCUS_STRING_HANDLER(setupdwarfgame) +{ + if (screen->doing_custom_settings) + focusStrings.push_back(baseFocus + "/CustomSettings"); + else if (game->main_interface.options.open) + focusStrings.push_back(baseFocus + "/Abort"); + else if (screen->initial_selection == 1) + focusStrings.push_back(baseFocus + "/Default"); + else if (game->main_interface.name_creator.open) { + switch (game->main_interface.name_creator.context) { + case df::name_creator_context_type::EMBARK_FORT_NAME: + focusStrings.push_back(baseFocus + "/FortName"); + break; + case df::name_creator_context_type::EMBARK_GROUP_NAME: + focusStrings.push_back(baseFocus + "/GroupName"); + break; + default: + break; + } + } + else if (game->main_interface.image_creator.open) { + focusStrings.push_back(baseFocus + "/GroupSymbol"); + } + else if (screen->viewing_objections != 0) + focusStrings.push_back(baseFocus + "/Objections"); + else { + switch (screen->mode) { + case 0: focusStrings.push_back(baseFocus + "/Dwarves"); break; + case 1: focusStrings.push_back(baseFocus + "/Items"); break; + case 2: focusStrings.push_back(baseFocus + "/Animals"); break; + default: + break; + } + } + + if (focusStrings.empty()) + focusStrings.push_back(baseFocus + "/Default"); +} + DEFINE_GET_FOCUS_STRING_HANDLER(legends) { if (screen->init_stage != -1) From eefd38c66cc78d3159a7e85096bcade24dd441a7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 26 Sep 2023 03:52:24 -0700 Subject: [PATCH 626/851] align mouse button semantics to DF we, um, had it backwards --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 4 +- library/LuaTools.cpp | 72 +++++++++---------- library/lua/gui.lua | 23 ++---- library/lua/gui/dialogs.lua | 8 +-- library/lua/gui/widgets.lua | 37 +++++----- library/modules/Screen.cpp | 10 +++ plugins/lua/buildingplan/inspectoroverlay.lua | 4 +- plugins/lua/buildingplan/itemselection.lua | 4 +- plugins/lua/buildingplan/planneroverlay.lua | 8 +-- plugins/lua/hotkeys.lua | 8 +-- plugins/lua/overlay.lua | 3 - plugins/lua/sort.lua | 4 +- plugins/lua/zone.lua | 9 ++- test/library/gui/widgets.EditField.lua | 6 +- test/library/gui/widgets.Scrollbar.lua | 18 ++--- test/library/gui/widgets.lua | 4 +- 17 files changed, 110 insertions(+), 113 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 9efb86430..9e377dd4f 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -66,6 +66,7 @@ Template for new versions: ## API ## Lua +- mouse key events are now aligned with internal DF semantics: ``_MOUSE_L`` indicates that the left mouse button has just been pressed and ``_MOUSE_L_DOWN`` indicates that the left mouse button is being held down. similar for ``_MOUSE_R`` and ``_MOUSE_M``. 3rd party scripts may have to adjust. ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 1cba8284e..6eeb2dbe7 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2528,10 +2528,10 @@ Supported callbacks and fields are: Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code for convenience. ``_MOUSE_L, _MOUSE_R, _MOUSE_M`` - If the left, right, and/or middle mouse button is being pressed. + If the left, right, and/or middle mouse button was just pressed. ``_MOUSE_L_DOWN, _MOUSE_R_DOWN, _MOUSE_M_DOWN`` - If the left, right, and/or middle mouse button was just pressed. + If the left, right, and/or middle mouse button is being held down. If this method is omitted, the screen is dismissed on reception of the ``LEAVESCREEN`` key. diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index ffeb4980a..87699641d 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -131,12 +131,12 @@ void DFHack::Lua::GetVector(lua_State *state, std::vector &pvec, in } } -static bool trigger_inhibit_l_down = false; -static bool trigger_inhibit_r_down = false; -static bool trigger_inhibit_m_down = false; -static bool inhibit_l_down = false; -static bool inhibit_r_down = false; -static bool inhibit_m_down = false; +static bool trigger_inhibit_l = false; +static bool trigger_inhibit_r = false; +static bool trigger_inhibit_m = false; +static bool inhibit_l = false; +static bool inhibit_r = false; +static bool inhibit_m = false; void DFHack::Lua::PushInterfaceKeys(lua_State *L, const std::set &keys) { @@ -161,32 +161,32 @@ void DFHack::Lua::PushInterfaceKeys(lua_State *L, } if (df::global::enabler) { - if (!inhibit_l_down && df::global::enabler->mouse_lbut_down) { + if (!inhibit_l && df::global::enabler->mouse_lbut) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_L_DOWN"); - trigger_inhibit_l_down = true; + lua_setfield(L, -2, "_MOUSE_L"); + trigger_inhibit_l = true; } - if (!inhibit_r_down && df::global::enabler->mouse_rbut_down) { + if (!inhibit_r && df::global::enabler->mouse_rbut) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_R_DOWN"); - trigger_inhibit_r_down = true; + lua_setfield(L, -2, "_MOUSE_R"); + trigger_inhibit_r = true; } - if (!inhibit_m_down && df::global::enabler->mouse_mbut_down) { + if (!inhibit_m && df::global::enabler->mouse_mbut) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_M_DOWN"); - trigger_inhibit_m_down = true; + lua_setfield(L, -2, "_MOUSE_M"); + trigger_inhibit_m = true; } - if (df::global::enabler->mouse_lbut) { + if (df::global::enabler->mouse_lbut_down) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_L"); + lua_setfield(L, -2, "_MOUSE_L_DOWN"); } - if (df::global::enabler->mouse_rbut) { + if (df::global::enabler->mouse_rbut_down) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_R"); + lua_setfield(L, -2, "_MOUSE_R_DOWN"); } - if (df::global::enabler->mouse_mbut) { + if (df::global::enabler->mouse_mbut_down) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_M"); + lua_setfield(L, -2, "_MOUSE_M_DOWN"); } } } @@ -2159,25 +2159,25 @@ void DFHack::Lua::Core::Reset(color_ostream &out, const char *where) lua_settop(State, 0); } - if (trigger_inhibit_l_down) { - trigger_inhibit_l_down = false; - inhibit_l_down = true; + if (trigger_inhibit_l) { + trigger_inhibit_l = false; + inhibit_l = true; } - if (trigger_inhibit_r_down) { - trigger_inhibit_r_down = false; - inhibit_r_down = true; + if (trigger_inhibit_r) { + trigger_inhibit_r = false; + inhibit_r = true; } - if (trigger_inhibit_m_down) { - trigger_inhibit_m_down = false; - inhibit_m_down = true; + if (trigger_inhibit_m) { + trigger_inhibit_m = false; + inhibit_m = true; } if (df::global::enabler) { - if (!df::global::enabler->mouse_lbut) - inhibit_l_down = false; - if (!df::global::enabler->mouse_rbut) - inhibit_r_down = false; - if (!df::global::enabler->mouse_mbut) - inhibit_m_down = false; + if (!df::global::enabler->mouse_lbut_down) + inhibit_l = false; + if (!df::global::enabler->mouse_rbut_down) + inhibit_r = false; + if (!df::global::enabler->mouse_mbut_down) + inhibit_m = false; } } diff --git a/library/lua/gui.lua b/library/lua/gui.lua index bba7222b9..ba49e0cdc 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -696,16 +696,12 @@ end DEFAULT_INITIAL_PAUSE = true -local zscreen_inhibit_mouse_l = false - -- ensure underlying DF screens don't also react to handled clicks function markMouseClicksHandled(keys) - if keys._MOUSE_L_DOWN then - -- note we can't clear mouse_lbut here. otherwise we break dragging, - df.global.enabler.mouse_lbut_down = 0 - zscreen_inhibit_mouse_l = true + if keys._MOUSE_L then + df.global.enabler.mouse_lbut = 0 end - if keys._MOUSE_R_DOWN then + if keys._MOUSE_R then df.global.enabler.mouse_rbut_down = 0 df.global.enabler.mouse_rbut = 0 end @@ -789,7 +785,7 @@ function ZScreen:onInput(keys) local has_mouse = self:isMouseOver() if not self:hasFocus() then if has_mouse and - (keys._MOUSE_L_DOWN or keys._MOUSE_R_DOWN or + (keys._MOUSE_L or keys._MOUSE_R or keys.CONTEXT_SCROLL_UP or keys.CONTEXT_SCROLL_DOWN or keys.CONTEXT_SCROLL_PAGEUP or keys.CONTEXT_SCROLL_PAGEDOWN) then self:raise() @@ -804,22 +800,15 @@ function ZScreen:onInput(keys) return end - if self.pass_mouse_clicks and keys._MOUSE_L_DOWN and not has_mouse then + if self.pass_mouse_clicks and keys._MOUSE_L and not has_mouse then self.defocused = self.defocusable self:sendInputToParent(keys) return - elseif keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + elseif keys.LEAVESCREEN or keys._MOUSE_R then self:dismiss() markMouseClicksHandled(keys) return else - if zscreen_inhibit_mouse_l then - if keys._MOUSE_L then - return - else - zscreen_inhibit_mouse_l = false - end - 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 or diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua index 499fa6305..95a56d0c4 100644 --- a/library/lua/gui/dialogs.lua +++ b/library/lua/gui/dialogs.lua @@ -57,11 +57,11 @@ function MessageBox:onDestroy() end function MessageBox:onInput(keys) - if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R then self:dismiss() if keys.SELECT and self.on_accept then self.on_accept() - elseif (keys.LEAVESCREEN or keys._MOUSE_R_DOWN) and self.on_cancel then + elseif (keys.LEAVESCREEN or keys._MOUSE_R) and self.on_cancel then self.on_cancel() end gui.markMouseClicksHandled(keys) @@ -129,7 +129,7 @@ function InputBox:onInput(keys) self.on_input(self.subviews.edit.text) end return true - elseif keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + elseif keys.LEAVESCREEN or keys._MOUSE_R then self:dismiss() if self.on_cancel then self.on_cancel() @@ -231,7 +231,7 @@ function ListBox:getWantedFrameSize() end function ListBox:onInput(keys) - if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.LEAVESCREEN or keys._MOUSE_R then self:dismiss() if self.on_cancel then self.on_cancel() diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 6a0a0091b..05d237f35 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -273,7 +273,7 @@ end function Panel:onInput(keys) if self.kbd_get_pos then - if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R then Panel_end_drag(self, not keys.SELECT and self.saved_frame or nil, not not keys.SELECT) return true @@ -281,7 +281,6 @@ function Panel:onInput(keys) for code in pairs(keys) do local dx, dy = guidm.get_movement_delta(code, 1, 10) if dx then - local frame_rect = self.frame_rect local kbd_pos = self.kbd_get_pos() kbd_pos.x = kbd_pos.x + dx kbd_pos.y = kbd_pos.y + dy @@ -292,9 +291,9 @@ function Panel:onInput(keys) return end if self.drag_offset then - if keys._MOUSE_R_DOWN then + if keys._MOUSE_R then Panel_end_drag(self, self.saved_frame) - elseif keys._MOUSE_L then + elseif keys._MOUSE_L_DOWN then Panel_update_frame(self, Panel_make_frame(self)) end return true @@ -302,7 +301,7 @@ function Panel:onInput(keys) if Panel.super.onInput(self, keys) then return true end - if not keys._MOUSE_L_DOWN then return end + if not keys._MOUSE_L then return end local x,y = self:getMouseFramePos() if not x then return end @@ -489,7 +488,7 @@ function Panel:onRenderFrame(dc, rect) dc:seek(pos.x, pos.y):pen(pen):char(string.char(0xDB)) end if self.drag_offset and not self.kbd_get_pos - and df.global.enabler.mouse_lbut == 0 then + and df.global.enabler.mouse_lbut_down == 0 then Panel_end_drag(self, nil, true) end end @@ -718,7 +717,7 @@ function EditField:onInput(keys) end end - if self.key and (keys.LEAVESCREEN or keys._MOUSE_R_DOWN) then + if self.key and (keys.LEAVESCREEN or keys._MOUSE_R) then self:setText(self.saved_text) self:setFocus(false) return true @@ -740,8 +739,8 @@ function EditField:onInput(keys) end end return not not self.key - elseif keys._MOUSE_L then - local mouse_x, mouse_y = self:getMousePos() + elseif keys._MOUSE_L_DOWN then + local mouse_x = self:getMousePos() if mouse_x then self:setCursor(self.start_pos + mouse_x - (self.text_offset or 0)) return true @@ -986,7 +985,7 @@ function Scrollbar:onRenderBody(dc) if self.is_dragging then scrollbar_do_drag(self) end - if df.global.enabler.mouse_lbut == 0 then + if df.global.enabler.mouse_lbut_down == 0 then self.last_scroll_ms = 0 self.is_dragging = false self.scroll_spec = nil @@ -1023,7 +1022,7 @@ function Scrollbar:onInput(keys) return true end end - if not keys._MOUSE_L_DOWN then return false end + if not keys._MOUSE_L then return false end local _,y = self:getMousePos() if not y then return false end local scroll_spec = nil @@ -1386,11 +1385,11 @@ function Label:onInput(keys) if self:inputToSubviews(keys) then return true end - if keys._MOUSE_L_DOWN and self:getMousePos() and self.on_click then + if keys._MOUSE_L and self:getMousePos() and self.on_click then self.on_click() return true end - if keys._MOUSE_R_DOWN and self:getMousePos() and self.on_rclick then + if keys._MOUSE_R and self:getMousePos() and self.on_rclick then self.on_rclick() return true end @@ -1498,7 +1497,7 @@ end function HotkeyLabel:onInput(keys) if HotkeyLabel.super.onInput(self, keys) then return true - elseif keys._MOUSE_L_DOWN and self:getMousePos() and self.on_activate + elseif keys._MOUSE_L and self:getMousePos() and self.on_activate and not is_disabled(self) then self.on_activate() return true @@ -1658,7 +1657,7 @@ end function CycleHotkeyLabel:onInput(keys) if CycleHotkeyLabel.super.onInput(self, keys) then return true - elseif keys._MOUSE_L_DOWN and self:getMousePos() and not is_disabled(self) then + elseif keys._MOUSE_L and self:getMousePos() and not is_disabled(self) then self:cycle() return true end @@ -1962,7 +1961,7 @@ function List:onInput(keys) return self:submit() elseif keys.CUSTOM_SHIFT_ENTER then return self:submit2() - elseif keys._MOUSE_L_DOWN then + elseif keys._MOUSE_L then local idx = self:getIdxUnderMouse() if idx then local now_ms = dfhack.getTickCount() @@ -2317,7 +2316,7 @@ end function Tab:onInput(keys) if Tab.super.onInput(self, keys) then return true end - if keys._MOUSE_L_DOWN and self:getMousePos() then + if keys._MOUSE_L and self:getMousePos() then self.on_select(self.id) return true end @@ -2419,7 +2418,7 @@ local function rangeslider_get_width_per_idx(self) end function RangeSlider:onInput(keys) - if not keys._MOUSE_L_DOWN then return false end + if not keys._MOUSE_L 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() @@ -2527,7 +2526,7 @@ function RangeSlider:onRenderBody(dc, rect) if self.is_dragging_target then rangeslider_do_drag(self, width_per_idx) end - if df.global.enabler.mouse_lbut == 0 then + if df.global.enabler.mouse_lbut_down == 0 then self.is_dragging_target = nil self.is_dragging_idx = nil end diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 5f98c40e5..a5b347493 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -1004,6 +1004,8 @@ dfhack_lua_viewscreen::~dfhack_lua_viewscreen() void dfhack_lua_viewscreen::render() { + using df::global::enabler; + if (Screen::isDismissed(this)) { if (parent) @@ -1011,6 +1013,14 @@ void dfhack_lua_viewscreen::render() return; } + if (enabler && + (enabler->mouse_lbut_down || enabler->mouse_rbut_down || enabler->mouse_mbut_down)) + { + // synthesize feed events for held mouse buttons + std::set keys; + feed(&keys); + } + dfhack_viewscreen::render(); safe_call_lua(do_render, 0, 0); diff --git a/plugins/lua/buildingplan/inspectoroverlay.lua b/plugins/lua/buildingplan/inspectoroverlay.lua index 1fcf19028..3c6f0ed5e 100644 --- a/plugins/lua/buildingplan/inspectoroverlay.lua +++ b/plugins/lua/buildingplan/inspectoroverlay.lua @@ -127,9 +127,9 @@ function InspectorOverlay:onInput(keys) if not require('plugins.buildingplan').isPlannedBuilding(dfhack.gui.getSelectedBuilding(true)) then return false end - if keys._MOUSE_L_DOWN and mouse_is_over_resume_button(self.frame_parent_rect) then + if keys._MOUSE_L and mouse_is_over_resume_button(self.frame_parent_rect) then return true - elseif keys._MOUSE_L_DOWN or keys._MOUSE_R_DOWN or keys.LEAVESCREEN then + elseif keys._MOUSE_L or keys._MOUSE_R or keys.LEAVESCREEN then self:reset() end return InspectorOverlay.super.onInput(self, keys) diff --git a/plugins/lua/buildingplan/itemselection.lua b/plugins/lua/buildingplan/itemselection.lua index 84e866502..9dfd0cc69 100644 --- a/plugins/lua/buildingplan/itemselection.lua +++ b/plugins/lua/buildingplan/itemselection.lua @@ -366,10 +366,10 @@ function ItemSelection:submit(choices) end function ItemSelection:onInput(keys) - if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.LEAVESCREEN or keys._MOUSE_R then self.on_cancel() return true - elseif keys._MOUSE_L_DOWN then + elseif keys._MOUSE_L then local list = self.subviews.flist.list local idx = list:getIdxUnderMouse() if idx then diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index ebd8e6e02..2cc15dfde 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -272,7 +272,7 @@ function ItemLine:reset() end function ItemLine:onInput(keys) - if keys._MOUSE_L_DOWN and self:getMousePos() then + if keys._MOUSE_L and self:getMousePos() then self.on_select(self.idx) end return ItemLine.super.onInput(self, keys) @@ -739,7 +739,7 @@ end function PlannerOverlay:onInput(keys) if not is_plannable() then return false end - if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.LEAVESCREEN or keys._MOUSE_R then if uibs.selection_pos:isValid() then uibs.selection_pos:clear() return true @@ -758,7 +758,7 @@ function PlannerOverlay:onInput(keys) return true end if self:is_minimized() then return false end - if keys._MOUSE_L_DOWN then + if keys._MOUSE_L then if is_over_options_panel() then return false end local detect_rect = copyall(self.frame_rect) detect_rect.height = self.subviews.main.frame_rect.height + @@ -828,7 +828,7 @@ function PlannerOverlay:onInput(keys) end end end - return keys._MOUSE_L or keys.SELECT + return keys._MOUSE_L_DOWN or keys.SELECT end function PlannerOverlay:render(dc) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 8eff17aae..80f8816e8 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -269,24 +269,24 @@ function Menu:onSubmit2(_, choice) end function Menu:onInput(keys) - if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.LEAVESCREEN or keys._MOUSE_R then return false elseif keys.KEYBOARD_CURSOR_RIGHT then self:onSubmit2(self.subviews.list:getSelected()) return true - elseif keys._MOUSE_L_DOWN then + elseif keys._MOUSE_L then local list = self.subviews.list local x = list:getMousePos() if x == 0 then -- clicked on icon self:onSubmit2(list:getSelected()) - df.global.enabler.mouse_lbut = 0 + gui.markMouseClicksHandled(keys) return true end if not self:getMouseFramePos() then self.parent_view:dismiss() return true end - df.global.enabler.mouse_lbut = 0 + gui.markMouseClicksHandled(keys) end self:inputToSubviews(keys) return true -- we're modal diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index d3f0b9c9d..cd5286d0d 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -507,9 +507,6 @@ function feed_viewscreen_widgets(vs_name, vs, keys) return false end gui.markMouseClicksHandled(keys) - if keys._MOUSE_L_DOWN then - df.global.enabler.mouse_lbut = 0 - end return true end diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 15d9ebabb..cc24d2e3e 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1148,9 +1148,7 @@ function SquadAssignmentOverlay:refresh_list(sort_widget, sort_fn) end function SquadAssignmentOverlay:onInput(keys) - if keys._MOUSE_R_DOWN or - keys._MOUSE_L_DOWN and not self:getMouseFramePos() - then + if keys._MOUSE_R or (keys._MOUSE_L and not self:getMouseFramePos()) then -- if any click is made outside of our window, we may need to refresh our list self.dirty = true end diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 3c07b609f..13182cef1 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -801,10 +801,12 @@ end function AssignAnimalScreen:onInput(keys) local handled = AssignAnimalScreen.super.onInput(self, keys) if not self.is_valid_ui_state() then - view:dismiss() + if view then + view:dismiss() + end return end - if keys._MOUSE_L_DOWN then + if keys._MOUSE_L then -- if any click is made outside of our window, we need to recheck unit properties local window = self.subviews[1] if not window:getMouseFramePos() then @@ -818,7 +820,7 @@ function AssignAnimalScreen:onInput(keys) end function AssignAnimalScreen:onRenderFrame() - if not self.is_valid_ui_state() then + if view and not self.is_valid_ui_state() then view:dismiss() end end @@ -1072,6 +1074,7 @@ function CageChainOverlay:init() frame={t=0, l=0, r=0, h=1}, label='DFHack assign', key='CUSTOM_CTRL_T', + visible=is_valid_building, on_activate=function() view = view and view:raise() or show_cage_chain_screen() end, }, } diff --git a/test/library/gui/widgets.EditField.lua b/test/library/gui/widgets.EditField.lua index 88625a7bf..8418b67d4 100644 --- a/test/library/gui/widgets.EditField.lua +++ b/test/library/gui/widgets.EditField.lua @@ -42,17 +42,17 @@ function test.editfield_click() expect.eq(5, e.cursor) mock.patch(e, 'getMousePos', mock.func(0), function() - e:onInput{_MOUSE_L=true} + e:onInput{_MOUSE_L_DOWN=true} expect.eq(1, e.cursor) end) mock.patch(e, 'getMousePos', mock.func(20), function() - e:onInput{_MOUSE_L=true} + e:onInput{_MOUSE_L_DOWN=true} expect.eq(5, e.cursor, 'should only seek to end of text') end) mock.patch(e, 'getMousePos', mock.func(2), function() - e:onInput{_MOUSE_L=true} + e:onInput{_MOUSE_L_DOWN=true} expect.eq(3, e.cursor) end) end diff --git a/test/library/gui/widgets.Scrollbar.lua b/test/library/gui/widgets.Scrollbar.lua index 548792b3d..dd490256c 100644 --- a/test/library/gui/widgets.Scrollbar.lua +++ b/test/library/gui/widgets.Scrollbar.lua @@ -59,37 +59,37 @@ function test.onInput() s:update(23, 10, 50) expect.false_(s:onInput{}, 'no mouse down') - expect.false_(s:onInput{_MOUSE_L_DOWN=true}, 'no y coord') + expect.false_(s:onInput{_MOUSE_L=true}, 'no y coord') spec, y = nil, 0 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('up_small', spec, 'on up arrow') spec, y = nil, 1 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('up_large', spec, 'on body above bar') spec, y = nil, 44 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('up_large', spec, 'on body just above bar') spec, y = nil, 45 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.nil_(spec, 'on top of bar') spec, y = nil, 63 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.nil_(spec, 'on bottom of bar') spec, y = nil, 64 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('down_large', spec, 'on body just below bar') spec, y = nil, 98 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('down_large', spec, 'on body below bar') spec, y = nil, 99 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('down_small', spec, 'on down arrow') end diff --git a/test/library/gui/widgets.lua b/test/library/gui/widgets.lua index 88d3ac952..b37fbe04d 100644 --- a/test/library/gui/widgets.lua +++ b/test/library/gui/widgets.lua @@ -7,7 +7,7 @@ function test.hotkeylabel_click() local l = widgets.HotkeyLabel{key='SELECT', on_activate=func} mock.patch(l, 'getMousePos', mock.func(0), function() - l:onInput{_MOUSE_L_DOWN=true} + l:onInput{_MOUSE_L=true} expect.eq(1, func.call_count) end) end @@ -33,7 +33,7 @@ function test.togglehotkeylabel_click() local l = widgets.ToggleHotkeyLabel{} expect.true_(l:getOptionValue()) mock.patch(l, 'getMousePos', mock.func(0), function() - l:onInput{_MOUSE_L_DOWN=true} + l:onInput{_MOUSE_L=true} expect.false_(l:getOptionValue()) end) end From 49c05aa3982e78b265d055517ac0d7d65bd0980d Mon Sep 17 00:00:00 2001 From: Mikhail Panov Date: Tue, 26 Sep 2023 17:54:34 +0300 Subject: [PATCH 627/851] Updated changelog.txt --- docs/changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 9efb86430..f5907f4cc 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -75,6 +75,9 @@ Template for new versions: - Linux launcher: allow Steam Overlay and game streaming to function - `autobutcher`: don't ignore semi-wild units when marking units for slaughter +## Misc Improvements +- 'sort': Improve combat skill scale thresholds + # 50.09-r4 ## New Features From e25364266081bad2f612df062c5208a146c8c1ce Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 27 Sep 2023 02:23:08 +0000 Subject: [PATCH 628/851] 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 e6d83ccae..52fe6b277 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e6d83ccaee5b5a3c663b56046ae55a7389742da8 +Subproject commit 52fe6b27723ba7e3064ae03c1a7ae5712c3dc0ec diff --git a/scripts b/scripts index a8aacf9b3..4032be431 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit a8aacf9b3e8d71c338f8d087792ee8aa39a85220 +Subproject commit 4032be431a669ac822583dc3ccca3c6c07c8e3aa From de5b88c8c76541bff29831fc336bcc3dbd46101e Mon Sep 17 00:00:00 2001 From: Mikhail Panov Date: Wed, 27 Sep 2023 22:47:05 +0300 Subject: [PATCH 629/851] Added info about workorder-recheck removal to Removed.rst. --- docs/about/Removed.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index 4b61c951e..4d8f8fc6e 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -10,6 +10,13 @@ work (e.g. links from the `changelog`). :local: :depth: 1 +.. _workorder-recheck: + +workorder-recheck +================= +Tool to set 'Checking' status of the selected work order forcing manager to reevaluate its +conditions. Merged into `orders`. + .. _autohauler: autohauler From 32a2d9f9b5c94e3651943542d84c89a82ff4b77f Mon Sep 17 00:00:00 2001 From: Mikhail Date: Mon, 18 Sep 2023 12:49:36 +0300 Subject: [PATCH 630/851] Removed redundant uppercase in mental stability formula. Reworked thresholds for combat skill effectiveness formulas to have a higher 100 cap (more descriptive about very strong warriors). --- plugins/lua/sort.lua | 74 ++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 15d9ebabb..778bc87b9 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -212,7 +212,7 @@ local function melee_skill_effectiveness(unit) end local function get_melee_skill_effectiveness_rating(unit) - return get_rating(melee_skill_effectiveness(unit), 350000, 2350000, 78, 64, 49, 35) + return get_rating(melee_skill_effectiveness(unit), 350000, 2750000, 64, 52, 40, 28) end local function make_sort_by_melee_skill_effectiveness_desc() @@ -272,7 +272,7 @@ local function ranged_skill_effectiveness(unit) end local function get_ranged_skill_effectiveness_rating(unit) - return get_rating(ranged_skill_effectiveness(unit), 0, 500000, 90, 62, 44, 27) + return get_rating(ranged_skill_effectiveness(unit), 0, 800000, 72, 52, 31, 11) end local function make_sort_by_ranged_skill_effectiveness_desc(list) @@ -345,41 +345,41 @@ end -- Statistical rating that is higher for dwarves that are mentally stable local function get_mental_stability(unit) - local ALTRUISM = unit.status.current_soul.personality.traits.ALTRUISM - local ANXIETY_PROPENSITY = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY - local BRAVERY = unit.status.current_soul.personality.traits.BRAVERY - local CHEER_PROPENSITY = unit.status.current_soul.personality.traits.CHEER_PROPENSITY - local CURIOUS = unit.status.current_soul.personality.traits.CURIOUS - local DISCORD = unit.status.current_soul.personality.traits.DISCORD - local DUTIFULNESS = unit.status.current_soul.personality.traits.DUTIFULNESS - local EMOTIONALLY_OBSESSIVE = unit.status.current_soul.personality.traits.EMOTIONALLY_OBSESSIVE - local HUMOR = unit.status.current_soul.personality.traits.HUMOR - local LOVE_PROPENSITY = unit.status.current_soul.personality.traits.LOVE_PROPENSITY - local PERSEVERENCE = unit.status.current_soul.personality.traits.PERSEVERENCE - local POLITENESS = unit.status.current_soul.personality.traits.POLITENESS - local PRIVACY = unit.status.current_soul.personality.traits.PRIVACY - local STRESS_VULNERABILITY = unit.status.current_soul.personality.traits.STRESS_VULNERABILITY - local TOLERANT = unit.status.current_soul.personality.traits.TOLERANT - - local CRAFTSMANSHIP = setbelief.getUnitBelief(unit, df.value_type['CRAFTSMANSHIP']) - local FAMILY = setbelief.getUnitBelief(unit, df.value_type['FAMILY']) - local HARMONY = setbelief.getUnitBelief(unit, df.value_type['HARMONY']) - local INDEPENDENCE = setbelief.getUnitBelief(unit, df.value_type['INDEPENDENCE']) - local KNOWLEDGE = setbelief.getUnitBelief(unit, df.value_type['KNOWLEDGE']) - local LEISURE_TIME = setbelief.getUnitBelief(unit, df.value_type['LEISURE_TIME']) - local NATURE = setbelief.getUnitBelief(unit, df.value_type['NATURE']) - local SKILL = setbelief.getUnitBelief(unit, df.value_type['SKILL']) - - -- Calculate the rating using the defined variables - local rating = (CRAFTSMANSHIP * -0.01) + (FAMILY * -0.09) + (HARMONY * 0.05) - + (INDEPENDENCE * 0.06) + (KNOWLEDGE * -0.30) + (LEISURE_TIME * 0.24) - + (NATURE * 0.27) + (SKILL * -0.21) + (ALTRUISM * 0.13) - + (ANXIETY_PROPENSITY * -0.06) + (BRAVERY * 0.06) - + (CHEER_PROPENSITY * 0.41) + (CURIOUS * -0.06) + (DISCORD * 0.14) - + (DUTIFULNESS * -0.03) + (EMOTIONALLY_OBSESSIVE * -0.13) - + (HUMOR * -0.05) + (LOVE_PROPENSITY * 0.15) + (PERSEVERENCE * -0.07) - + (POLITENESS * -0.14) + (PRIVACY * 0.03) + (STRESS_VULNERABILITY * -0.20) - + (TOLERANT * -0.11) + local altruism = unit.status.current_soul.personality.traits.ALTRUISM + local anxiety_propensity = unit.status.current_soul.personality.traits.ANXIETY_PROPENSITY + local bravery = unit.status.current_soul.personality.traits.BRAVERY + local cheer_propensity = unit.status.current_soul.personality.traits.CHEER_PROPENSITY + local curious = unit.status.current_soul.personality.traits.CURIOUS + local discord = unit.status.current_soul.personality.traits.DISCORD + local dutifulness = unit.status.current_soul.personality.traits.DUTIFULNESS + local emotionally_obsessive = unit.status.current_soul.personality.traits.EMOTIONALLY_OBSESSIVE + local humor = unit.status.current_soul.personality.traits.HUMOR + local love_propensity = unit.status.current_soul.personality.traits.LOVE_PROPENSITY + local perseverence = unit.status.current_soul.personality.traits.PERSEVERENCE + local politeness = unit.status.current_soul.personality.traits.POLITENESS + local privacy = unit.status.current_soul.personality.traits.PRIVACY + local stress_vulnerability = unit.status.current_soul.personality.traits.STRESS_VULNERABILITY + local tolerant = unit.status.current_soul.personality.traits.TOLERANT + + local craftsmanship = setbelief.getUnitBelief(unit, df.value_type['CRAFTSMANSHIP']) + local family = setbelief.getUnitBelief(unit, df.value_type['FAMILY']) + local harmony = setbelief.getUnitBelief(unit, df.value_type['HARMONY']) + local independence = setbelief.getUnitBelief(unit, df.value_type['INDEPENDENCE']) + local knowledge = setbelief.getUnitBelief(unit, df.value_type['KNOWLEDGE']) + local leisure_time = setbelief.getUnitBelief(unit, df.value_type['LEISURE_TIME']) + local nature = setbelief.getUnitBelief(unit, df.value_type['NATURE']) + local skill = setbelief.getUnitBelief(unit, df.value_type['SKILL']) + + -- calculate the rating using the defined variables + local rating = (craftsmanship * -0.01) + (family * -0.09) + (harmony * 0.05) + + (independence * 0.06) + (knowledge * -0.30) + (leisure_time * 0.24) + + (nature * 0.27) + (skill * -0.21) + (altruism * 0.13) + + (anxiety_propensity * -0.06) + (bravery * 0.06) + + (cheer_propensity * 0.41) + (curious * -0.06) + (discord * 0.14) + + (dutifulness * -0.03) + (emotionally_obsessive * -0.13) + + (humor * -0.05) + (love_propensity * 0.15) + (perseverence * -0.07) + + (politeness * -0.14) + (privacy * 0.03) + (stress_vulnerability * -0.20) + + (tolerant * -0.11) return rating end From 73fed1e833b6ce5d76459721d77bd08c1c3660c6 Mon Sep 17 00:00:00 2001 From: Mikhail Panov Date: Tue, 26 Sep 2023 17:54:34 +0300 Subject: [PATCH 631/851] Updated changelog.txt --- docs/changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 9efb86430..f5907f4cc 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -75,6 +75,9 @@ Template for new versions: - Linux launcher: allow Steam Overlay and game streaming to function - `autobutcher`: don't ignore semi-wild units when marking units for slaughter +## Misc Improvements +- 'sort': Improve combat skill scale thresholds + # 50.09-r4 ## New Features From 6ad724b4831f19f46ae62bede574e1817c3ba21c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 26 Sep 2023 03:45:15 -0700 Subject: [PATCH 632/851] add detailed focus strings for setupdwarfgame --- library/modules/Gui.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 9eee284ac..58763262f 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -87,6 +87,7 @@ using namespace DFHack; #include "df/viewscreen_dwarfmodest.h" #include "df/viewscreen_legendsst.h" #include "df/viewscreen_new_regionst.h" +#include "df/viewscreen_setupdwarfgamest.h" #include "df/viewscreen_titlest.h" #include "df/world.h" @@ -174,6 +175,45 @@ DEFINE_GET_FOCUS_STRING_HANDLER(new_region) focusStrings.push_back(baseFocus); } +DEFINE_GET_FOCUS_STRING_HANDLER(setupdwarfgame) +{ + if (screen->doing_custom_settings) + focusStrings.push_back(baseFocus + "/CustomSettings"); + else if (game->main_interface.options.open) + focusStrings.push_back(baseFocus + "/Abort"); + else if (screen->initial_selection == 1) + focusStrings.push_back(baseFocus + "/Default"); + else if (game->main_interface.name_creator.open) { + switch (game->main_interface.name_creator.context) { + case df::name_creator_context_type::EMBARK_FORT_NAME: + focusStrings.push_back(baseFocus + "/FortName"); + break; + case df::name_creator_context_type::EMBARK_GROUP_NAME: + focusStrings.push_back(baseFocus + "/GroupName"); + break; + default: + break; + } + } + else if (game->main_interface.image_creator.open) { + focusStrings.push_back(baseFocus + "/GroupSymbol"); + } + else if (screen->viewing_objections != 0) + focusStrings.push_back(baseFocus + "/Objections"); + else { + switch (screen->mode) { + case 0: focusStrings.push_back(baseFocus + "/Dwarves"); break; + case 1: focusStrings.push_back(baseFocus + "/Items"); break; + case 2: focusStrings.push_back(baseFocus + "/Animals"); break; + default: + break; + } + } + + if (focusStrings.empty()) + focusStrings.push_back(baseFocus + "/Default"); +} + DEFINE_GET_FOCUS_STRING_HANDLER(legends) { if (screen->init_stage != -1) From 5c670d20db0b7d1387c60c9d4ecb32d488f20792 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 26 Sep 2023 03:52:24 -0700 Subject: [PATCH 633/851] align mouse button semantics to DF we, um, had it backwards --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 4 +- library/LuaTools.cpp | 72 +++++++++---------- library/lua/gui.lua | 23 ++---- library/lua/gui/dialogs.lua | 8 +-- library/lua/gui/widgets.lua | 37 +++++----- library/modules/Screen.cpp | 10 +++ plugins/lua/buildingplan/inspectoroverlay.lua | 4 +- plugins/lua/buildingplan/itemselection.lua | 4 +- plugins/lua/buildingplan/planneroverlay.lua | 8 +-- plugins/lua/hotkeys.lua | 8 +-- plugins/lua/overlay.lua | 3 - plugins/lua/sort.lua | 4 +- plugins/lua/zone.lua | 9 ++- test/library/gui/widgets.EditField.lua | 6 +- test/library/gui/widgets.Scrollbar.lua | 18 ++--- test/library/gui/widgets.lua | 4 +- 17 files changed, 110 insertions(+), 113 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index f5907f4cc..aec12a96f 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -66,6 +66,7 @@ Template for new versions: ## API ## Lua +- mouse key events are now aligned with internal DF semantics: ``_MOUSE_L`` indicates that the left mouse button has just been pressed and ``_MOUSE_L_DOWN`` indicates that the left mouse button is being held down. similar for ``_MOUSE_R`` and ``_MOUSE_M``. 3rd party scripts may have to adjust. ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 1cba8284e..6eeb2dbe7 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2528,10 +2528,10 @@ Supported callbacks and fields are: Maps to an integer in range 0-255. Duplicates a separate "STRING_A???" code for convenience. ``_MOUSE_L, _MOUSE_R, _MOUSE_M`` - If the left, right, and/or middle mouse button is being pressed. + If the left, right, and/or middle mouse button was just pressed. ``_MOUSE_L_DOWN, _MOUSE_R_DOWN, _MOUSE_M_DOWN`` - If the left, right, and/or middle mouse button was just pressed. + If the left, right, and/or middle mouse button is being held down. If this method is omitted, the screen is dismissed on reception of the ``LEAVESCREEN`` key. diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index ffeb4980a..87699641d 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -131,12 +131,12 @@ void DFHack::Lua::GetVector(lua_State *state, std::vector &pvec, in } } -static bool trigger_inhibit_l_down = false; -static bool trigger_inhibit_r_down = false; -static bool trigger_inhibit_m_down = false; -static bool inhibit_l_down = false; -static bool inhibit_r_down = false; -static bool inhibit_m_down = false; +static bool trigger_inhibit_l = false; +static bool trigger_inhibit_r = false; +static bool trigger_inhibit_m = false; +static bool inhibit_l = false; +static bool inhibit_r = false; +static bool inhibit_m = false; void DFHack::Lua::PushInterfaceKeys(lua_State *L, const std::set &keys) { @@ -161,32 +161,32 @@ void DFHack::Lua::PushInterfaceKeys(lua_State *L, } if (df::global::enabler) { - if (!inhibit_l_down && df::global::enabler->mouse_lbut_down) { + if (!inhibit_l && df::global::enabler->mouse_lbut) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_L_DOWN"); - trigger_inhibit_l_down = true; + lua_setfield(L, -2, "_MOUSE_L"); + trigger_inhibit_l = true; } - if (!inhibit_r_down && df::global::enabler->mouse_rbut_down) { + if (!inhibit_r && df::global::enabler->mouse_rbut) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_R_DOWN"); - trigger_inhibit_r_down = true; + lua_setfield(L, -2, "_MOUSE_R"); + trigger_inhibit_r = true; } - if (!inhibit_m_down && df::global::enabler->mouse_mbut_down) { + if (!inhibit_m && df::global::enabler->mouse_mbut) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_M_DOWN"); - trigger_inhibit_m_down = true; + lua_setfield(L, -2, "_MOUSE_M"); + trigger_inhibit_m = true; } - if (df::global::enabler->mouse_lbut) { + if (df::global::enabler->mouse_lbut_down) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_L"); + lua_setfield(L, -2, "_MOUSE_L_DOWN"); } - if (df::global::enabler->mouse_rbut) { + if (df::global::enabler->mouse_rbut_down) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_R"); + lua_setfield(L, -2, "_MOUSE_R_DOWN"); } - if (df::global::enabler->mouse_mbut) { + if (df::global::enabler->mouse_mbut_down) { lua_pushboolean(L, true); - lua_setfield(L, -2, "_MOUSE_M"); + lua_setfield(L, -2, "_MOUSE_M_DOWN"); } } } @@ -2159,25 +2159,25 @@ void DFHack::Lua::Core::Reset(color_ostream &out, const char *where) lua_settop(State, 0); } - if (trigger_inhibit_l_down) { - trigger_inhibit_l_down = false; - inhibit_l_down = true; + if (trigger_inhibit_l) { + trigger_inhibit_l = false; + inhibit_l = true; } - if (trigger_inhibit_r_down) { - trigger_inhibit_r_down = false; - inhibit_r_down = true; + if (trigger_inhibit_r) { + trigger_inhibit_r = false; + inhibit_r = true; } - if (trigger_inhibit_m_down) { - trigger_inhibit_m_down = false; - inhibit_m_down = true; + if (trigger_inhibit_m) { + trigger_inhibit_m = false; + inhibit_m = true; } if (df::global::enabler) { - if (!df::global::enabler->mouse_lbut) - inhibit_l_down = false; - if (!df::global::enabler->mouse_rbut) - inhibit_r_down = false; - if (!df::global::enabler->mouse_mbut) - inhibit_m_down = false; + if (!df::global::enabler->mouse_lbut_down) + inhibit_l = false; + if (!df::global::enabler->mouse_rbut_down) + inhibit_r = false; + if (!df::global::enabler->mouse_mbut_down) + inhibit_m = false; } } diff --git a/library/lua/gui.lua b/library/lua/gui.lua index bba7222b9..ba49e0cdc 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -696,16 +696,12 @@ end DEFAULT_INITIAL_PAUSE = true -local zscreen_inhibit_mouse_l = false - -- ensure underlying DF screens don't also react to handled clicks function markMouseClicksHandled(keys) - if keys._MOUSE_L_DOWN then - -- note we can't clear mouse_lbut here. otherwise we break dragging, - df.global.enabler.mouse_lbut_down = 0 - zscreen_inhibit_mouse_l = true + if keys._MOUSE_L then + df.global.enabler.mouse_lbut = 0 end - if keys._MOUSE_R_DOWN then + if keys._MOUSE_R then df.global.enabler.mouse_rbut_down = 0 df.global.enabler.mouse_rbut = 0 end @@ -789,7 +785,7 @@ function ZScreen:onInput(keys) local has_mouse = self:isMouseOver() if not self:hasFocus() then if has_mouse and - (keys._MOUSE_L_DOWN or keys._MOUSE_R_DOWN or + (keys._MOUSE_L or keys._MOUSE_R or keys.CONTEXT_SCROLL_UP or keys.CONTEXT_SCROLL_DOWN or keys.CONTEXT_SCROLL_PAGEUP or keys.CONTEXT_SCROLL_PAGEDOWN) then self:raise() @@ -804,22 +800,15 @@ function ZScreen:onInput(keys) return end - if self.pass_mouse_clicks and keys._MOUSE_L_DOWN and not has_mouse then + if self.pass_mouse_clicks and keys._MOUSE_L and not has_mouse then self.defocused = self.defocusable self:sendInputToParent(keys) return - elseif keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + elseif keys.LEAVESCREEN or keys._MOUSE_R then self:dismiss() markMouseClicksHandled(keys) return else - if zscreen_inhibit_mouse_l then - if keys._MOUSE_L then - return - else - zscreen_inhibit_mouse_l = false - end - 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 or diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua index 499fa6305..95a56d0c4 100644 --- a/library/lua/gui/dialogs.lua +++ b/library/lua/gui/dialogs.lua @@ -57,11 +57,11 @@ function MessageBox:onDestroy() end function MessageBox:onInput(keys) - if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R then self:dismiss() if keys.SELECT and self.on_accept then self.on_accept() - elseif (keys.LEAVESCREEN or keys._MOUSE_R_DOWN) and self.on_cancel then + elseif (keys.LEAVESCREEN or keys._MOUSE_R) and self.on_cancel then self.on_cancel() end gui.markMouseClicksHandled(keys) @@ -129,7 +129,7 @@ function InputBox:onInput(keys) self.on_input(self.subviews.edit.text) end return true - elseif keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + elseif keys.LEAVESCREEN or keys._MOUSE_R then self:dismiss() if self.on_cancel then self.on_cancel() @@ -231,7 +231,7 @@ function ListBox:getWantedFrameSize() end function ListBox:onInput(keys) - if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.LEAVESCREEN or keys._MOUSE_R then self:dismiss() if self.on_cancel then self.on_cancel() diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 6a0a0091b..05d237f35 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -273,7 +273,7 @@ end function Panel:onInput(keys) if self.kbd_get_pos then - if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.SELECT or keys.LEAVESCREEN or keys._MOUSE_R then Panel_end_drag(self, not keys.SELECT and self.saved_frame or nil, not not keys.SELECT) return true @@ -281,7 +281,6 @@ function Panel:onInput(keys) for code in pairs(keys) do local dx, dy = guidm.get_movement_delta(code, 1, 10) if dx then - local frame_rect = self.frame_rect local kbd_pos = self.kbd_get_pos() kbd_pos.x = kbd_pos.x + dx kbd_pos.y = kbd_pos.y + dy @@ -292,9 +291,9 @@ function Panel:onInput(keys) return end if self.drag_offset then - if keys._MOUSE_R_DOWN then + if keys._MOUSE_R then Panel_end_drag(self, self.saved_frame) - elseif keys._MOUSE_L then + elseif keys._MOUSE_L_DOWN then Panel_update_frame(self, Panel_make_frame(self)) end return true @@ -302,7 +301,7 @@ function Panel:onInput(keys) if Panel.super.onInput(self, keys) then return true end - if not keys._MOUSE_L_DOWN then return end + if not keys._MOUSE_L then return end local x,y = self:getMouseFramePos() if not x then return end @@ -489,7 +488,7 @@ function Panel:onRenderFrame(dc, rect) dc:seek(pos.x, pos.y):pen(pen):char(string.char(0xDB)) end if self.drag_offset and not self.kbd_get_pos - and df.global.enabler.mouse_lbut == 0 then + and df.global.enabler.mouse_lbut_down == 0 then Panel_end_drag(self, nil, true) end end @@ -718,7 +717,7 @@ function EditField:onInput(keys) end end - if self.key and (keys.LEAVESCREEN or keys._MOUSE_R_DOWN) then + if self.key and (keys.LEAVESCREEN or keys._MOUSE_R) then self:setText(self.saved_text) self:setFocus(false) return true @@ -740,8 +739,8 @@ function EditField:onInput(keys) end end return not not self.key - elseif keys._MOUSE_L then - local mouse_x, mouse_y = self:getMousePos() + elseif keys._MOUSE_L_DOWN then + local mouse_x = self:getMousePos() if mouse_x then self:setCursor(self.start_pos + mouse_x - (self.text_offset or 0)) return true @@ -986,7 +985,7 @@ function Scrollbar:onRenderBody(dc) if self.is_dragging then scrollbar_do_drag(self) end - if df.global.enabler.mouse_lbut == 0 then + if df.global.enabler.mouse_lbut_down == 0 then self.last_scroll_ms = 0 self.is_dragging = false self.scroll_spec = nil @@ -1023,7 +1022,7 @@ function Scrollbar:onInput(keys) return true end end - if not keys._MOUSE_L_DOWN then return false end + if not keys._MOUSE_L then return false end local _,y = self:getMousePos() if not y then return false end local scroll_spec = nil @@ -1386,11 +1385,11 @@ function Label:onInput(keys) if self:inputToSubviews(keys) then return true end - if keys._MOUSE_L_DOWN and self:getMousePos() and self.on_click then + if keys._MOUSE_L and self:getMousePos() and self.on_click then self.on_click() return true end - if keys._MOUSE_R_DOWN and self:getMousePos() and self.on_rclick then + if keys._MOUSE_R and self:getMousePos() and self.on_rclick then self.on_rclick() return true end @@ -1498,7 +1497,7 @@ end function HotkeyLabel:onInput(keys) if HotkeyLabel.super.onInput(self, keys) then return true - elseif keys._MOUSE_L_DOWN and self:getMousePos() and self.on_activate + elseif keys._MOUSE_L and self:getMousePos() and self.on_activate and not is_disabled(self) then self.on_activate() return true @@ -1658,7 +1657,7 @@ end function CycleHotkeyLabel:onInput(keys) if CycleHotkeyLabel.super.onInput(self, keys) then return true - elseif keys._MOUSE_L_DOWN and self:getMousePos() and not is_disabled(self) then + elseif keys._MOUSE_L and self:getMousePos() and not is_disabled(self) then self:cycle() return true end @@ -1962,7 +1961,7 @@ function List:onInput(keys) return self:submit() elseif keys.CUSTOM_SHIFT_ENTER then return self:submit2() - elseif keys._MOUSE_L_DOWN then + elseif keys._MOUSE_L then local idx = self:getIdxUnderMouse() if idx then local now_ms = dfhack.getTickCount() @@ -2317,7 +2316,7 @@ end function Tab:onInput(keys) if Tab.super.onInput(self, keys) then return true end - if keys._MOUSE_L_DOWN and self:getMousePos() then + if keys._MOUSE_L and self:getMousePos() then self.on_select(self.id) return true end @@ -2419,7 +2418,7 @@ local function rangeslider_get_width_per_idx(self) end function RangeSlider:onInput(keys) - if not keys._MOUSE_L_DOWN then return false end + if not keys._MOUSE_L 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() @@ -2527,7 +2526,7 @@ function RangeSlider:onRenderBody(dc, rect) if self.is_dragging_target then rangeslider_do_drag(self, width_per_idx) end - if df.global.enabler.mouse_lbut == 0 then + if df.global.enabler.mouse_lbut_down == 0 then self.is_dragging_target = nil self.is_dragging_idx = nil end diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index 5f98c40e5..a5b347493 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -1004,6 +1004,8 @@ dfhack_lua_viewscreen::~dfhack_lua_viewscreen() void dfhack_lua_viewscreen::render() { + using df::global::enabler; + if (Screen::isDismissed(this)) { if (parent) @@ -1011,6 +1013,14 @@ void dfhack_lua_viewscreen::render() return; } + if (enabler && + (enabler->mouse_lbut_down || enabler->mouse_rbut_down || enabler->mouse_mbut_down)) + { + // synthesize feed events for held mouse buttons + std::set keys; + feed(&keys); + } + dfhack_viewscreen::render(); safe_call_lua(do_render, 0, 0); diff --git a/plugins/lua/buildingplan/inspectoroverlay.lua b/plugins/lua/buildingplan/inspectoroverlay.lua index 1fcf19028..3c6f0ed5e 100644 --- a/plugins/lua/buildingplan/inspectoroverlay.lua +++ b/plugins/lua/buildingplan/inspectoroverlay.lua @@ -127,9 +127,9 @@ function InspectorOverlay:onInput(keys) if not require('plugins.buildingplan').isPlannedBuilding(dfhack.gui.getSelectedBuilding(true)) then return false end - if keys._MOUSE_L_DOWN and mouse_is_over_resume_button(self.frame_parent_rect) then + if keys._MOUSE_L and mouse_is_over_resume_button(self.frame_parent_rect) then return true - elseif keys._MOUSE_L_DOWN or keys._MOUSE_R_DOWN or keys.LEAVESCREEN then + elseif keys._MOUSE_L or keys._MOUSE_R or keys.LEAVESCREEN then self:reset() end return InspectorOverlay.super.onInput(self, keys) diff --git a/plugins/lua/buildingplan/itemselection.lua b/plugins/lua/buildingplan/itemselection.lua index 84e866502..9dfd0cc69 100644 --- a/plugins/lua/buildingplan/itemselection.lua +++ b/plugins/lua/buildingplan/itemselection.lua @@ -366,10 +366,10 @@ function ItemSelection:submit(choices) end function ItemSelection:onInput(keys) - if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.LEAVESCREEN or keys._MOUSE_R then self.on_cancel() return true - elseif keys._MOUSE_L_DOWN then + elseif keys._MOUSE_L then local list = self.subviews.flist.list local idx = list:getIdxUnderMouse() if idx then diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index ebd8e6e02..2cc15dfde 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -272,7 +272,7 @@ function ItemLine:reset() end function ItemLine:onInput(keys) - if keys._MOUSE_L_DOWN and self:getMousePos() then + if keys._MOUSE_L and self:getMousePos() then self.on_select(self.idx) end return ItemLine.super.onInput(self, keys) @@ -739,7 +739,7 @@ end function PlannerOverlay:onInput(keys) if not is_plannable() then return false end - if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.LEAVESCREEN or keys._MOUSE_R then if uibs.selection_pos:isValid() then uibs.selection_pos:clear() return true @@ -758,7 +758,7 @@ function PlannerOverlay:onInput(keys) return true end if self:is_minimized() then return false end - if keys._MOUSE_L_DOWN then + if keys._MOUSE_L then if is_over_options_panel() then return false end local detect_rect = copyall(self.frame_rect) detect_rect.height = self.subviews.main.frame_rect.height + @@ -828,7 +828,7 @@ function PlannerOverlay:onInput(keys) end end end - return keys._MOUSE_L or keys.SELECT + return keys._MOUSE_L_DOWN or keys.SELECT end function PlannerOverlay:render(dc) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 8eff17aae..80f8816e8 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -269,24 +269,24 @@ function Menu:onSubmit2(_, choice) end function Menu:onInput(keys) - if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + if keys.LEAVESCREEN or keys._MOUSE_R then return false elseif keys.KEYBOARD_CURSOR_RIGHT then self:onSubmit2(self.subviews.list:getSelected()) return true - elseif keys._MOUSE_L_DOWN then + elseif keys._MOUSE_L then local list = self.subviews.list local x = list:getMousePos() if x == 0 then -- clicked on icon self:onSubmit2(list:getSelected()) - df.global.enabler.mouse_lbut = 0 + gui.markMouseClicksHandled(keys) return true end if not self:getMouseFramePos() then self.parent_view:dismiss() return true end - df.global.enabler.mouse_lbut = 0 + gui.markMouseClicksHandled(keys) end self:inputToSubviews(keys) return true -- we're modal diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index d3f0b9c9d..cd5286d0d 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -507,9 +507,6 @@ function feed_viewscreen_widgets(vs_name, vs, keys) return false end gui.markMouseClicksHandled(keys) - if keys._MOUSE_L_DOWN then - df.global.enabler.mouse_lbut = 0 - end return true end diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 778bc87b9..6d8c8a298 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1148,9 +1148,7 @@ function SquadAssignmentOverlay:refresh_list(sort_widget, sort_fn) end function SquadAssignmentOverlay:onInput(keys) - if keys._MOUSE_R_DOWN or - keys._MOUSE_L_DOWN and not self:getMouseFramePos() - then + if keys._MOUSE_R or (keys._MOUSE_L and not self:getMouseFramePos()) then -- if any click is made outside of our window, we may need to refresh our list self.dirty = true end diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 3c07b609f..13182cef1 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -801,10 +801,12 @@ end function AssignAnimalScreen:onInput(keys) local handled = AssignAnimalScreen.super.onInput(self, keys) if not self.is_valid_ui_state() then - view:dismiss() + if view then + view:dismiss() + end return end - if keys._MOUSE_L_DOWN then + if keys._MOUSE_L then -- if any click is made outside of our window, we need to recheck unit properties local window = self.subviews[1] if not window:getMouseFramePos() then @@ -818,7 +820,7 @@ function AssignAnimalScreen:onInput(keys) end function AssignAnimalScreen:onRenderFrame() - if not self.is_valid_ui_state() then + if view and not self.is_valid_ui_state() then view:dismiss() end end @@ -1072,6 +1074,7 @@ function CageChainOverlay:init() frame={t=0, l=0, r=0, h=1}, label='DFHack assign', key='CUSTOM_CTRL_T', + visible=is_valid_building, on_activate=function() view = view and view:raise() or show_cage_chain_screen() end, }, } diff --git a/test/library/gui/widgets.EditField.lua b/test/library/gui/widgets.EditField.lua index 88625a7bf..8418b67d4 100644 --- a/test/library/gui/widgets.EditField.lua +++ b/test/library/gui/widgets.EditField.lua @@ -42,17 +42,17 @@ function test.editfield_click() expect.eq(5, e.cursor) mock.patch(e, 'getMousePos', mock.func(0), function() - e:onInput{_MOUSE_L=true} + e:onInput{_MOUSE_L_DOWN=true} expect.eq(1, e.cursor) end) mock.patch(e, 'getMousePos', mock.func(20), function() - e:onInput{_MOUSE_L=true} + e:onInput{_MOUSE_L_DOWN=true} expect.eq(5, e.cursor, 'should only seek to end of text') end) mock.patch(e, 'getMousePos', mock.func(2), function() - e:onInput{_MOUSE_L=true} + e:onInput{_MOUSE_L_DOWN=true} expect.eq(3, e.cursor) end) end diff --git a/test/library/gui/widgets.Scrollbar.lua b/test/library/gui/widgets.Scrollbar.lua index 548792b3d..dd490256c 100644 --- a/test/library/gui/widgets.Scrollbar.lua +++ b/test/library/gui/widgets.Scrollbar.lua @@ -59,37 +59,37 @@ function test.onInput() s:update(23, 10, 50) expect.false_(s:onInput{}, 'no mouse down') - expect.false_(s:onInput{_MOUSE_L_DOWN=true}, 'no y coord') + expect.false_(s:onInput{_MOUSE_L=true}, 'no y coord') spec, y = nil, 0 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('up_small', spec, 'on up arrow') spec, y = nil, 1 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('up_large', spec, 'on body above bar') spec, y = nil, 44 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('up_large', spec, 'on body just above bar') spec, y = nil, 45 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.nil_(spec, 'on top of bar') spec, y = nil, 63 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.nil_(spec, 'on bottom of bar') spec, y = nil, 64 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('down_large', spec, 'on body just below bar') spec, y = nil, 98 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('down_large', spec, 'on body below bar') spec, y = nil, 99 - expect.true_(s:onInput{_MOUSE_L_DOWN=true}) + expect.true_(s:onInput{_MOUSE_L=true}) expect.eq('down_small', spec, 'on down arrow') end diff --git a/test/library/gui/widgets.lua b/test/library/gui/widgets.lua index 88d3ac952..b37fbe04d 100644 --- a/test/library/gui/widgets.lua +++ b/test/library/gui/widgets.lua @@ -7,7 +7,7 @@ function test.hotkeylabel_click() local l = widgets.HotkeyLabel{key='SELECT', on_activate=func} mock.patch(l, 'getMousePos', mock.func(0), function() - l:onInput{_MOUSE_L_DOWN=true} + l:onInput{_MOUSE_L=true} expect.eq(1, func.call_count) end) end @@ -33,7 +33,7 @@ function test.togglehotkeylabel_click() local l = widgets.ToggleHotkeyLabel{} expect.true_(l:getOptionValue()) mock.patch(l, 'getMousePos', mock.func(0), function() - l:onInput{_MOUSE_L_DOWN=true} + l:onInput{_MOUSE_L=true} expect.false_(l:getOptionValue()) end) end From 888c88dfcf7399663ae4066dd419292c9e836b70 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 27 Sep 2023 02:23:08 +0000 Subject: [PATCH 634/851] 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 e6d83ccae..52fe6b277 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e6d83ccaee5b5a3c663b56046ae55a7389742da8 +Subproject commit 52fe6b27723ba7e3064ae03c1a7ae5712c3dc0ec diff --git a/scripts b/scripts index a8aacf9b3..4032be431 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit a8aacf9b3e8d71c338f8d087792ee8aa39a85220 +Subproject commit 4032be431a669ac822583dc3ccca3c6c07c8e3aa From f5aab7ee45f2d14542b793a6972271d95e84408d Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Wed, 27 Sep 2023 20:32:46 +0100 Subject: [PATCH 635/851] pulled event handler calls out of the loops over global vectors to avoid potential iterator invalidation by an event callback, and did some tidying --- library/modules/EventManager.cpp | 279 ++++++++++++++++++------------- 1 file changed, 164 insertions(+), 115 deletions(-) diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index 02b1892e9..ddc46942d 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -43,6 +43,7 @@ #include #include #include +#include namespace DFHack { DBG_DECLARE(eventmanager, log, DebugCategory::LINFO); @@ -246,6 +247,15 @@ static int32_t reportToRelevantUnitsTime = -1; //interaction static int32_t lastReportInteraction; +struct hash_pair { + template + size_t operator()(const std::pair& p) const { + auto h1 = std::hash{}(p.first); + auto h2 = std::hash{}(p.second); + return h1 ^ (h2 << 1); + } +}; + void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event event) { static bool doOnce = false; // const string eventNames[] = {"world loaded", "world unloaded", "map loaded", "map unloaded", "viewscreen changed", "core initialized", "begin unload", "paused", "unpaused"}; @@ -276,9 +286,9 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event gameLoaded = false; multimap copy(handlers[EventType::UNLOAD].begin(), handlers[EventType::UNLOAD].end()); - for (auto &key_value : copy) { + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for map unloaded state change event\n"); - key_value.second.eventHandler(out, nullptr); + handle.eventHandler(out, nullptr); } } else if ( event == DFHack::SC_MAP_LOADED ) { /* @@ -375,8 +385,7 @@ void DFHack::EventManager::manageEvents(color_ostream& out) { continue; int32_t eventFrequency = -100; if ( a != EventType::TICK ) - for (auto &key_value : handlers[a]) { - EventHandler &handle = key_value.second; + for (auto &[_,handle] : handlers[a]) { if (handle.freq < eventFrequency || eventFrequency == -100 ) eventFrequency = handle.freq; } @@ -439,8 +448,7 @@ static void manageJobInitiatedEvent(color_ostream& out) { continue; if ( link->item->id <= lastJobId ) continue; - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for job initiated event\n"); handle.eventHandler(out, (void*)link->item); } @@ -455,18 +463,21 @@ static void manageJobStartedEvent(color_ostream& out) { static unordered_set startedJobs; + vector new_started_jobs; // iterate event handler callbacks multimap copy(handlers[EventType::JOB_STARTED].begin(), handlers[EventType::JOB_STARTED].end()); for (df::job_list_link* link = df::global::world->jobs.list.next; link != nullptr; link = link->next) { df::job* job = link->item; if (job && Job::getWorker(job) && !startedJobs.count(job->id)) { startedJobs.emplace(job->id); - for (auto &key_value : copy) { - auto &handler = key_value.second; - // the jobs must have a worker to start - DEBUG(log,out).print("calling handler for job started event\n"); - handler.eventHandler(out, job); - } + new_started_jobs.emplace_back(job); + } + } + for (df::job* job : new_started_jobs) { + for (auto &[_,handle] : copy) { + // the jobs must have a worker to start + DEBUG(log,out).print("calling handler for job started event\n"); + handle.eventHandler(out, job); } } } @@ -556,6 +567,8 @@ static void manageJobCompletedEvent(color_ostream& out) { } #endif + vector new_jobs_completed; + vector new_jobs_completed_repeats; for (auto &prevJob : prevJobs) { //if it happened within a tick, must have been cancelled by the user or a plugin: not completed if ( tick1 <= tick0 ) @@ -573,11 +586,7 @@ static void manageJobCompletedEvent(color_ostream& out) { continue; //still false positive if cancelled at EXACTLY the right time, but experiments show this doesn't happen - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; - DEBUG(log,out).print("calling handler for repeated job completed event\n"); - handle.eventHandler(out, (void*)&job0); - } + new_jobs_completed_repeats.emplace_back(&job0); continue; } @@ -586,10 +595,19 @@ static void manageJobCompletedEvent(color_ostream& out) { if ( job0.flags.bits.repeat || job0.completion_timer != 0 ) continue; - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + new_jobs_completed.emplace_back(&job0); + } + + for (df::job* job : new_jobs_completed_repeats) { + for (auto &[_,handle] : copy) { + DEBUG(log,out).print("calling handler for repeated job completed event\n"); + handle.eventHandler(out, (void*) job); + } + } + for (df::job* job : new_jobs_completed) { + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for job completed event\n"); - handle.eventHandler(out, (void*)&job0); + handle.eventHandler(out, (void*) job); } } @@ -617,15 +635,17 @@ static void manageNewUnitActiveEvent(color_ostream& out) { multimap copy(handlers[EventType::UNIT_NEW_ACTIVE].begin(), handlers[EventType::UNIT_NEW_ACTIVE].end()); // iterate event handler callbacks - for (auto &key_value : copy) { - auto &handler = key_value.second; - for (df::unit* unit : df::global::world->units.active) { - int32_t id = unit->id; - if (!activeUnits.count(id)) { - activeUnits.emplace(id); - DEBUG(log,out).print("calling handler for new unit event\n"); - handler.eventHandler(out, (void*) intptr_t(id)); // intptr_t() avoids cast from smaller type warning - } + vector new_active_unit_ids; + for (df::unit* unit : df::global::world->units.active) { + if (!activeUnits.count(unit->id)) { + activeUnits.emplace(unit->id); + new_active_unit_ids.emplace_back(unit->id); + } + } + for (int32_t unit_id : new_active_unit_ids) { + for (auto &[_,handle] : copy) { + DEBUG(log,out).print("calling handler for new unit event\n"); + handle.eventHandler(out, (void*) intptr_t(unit_id)); // intptr_t() avoids cast from smaller type warning } } } @@ -635,6 +655,7 @@ static void manageUnitDeathEvent(color_ostream& out) { if (!df::global::world) return; multimap copy(handlers[EventType::UNIT_DEATH].begin(), handlers[EventType::UNIT_DEATH].end()); + vector dead_unit_ids; for (auto unit : df::global::world->units.all) { //if ( unit->counters.death_id == -1 ) { if ( Units::isActive(unit) ) { @@ -644,13 +665,15 @@ static void manageUnitDeathEvent(color_ostream& out) { //dead: if dead since last check, trigger events if ( livingUnits.find(unit->id) == livingUnits.end() ) continue; + livingUnits.erase(unit->id); + dead_unit_ids.emplace_back(unit->id); + } - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + for (int32_t unit_id : dead_unit_ids) { + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for unit death event\n"); - handle.eventHandler(out, (void*)intptr_t(unit->id)); + handle.eventHandler(out, (void*)intptr_t(unit_id)); } - livingUnits.erase(unit->id); } } @@ -666,6 +689,8 @@ static void manageItemCreationEvent(color_ostream& out) { multimap copy(handlers[EventType::ITEM_CREATED].begin(), handlers[EventType::ITEM_CREATED].end()); size_t index = df::item::binsearch_index(df::global::world->items.all, nextItem, false); if ( index != 0 ) index--; + + std::vector created_items; for ( size_t a = index; a < df::global::world->items.all.size(); a++ ) { df::item* item = df::global::world->items.all[a]; //already processed @@ -683,12 +708,17 @@ static void manageItemCreationEvent(color_ostream& out) { //spider webs don't count if ( item->flags.bits.spider_web ) continue; - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + created_items.push_back(item->id); + } + + // handle all created items + for (int32_t item_id : created_items) { + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for item created event\n"); - handle.eventHandler(out, (void*)intptr_t(item->id)); + handle.eventHandler(out, (void*)intptr_t(item_id)); } } + nextItem = *df::global::item_next_id; } @@ -703,6 +733,7 @@ static void manageBuildingEvent(color_ostream& out) { **/ multimap copy(handlers[EventType::BUILDING].begin(), handlers[EventType::BUILDING].end()); //first alert people about new buildings + vector new_buildings; for ( int32_t a = nextBuilding; a < *df::global::building_next_id; a++ ) { int32_t index = df::building::binsearch_index(df::global::world->buildings.all, a); if ( index == -1 ) { @@ -711,29 +742,32 @@ static void manageBuildingEvent(color_ostream& out) { continue; } buildings.insert(a); - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; - DEBUG(log,out).print("calling handler for created building event\n"); - handle.eventHandler(out, (void*)intptr_t(a)); - } + new_buildings.emplace_back(a); + } nextBuilding = *df::global::building_next_id; + std::for_each(new_buildings.begin(), new_buildings.end(), [&](int32_t building){ + for (auto &[_,handle] : copy) { + DEBUG(log,out).print("calling handler for created building event\n"); + handle.eventHandler(out, (void*)intptr_t(building)); + } + }); + //now alert people about destroyed buildings - for ( auto a = buildings.begin(); a != buildings.end(); ) { - int32_t id = *a; + for ( auto it = buildings.begin(); it != buildings.end(); ) { + int32_t id = *it; int32_t index = df::building::binsearch_index(df::global::world->buildings.all,id); if ( index != -1 ) { - a++; + ++it; continue; } - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for destroyed building event\n"); handle.eventHandler(out, (void*)intptr_t(id)); } - a = buildings.erase(a); + it = buildings.erase(it); } } @@ -743,35 +777,41 @@ static void manageConstructionEvent(color_ostream& out) { //unordered_set constructionsNow(df::global::world->constructions.begin(), df::global::world->constructions.end()); multimap copy(handlers[EventType::CONSTRUCTION].begin(), handlers[EventType::CONSTRUCTION].end()); - // find & send construction removals - for (auto iter = constructions.begin(); iter != constructions.end();) { - auto &construction = *iter; - // if we can't find it, it was removed - if (df::construction::find(construction.pos) != nullptr) { - ++iter; - continue; + + unordered_set next_construction_set; // will be swapped with constructions + next_construction_set.reserve(constructions.bucket_count()); + vector new_constructions; + + // find new constructions - swapping found constructions over from constructions to next_construction_set + for (auto c : df::global::world->constructions) { + auto &construction = *c; + auto it = constructions.find(construction); + if (it == constructions.end()) { + // handle new construction event later + new_constructions.emplace_back(construction); } - // send construction to handlers, because it was removed - for (const auto &key_value: copy) { - EventHandler handle = key_value.second; + else { + constructions.erase(it); + } + next_construction_set.emplace(construction); + } + + constructions.swap(next_construction_set); + + // now next_construction_set contains all the constructions that were removed (not found in df::global::world->constructions) + for (auto& construction : next_construction_set) { + // handle construction removed event + for (const auto &[_,handle]: copy) { DEBUG(log,out).print("calling handler for destroyed construction event\n"); handle.eventHandler(out, (void*) &construction); } - // erase from existent constructions - iter = constructions.erase(iter); } - // find & send construction additions - for (auto c: df::global::world->constructions) { - auto &construction = *c; - // add construction to constructions, if it isn't already present - if (constructions.emplace(construction).second) { - // send construction to handlers, because it is new - for (const auto &key_value: copy) { - EventHandler handle = key_value.second; - DEBUG(log,out).print("calling handler for created construction event\n"); - handle.eventHandler(out, (void*) &construction); - } + // now handle all the new constructions + for (auto& construction : new_constructions) { + for (const auto &[_,handle]: copy) { + DEBUG(log,out).print("calling handler for created construction event\n"); + handle.eventHandler(out, (void*) &construction); } } } @@ -781,6 +821,8 @@ static void manageSyndromeEvent(color_ostream& out) { return; multimap copy(handlers[EventType::SYNDROME].begin(), handlers[EventType::SYNDROME].end()); int32_t highestTime = -1; + + std::vector new_syndrome_data; for (auto unit : df::global::world->units.all) { /* @@ -795,14 +837,16 @@ static void manageSyndromeEvent(color_ostream& out) { if ( startTime <= lastSyndromeTime ) continue; - SyndromeData data(unit->id, b); - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; - DEBUG(log,out).print("calling handler for syndrome event\n"); - handle.eventHandler(out, (void*)&data); - } + new_syndrome_data.emplace_back(unit->id, b); + } + } + for (auto& data : new_syndrome_data) { + for (auto &[_,handle] : copy) { + DEBUG(log,out).print("calling handler for syndrome event\n"); + handle.eventHandler(out, (void*)&data); } } + lastSyndromeTime = highestTime; } @@ -815,8 +859,7 @@ static void manageInvasionEvent(color_ostream& out) { return; nextInvasion = df::global::plotinfo->invasions.next_id; - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for invasion event\n"); handle.eventHandler(out, (void*)intptr_t(nextInvasion-1)); } @@ -829,6 +872,11 @@ static void manageEquipmentEvent(color_ostream& out) { unordered_map itemIdToInventoryItem; unordered_set currentlyEquipped; + + vector equipment_pickups; + vector equipment_drops; + vector equipment_changes; + for (auto unit : df::global::world->units.all) { itemIdToInventoryItem.clear(); currentlyEquipped.clear(); @@ -856,12 +904,7 @@ static void manageEquipmentEvent(color_ostream& out) { auto c = itemIdToInventoryItem.find(dfitem_new->item->id); if ( c == itemIdToInventoryItem.end() ) { //new item equipped (probably just picked up) - InventoryChangeData data(unit->id, nullptr, &item_new); - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; - DEBUG(log,out).print("calling handler for new item equipped inventory change event\n"); - handle.eventHandler(out, (void*)&data); - } + equipment_pickups.emplace_back(unit->id, nullptr, &item_new); continue; } InventoryItem item_old = (*c).second; @@ -872,24 +915,14 @@ static void manageEquipmentEvent(color_ostream& out) { continue; //some sort of change in how it's equipped - InventoryChangeData data(unit->id, &item_old, &item_new); - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; - DEBUG(log,out).print("calling handler for inventory change event\n"); - handle.eventHandler(out, (void*)&data); - } + equipment_changes.emplace_back(unit->id, nullptr, &item_new); } //check for dropped items for (auto i : v) { if ( currentlyEquipped.find(i.itemId) != currentlyEquipped.end() ) continue; //TODO: delete ptr if invalid - InventoryChangeData data(unit->id, &i, nullptr); - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; - DEBUG(log,out).print("calling handler for dropped item inventory change event\n"); - handle.eventHandler(out, (void*)&data); - } + equipment_drops.emplace_back(unit->id, &i, nullptr); } if ( !hadEquipment ) delete temp; @@ -902,6 +935,26 @@ static void manageEquipmentEvent(color_ostream& out) { equipment.push_back(item); } } + + // now handle events + std::for_each(equipment_pickups.begin(), equipment_drops.end(), [&](InventoryChangeData& data) { + for (auto &[_, handle] : copy) { + DEBUG(log,out).print("calling handler for new item equipped inventory change event\n"); + handle.eventHandler(out, (void*) &data); + } + }); + std::for_each(equipment_drops.begin(), equipment_drops.end(), [&](InventoryChangeData& data) { + for (auto &[_, handle] : copy) { + DEBUG(log,out).print("calling handler for dropped item inventory change event\n"); + handle.eventHandler(out, (void*) &data); + } + }); + std::for_each(equipment_changes.begin(), equipment_changes.end(), [&](InventoryChangeData& data) { + for (auto &[_, handle] : copy) { + DEBUG(log,out).print("calling handler for inventory change event\n"); + handle.eventHandler(out, (void*) &data); + } + }); } static void updateReportToRelevantUnits() { @@ -939,8 +992,7 @@ static void manageReportEvent(color_ostream& out) { for ( ; idx < reports.size(); idx++ ) { df::report* report = reports[idx]; - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for report event\n"); handle.eventHandler(out, (void*)intptr_t(report->id)); } @@ -981,7 +1033,7 @@ static void manageUnitAttackEvent(color_ostream& out) { if ( strikeReports.empty() ) return; updateReportToRelevantUnits(); - map > alreadyDone; + unordered_set, hash_pair> already_done; for (int reportId : strikeReports) { df::report* report = df::report::find(reportId); if ( !report ) @@ -1011,27 +1063,25 @@ static void manageUnitAttackEvent(color_ostream& out) { UnitAttackData data{}; data.report_id = report->id; - if ( wound1 && !alreadyDone[unit1->id][unit2->id] ) { + if ( wound1 && already_done.find(std::make_pair(unit1->id,unit2->id)) == already_done.end() ) { data.attacker = unit1->id; data.defender = unit2->id; data.wound = wound1->id; - alreadyDone[data.attacker][data.defender] = 1; - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + already_done.emplace(unit1->id, unit2->id); + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for unit1 attack unit attack event\n"); handle.eventHandler(out, (void*)&data); } } - if ( wound2 && !alreadyDone[unit1->id][unit2->id] ) { + if ( wound2 && already_done.find(std::make_pair(unit1->id,unit2->id)) == already_done.end() ) { data.attacker = unit2->id; data.defender = unit1->id; data.wound = wound2->id; - alreadyDone[data.attacker][data.defender] = 1; - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + already_done.emplace(unit1->id, unit2->id); + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for unit2 attack unit attack event\n"); handle.eventHandler(out, (void*)&data); } @@ -1041,9 +1091,9 @@ static void manageUnitAttackEvent(color_ostream& out) { data.attacker = unit2->id; data.defender = unit1->id; data.wound = -1; - alreadyDone[data.attacker][data.defender] = 1; - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + + already_done.emplace(unit1->id, unit2->id); + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for unit1 killed unit attack event\n"); handle.eventHandler(out, (void*)&data); } @@ -1053,9 +1103,9 @@ static void manageUnitAttackEvent(color_ostream& out) { data.attacker = unit1->id; data.defender = unit2->id; data.wound = -1; - alreadyDone[data.attacker][data.defender] = 1; - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + + already_done.emplace(unit1->id, unit2->id); + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for unit2 killed unit attack event\n"); handle.eventHandler(out, (void*)&data); } @@ -1313,8 +1363,7 @@ static void manageInteractionEvent(color_ostream& out) { lastAttacker = df::unit::find(data.attacker); //lastDefender = df::unit::find(data.defender); //fire event - for (auto &key_value : copy) { - EventHandler &handle = key_value.second; + for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for interaction event\n"); handle.eventHandler(out, (void*)&data); } From 78bea2a55089d08173d955a750fd778cc214c4f8 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Wed, 27 Sep 2023 23:34:19 +0100 Subject: [PATCH 636/851] fixed a typo brain fart moment --- library/modules/EventManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index ddc46942d..cb3f3e76f 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -937,7 +937,7 @@ static void manageEquipmentEvent(color_ostream& out) { } // now handle events - std::for_each(equipment_pickups.begin(), equipment_drops.end(), [&](InventoryChangeData& data) { + std::for_each(equipment_pickups.begin(), equipment_pickups.end(), [&](InventoryChangeData& data) { for (auto &[_, handle] : copy) { DEBUG(log,out).print("calling handler for new item equipped inventory change event\n"); handle.eventHandler(out, (void*) &data); From d44499b970fc7fe0b4581b117ca8a0a7e9d85407 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 28 Sep 2023 07:13:26 +0000 Subject: [PATCH 637/851] 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 52fe6b277..9312906c5 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 52fe6b27723ba7e3064ae03c1a7ae5712c3dc0ec +Subproject commit 9312906c5a33feea50c0c32cd683ad22fb87822c diff --git a/scripts b/scripts index 4032be431..76f5a2b10 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 4032be431a669ac822583dc3ccca3c6c07c8e3aa +Subproject commit 76f5a2b101f0817857c9dfa8dd3d9f076137aafc From 70ff728fba68e18d1eb4f0a3146dbc9146d4eaaf Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Thu, 28 Sep 2023 16:19:32 +0100 Subject: [PATCH 638/851] manageJobStartedEvent handle moved to inner loop and iterates from previous in linked list in case it is removed. fix a bug with item change events and using invalidated stack pointer as item data. swapped order of destroyed and created building event calls, and a couple other improvements --- library/modules/EventManager.cpp | 98 ++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 42 deletions(-) diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index cb3f3e76f..14fac42b3 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -466,18 +466,22 @@ static void manageJobStartedEvent(color_ostream& out) { vector new_started_jobs; // iterate event handler callbacks multimap copy(handlers[EventType::JOB_STARTED].begin(), handlers[EventType::JOB_STARTED].end()); - for (df::job_list_link* link = df::global::world->jobs.list.next; link != nullptr; link = link->next) { - df::job* job = link->item; + + for (df::job_list_link* link = &df::global::world->jobs.list; link->next != nullptr; link = link->next) { + df::job* job = link->next->item; + int32_t j_id = job->id; if (job && Job::getWorker(job) && !startedJobs.count(job->id)) { startedJobs.emplace(job->id); - new_started_jobs.emplace_back(job); + for (auto &[_,handle] : copy) { + // the jobs must have a worker to start + DEBUG(log,out).print("calling handler for job started event\n"); + handle.eventHandler(out, job); + } } - } - for (df::job* job : new_started_jobs) { - for (auto &[_,handle] : copy) { - // the jobs must have a worker to start - DEBUG(log,out).print("calling handler for job started event\n"); - handle.eventHandler(out, job); + if (link->next == nullptr || link->next->item->id != j_id) { + if ( Once::doOnce("EventManager jobstarted job removed") ) { + out.print("%s,%d: job %u removed from jobs linked list\n", __FILE__, __LINE__, j_id); + } } } } @@ -498,11 +502,11 @@ static void manageJobCompletedEvent(color_ostream& out) { int32_t tick1 = df::global::world->frame_counter; multimap copy(handlers[EventType::JOB_COMPLETED].begin(), handlers[EventType::JOB_COMPLETED].end()); - map nowJobs; + unordered_map nowJobs; for ( df::job_list_link* link = &df::global::world->jobs.list; link != nullptr; link = link->next ) { if ( link->item == nullptr ) continue; - nowJobs[link->item->id] = link->item; + nowJobs.emplace(link->item->id, link->item); } #if 0 @@ -567,8 +571,6 @@ static void manageJobCompletedEvent(color_ostream& out) { } #endif - vector new_jobs_completed; - vector new_jobs_completed_repeats; for (auto &prevJob : prevJobs) { //if it happened within a tick, must have been cancelled by the user or a plugin: not completed if ( tick1 <= tick0 ) @@ -586,7 +588,10 @@ static void manageJobCompletedEvent(color_ostream& out) { continue; //still false positive if cancelled at EXACTLY the right time, but experiments show this doesn't happen - new_jobs_completed_repeats.emplace_back(&job0); + for (auto &[_,handle] : copy) { + DEBUG(log,out).print("calling handler for repeated job completed event\n"); + handle.eventHandler(out, (void*) &job0); + } continue; } @@ -595,37 +600,27 @@ static void manageJobCompletedEvent(color_ostream& out) { if ( job0.flags.bits.repeat || job0.completion_timer != 0 ) continue; - new_jobs_completed.emplace_back(&job0); - } - - for (df::job* job : new_jobs_completed_repeats) { - for (auto &[_,handle] : copy) { - DEBUG(log,out).print("calling handler for repeated job completed event\n"); - handle.eventHandler(out, (void*) job); - } - } - for (df::job* job : new_jobs_completed) { for (auto &[_,handle] : copy) { DEBUG(log,out).print("calling handler for job completed event\n"); - handle.eventHandler(out, (void*) job); + handle.eventHandler(out, (void*) &job0); } } //erase old jobs, copy over possibly altered jobs - for (auto &prevJob : prevJobs) { - Job::deleteJobStruct(prevJob.second, true); + for (auto &[_,prev_job] : prevJobs) { + Job::deleteJobStruct(prev_job, true); } prevJobs.clear(); //create new jobs - for (auto &nowJob : nowJobs) { + for (auto &[_,now_job] : nowJobs) { /*map::iterator i = prevJobs.find((*j).first); if ( i != prevJobs.end() ) { continue; }*/ - df::job* newJob = Job::cloneJobStruct(nowJob.second, true); - prevJobs[newJob->id] = newJob; + df::job* newJob = Job::cloneJobStruct(now_job, true); + prevJobs.emplace(newJob->id, newJob); } } @@ -662,6 +657,7 @@ static void manageUnitDeathEvent(color_ostream& out) { livingUnits.insert(unit->id); continue; } + if (!Units::isDead(unit)) continue; // for units that have left the map but aren't dead //dead: if dead since last check, trigger events if ( livingUnits.find(unit->id) == livingUnits.end() ) continue; @@ -747,13 +743,6 @@ static void manageBuildingEvent(color_ostream& out) { } nextBuilding = *df::global::building_next_id; - std::for_each(new_buildings.begin(), new_buildings.end(), [&](int32_t building){ - for (auto &[_,handle] : copy) { - DEBUG(log,out).print("calling handler for created building event\n"); - handle.eventHandler(out, (void*)intptr_t(building)); - } - }); - //now alert people about destroyed buildings for ( auto it = buildings.begin(); it != buildings.end(); ) { int32_t id = *it; @@ -769,6 +758,14 @@ static void manageBuildingEvent(color_ostream& out) { } it = buildings.erase(it); } + + //alert people about newly created buildings + std::for_each(new_buildings.begin(), new_buildings.end(), [&](int32_t building){ + for (auto &[_,handle] : copy) { + DEBUG(log,out).print("calling handler for created building event\n"); + handle.eventHandler(out, (void*)intptr_t(building)); + } + }); } static void manageConstructionEvent(color_ostream& out) { @@ -877,6 +874,13 @@ static void manageEquipmentEvent(color_ostream& out) { vector equipment_drops; vector equipment_changes; + + // This vector stores the pointers to newly created changed items + // needed as the stack allocated temporary (in the loop) is lost when we go to + // handle the event calls, so we move that data to the heap if its needed, + // and then once we are done we delete everything. + vector changed_items; + for (auto unit : df::global::world->units.all) { itemIdToInventoryItem.clear(); currentlyEquipped.clear(); @@ -904,25 +908,30 @@ static void manageEquipmentEvent(color_ostream& out) { auto c = itemIdToInventoryItem.find(dfitem_new->item->id); if ( c == itemIdToInventoryItem.end() ) { //new item equipped (probably just picked up) - equipment_pickups.emplace_back(unit->id, nullptr, &item_new); + changed_items.emplace_back(new InventoryItem(item_new)); + equipment_pickups.emplace_back(unit->id, nullptr, changed_items.back()); continue; } - InventoryItem item_old = (*c).second; + InventoryItem item_old = c->second; df::unit_inventory_item& item0 = item_old.item; df::unit_inventory_item& item1 = item_new.item; if ( item0.mode == item1.mode && item0.body_part_id == item1.body_part_id && item0.wound_id == item1.wound_id ) continue; //some sort of change in how it's equipped - - equipment_changes.emplace_back(unit->id, nullptr, &item_new); + changed_items.emplace_back(new InventoryItem(item_new)); + InventoryItem* item_new_ptr = changed_items.back(); + changed_items.emplace_back(new InventoryItem(item_old)); + InventoryItem* item_old_ptr = changed_items.back(); + equipment_changes.emplace_back(unit->id, item_old_ptr, item_new_ptr); } //check for dropped items for (auto i : v) { if ( currentlyEquipped.find(i.itemId) != currentlyEquipped.end() ) continue; //TODO: delete ptr if invalid - equipment_drops.emplace_back(unit->id, &i, nullptr); + changed_items.emplace_back(new InventoryItem(i)); + equipment_drops.emplace_back(unit->id, changed_items.back(), nullptr); } if ( !hadEquipment ) delete temp; @@ -955,6 +964,11 @@ static void manageEquipmentEvent(color_ostream& out) { handle.eventHandler(out, (void*) &data); } }); + + // clean up changed items list + std::for_each(changed_items.begin(), changed_items.end(), [](InventoryItem* p){ + delete p; + }); } static void updateReportToRelevantUnits() { From 09129ddec06dac85e919a515f1b0fef55fa9e458 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 28 Sep 2023 13:56:11 -0700 Subject: [PATCH 639/851] brighten ascii logo on hover as was originally intended. why is fg "de-bolded" by pens? --- docs/changelog.txt | 1 + plugins/lua/hotkeys.lua | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index aec12a96f..1859a7f79 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -60,6 +60,7 @@ Template for new versions: ## Misc Improvements - `dig`: `digtype` command now has options to choose between designating only visible tiles or hidden tiles, as well as "auto" dig mode. Z-level options adjusted to allow choosing z-levels above, below, or the same as the cursor. +- `hotkeys`: make the DFHack logo brighten on hover in ascii mode to indicate that it is clickable ## Documentation diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 80f8816e8..71fda3d86 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -65,6 +65,7 @@ function HotspotMenuWidget:init() tile=function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, ch=ch, fg=COLOR_WHITE, + bold=true, } end local function get_tile_token(idx, ch) From bff1b5e7b09cf77cb51a4bb2ef8e0596aaf6a9d2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 28 Sep 2023 14:41:30 -0700 Subject: [PATCH 640/851] make the ascii DFHack logo easier to read --- docs/changelog.txt | 1 + plugins/lua/hotkeys.lua | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1859a7f79..0c6b35fab 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -61,6 +61,7 @@ Template for new versions: ## Misc Improvements - `dig`: `digtype` command now has options to choose between designating only visible tiles or hidden tiles, as well as "auto" dig mode. Z-level options adjusted to allow choosing z-levels above, below, or the same as the cursor. - `hotkeys`: make the DFHack logo brighten on hover in ascii mode to indicate that it is clickable +- `hotkeys`: use vertical bars instead of "!" symbols for the DFHack logo to make it easier to read ## Documentation diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 71fda3d86..6335de5e5 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -79,9 +79,9 @@ function HotspotMenuWidget:init() self:addviews{ widgets.Label{ text={ - get_tile_token(1, '!'), get_tile_token(2, 'D'), get_tile_token(3, 'F'), get_tile_token(4, '!'), NEWLINE, - get_tile_token(5, '!'), get_tile_token(6, 'H'), get_tile_token(7, 'a'), get_tile_token(8, '!'), NEWLINE, - get_tile_token(9, '!'), get_tile_token(10, 'c'), get_tile_token(11, 'k'), get_tile_token(12, '!'), + get_tile_token(1, 179), get_tile_token(2, 'D'), get_tile_token(3, 'F'), get_tile_token(4, 179), NEWLINE, + get_tile_token(5, 179), get_tile_token(6, 'H'), get_tile_token(7, 'a'), get_tile_token(8, 179), NEWLINE, + get_tile_token(9, 179), get_tile_token(10, 'c'), get_tile_token(11, 'k'), get_tile_token(12, 179), }, on_click=function() dfhack.run_command('hotkeys') end, }, From 13f83d2f95104bb03f8c8a4eb09b29e393506797 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 28 Sep 2023 16:35:29 -0700 Subject: [PATCH 641/851] protect against bad values in TranslateName --- docs/changelog.txt | 1 + library/modules/Translation.cpp | 49 +++++++++++++++++++++++++++------ plugins/autoslab.cpp | 20 +------------- 3 files changed, 42 insertions(+), 28 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1859a7f79..c9e24e70f 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -60,6 +60,7 @@ Template for new versions: ## Misc Improvements - `dig`: `digtype` command now has options to choose between designating only visible tiles or hidden tiles, as well as "auto" dig mode. Z-level options adjusted to allow choosing z-levels above, below, or the same as the cursor. +- ``dfhack.TranslateName``: protect against bad language indices added by mods - `hotkeys`: make the DFHack logo brighten on hover in ascii mode to indicate that it is clickable ## Documentation diff --git a/library/modules/Translation.cpp b/library/modules/Translation.cpp index 282039c02..af06eeb49 100644 --- a/library/modules/Translation.cpp +++ b/library/modules/Translation.cpp @@ -131,6 +131,37 @@ void Translation::setNickname(df::language_name *name, std::string nick) } } +static string translate_word(const df::language_name * name, size_t word_idx) { + CHECK_NULL_POINTER(name); + + auto translation = vector_get(world->raws.language.translations, name->language); + if (!translation) + return ""; + + auto word = vector_get(translation->words, word_idx); + if (!word) + return ""; + + return *word; +} + +static string translate_english_word(const df::language_name * name, size_t part_idx) { + CHECK_NULL_POINTER(name); + + if (part_idx >= 7) + return ""; + + auto words = vector_get(world->raws.language.words, name->words[part_idx]); + if (!words) + return ""; + + df::part_of_speech part = name->parts_of_speech[part_idx]; + if (part < df::part_of_speech::Noun || part > df::part_of_speech::VerbGerund) + return ""; + + return words->forms[part]; +} + string Translation::TranslateName(const df::language_name * name, bool inEnglish, bool onlyLastPart) { CHECK_NULL_POINTER(name); @@ -166,20 +197,20 @@ string Translation::TranslateName(const df::language_name * name, bool inEnglish { word.clear(); if (name->words[0] >= 0) - word.append(*world->raws.language.translations[name->language]->words[name->words[0]]); + word.append(translate_word(name, name->words[0])); if (name->words[1] >= 0) - word.append(*world->raws.language.translations[name->language]->words[name->words[1]]); + word.append(translate_word(name, name->words[1])); addNameWord(out, word); } word.clear(); for (int i = 2; i <= 5; i++) if (name->words[i] >= 0) - word.append(*world->raws.language.translations[name->language]->words[name->words[i]]); + word.append(translate_word(name, name->words[i])); addNameWord(out, word); if (name->words[6] >= 0) { word.clear(); - word.append(*world->raws.language.translations[name->language]->words[name->words[6]]); + word.append(translate_word(name, name->words[6])); addNameWord(out, word); } } @@ -189,9 +220,9 @@ string Translation::TranslateName(const df::language_name * name, bool inEnglish { word.clear(); if (name->words[0] >= 0) - word.append(world->raws.language.words[name->words[0]]->forms[name->parts_of_speech[0]]); + word.append(translate_english_word(name, 0)); if (name->words[1] >= 0) - word.append(world->raws.language.words[name->words[1]]->forms[name->parts_of_speech[1]]); + word.append(translate_english_word(name, 1)); addNameWord(out, word); } if (name->words[2] >= 0 || name->words[3] >= 0 || name->words[4] >= 0 || name->words[5] >= 0) @@ -201,10 +232,10 @@ string Translation::TranslateName(const df::language_name * name, bool inEnglish else out.append("The"); } - for (int i = 2; i <= 5; i++) + for (size_t i = 2; i <= 5; i++) { if (name->words[i] >= 0) - addNameWord(out, world->raws.language.words[name->words[i]]->forms[name->parts_of_speech[i]]); + addNameWord(out, translate_english_word(name, i)); } if (name->words[6] >= 0) { @@ -213,7 +244,7 @@ string Translation::TranslateName(const df::language_name * name, bool inEnglish else out.append("Of"); - addNameWord(out, world->raws.language.words[name->words[6]]->forms[name->parts_of_speech[6]]); + addNameWord(out, translate_english_word(name, 6)); } } diff --git a/plugins/autoslab.cpp b/plugins/autoslab.cpp index e78314bfd..32382a217 100644 --- a/plugins/autoslab.cpp +++ b/plugins/autoslab.cpp @@ -151,24 +151,6 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out) return CR_OK; } -// Name functions taken from manipulator.cpp -static std::string get_first_name(df::unit *unit) -{ - return Translation::capitalize(unit->name.first_name); -} - -static std::string get_last_name(df::unit *unit) -{ - df::language_name name = unit->name; - std::string ret = ""; - for (int i = 0; i < 2; i++) - { - if (name.words[i] >= 0) - ret += *world->raws.language.translations[name.language]->words[name.words[i]]; - } - return Translation::capitalize(ret); -} - // Queue up a single order to engrave the slab for the given unit static void createSlabJob(df::unit *unit) { @@ -212,7 +194,7 @@ static void checkslabs(color_ostream &out) ) { createSlabJob(ghost); - auto fullName = get_first_name(ghost) + " " + get_last_name(ghost); + auto fullName = Translation::capitalize(Translation::TranslateName(&ghost->name, false), true); out.print("Added slab order for ghost %s\n", fullName.c_str()); } } From af65f185a1be7cf992fc17fe5d8d58dd9fa77855 Mon Sep 17 00:00:00 2001 From: Myk Date: Thu, 28 Sep 2023 17:43:06 -0700 Subject: [PATCH 642/851] Remove unneeded capitalize --- plugins/autoslab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/autoslab.cpp b/plugins/autoslab.cpp index 32382a217..82333c822 100644 --- a/plugins/autoslab.cpp +++ b/plugins/autoslab.cpp @@ -194,7 +194,7 @@ static void checkslabs(color_ostream &out) ) { createSlabJob(ghost); - auto fullName = Translation::capitalize(Translation::TranslateName(&ghost->name, false), true); + auto fullName = Translation::TranslateName(&ghost->name, false); out.print("Added slab order for ghost %s\n", fullName.c_str()); } } From e1bf8c47fa2ec7bb30e6b07c4ac056b7e83aa098 Mon Sep 17 00:00:00 2001 From: Myk Date: Thu, 28 Sep 2023 20:12:40 -0700 Subject: [PATCH 643/851] 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 c9e24e70f..d6377e1ec 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -60,7 +60,7 @@ Template for new versions: ## Misc Improvements - `dig`: `digtype` command now has options to choose between designating only visible tiles or hidden tiles, as well as "auto" dig mode. Z-level options adjusted to allow choosing z-levels above, below, or the same as the cursor. -- ``dfhack.TranslateName``: protect against bad language indices added by mods +- ``dfhack.TranslateName()``: fixed crash on certain invalid names, which affected `warn-starving` - `hotkeys`: make the DFHack logo brighten on hover in ascii mode to indicate that it is clickable ## Documentation From 965c453b9b7c701b7fef5338bf53693210c09d11 Mon Sep 17 00:00:00 2001 From: Myk Date: Thu, 28 Sep 2023 20:13:55 -0700 Subject: [PATCH 644/851] 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 d6377e1ec..7f1944d08 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,10 +57,10 @@ Template for new versions: ## Fixes - `autolabor`: now unconditionally re-enables vanilla work details when the fort or the plugin is unloaded +- ``dfhack.TranslateName()``: fixed crash on certain invalid names, which affected `warn-starving` ## Misc Improvements - `dig`: `digtype` command now has options to choose between designating only visible tiles or hidden tiles, as well as "auto" dig mode. Z-level options adjusted to allow choosing z-levels above, below, or the same as the cursor. -- ``dfhack.TranslateName()``: fixed crash on certain invalid names, which affected `warn-starving` - `hotkeys`: make the DFHack logo brighten on hover in ascii mode to indicate that it is clickable ## Documentation From 986e64aed06be13182f74dcbce8edd4babb0fb53 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 29 Sep 2023 12:27:09 +0100 Subject: [PATCH 645/851] new plugin preserve-tombs ensures that units that die keep their tomb assignments in death --- plugins/CMakeLists.txt | 1 + plugins/preserve-tombs.cpp | 243 +++++++++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 plugins/preserve-tombs.cpp diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index b96606284..392a69dcc 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -144,6 +144,7 @@ if(BUILD_SUPPORTED) dfhack_plugin(pathable pathable.cpp LINK_LIBRARIES lua) #dfhack_plugin(petcapRemover petcapRemover.cpp) #dfhack_plugin(plants plants.cpp) + dfhack_plugin(preserve-tombs preserve-tombs.cpp) dfhack_plugin(probe probe.cpp) dfhack_plugin(prospector prospector.cpp LINK_LIBRARIES lua) #dfhack_plugin(power-meter power-meter.cpp LINK_LIBRARIES lua) diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp new file mode 100644 index 000000000..857597d23 --- /dev/null +++ b/plugins/preserve-tombs.cpp @@ -0,0 +1,243 @@ +#include "Debug.h" +#include "PluginManager.h" +#include "MiscUtils.h" + +#include +#include +#include +#include +#include +#include + +#include "modules/Units.h" +#include "modules/Buildings.h" +#include "modules/Persistence.h" +#include "modules/EventManager.h" +#include "modules/World.h" + +#include "df/world.h" +#include "df/unit.h" +#include "df/building.h" +#include "df/building_civzonest.h" + +using namespace DFHack; +using namespace df::enums; + + +// +DFHACK_PLUGIN("preserve-tombs"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + +REQUIRE_GLOBAL(world); + + +static const std::string CONFIG_KEY = std::string(plugin_name) + "/config"; +static PersistentDataItem config; + +static int32_t cycle_timestamp; +static int32_t cycle_freq; + +enum ConfigValues { + CONFIG_IS_ENABLED = 0, + CONFIG_CYCLES = 1 +}; + +static std::unordered_map tomb_assignments; + +namespace DFHack { + DBG_DECLARE(preservetombs, config, DebugCategory::LINFO); +} + + +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); +} + +static bool assign_to_tomb(int32_t unit_id, int32_t building_id); +static void update_tomb_assignments(color_ostream& out); +void onUnitDeath(color_ostream& out, void* ptr); + +DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { + return CR_OK; +} + +// event listener +EventManager::EventHandler assign_tomb_handler(onUnitDeath, 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(config,out).print("%s from the API; persisting\n", + is_enabled ? "enabled" : "disabled"); + set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); + EventManager::registerListener(EventManager::EventType::UNIT_DEATH, assign_tomb_handler, plugin_self); + if (enable) + update_tomb_assignments(out); + } else { + EventManager::unregisterAll(plugin_self); + DEBUG(config,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(config,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(config,out).print("no config found in this save; initializing\n"); + config = World::AddPersistentData(CONFIG_KEY); + set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); + set_config_val(config, CONFIG_CYCLES, 25); + } + + is_enabled = get_config_bool(config, CONFIG_IS_ENABLED); + cycle_freq = get_config_val(config, CONFIG_CYCLES); + DEBUG(config,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(config,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_freq) + update_tomb_assignments(out); + return CR_OK; +} +// + + + + +// On unit death - check if we assigned them a tomb +// +// +void onUnitDeath(color_ostream& out, void* ptr) { + // input is void* that contains the unit id + int32_t unit_id = reinterpret_cast(ptr); + + // check if unit was assigned a tomb in life + auto it = tomb_assignments.find(unit_id); + if (it == tomb_assignments.end()) return; + + // assign that unit to their previously assigned tomb in life + int32_t building_id = it->second; + if (!assign_to_tomb(unit_id, building_id)) return; + + // success, print status update and remove assignment from our memo-list + out.print("Unit %d died - assigning them to tomb %d\n", unit_id, building_id); + tomb_assignments.erase(it); + +} + + +// Update tomb assignments +// +// +static void update_tomb_assignments(color_ostream &out) { + + // check tomb civzones for assigned units + for (auto* bld : world->buildings.other.ZONE_TOMB) { + + auto* tomb = virtual_cast(bld); + if (!tomb || !tomb->flags.bits.exists) continue; + if (!tomb->assigned_unit) continue; + if (Units::isDead(tomb->assigned_unit)) continue; // we only care about living units + + auto it = tomb_assignments.find(tomb->assigned_unit_id); + + if (it == tomb_assignments.end()) { + tomb_assignments.emplace(tomb->assigned_unit_id, tomb->id); + out.print("%s new tomb assignment, unit %d to tomb %d\n", plugin_name, tomb->assigned_unit_id, tomb->id); + } + + else { + if (it->second != tomb->id) { + out.print("%s tomb assignment to %d changed, (old: %d, new: %d)\n", plugin_name, tomb->assigned_unit_id, it->second, tomb->id); + } + it->second = tomb->id; + } + + } + + // now check our civzones for unassignment / deleted zone / + std::erase_if(tomb_assignments, [&](const std::pair& pair){ + const auto &[unit_id, building_id] = pair; + + const size_t tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); + if (tomb_idx == -1) { + out.print("%s tomb missing: %d - removing\n", plugin_name, building_id); + return true; + } + const auto tomb = virtual_cast(world->buildings.other.ZONE_TOMB[tomb_idx]); + if (!tomb || !tomb->flags.bits.exists) { + out.print("%s tomb missing: %d - removing\n", plugin_name, building_id); + return true; + } + if (tomb->assigned_unit_id != unit_id) { + out.print("%s unassigned unit %d from tomb %d - removing\n", unit_id, building_id); + return true; + } + + return false; + }); + +} + + +// ASSIGN UNIT TO TOMB +// +// +static bool assign_to_tomb(int32_t unit_id, int32_t building_id) { + + size_t unit_idx = Units::findIndexById(unit_id); + if (unit_idx == -1) return false; + + df::unit* unit = world->units.all[unit_idx]; + if (!Units::isDead(unit)) return false; + + size_t tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); + if (tomb_idx == -1) return false; + + df::building_civzonest* tomb = virtual_cast(world->buildings.other.ZONE_TOMB[tomb_idx]); + if (!tomb || tomb->assigned_unit) return false; // in the game we cannot reassign tombs - more research is required to see if reassignment is safe. + + Buildings::setOwner(tomb, unit); + return true; +} \ No newline at end of file From 2a145d06b622b273f4ff619620581e1dc35fd6b9 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 29 Sep 2023 13:11:13 +0100 Subject: [PATCH 646/851] fixed crash on tomb unassignment (caused by incorrect params passed to formatted string) --- plugins/preserve-tombs.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp index 857597d23..245ce5949 100644 --- a/plugins/preserve-tombs.cpp +++ b/plugins/preserve-tombs.cpp @@ -70,6 +70,7 @@ static void update_tomb_assignments(color_ostream& out); void onUnitDeath(color_ostream& out, void* ptr); DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { + tomb_assignments.clear(); return CR_OK; } @@ -77,6 +78,7 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector & pair){ - const auto &[unit_id, building_id] = pair; + for (auto it = tomb_assignments.begin(); it != tomb_assignments.end(); ++it){ + auto &[unit_id, building_id] = *it; const size_t tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); if (tomb_idx == -1) { out.print("%s tomb missing: %d - removing\n", plugin_name, building_id); - return true; + it = tomb_assignments.erase(it); + continue; } const auto tomb = virtual_cast(world->buildings.other.ZONE_TOMB[tomb_idx]); if (!tomb || !tomb->flags.bits.exists) { out.print("%s tomb missing: %d - removing\n", plugin_name, building_id); - return true; + it = tomb_assignments.erase(it); + continue; } if (tomb->assigned_unit_id != unit_id) { - out.print("%s unassigned unit %d from tomb %d - removing\n", unit_id, building_id); - return true; + out.print("%s unassigned unit %d from tomb %d - removing\n", plugin_name, unit_id, building_id); + it = tomb_assignments.erase(it); + continue; } - - return false; - }); + } } From b0a15b2e8a5319fb896cd927ee2b63ad00ba3775 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 29 Sep 2023 13:38:52 +0100 Subject: [PATCH 647/851] added command to show status of preservetombs (is enabled or disabled) --- plugins/preserve-tombs.cpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp index 245ce5949..d80ca3b03 100644 --- a/plugins/preserve-tombs.cpp +++ b/plugins/preserve-tombs.cpp @@ -68,12 +68,27 @@ static void set_config_bool(PersistentDataItem &c, int index, bool value) { static bool assign_to_tomb(int32_t unit_id, int32_t building_id); static void update_tomb_assignments(color_ostream& out); void onUnitDeath(color_ostream& out, void* ptr); +static command_result do_command(color_ostream& out, std::vector& params); DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { - tomb_assignments.clear(); + commands.push_back(PluginCommand( + plugin_name, + "Preserves tomb assignments to units when they die.", + do_command)); return CR_OK; } +static command_result do_command(color_ostream& out, std::vector& params) { + if (params.size() != 1 || params[0] != "status") { + out.print("%s wrong usage", plugin_name); + return CR_WRONG_USAGE; + } + else { + out.print("%s is currently %s", plugin_name, is_enabled ? "enabled" : "disabled"); + return CR_OK; + } +} + // event listener EventManager::EventHandler assign_tomb_handler(onUnitDeath, 0); @@ -154,7 +169,7 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out) { void onUnitDeath(color_ostream& out, void* ptr) { // input is void* that contains the unit id int32_t unit_id = reinterpret_cast(ptr); - + // check if unit was assigned a tomb in life auto it = tomb_assignments.find(unit_id); if (it == tomb_assignments.end()) return; @@ -199,10 +214,10 @@ static void update_tomb_assignments(color_ostream &out) { } - // now check our civzones for unassignment / deleted zone / + // now check our civzones for unassignment / deleted zone / for (auto it = tomb_assignments.begin(); it != tomb_assignments.end(); ++it){ auto &[unit_id, building_id] = *it; - + const size_t tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); if (tomb_idx == -1) { out.print("%s tomb missing: %d - removing\n", plugin_name, building_id); @@ -229,13 +244,13 @@ static void update_tomb_assignments(color_ostream &out) { // // static bool assign_to_tomb(int32_t unit_id, int32_t building_id) { - + size_t unit_idx = Units::findIndexById(unit_id); if (unit_idx == -1) return false; - + df::unit* unit = world->units.all[unit_idx]; if (!Units::isDead(unit)) return false; - + size_t tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); if (tomb_idx == -1) return false; From 0b2989fb1508fe6291ccee57dd4077f59b1f720d Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 29 Sep 2023 14:08:49 +0100 Subject: [PATCH 648/851] preservetombs status now shows list of all tracked tomb assignments --- plugins/preserve-tombs.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp index d80ca3b03..e9964d2f1 100644 --- a/plugins/preserve-tombs.cpp +++ b/plugins/preserve-tombs.cpp @@ -84,7 +84,14 @@ static command_result do_command(color_ostream& out, std::vector& p return CR_WRONG_USAGE; } else { - out.print("%s is currently %s", plugin_name, is_enabled ? "enabled" : "disabled"); + out.print("%s is currently %s\n", plugin_name, is_enabled ? "enabled" : "disabled"); + if (is_enabled) { + out.print("tracked tomb assignments:\n"); + std::for_each(tomb_assignments.begin(), tomb_assignments.end(), [&out](const auto& p){ + auto& [unit_id, building_id] = p; + out.print("unit %d -> building %d\n", unit_id, building_id); + }); + } return CR_OK; } } @@ -138,6 +145,7 @@ DFhackCExport command_result plugin_load_data (color_ostream &out) { DEBUG(config,out).print("loading persisted enabled state: %s\n", is_enabled ? "true" : "false"); + if (is_enabled) update_tomb_assignments(out); return CR_OK; } @@ -255,7 +263,7 @@ static bool assign_to_tomb(int32_t unit_id, int32_t building_id) { if (tomb_idx == -1) return false; df::building_civzonest* tomb = virtual_cast(world->buildings.other.ZONE_TOMB[tomb_idx]); - if (!tomb || tomb->assigned_unit) return false; // in the game we cannot reassign tombs - more research is required to see if reassignment is safe. + if (!tomb || tomb->assigned_unit) return false; Buildings::setOwner(tomb, unit); return true; From df5de8b7ec26b6fbc9bd6a7beb3de0f82707d12a Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 29 Sep 2023 14:21:44 +0100 Subject: [PATCH 649/851] added doc and changelog entry for preserve-tombs plugin --- docs/changelog.txt | 1 + docs/plugins/preserve-tombs.rst | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 docs/plugins/preserve-tombs.rst diff --git a/docs/changelog.txt b/docs/changelog.txt index f819587de..07ed84ebf 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -52,6 +52,7 @@ Template for new versions: # Future ## New Tools +- `preserve-tombs`: tracks tomb assignments to living units and ensures that the tomb stays assigned to them when they die. ## New Features diff --git a/docs/plugins/preserve-tombs.rst b/docs/plugins/preserve-tombs.rst new file mode 100644 index 000000000..7c148e3ee --- /dev/null +++ b/docs/plugins/preserve-tombs.rst @@ -0,0 +1,22 @@ +preserve-tombs +============== + +.. dfhack-tool:: + :summary: Fix tombs being unassigned to units on death + :tags: fort bugfix + +If you find that the tombs you assign to units get unassigned from them when +they die (e.g. your nobles), this tool can help fix that. + +Usage +----- + +:: + + enable preserve-tombs + preserve-tombs status + +This tool runs in the background. You can check the status of the plugin +by running ``preserve-tombs status`` which will show whether the plugin +is enabled and if so, display a list of all tracked tomb assignments +to living units. From 579fe6ee766222e595b17ba1a5534ad42fb9638a Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 29 Sep 2023 14:24:42 +0100 Subject: [PATCH 650/851] fixed sign compare issue linux build --- plugins/preserve-tombs.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp index e9964d2f1..8d82146b2 100644 --- a/plugins/preserve-tombs.cpp +++ b/plugins/preserve-tombs.cpp @@ -226,7 +226,7 @@ static void update_tomb_assignments(color_ostream &out) { for (auto it = tomb_assignments.begin(); it != tomb_assignments.end(); ++it){ auto &[unit_id, building_id] = *it; - const size_t tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); + const int tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); if (tomb_idx == -1) { out.print("%s tomb missing: %d - removing\n", plugin_name, building_id); it = tomb_assignments.erase(it); @@ -253,13 +253,13 @@ static void update_tomb_assignments(color_ostream &out) { // static bool assign_to_tomb(int32_t unit_id, int32_t building_id) { - size_t unit_idx = Units::findIndexById(unit_id); + const int unit_idx = Units::findIndexById(unit_id); if (unit_idx == -1) return false; df::unit* unit = world->units.all[unit_idx]; if (!Units::isDead(unit)) return false; - size_t tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); + const int tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); if (tomb_idx == -1) return false; df::building_civzonest* tomb = virtual_cast(world->buildings.other.ZONE_TOMB[tomb_idx]); From 028fbc34ade99fc91e43cee3d35655e87c0e736b Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 29 Sep 2023 14:30:01 +0100 Subject: [PATCH 651/851] using std::erase_if instead of iterator loop --- plugins/preserve-tombs.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp index 8d82146b2..6730dee76 100644 --- a/plugins/preserve-tombs.cpp +++ b/plugins/preserve-tombs.cpp @@ -222,28 +222,27 @@ static void update_tomb_assignments(color_ostream &out) { } - // now check our civzones for unassignment / deleted zone / - for (auto it = tomb_assignments.begin(); it != tomb_assignments.end(); ++it){ - auto &[unit_id, building_id] = *it; + // now check our civzones for unassignment / deleted zone + std::erase_if(tomb_assignments,[&](const auto& p){ + auto &[unit_id, building_id] = p; const int tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); if (tomb_idx == -1) { out.print("%s tomb missing: %d - removing\n", plugin_name, building_id); - it = tomb_assignments.erase(it); - continue; + return true; } const auto tomb = virtual_cast(world->buildings.other.ZONE_TOMB[tomb_idx]); if (!tomb || !tomb->flags.bits.exists) { out.print("%s tomb missing: %d - removing\n", plugin_name, building_id); - it = tomb_assignments.erase(it); - continue; + return true; } if (tomb->assigned_unit_id != unit_id) { out.print("%s unassigned unit %d from tomb %d - removing\n", plugin_name, unit_id, building_id); - it = tomb_assignments.erase(it); - continue; + return true; } - } + + return false; + }); } From 7933e291191e58eba0cdb9e6c2e66c8d25eed2c9 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 29 Sep 2023 14:45:46 +0100 Subject: [PATCH 652/851] newline at eof - preservetombs.cpp --- plugins/preserve-tombs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp index 6730dee76..0fa9d5b36 100644 --- a/plugins/preserve-tombs.cpp +++ b/plugins/preserve-tombs.cpp @@ -266,4 +266,4 @@ static bool assign_to_tomb(int32_t unit_id, int32_t building_id) { Buildings::setOwner(tomb, unit); return true; -} \ No newline at end of file +} From 51173fb9fea6002c8777ea3ceb30f5a4b674080e Mon Sep 17 00:00:00 2001 From: Mikhail Panov Date: Fri, 29 Sep 2023 17:34:48 +0300 Subject: [PATCH 653/851] Removed material and job type sortings. --- docs/plugins/orders.rst | 10 --- plugins/lua/orders.lua | 26 ++----- plugins/orders.cpp | 150 ---------------------------------------- 3 files changed, 6 insertions(+), 180 deletions(-) diff --git a/docs/plugins/orders.rst b/docs/plugins/orders.rst index 9bf220a06..d8d3fe585 100644 --- a/docs/plugins/orders.rst +++ b/docs/plugins/orders.rst @@ -28,16 +28,6 @@ Usage Sorts current manager orders by repeat frequency so repeating orders don't prevent one-time orders from ever being completed. The sorting order is: one-time orders first, then yearly, seasonally, monthly, and finally, daily. -``orders sort_type`` - Sorts current manager orders by job type, making it easier to locate orders - that produce similar items. The sorting is done by reaction name, job type - and item subtype. If orders are equal by these fields the sorting falls back - to sort by frequency. -``orders sort_material`` - Sorts current manager orders by material, making it easier to locate orders - that produce items of the same material. The sorting is done by material type - and material category. If orders are equal by these fields the sorting falls back - to sort by job type. You can keep your orders automatically sorted by adding the following command to your ``dfhack-config/init/onMapLoad.init`` file:: diff --git a/plugins/lua/orders.lua b/plugins/lua/orders.lua index c84dfa5f7..1a3208336 100644 --- a/plugins/lua/orders.lua +++ b/plugins/lua/orders.lua @@ -79,7 +79,7 @@ OrdersOverlay.ATTRS{ default_pos={x=53,y=-6}, default_enabled=true, viewscreens='dwarfmode/Info/WORK_ORDERS/Default', - frame={w=73, h=4}, + frame={w=46, h=4}, } function OrdersOverlay:init() @@ -114,31 +114,17 @@ function OrdersOverlay:init() }, widgets.HotkeyLabel{ frame={t=1, l=15}, - label='clear', - key='CUSTOM_CTRL_C', - auto_width=true, - on_activate=do_clear, - }, - widgets.HotkeyLabel{ - frame={t=0, l=30}, - label='sort by freq', + label='sort', key='CUSTOM_CTRL_O', auto_width=true, on_activate=do_sort, }, widgets.HotkeyLabel{ - frame={t=1, l=30}, - label='sort by type', - key='CUSTOM_CTRL_J', - auto_width=true, - on_activate=do_sort_type, - }, - widgets.HotkeyLabel{ - frame={t=0, l=52}, - label='sort by mat', - key='CUSTOM_CTRL_T', + frame={t=0, l=31}, + label='clear', + key='CUSTOM_CTRL_C', auto_width=true, - on_activate=do_sort_mat, + on_activate=do_clear, }, }, } diff --git a/plugins/orders.cpp b/plugins/orders.cpp index 77e8d5fa8..a84f14172 100644 --- a/plugins/orders.cpp +++ b/plugins/orders.cpp @@ -67,8 +67,6 @@ static command_result orders_export_command(color_ostream & out, const std::stri static command_result orders_import_command(color_ostream & out, const std::string & name); static command_result orders_clear_command(color_ostream & out); static command_result orders_sort_command(color_ostream & out); -static command_result orders_sort_type_command(color_ostream & out); -static command_result orders_sort_material_command(color_ostream & out); static command_result orders_recheck_command(color_ostream & out); static command_result orders_recheck_current_command(color_ostream & out); @@ -118,16 +116,6 @@ static command_result orders_command(color_ostream & out, std::vectorfrequency != b->frequency) - { - return compare_freq(a, b); - } - - // Determine if only one order has reaction_name - bool a_has_reaction_name = !a->reaction_name.empty(); - bool b_has_reaction_name = !b->reaction_name.empty(); - - if (a_has_reaction_name != b_has_reaction_name) - { - return a_has_reaction_name; - } - else if (a_has_reaction_name && b_has_reaction_name) - { - if (a->reaction_name != b->reaction_name) - { - return a->reaction_name < b->reaction_name; - } - } - - // Compare job_type - if (enum_item_key(a->job_type) != enum_item_key(b->job_type)) - { - return enum_item_key(a->job_type) < enum_item_key(b->job_type); - } - - // Compare item subtype - bool a_has_item_subtype = (a->item_subtype != -1); - bool b_has_item_subtype = (b->item_subtype != -1); - - if (a_has_item_subtype != b_has_item_subtype) - { - return a_has_item_subtype; - } - else if (a_has_item_subtype && b_has_item_subtype) - { - if (a->item_subtype != b->item_subtype) - { - return a->item_subtype < b->item_subtype; - } - } - - // By default orders are the same - return false; -} - -static command_result orders_sort_type_command(color_ostream & out) -{ - CoreSuspender suspend; - if (!std::is_sorted(world->manager_orders.begin(), - world->manager_orders.end(), - compare_type)) - { - std::stable_sort(world->manager_orders.begin(), - world->manager_orders.end(), - compare_type); - out << "Manager orders are sorted by job type." << std::endl; - } - - return CR_OK; -} - -static bool compare_material(df::manager_order *a, df::manager_order *b) -{ - // Goal: Sort orders to easily find them in the list and to see dupclicated orders. - // Sorting by materials - - // Divide orders by frequency first - if (a->frequency != b->frequency) - { - return compare_freq(a, b); - } - - // Determine if only one of the orders has mat_type - bool a_has_material = (a->mat_type != -1 || a->mat_index != -1); - bool b_has_material = (b->mat_type != -1 || b->mat_index != -1); - - if (a_has_material != b_has_material) - { - return a_has_material; - } - else if (a_has_material && b_has_material) - { - // Compare mat_type using MaterialInfo - if (MaterialInfo(a).getToken() != MaterialInfo(b).getToken()) - { - return MaterialInfo(a).getToken() < MaterialInfo(b).getToken(); - } - } - - // Determine if only one order has material_category - bool a_has_material_category = (a->material_category.whole != 0); - bool b_has_material_category = (b->material_category.whole != 0); - - if (a_has_material_category != b_has_material_category) - { - return a_has_material_category; - } - else if (a_has_material_category && b_has_material_category) - { - std::vector a_mats, b_mats; - bitfield_to_string(&a_mats, a->material_category); - bitfield_to_string(&b_mats, b->material_category); - - // Checking that mats are not empty just in case - if (!a_mats.empty() && !b_mats.empty() && a_mats[0] != b_mats[0]) - { - return a_mats[0] < b_mats[0]; - } - } - - // Fall back to material sort - return compare_type(a, b); -} - -static command_result orders_sort_material_command(color_ostream & out) -{ - CoreSuspender suspend; - if (!std::is_sorted(world->manager_orders.begin(), - world->manager_orders.end(), - compare_material)) - { - std::stable_sort(world->manager_orders.begin(), - world->manager_orders.end(), - compare_material); - out << "Manager orders are sorted by material." << std::endl; - } - - return CR_OK; -} - static command_result orders_recheck_command(color_ostream & out) { for (auto it : world->manager_orders) From feaf0d6bb35d1e81bb7f70a40c4512913687a914 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Fri, 29 Sep 2023 15:36:16 +0100 Subject: [PATCH 654/851] update changelog --- docs/changelog.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index f819587de..315f37841 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,11 +58,14 @@ Template for new versions: ## Fixes - `autolabor`: now unconditionally re-enables vanilla work details when the fort or the plugin is unloaded - ``dfhack.TranslateName()``: fixed crash on certain invalid names, which affected `warn-starving` +- EventManager: Unit death event no longer misfires on units leaving the map ## Misc Improvements - `dig`: `digtype` command now has options to choose between designating only visible tiles or hidden tiles, as well as "auto" dig mode. Z-level options adjusted to allow choosing z-levels above, below, or the same as the cursor. - `hotkeys`: make the DFHack logo brighten on hover in ascii mode to indicate that it is clickable - `hotkeys`: use vertical bars instead of "!" symbols for the DFHack logo to make it easier to read +- EventManager: guarded against potential iterator invalidation if one of the event listeners modified the global data structure being iterated over +- EventManager: changed firing order of building created and building destroyed events to improve performance in the building location cache. ## Documentation From e868612985ca2608409e042dbb8d33f88b76c732 Mon Sep 17 00:00:00 2001 From: Mikhail Panov Date: Fri, 29 Sep 2023 17:41:18 +0300 Subject: [PATCH 655/851] Rephrased description in rst files. --- docs/about/Removed.rst | 4 ++-- docs/plugins/orders.rst | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index 4d8f8fc6e..86d7e0f75 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -14,8 +14,8 @@ work (e.g. links from the `changelog`). workorder-recheck ================= -Tool to set 'Checking' status of the selected work order forcing manager to reevaluate its -conditions. Merged into `orders`. +Tool to set 'Checking' status of the selected work order, allowing conditions to be +reevaluated. Merged into `orders`. .. _autohauler: diff --git a/docs/plugins/orders.rst b/docs/plugins/orders.rst index d8d3fe585..acb25fe99 100644 --- a/docs/plugins/orders.rst +++ b/docs/plugins/orders.rst @@ -18,9 +18,9 @@ Usage ``orders clear`` Deletes all manager orders in the current embark. ``orders recheck [this]`` - Sets the status to ``Checking`` (from ``Active``) of all work orders or one - currently viewed if 'this' option is passed. Work order conditions screen - should be open in this case. This makes the manager reevaluate its conditions. + Sets the status to ``Checking`` (from ``Active``) for all work orders. if the + "this" option is passed, only sets the status for the workorder whose condition + details page is open. This makes the manager reevaluate its conditions. This is especially useful for an order that had its conditions met when it was started, but the requisite items have since disappeared and the workorder is now generating job cancellation spam. From 7b8721965753f19cf07c391f960a046b8048a1b5 Mon Sep 17 00:00:00 2001 From: Myk Date: Fri, 29 Sep 2023 09:40:52 -0700 Subject: [PATCH 656/851] Update plugins/lua/orders.lua --- plugins/lua/orders.lua | 8 -------- 1 file changed, 8 deletions(-) diff --git a/plugins/lua/orders.lua b/plugins/lua/orders.lua index 1a3208336..df8710739 100644 --- a/plugins/lua/orders.lua +++ b/plugins/lua/orders.lua @@ -66,14 +66,6 @@ local function do_recheck() dfhack.run_command('orders', 'recheck') end -local function do_sort_type() - dfhack.run_command('orders', 'sort_type') -end - -local function do_sort_mat() - dfhack.run_command('orders', 'sort_material') -end - OrdersOverlay = defclass(OrdersOverlay, overlay.OverlayWidget) OrdersOverlay.ATTRS{ default_pos={x=53,y=-6}, From a52386474ae7b8133ec5b9761f71be13152d2b39 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 29 Sep 2023 16:42:47 +0000 Subject: [PATCH 657/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 76f5a2b10..73eac0413 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 76f5a2b101f0817857c9dfa8dd3d9f076137aafc +Subproject commit 73eac04134b3e7d89b7be1bc355dddab38c5656d From c6ad1dd24d86439a89d1c9840a733bc56fdcb575 Mon Sep 17 00:00:00 2001 From: Myk Date: Fri, 29 Sep 2023 09:58:33 -0700 Subject: [PATCH 658/851] Update tubefill.rst --- docs/plugins/tubefill.rst | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/plugins/tubefill.rst b/docs/plugins/tubefill.rst index 80282f6d9..ff668f8df 100644 --- a/docs/plugins/tubefill.rst +++ b/docs/plugins/tubefill.rst @@ -5,7 +5,11 @@ tubefill :summary: Replenishes mined-out adamantine. :tags: fort armok map -Veins that were originally hollow will be left alone. +This tool replaces mined-out tiles of adamantine spires with fresh, undug +adamantine walls, ready to be re-harvested. Empty tiles within the spire that +used to contain special gemstones, obsidian, water, or magma will also be +replaced with fresh adamantine. Adamantine spires that were originally hollow +will be left hollow. See below for more details. Usage ----- From ffd166a41fc01ae76ad8fbc890a7c7abb00e483d Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 29 Sep 2023 18:26:00 +0000 Subject: [PATCH 659/851] 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 9312906c5..bcfb0fb3b 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9312906c5a33feea50c0c32cd683ad22fb87822c +Subproject commit bcfb0fb3ba82939f353bda9908d39877661d9c81 From 56e782d9bb10bb9c02376f5e37edb25763b88721 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 30 Sep 2023 04:47:59 +0000 Subject: [PATCH 660/851] 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 bcfb0fb3b..dc1d5c80f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit bcfb0fb3ba82939f353bda9908d39877661d9c81 +Subproject commit dc1d5c80f03a68f6d58ff4f8dbbdf6855a7e9781 diff --git a/scripts b/scripts index 73eac0413..57c859394 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 73eac04134b3e7d89b7be1bc355dddab38c5656d +Subproject commit 57c859394936f9183d95426f75a5d3e9b305dd2a From 6be9de5e518aec7cd751273782f22653d608623c Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sat, 30 Sep 2023 12:30:40 +0100 Subject: [PATCH 661/851] preserve-tombs added option to change tick rate, changed default update frequency, changed some print to debug statements, some other adjustments --- docs/plugins/preserve-tombs.rst | 19 ++++---- plugins/preserve-tombs.cpp | 77 +++++++++++++++++++++++---------- 2 files changed, 65 insertions(+), 31 deletions(-) diff --git a/docs/plugins/preserve-tombs.rst b/docs/plugins/preserve-tombs.rst index 7c148e3ee..e667e64b0 100644 --- a/docs/plugins/preserve-tombs.rst +++ b/docs/plugins/preserve-tombs.rst @@ -11,12 +11,15 @@ they die (e.g. your nobles), this tool can help fix that. Usage ----- -:: +``enable preserve-tombs`` + enable the plugin +``preserve-tombs status`` + check the status of the plugin, and if the plugin is enabled, + lists all tracked tomb assignments +``preserve-tombs update`` + forces an immediate update of the tomb assignments. +``preserve-tombs freq [val]`` + changes the rate at which the plugin rechecks and updates + tomb assignments, in ticks (default is ``100``) - enable preserve-tombs - preserve-tombs status - -This tool runs in the background. You can check the status of the plugin -by running ``preserve-tombs status`` which will show whether the plugin -is enabled and if so, display a list of all tracked tomb assignments -to living units. +This tool runs in the background. \ No newline at end of file diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp index 0fa9d5b36..f75b7aeb7 100644 --- a/plugins/preserve-tombs.cpp +++ b/plugins/preserve-tombs.cpp @@ -14,6 +14,7 @@ #include "modules/Persistence.h" #include "modules/EventManager.h" #include "modules/World.h" +#include "modules/Translation.h" #include "df/world.h" #include "df/unit.h" @@ -46,6 +47,8 @@ static std::unordered_map tomb_assignments; namespace DFHack { DBG_DECLARE(preservetombs, config, DebugCategory::LINFO); + DBG_DECLARE(preservetombs, cycle, DebugCategory::LINFO); + DBG_DECLARE(preservetombs, event, DebugCategory::LINFO); } @@ -79,28 +82,50 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector & params) { - if (params.size() != 1 || params[0] != "status") { - out.print("%s wrong usage", plugin_name); + if (params.size() == 0) { + out.print("%s wrong usage\n", plugin_name); return CR_WRONG_USAGE; } - else { + if (params[0] == "status") { out.print("%s is currently %s\n", plugin_name, is_enabled ? "enabled" : "disabled"); if (is_enabled) { + out.print("Update frequency: %d ticks", cycle_freq); out.print("tracked tomb assignments:\n"); std::for_each(tomb_assignments.begin(), tomb_assignments.end(), [&out](const auto& p){ auto& [unit_id, building_id] = p; - out.print("unit %d -> building %d\n", unit_id, building_id); + auto* unit = df::unit::find(unit_id); + std::string name = unit ? Translation::TranslateName(&unit->name) : "UNKNOWN UNIT" ; + out.print("%s (id %d) -> building %d\n", name.c_str(), unit_id, building_id); }); } return CR_OK; } + if (params[0] == "update") { + CoreSuspender suspend; + update_tomb_assignments(out); + out.print("Updated tomb assignments\n"); + return CR_OK; + } + if (params.size() < 2) { + out.print("%s wrong usage\n", plugin_name); + return CR_WRONG_USAGE; + } + if (params[0] == "ticks" || params[0] == "freq" || params[0] == "rate") { + int new_tickrate = std::stoi(params[1]); + if (new_tickrate <= 0) { + out.print("new tickrate (%d) cannot be <= 0\n", new_tickrate); + return CR_WRONG_USAGE; + } + cycle_freq = new_tickrate; + set_config_val(config, CONFIG_CYCLES, cycle_freq); + } + return CR_WRONG_USAGE; } // event listener EventManager::EventHandler assign_tomb_handler(onUnitDeath, 0); DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { - tomb_assignments.clear(); if (!Core::getInstance().isWorldLoaded()) { out.printerr("Cannot enable %s without a loaded world.\n", plugin_name); return CR_FAILURE; @@ -111,11 +136,15 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { DEBUG(config,out).print("%s from the API; persisting\n", is_enabled ? "enabled" : "disabled"); set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); - EventManager::registerListener(EventManager::EventType::UNIT_DEATH, assign_tomb_handler, plugin_self); - if (enable) + if (enable) { + EventManager::registerListener(EventManager::EventType::UNIT_DEATH, assign_tomb_handler, plugin_self); update_tomb_assignments(out); + } + else { + tomb_assignments.clear(); + EventManager::unregisterAll(plugin_self); + } } else { - EventManager::unregisterAll(plugin_self); DEBUG(config,out).print("%s from the API, but already %s; no action\n", is_enabled ? "enabled" : "disabled", is_enabled ? "enabled" : "disabled"); @@ -137,7 +166,7 @@ DFhackCExport command_result plugin_load_data (color_ostream &out) { DEBUG(config,out).print("no config found in this save; initializing\n"); config = World::AddPersistentData(CONFIG_KEY); set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); - set_config_val(config, CONFIG_CYCLES, 25); + set_config_val(config, CONFIG_CYCLES, 100); } is_enabled = get_config_bool(config, CONFIG_IS_ENABLED); @@ -145,7 +174,6 @@ DFhackCExport command_result plugin_load_data (color_ostream &out) { DEBUG(config,out).print("loading persisted enabled state: %s\n", is_enabled ? "true" : "false"); - if (is_enabled) update_tomb_assignments(out); return CR_OK; } @@ -157,6 +185,7 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan plugin_name); is_enabled = false; } + EventManager::unregisterAll(plugin_self); } return CR_OK; } @@ -184,10 +213,12 @@ void onUnitDeath(color_ostream& out, void* ptr) { // assign that unit to their previously assigned tomb in life int32_t building_id = it->second; - if (!assign_to_tomb(unit_id, building_id)) return; - + if (!assign_to_tomb(unit_id, building_id)) { + DEBUG(event, out).print("Unit %d died - but failed to assign them to tomb %d\n", unit_id, building_id); + return; + } // success, print status update and remove assignment from our memo-list - out.print("Unit %d died - assigning them to tomb %d\n", unit_id, building_id); + INFO(event, out).print("Unit %d died - assigning them to tomb %d\n", unit_id, building_id); tomb_assignments.erase(it); } @@ -197,7 +228,7 @@ void onUnitDeath(color_ostream& out, void* ptr) { // // static void update_tomb_assignments(color_ostream &out) { - + cycle_timestamp = world->frame_counter; // check tomb civzones for assigned units for (auto* bld : world->buildings.other.ZONE_TOMB) { @@ -210,12 +241,14 @@ static void update_tomb_assignments(color_ostream &out) { if (it == tomb_assignments.end()) { tomb_assignments.emplace(tomb->assigned_unit_id, tomb->id); - out.print("%s new tomb assignment, unit %d to tomb %d\n", plugin_name, tomb->assigned_unit_id, tomb->id); + DEBUG(cycle, out).print("%s new tomb assignment, unit %d to tomb %d\n", + plugin_name, tomb->assigned_unit_id, tomb->id); } else { if (it->second != tomb->id) { - out.print("%s tomb assignment to %d changed, (old: %d, new: %d)\n", plugin_name, tomb->assigned_unit_id, it->second, tomb->id); + DEBUG(cycle, out).print("%s tomb assignment to %d changed, (old: %d, new: %d)\n", + plugin_name, tomb->assigned_unit_id, it->second, tomb->id); } it->second = tomb->id; } @@ -228,16 +261,16 @@ static void update_tomb_assignments(color_ostream &out) { const int tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); if (tomb_idx == -1) { - out.print("%s tomb missing: %d - removing\n", plugin_name, building_id); + DEBUG(cycle, out).print("%s tomb missing: %d - removing\n", plugin_name, building_id); return true; } const auto tomb = virtual_cast(world->buildings.other.ZONE_TOMB[tomb_idx]); if (!tomb || !tomb->flags.bits.exists) { - out.print("%s tomb missing: %d - removing\n", plugin_name, building_id); + DEBUG(cycle, out).print("%s tomb missing: %d - removing\n", plugin_name, building_id); return true; } if (tomb->assigned_unit_id != unit_id) { - out.print("%s unassigned unit %d from tomb %d - removing\n", plugin_name, unit_id, building_id); + DEBUG(cycle, out).print("%s unassigned unit %d from tomb %d - removing\n", plugin_name, unit_id, building_id); return true; } @@ -252,11 +285,9 @@ static void update_tomb_assignments(color_ostream &out) { // static bool assign_to_tomb(int32_t unit_id, int32_t building_id) { - const int unit_idx = Units::findIndexById(unit_id); - if (unit_idx == -1) return false; + df::unit* unit = df::unit::find(unit_id); - df::unit* unit = world->units.all[unit_idx]; - if (!Units::isDead(unit)) return false; + if (!unit || !Units::isDead(unit)) return false; const int tomb_idx = binsearch_index(world->buildings.other.ZONE_TOMB, building_id); if (tomb_idx == -1) return false; From 7e75fd6ebc10faf5237afa1f9fa2fec7639371b9 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sat, 30 Sep 2023 12:49:46 +0100 Subject: [PATCH 662/851] eof fix --- docs/plugins/preserve-tombs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/preserve-tombs.rst b/docs/plugins/preserve-tombs.rst index e667e64b0..846c6c553 100644 --- a/docs/plugins/preserve-tombs.rst +++ b/docs/plugins/preserve-tombs.rst @@ -22,4 +22,4 @@ Usage changes the rate at which the plugin rechecks and updates tomb assignments, in ticks (default is ``100``) -This tool runs in the background. \ No newline at end of file +This tool runs in the background. From e2dcced8ef23861f64daa34e7960af1785c1497d Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sat, 30 Sep 2023 13:21:04 +0100 Subject: [PATCH 663/851] preserve-tombs command guarded from using update argument when plugin not enabled --- plugins/preserve-tombs.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp index f75b7aeb7..9216a5de4 100644 --- a/plugins/preserve-tombs.cpp +++ b/plugins/preserve-tombs.cpp @@ -101,6 +101,10 @@ static command_result do_command(color_ostream& out, std::vector& p return CR_OK; } if (params[0] == "update") { + if (!is_enabled) { + out.printerr("Cannot update %s when not enabled", plugin_name); + return CR_FAILURE; + } CoreSuspender suspend; update_tomb_assignments(out); out.print("Updated tomb assignments\n"); From 7d3764d3ec1708e6b8d8feef3236914f60463983 Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sat, 30 Sep 2023 14:42:29 +0100 Subject: [PATCH 664/851] removed option to set tickrate for preserve-tombs, fixed at 100 tick interval --- docs/plugins/preserve-tombs.rst | 12 +++++------- plugins/preserve-tombs.cpp | 27 +++++---------------------- 2 files changed, 10 insertions(+), 29 deletions(-) diff --git a/docs/plugins/preserve-tombs.rst b/docs/plugins/preserve-tombs.rst index 846c6c553..045d15a5a 100644 --- a/docs/plugins/preserve-tombs.rst +++ b/docs/plugins/preserve-tombs.rst @@ -13,13 +13,11 @@ Usage ``enable preserve-tombs`` enable the plugin -``preserve-tombs status`` +``preserve-tombs [status]`` check the status of the plugin, and if the plugin is enabled, - lists all tracked tomb assignments + lists all currently tracked tomb assignments ``preserve-tombs update`` - forces an immediate update of the tomb assignments. -``preserve-tombs freq [val]`` - changes the rate at which the plugin rechecks and updates - tomb assignments, in ticks (default is ``100``) + forces an immediate update of the tomb assignments. This plugin + automatically updates the tomb assignments once every 100 ticks. -This tool runs in the background. +This tool runs in the background. diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp index 9216a5de4..3e5cea1d2 100644 --- a/plugins/preserve-tombs.cpp +++ b/plugins/preserve-tombs.cpp @@ -36,11 +36,10 @@ static const std::string CONFIG_KEY = std::string(plugin_name) + "/config"; static PersistentDataItem config; static int32_t cycle_timestamp; -static int32_t cycle_freq; +static constexpr int32_t cycle_freq = 100; enum ConfigValues { CONFIG_IS_ENABLED = 0, - CONFIG_CYCLES = 1 }; static std::unordered_map tomb_assignments; @@ -82,14 +81,13 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector & params) { - if (params.size() == 0) { - out.print("%s wrong usage\n", plugin_name); - return CR_WRONG_USAGE; + if (!Core::getInstance().isWorldLoaded()) { + out.printerr("Cannot use %s without a loaded world.\n", plugin_name); + return CR_FAILURE; } - if (params[0] == "status") { + if (params.size() == 0 || params[0] == "status") { out.print("%s is currently %s\n", plugin_name, is_enabled ? "enabled" : "disabled"); if (is_enabled) { - out.print("Update frequency: %d ticks", cycle_freq); out.print("tracked tomb assignments:\n"); std::for_each(tomb_assignments.begin(), tomb_assignments.end(), [&out](const auto& p){ auto& [unit_id, building_id] = p; @@ -110,19 +108,6 @@ static command_result do_command(color_ostream& out, std::vector& p out.print("Updated tomb assignments\n"); return CR_OK; } - if (params.size() < 2) { - out.print("%s wrong usage\n", plugin_name); - return CR_WRONG_USAGE; - } - if (params[0] == "ticks" || params[0] == "freq" || params[0] == "rate") { - int new_tickrate = std::stoi(params[1]); - if (new_tickrate <= 0) { - out.print("new tickrate (%d) cannot be <= 0\n", new_tickrate); - return CR_WRONG_USAGE; - } - cycle_freq = new_tickrate; - set_config_val(config, CONFIG_CYCLES, cycle_freq); - } return CR_WRONG_USAGE; } @@ -170,11 +155,9 @@ DFhackCExport command_result plugin_load_data (color_ostream &out) { DEBUG(config,out).print("no config found in this save; initializing\n"); config = World::AddPersistentData(CONFIG_KEY); set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); - set_config_val(config, CONFIG_CYCLES, 100); } is_enabled = get_config_bool(config, CONFIG_IS_ENABLED); - cycle_freq = get_config_val(config, CONFIG_CYCLES); DEBUG(config,out).print("loading persisted enabled state: %s\n", is_enabled ? "true" : "false"); From a8e09ac8d4e84f667e59f4bb260b8fad96304c9a Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sat, 30 Sep 2023 14:55:22 +0100 Subject: [PATCH 665/851] removed trailing ws --- docs/plugins/preserve-tombs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/preserve-tombs.rst b/docs/plugins/preserve-tombs.rst index 045d15a5a..67e7ceff6 100644 --- a/docs/plugins/preserve-tombs.rst +++ b/docs/plugins/preserve-tombs.rst @@ -20,4 +20,4 @@ Usage forces an immediate update of the tomb assignments. This plugin automatically updates the tomb assignments once every 100 ticks. -This tool runs in the background. +This tool runs in the background. From b672e40851cb862f8ab1277de6aee1fc56341c7f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 30 Sep 2023 22:37:27 -0700 Subject: [PATCH 666/851] clean up changelog --- docs/changelog.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 4db2bbf77..8d3d45778 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,23 +58,24 @@ Template for new versions: ## New Features ## Fixes -- `autolabor`: now unconditionally re-enables vanilla work details when the fort or the plugin is unloaded +- `autolabor`: ensure vanilla work details are reinstated when the fort or the plugin is unloaded - ``dfhack.TranslateName()``: fixed crash on certain invalid names, which affected `warn-starving` - EventManager: Unit death event no longer misfires on units leaving the map ## Misc Improvements -- `dig`: `digtype` command now has options to choose between designating only visible tiles or hidden tiles, as well as "auto" dig mode. Z-level options adjusted to allow choosing z-levels above, below, or the same as the cursor. +- `digtype`: designate only visible tiles by default, and use "auto" dig mode for following veins +- `digtype`: added options for designating only current z-level, this z-level and above, and this z-level and below - `hotkeys`: make the DFHack logo brighten on hover in ascii mode to indicate that it is clickable -- `hotkeys`: use vertical bars instead of "!" symbols for the DFHack logo to make it easier to read -- EventManager: guarded against potential iterator invalidation if one of the event listeners modified the global data structure being iterated over -- EventManager: changed firing order of building created and building destroyed events to improve performance in the building location cache. +- `hotkeys`: use vertical bars instead of "!" symbols for the DFHack logo in ascii mode to make it easier to read +- EventManager: guard against potential iterator invalidation if one of the event listeners were to modify the global data structure being iterated over +- EventManager: for ``onBuildingCreatedDestroyed`` events, changed firing order of events so destroyed events come before created events ## Documentation ## API ## Lua -- mouse key events are now aligned with internal DF semantics: ``_MOUSE_L`` indicates that the left mouse button has just been pressed and ``_MOUSE_L_DOWN`` indicates that the left mouse button is being held down. similar for ``_MOUSE_R`` and ``_MOUSE_M``. 3rd party scripts may have to adjust. +- mouse key events are now aligned with internal DF semantics: ``_MOUSE_L`` indicates that the left mouse button has just been pressed and ``_MOUSE_L_DOWN`` indicates that the left mouse button is being held down. similarly for ``_MOUSE_R`` and ``_MOUSE_M``. 3rd party scripts may have to adjust. ## Removed From 6e2adaa3a92cf6981bed18ca8282a1e715c1e774 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 30 Sep 2023 23:31:56 -0700 Subject: [PATCH 667/851] don't conflict with macro recording key --- plugins/lua/orders.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/orders.lua b/plugins/lua/orders.lua index df8710739..102580fab 100644 --- a/plugins/lua/orders.lua +++ b/plugins/lua/orders.lua @@ -100,7 +100,7 @@ function OrdersOverlay:init() widgets.HotkeyLabel{ frame={t=0, l=15}, label='recheck', - key='CUSTOM_CTRL_R', + key='CUSTOM_CTRL_K', auto_width=true, on_activate=do_recheck, }, From cd12e41fd7aa7d7a52c9e9cab97d89273bef0764 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 30 Sep 2023 23:54:25 -0700 Subject: [PATCH 668/851] update enabler mouse state when mouse clicks are handled in dialogs --- library/lua/gui/dialogs.lua | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua index 95a56d0c4..5778cc767 100644 --- a/library/lua/gui/dialogs.lua +++ b/library/lua/gui/dialogs.lua @@ -67,7 +67,10 @@ function MessageBox:onInput(keys) gui.markMouseClicksHandled(keys) return true end - return self:inputToSubviews(keys) + if self:inputToSubviews(keys) then + gui.markMouseClicksHandled(keys) + return true + end end function showMessage(title, text, tcolor, on_close) @@ -137,7 +140,10 @@ function InputBox:onInput(keys) gui.markMouseClicksHandled(keys) return true end - return self:inputToSubviews(keys) + if self:inputToSubviews(keys) then + gui.markMouseClicksHandled(keys) + return true + end end function showInputPrompt(title, text, tcolor, input, on_input, on_cancel, min_width) @@ -239,7 +245,10 @@ function ListBox:onInput(keys) gui.markMouseClicksHandled(keys) return true end - return self:inputToSubviews(keys) + if self:inputToSubviews(keys) then + gui.markMouseClicksHandled(keys) + return true + end end function showListPrompt(title, text, tcolor, choices, on_select, on_cancel, min_width, filter) From a5fbd791cd943f64f7fca6ec13e45460c89f4149 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 1 Oct 2023 07:13:02 +0000 Subject: [PATCH 669/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 57c859394..55d0463cd 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 57c859394936f9183d95426f75a5d3e9b305dd2a +Subproject commit 55d0463cdb67165f746a3f2c0f4dd87c6ef86eec From 211b34c618cdafdafd1bc756bce3ea3c7622cbf6 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 1 Oct 2023 08:35:42 +0000 Subject: [PATCH 670/851] 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 dc1d5c80f..b313b69ad 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit dc1d5c80f03a68f6d58ff4f8dbbdf6855a7e9781 +Subproject commit b313b69adafef0bc3597df285504b729c44bea86 diff --git a/scripts b/scripts index 55d0463cd..8259d95e9 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 55d0463cdb67165f746a3f2c0f4dd87c6ef86eec +Subproject commit 8259d95e9ee9d88c88f32b22608d0d8c977aac18 From 0dba8919932102195857fbc32ef2df96830fb002 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 1 Oct 2023 08:43:59 -0700 Subject: [PATCH 671/851] clean out some unused dependencies --- library/lua/gui/buildings.lua | 2 -- library/lua/gui/materials.lua | 1 - 2 files changed, 3 deletions(-) diff --git a/library/lua/gui/buildings.lua b/library/lua/gui/buildings.lua index 8871346f2..433afb1ba 100644 --- a/library/lua/gui/buildings.lua +++ b/library/lua/gui/buildings.lua @@ -4,8 +4,6 @@ local _ENV = mkmodule('gui.buildings') local gui = require('gui') local widgets = require('gui.widgets') -local dlg = require('gui.dialogs') -local utils = require('utils') ARROW = string.char(26) diff --git a/library/lua/gui/materials.lua b/library/lua/gui/materials.lua index eea881768..aa070ea73 100644 --- a/library/lua/gui/materials.lua +++ b/library/lua/gui/materials.lua @@ -5,7 +5,6 @@ local _ENV = mkmodule('gui.materials') local gui = require('gui') local widgets = require('gui.widgets') local dlg = require('gui.dialogs') -local utils = require('utils') ARROW = string.char(26) From 0956c06341265180804564f3a22536bb4ac988ff Mon Sep 17 00:00:00 2001 From: Najeeb Al-Shabibi Date: Sun, 1 Oct 2023 17:33:53 +0100 Subject: [PATCH 672/851] update arg changed to 'now' for consistency --- docs/plugins/preserve-tombs.rst | 2 +- plugins/preserve-tombs.cpp | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/docs/plugins/preserve-tombs.rst b/docs/plugins/preserve-tombs.rst index 67e7ceff6..e1d0ba8ce 100644 --- a/docs/plugins/preserve-tombs.rst +++ b/docs/plugins/preserve-tombs.rst @@ -16,7 +16,7 @@ Usage ``preserve-tombs [status]`` check the status of the plugin, and if the plugin is enabled, lists all currently tracked tomb assignments -``preserve-tombs update`` +``preserve-tombs now`` forces an immediate update of the tomb assignments. This plugin automatically updates the tomb assignments once every 100 ticks. diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp index 3e5cea1d2..976b6bd22 100644 --- a/plugins/preserve-tombs.cpp +++ b/plugins/preserve-tombs.cpp @@ -98,7 +98,7 @@ static command_result do_command(color_ostream& out, std::vector& p } return CR_OK; } - if (params[0] == "update") { + if (params[0] == "now") { if (!is_enabled) { out.printerr("Cannot update %s when not enabled", plugin_name); return CR_FAILURE; @@ -232,11 +232,9 @@ static void update_tomb_assignments(color_ostream &out) { plugin_name, tomb->assigned_unit_id, tomb->id); } - else { - if (it->second != tomb->id) { - DEBUG(cycle, out).print("%s tomb assignment to %d changed, (old: %d, new: %d)\n", - plugin_name, tomb->assigned_unit_id, it->second, tomb->id); - } + else if (it->second != tomb->id) { + DEBUG(cycle, out).print("%s tomb assignment to %d changed, (old: %d, new: %d)\n", + plugin_name, tomb->assigned_unit_id, it->second, tomb->id); it->second = tomb->id; } @@ -257,7 +255,7 @@ static void update_tomb_assignments(color_ostream &out) { return true; } if (tomb->assigned_unit_id != unit_id) { - DEBUG(cycle, out).print("%s unassigned unit %d from tomb %d - removing\n", plugin_name, unit_id, building_id); + DEBUG(cycle, out).print("%s unit %d unassigned from tomb %d - removing\n", plugin_name, unit_id, building_id); return true; } From a50013af26680351e283dde2a2f6d18d23bc5515 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 1 Oct 2023 18:57:06 +0000 Subject: [PATCH 673/851] 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 b313b69ad..22d59be19 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit b313b69adafef0bc3597df285504b729c44bea86 +Subproject commit 22d59be193d833bc822ae9b3f45d5c0639dbe886 diff --git a/scripts b/scripts index 8259d95e9..4250c075d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 8259d95e9ee9d88c88f32b22608d0d8c977aac18 +Subproject commit 4250c075d237b4da1efed8a9fd4af302b3f0c8c4 From 66b363b2918556470bb9a65ba726af8c7917757b Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 1 Oct 2023 20:24:16 +0000 Subject: [PATCH 674/851] 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 22d59be19..ab5c2aff1 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 22d59be193d833bc822ae9b3f45d5c0639dbe886 +Subproject commit ab5c2aff11c5f8c9c0f38820073be9ba51b8edce diff --git a/scripts b/scripts index 4250c075d..7911f7589 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 4250c075d237b4da1efed8a9fd4af302b3f0c8c4 +Subproject commit 7911f758979f1a8e9bf4d2ca893a3c1d9c9a43aa From 942cbe2015e6ef3f352a9df1b1db963a5141b109 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 1 Oct 2023 13:35:29 -0700 Subject: [PATCH 675/851] bump 50.11-r1 --- CMakeLists.txt | 2 +- docs/changelog.txt | 25 +++++++++++++++++-------- library/xml | 2 +- scripts | 2 +- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 74c37d4c7..c09fc6b71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_policy(SET CMP0074 NEW) project(dfhack) # set up versioning. -set(DF_VERSION "50.10") +set(DF_VERSION "50.11") set(DFHACK_RELEASE "r1") set(DFHACK_PRERELEASE FALSE) diff --git a/docs/changelog.txt b/docs/changelog.txt index 8d3d45778..db9fe5d88 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -53,10 +53,25 @@ Template for new versions: ## New Tools -- `tubefill`: (reinstated) replenishes mined-out adamantine - ## New Features +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 50.11-r1 + +## New Tools +- `tubefill`: (reinstated) replenishes mined-out adamantine + ## Fixes - `autolabor`: ensure vanilla work details are reinstated when the fort or the plugin is unloaded - ``dfhack.TranslateName()``: fixed crash on certain invalid names, which affected `warn-starving` @@ -70,15 +85,9 @@ Template for new versions: - EventManager: guard against potential iterator invalidation if one of the event listeners were to modify the global data structure being iterated over - EventManager: for ``onBuildingCreatedDestroyed`` events, changed firing order of events so destroyed events come before created events -## Documentation - -## API - ## Lua - mouse key events are now aligned with internal DF semantics: ``_MOUSE_L`` indicates that the left mouse button has just been pressed and ``_MOUSE_L_DOWN`` indicates that the left mouse button is being held down. similarly for ``_MOUSE_R`` and ``_MOUSE_M``. 3rd party scripts may have to adjust. -## Removed - # 50.10-r1 ## Fixes diff --git a/library/xml b/library/xml index ab5c2aff1..f38f3c495 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ab5c2aff11c5f8c9c0f38820073be9ba51b8edce +Subproject commit f38f3c4955d604f2b5a8e0d952e676a0ab05c053 diff --git a/scripts b/scripts index 7911f7589..bcfbfe51b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 7911f758979f1a8e9bf4d2ca893a3c1d9c9a43aa +Subproject commit bcfbfe51ba2256b0cfe3f172f51dea29d370cd82 From 8ed48901605a051c4b6a7312352a4b54648a9de3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 1 Oct 2023 16:21:25 -0700 Subject: [PATCH 676/851] put highlights first in the release notes template --- .github/release_template.md | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/.github/release_template.md b/.github/release_template.md index eb1c43146..9431a4e18 100644 --- a/.github/release_template.md +++ b/.github/release_template.md @@ -12,45 +12,45 @@ This release is compatible with all distributions of Dwarf Fortress: [Steam](htt Please report any issues (or feature requests) on the DFHack [GitHub issue tracker](https://github.com/DFHack/dfhack/issues). When reporting issues, please upload a zip file of your savegame and a zip file of your `mods` directory to the cloud and add links to the GitHub issue. Make sure your files are downloadable by "everyone with the link". We need your savegame to reproduce the problem and test the fix, and we need your active mods so we can load your savegame. Issues with savegames and mods attached get fixed first! -Announcements +Highlights ----------------------------------
-Annc 1, PSAs - -### Annc 1 +Highlight 1, Highlight 2 -Text +### Highlight 1 -### PSAs +Demo screenshot/vidcap -As always, remember that, just like the vanilla DF game, DFHack tools can also have bugs. It is a good idea to **save often and keep backups** of the forts that you care about. +Text -Many DFHack tools that worked in previous (pre-Steam) versions of DF have not been updated yet and are marked with the "unavailable" tag in their docs. If you try to run them, they will show a warning and exit immediately. You can run the command again to override the warning (though of course the tools may not work). We make no guarantees of reliability for the tools that are marked as "unavailable". +### Highlight 2 -The in-game interface for running DFHack commands (`gui/launcher`) will not show "unavailable" tools by default. You can still run them if you know their names, or you can turn on dev mode by hitting Ctrl-D while in `gui/launcher` and they will be added to the autocomplete list. Some tools do not compile yet and are not available at all, even when in dev mode. +Demo screenshot/vidcap -If you see a tool complaining about the lack of a cursor, know that it's referring to the **keyboard** cursor (which used to be the only real option in Dwarf Fortress). You can enable the keyboard cursor by entering mining mode or selecting the dump/forbid tool and hitting Alt-K (the DFHack keybinding for `toggle-kbd-cursor`. We're working on making DFHack tools more mouse-aware and accessible so this step isn't necessary in the future. +Text
-Highlights +Announcements ----------------------------------
-Highlight 1, Highlight 2 - -### Highlight 1 +Annc 1, PSAs -Demo screenshot/vidcap +### Annc 1 Text -### Highlight 2 +### PSAs -Demo screenshot/vidcap +As always, remember that, just like the vanilla DF game, DFHack tools can also have bugs. It is a good idea to **save often and keep backups** of the forts that you care about. -Text +Many DFHack tools that worked in previous (pre-Steam) versions of DF have not been updated yet and are marked with the "unavailable" tag in their docs. If you try to run them, they will show a warning and exit immediately. You can run the command again to override the warning (though of course the tools may not work). We make no guarantees of reliability for the tools that are marked as "unavailable". + +The in-game interface for running DFHack commands (`gui/launcher`) will not show "unavailable" tools by default. You can still run them if you know their names, or you can turn on dev mode by hitting Ctrl-D while in `gui/launcher` and they will be added to the autocomplete list. Some tools do not compile yet and are not available at all, even when in dev mode. + +If you see a tool complaining about the lack of a cursor, know that it's referring to the **keyboard** cursor (which used to be the only real option in Dwarf Fortress). You can enable the keyboard cursor by entering mining mode or selecting the dump/forbid tool and hitting Alt-K (the DFHack keybinding for `toggle-kbd-cursor`. We're working on making DFHack tools more mouse-aware and accessible so this step isn't necessary in the future.
@@ -61,5 +61,4 @@ Generated release notes New tools, fixes, and improvements %RELEASE_NOTES% - From 5d295400d25b5fe14bce27262af6e4ba7e68a3d9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 1 Oct 2023 16:28:18 -0700 Subject: [PATCH 677/851] centralize management of mouse state --- ci/test.lua | 3 --- docs/dev/Lua API.rst | 8 +++++++ library/include/modules/Screen.h | 1 + library/lua/gui.lua | 40 +++++++++++++------------------- library/lua/gui/dialogs.lua | 18 +++----------- library/modules/Screen.cpp | 18 +++++++++++++- plugins/lua/hotkeys.lua | 2 -- plugins/lua/overlay.lua | 1 - plugins/overlay.cpp | 2 +- 9 files changed, 46 insertions(+), 47 deletions(-) diff --git a/ci/test.lua b/ci/test.lua index 372d8f262..9a7c0d345 100644 --- a/ci/test.lua +++ b/ci/test.lua @@ -222,9 +222,6 @@ local function click_top_title_button(scr) df.global.gps.mouse_y = (sh // 2) + 3 end df.global.gps.precise_mouse_y = df.global.gps.mouse_y * df.global.gps.tile_pixel_y - df.global.enabler.tracking_on = 1 - df.global.enabler.mouse_lbut = 1 - df.global.enabler.mouse_lbut_down = 1 gui.simulateInput(scr, '_MOUSE_L') end diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 6eeb2dbe7..99dcabf7e 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3952,6 +3952,14 @@ Misc of keycodes to *true* or *false*. For instance, it is possible to use the table passed as argument to ``onInput``. + You can send mouse clicks as will by setting the ``_MOUSE_L`` key or other + mouse-related pseudo-keys documented with the ``screen:onInput(keys)`` + function above. Note that if you are simulating a click at a specific spot on + the screen, you must set ``df.global.gps.mouse_x`` and + ``df.global.gps.mouse_y`` if you are clicking on the interface layer or + ``df.global.gps.precise_mouse_x`` and ``df.global.gps.precise_mouse_y`` if + you are clickin on the map. + * ``mkdims_xy(x1,y1,x2,y2)`` Returns a table containing the arguments as fields, and also ``width`` and diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index 681398f89..96f1f6642 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -391,6 +391,7 @@ namespace DFHack virtual ~dfhack_lua_viewscreen(); static df::viewscreen *get_pointer(lua_State *L, int idx, bool make); + static void markInputAsHandled(); virtual bool is_lua_screen() { return true; } virtual bool isFocused() { return !defocused; } diff --git a/library/lua/gui.lua b/library/lua/gui.lua index ba49e0cdc..bb29124a5 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -15,8 +15,8 @@ TRANSPARENT_PEN = to_pen{tile=0, ch=0} KEEP_LOWER_PEN = to_pen{ch=32, fg=0, bg=0, keep_lower=true} local MOUSE_KEYS = { - _MOUSE_L = true, - _MOUSE_R = true, + _MOUSE_L = function(is_set) df.global.enabler.mouse_lbut = is_set and 1 or 0 end, + _MOUSE_R = function(is_set) df.global.enabler.mouse_rbut = is_set and 1 or 0 end, _MOUSE_M = true, _MOUSE_L_DOWN = true, _MOUSE_R_DOWN = true, @@ -27,7 +27,7 @@ local FAKE_INPUT_KEYS = copyall(MOUSE_KEYS) FAKE_INPUT_KEYS._STRING = true function simulateInput(screen,...) - local keys = {} + local keys, enabled_mouse_keys = {}, {} local function push_key(arg) local kv = arg if type(arg) == 'string' then @@ -35,6 +35,10 @@ function simulateInput(screen,...) if kv == nil and not FAKE_INPUT_KEYS[arg] then error('Invalid keycode: '..arg) end + if MOUSE_KEYS[arg] then + df.global.enabler.tracking_on = 1 + enabled_mouse_keys[arg] = true + end end if type(kv) == 'number' then keys[#keys+1] = kv @@ -57,6 +61,11 @@ function simulateInput(screen,...) end end end + for mk, fn in pairs(MOUSE_KEYS) do + if type(fn) == 'function' then + fn(enabled_mouse_keys[mk]) + end + end dscreen._doSimulateInput(screen, keys) end @@ -696,17 +705,6 @@ end DEFAULT_INITIAL_PAUSE = true --- ensure underlying DF screens don't also react to handled clicks -function markMouseClicksHandled(keys) - if keys._MOUSE_L then - df.global.enabler.mouse_lbut = 0 - end - if keys._MOUSE_R then - df.global.enabler.mouse_rbut_down = 0 - df.global.enabler.mouse_rbut = 0 - end -end - ZScreen = defclass(ZScreen, Screen) ZScreen.ATTRS{ defocusable=true, @@ -791,23 +789,17 @@ function ZScreen:onInput(keys) self:raise() else self:sendInputToParent(keys) - return + return true end end if ZScreen.super.onInput(self, keys) then - markMouseClicksHandled(keys) - return - end - - if self.pass_mouse_clicks and keys._MOUSE_L and not has_mouse then + -- noop + elseif self.pass_mouse_clicks and keys._MOUSE_L and not has_mouse then self.defocused = self.defocusable self:sendInputToParent(keys) - return elseif keys.LEAVESCREEN or keys._MOUSE_R then self:dismiss() - markMouseClicksHandled(keys) - return else local passit = self.pass_pause and keys.D_PAUSE if not passit and self.pass_mouse_clicks then @@ -829,8 +821,8 @@ function ZScreen:onInput(keys) if passit then self:sendInputToParent(keys) end - return end + return true end function ZScreen:raise() diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua index 5778cc767..7a0f86b3f 100644 --- a/library/lua/gui/dialogs.lua +++ b/library/lua/gui/dialogs.lua @@ -64,13 +64,9 @@ function MessageBox:onInput(keys) elseif (keys.LEAVESCREEN or keys._MOUSE_R) and self.on_cancel then self.on_cancel() end - gui.markMouseClicksHandled(keys) - return true - end - if self:inputToSubviews(keys) then - gui.markMouseClicksHandled(keys) return true end + return self:inputToSubviews(keys) end function showMessage(title, text, tcolor, on_close) @@ -137,13 +133,9 @@ function InputBox:onInput(keys) if self.on_cancel then self.on_cancel() end - gui.markMouseClicksHandled(keys) - return true - end - if self:inputToSubviews(keys) then - gui.markMouseClicksHandled(keys) return true end + return self:inputToSubviews(keys) end function showInputPrompt(title, text, tcolor, input, on_input, on_cancel, min_width) @@ -242,13 +234,9 @@ function ListBox:onInput(keys) if self.on_cancel then self.on_cancel() end - gui.markMouseClicksHandled(keys) - return true - end - if self:inputToSubviews(keys) then - gui.markMouseClicksHandled(keys) return true end + return self:inputToSubviews(keys) end function showListPrompt(title, text, tcolor, choices, on_select, on_cancel, min_width, filter) diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index a5b347493..dee7e2b75 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -956,6 +956,18 @@ int dfhack_lua_viewscreen::do_notify(lua_State *L) return 1; } +void dfhack_lua_viewscreen::markInputAsHandled() { + if (!enabler) + return; + + // clear text buffer + enabler->last_text_input[0] = '\0'; + + // mark clicked mouse buttons as handled + enabler->mouse_lbut = 0; + enabler->mouse_rbut = 0; +} + int dfhack_lua_viewscreen::do_input(lua_State *L) { auto self = get_self(L); @@ -977,7 +989,11 @@ int dfhack_lua_viewscreen::do_input(lua_State *L) lua_pushvalue(L, -2); Lua::PushInterfaceKeys(L, Screen::normalize_text_keys(*keys)); - lua_call(L, 2, 0); + lua_call(L, 2, 1); + if (lua_toboolean(L, -1)) + markInputAsHandled(); + lua_pop(L, 1); + self->update_focus(L, -1); return 0; } diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 6335de5e5..4c33f93ca 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -280,14 +280,12 @@ function Menu:onInput(keys) local x = list:getMousePos() if x == 0 then -- clicked on icon self:onSubmit2(list:getSelected()) - gui.markMouseClicksHandled(keys) return true end if not self:getMouseFramePos() then self.parent_view:dismiss() return true end - gui.markMouseClicksHandled(keys) end self:inputToSubviews(keys) return true -- we're modal diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index cd5286d0d..9751561a8 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -506,7 +506,6 @@ function feed_viewscreen_widgets(vs_name, vs, keys) not _feed_viewscreen_widgets('all', nil, keys) then return false end - gui.markMouseClicksHandled(keys) return true end diff --git a/plugins/overlay.cpp b/plugins/overlay.cpp index 3fec6091b..c94397956 100644 --- a/plugins/overlay.cpp +++ b/plugins/overlay.cpp @@ -86,7 +86,7 @@ struct viewscreen_overlay : T { if (!input_is_handled) INTERPOSE_NEXT(feed)(input); else - enabler->last_text_input[0] = '\0'; + dfhack_lua_viewscreen::markInputAsHandled(); } DEFINE_VMETHOD_INTERPOSE(void, render, ()) { INTERPOSE_NEXT(render)(); From c22ac294a0ba1e233fc2fa989492a162cc3d7537 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 1 Oct 2023 22:57:24 -0400 Subject: [PATCH 678/851] Re-add tags in embark-tools docs They appear to have accidentally been removed in 2627820bfa3df3841d78e79f9895f166346d0041 (no other plugins were affected) --- docs/plugins/embark-tools.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/embark-tools.rst b/docs/plugins/embark-tools.rst index f320706ff..0c76b887f 100644 --- a/docs/plugins/embark-tools.rst +++ b/docs/plugins/embark-tools.rst @@ -3,7 +3,7 @@ embark-tools .. dfhack-tool:: :summary: Extend the embark screen functionality. - + :tags: unavailable embark fort interface Usage ----- From cf7ca401902b3b8c3cda464c5b023785483d9dfc Mon Sep 17 00:00:00 2001 From: Myk Date: Sun, 1 Oct 2023 23:10:54 -0700 Subject: [PATCH 679/851] Update docs/dev/Lua API.rst Co-authored-by: Alan --- 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 99dcabf7e..49f0b3633 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3958,7 +3958,7 @@ Misc the screen, you must set ``df.global.gps.mouse_x`` and ``df.global.gps.mouse_y`` if you are clicking on the interface layer or ``df.global.gps.precise_mouse_x`` and ``df.global.gps.precise_mouse_y`` if - you are clickin on the map. + you are clicking on the map. * ``mkdims_xy(x1,y1,x2,y2)`` From b0bbe2bd5af35839c1274833688059d41570c95b Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 2 Oct 2023 07:13:30 +0000 Subject: [PATCH 680/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index bcfbfe51b..d2ad86165 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit bcfbfe51ba2256b0cfe3f172f51dea29d370cd82 +Subproject commit d2ad86165e89dc3b0f262eea00db8e2347cc4421 From 4e7725c1478de41395af1b38adc66b938f02b3d3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 05:43:36 +0000 Subject: [PATCH 681/851] [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.26.3 → 0.27.0](https://github.com/python-jsonschema/check-jsonschema/compare/0.26.3...0.27.0) --- .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 d9c148058..00228be82 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.26.3 + rev: 0.27.0 hooks: - id: check-github-workflows - repo: https://github.com/Lucas-C/pre-commit-hooks From 7d23ea73adaf5f9a5bb2281ed09c551f66b60b6a Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 3 Oct 2023 18:00:51 +0000 Subject: [PATCH 682/851] 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 f38f3c495..aeab463a0 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit f38f3c4955d604f2b5a8e0d952e676a0ab05c053 +Subproject commit aeab463a0d35ac9ff896db840735cabfa12df712 diff --git a/scripts b/scripts index d2ad86165..28bcd6e31 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit d2ad86165e89dc3b0f262eea00db8e2347cc4421 +Subproject commit 28bcd6e313ea6f87ffd805c8cf40360da5f21509 From 34b86772d80fde26a812891f2b20ae12afc71c59 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 30 Sep 2023 03:01:26 -0500 Subject: [PATCH 683/851] use df's translate_name function if available requires dfhack/df-structures#666 (included) needs testing on linux --- library/modules/Translation.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/library/modules/Translation.cpp b/library/modules/Translation.cpp index af06eeb49..8bd79d101 100644 --- a/library/modules/Translation.cpp +++ b/library/modules/Translation.cpp @@ -27,7 +27,7 @@ distribution. #include #include #include -using namespace std; +#include #include "modules/Translation.h" #include "VersionInfo.h" @@ -36,6 +36,7 @@ using namespace std; #include "ModuleFactory.h" #include "Core.h" #include "Error.h" +#include "Debug.h" using namespace DFHack; using namespace df::enums; @@ -44,10 +45,16 @@ using namespace df::enums; #include "df/world.h" #include "df/d_init.h" +using std::vector, std::string; + using df::global::world; using df::global::d_init; using df::global::gametype; +namespace DFHack { + DBG_DECLARE(core, translate, DebugCategory::LINFO); +} + bool Translation::IsValid () { return (world && (world->raws.language.words.size() > 0) && (world->raws.language.translations.size() > 0)); @@ -167,6 +174,23 @@ string Translation::TranslateName(const df::language_name * name, bool inEnglish CHECK_NULL_POINTER(name); string out; + + auto fp = df::global::translate_name; + + if (fp) { + DEBUG(translate).print("using df provided translate_name function\n"); + typedef std::function fun_type; + auto f = reinterpret_cast(fp); + try { + (*f)(*name, out, inEnglish, onlyLastPart); + return out; + } + catch (...) { + WARN(translate).print("df provided translate_name function threw an exception, falling back\n"); + } + } + + DEBUG(translate).print("using dfhack fallback translate_name function\n"); string word; if (!onlyLastPart) { From ad2c4dd0df063b8b5de97a779704fd2da5f0c9d0 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Sat, 30 Sep 2023 03:01:26 -0500 Subject: [PATCH 684/851] use df's translate_name function if available requires dfhack/df-structures#666 (included) needs testing on linux --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 41ca5a603..81bf3b1e6 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -59,6 +59,7 @@ Template for new versions: ## Fixes ## Misc Improvements +- Translate: will use DF's ``translate_name`` function, if available, instead of the DFHack emulation ## Documentation From 964c9d38ea7c3df28cfd0a97776544b458d0d875 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 4 Oct 2023 00:31:04 +0000 Subject: [PATCH 685/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 28bcd6e31..a8a7ec8bc 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 28bcd6e313ea6f87ffd805c8cf40360da5f21509 +Subproject commit a8a7ec8bc52ae8b63c1ae2a58f2904958734f3c5 From 082a97a0f6345529b0711a69753cce12343bc621 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Wed, 4 Oct 2023 01:10:16 -0500 Subject: [PATCH 686/851] remove refrence to unused field `wait_timer` is not really there; what we have labeled as `wait_timer` is actually padding so there is no need to do this --- plugins/strangemood.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/strangemood.cpp b/plugins/strangemood.cpp index b300eb795..88d1df071 100644 --- a/plugins/strangemood.cpp +++ b/plugins/strangemood.cpp @@ -1217,7 +1217,6 @@ command_result df_strangemood (color_ostream &out, vector & parameters) ref->setID(unit->id); job->general_refs.push_back(ref); unit->job.current_job = job; - job->wait_timer = 0; // Generate the artifact's name if (type == mood_type::Fell || type == mood_type::Macabre) From 89be6f56ef60303dbc0b34e22f7d87a128913701 Mon Sep 17 00:00:00 2001 From: Myk Date: Thu, 5 Oct 2023 12:56:46 -0700 Subject: [PATCH 687/851] Apply suggestions from code review --- plugins/preserve-tombs.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/preserve-tombs.cpp b/plugins/preserve-tombs.cpp index 976b6bd22..be560e1ce 100644 --- a/plugins/preserve-tombs.cpp +++ b/plugins/preserve-tombs.cpp @@ -75,7 +75,7 @@ static command_result do_command(color_ostream& out, std::vector& p DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( plugin_name, - "Preserves tomb assignments to units when they die.", + "Preserve tomb assignments when assigned units die.", do_command)); return CR_OK; } @@ -144,6 +144,8 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { DFhackCExport command_result plugin_shutdown (color_ostream &out) { DEBUG(config,out).print("shutting down %s\n", plugin_name); +// PluginManager handles unregistering our handler from EventManager, +// so we don't have to do that here return CR_OK; } @@ -201,11 +203,11 @@ void onUnitDeath(color_ostream& out, void* ptr) { // assign that unit to their previously assigned tomb in life int32_t building_id = it->second; if (!assign_to_tomb(unit_id, building_id)) { - DEBUG(event, out).print("Unit %d died - but failed to assign them to tomb %d\n", unit_id, building_id); + WARN(event, out).print("Unit %d died - but failed to assign them back to their tomb %d\n", unit_id, building_id); return; } // success, print status update and remove assignment from our memo-list - INFO(event, out).print("Unit %d died - assigning them to tomb %d\n", unit_id, building_id); + INFO(event, out).print("Unit %d died - assigning them back to their tomb\n", unit_id); tomb_assignments.erase(it); } From bad0448d345bfbb7a7a3cffd4c682a7673ac485d Mon Sep 17 00:00:00 2001 From: Myk Date: Thu, 5 Oct 2023 12:57:05 -0700 Subject: [PATCH 688/851] Update docs/plugins/preserve-tombs.rst --- docs/plugins/preserve-tombs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/preserve-tombs.rst b/docs/plugins/preserve-tombs.rst index e1d0ba8ce..2f01162c6 100644 --- a/docs/plugins/preserve-tombs.rst +++ b/docs/plugins/preserve-tombs.rst @@ -2,7 +2,7 @@ preserve-tombs ============== .. dfhack-tool:: - :summary: Fix tombs being unassigned to units on death + :summary: Preserve tomb assignments when assigned units die. :tags: fort bugfix If you find that the tombs you assign to units get unassigned from them when From 8a0956bc8316eb9c80edb86a80a9c375e409c973 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 5 Oct 2023 13:30:00 -0700 Subject: [PATCH 689/851] restore mouse state after sending input to parent --- library/lua/gui.lua | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index bb29124a5..4ee3eba4a 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -14,9 +14,15 @@ CLEAR_PEN = to_pen{tile=dfhack.internal.getAddress('init') and df.global.init.te TRANSPARENT_PEN = to_pen{tile=0, ch=0} KEEP_LOWER_PEN = to_pen{ch=32, fg=0, bg=0, keep_lower=true} +local function set_and_get_undo(field, is_set) + local prev_value = df.global.enabler[field] + df.global.enabler[field] = is_set and 1 or 0 + return function() df.global.enabler[field] = prev_value end +end + local MOUSE_KEYS = { - _MOUSE_L = function(is_set) df.global.enabler.mouse_lbut = is_set and 1 or 0 end, - _MOUSE_R = function(is_set) df.global.enabler.mouse_rbut = is_set and 1 or 0 end, + _MOUSE_L = curry(set_and_get_undo, 'mouse_lbut'), + _MOUSE_R = curry(set_and_get_undo, 'mouse_rbut'), _MOUSE_M = true, _MOUSE_L_DOWN = true, _MOUSE_R_DOWN = true, @@ -61,12 +67,16 @@ function simulateInput(screen,...) end end end + local undo_fns = {} for mk, fn in pairs(MOUSE_KEYS) do if type(fn) == 'function' then - fn(enabled_mouse_keys[mk]) + table.insert(undo_fns, fn(enabled_mouse_keys[mk])) end end dscreen._doSimulateInput(screen, keys) + for _, undo_fn in ipairs(undo_fns) do + undo_fn() + end end function mkdims_xy(x1,y1,x2,y2) From 194fb49f886958ee0b6b8ac4a9c1186881a33f38 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 5 Oct 2023 21:22:55 +0000 Subject: [PATCH 690/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index a8a7ec8bc..d76ac0b71 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit a8a7ec8bc52ae8b63c1ae2a58f2904958734f3c5 +Subproject commit d76ac0b710f989a8581d6f1a5c4afb70a99fee1a From b68a317c052e555c491a223ed75b51413ba4bc97 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 5 Oct 2023 14:25:14 -0700 Subject: [PATCH 691/851] fix encoding of cleanowned output --- plugins/cleanowned.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/cleanowned.cpp b/plugins/cleanowned.cpp index 3fece8bfe..c13f7826c 100644 --- a/plugins/cleanowned.cpp +++ b/plugins/cleanowned.cpp @@ -147,14 +147,14 @@ command_result df_cleanowned (color_ostream &out, vector & parameters) out.print( "[%d] %s (wear level %d)", item->id, - description.c_str(), + DF2CONSOLE(description).c_str(), item->getWear() ); df::unit *owner = Items::getOwner(item); if (owner) - out.print(", owner %s", Translation::TranslateName(&owner->name,false).c_str()); + out.print(", owner %s", DF2CONSOLE(Translation::TranslateName(&owner->name,false)).c_str()); if (!dry_run) { From beaba199391d9e6a3a2cdecf3ae11bed045f93b9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 6 Oct 2023 18:23:19 -0700 Subject: [PATCH 692/851] fix dig doc formatting --- docs/plugins/dig.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/plugins/dig.rst b/docs/plugins/dig.rst index 8d5c99536..2055a7572 100644 --- a/docs/plugins/dig.rst +++ b/docs/plugins/dig.rst @@ -147,15 +147,15 @@ Designation options: Other options: -``--zdown``, ``-d`` +``-d``, ``--zdown`` Only designates tiles on the cursor's z-level and below. -``--zup``, ``-u`` +``-u``, ``--zup`` Only designates tiles on the cursor's z-level and above. -``--cur-zlevel``, ``-z`` +``-z``, ``--cur-zlevel`` Only designates tiles on the same z-level as the cursor. -``--hidden``, ``-h`` +``-h``, ``--hidden`` Allows designation of hidden tiles, and picking a hidden tile as the target type. -``--no-auto``, ``-a`` +``-a``, ``--no-auto`` No automatic mining mode designation - useful if you want to avoid dwarves digging where you don't want them. digexp From 25600e45b092c04a177c4f72a60571e3992c0059 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 6 Oct 2023 18:25:24 -0700 Subject: [PATCH 693/851] support melting masterworks in logistics --- docs/changelog.txt | 1 + docs/plugins/logistics.rst | 4 ++ docs/plugins/stockpiles.rst | 8 +++- plugins/logistics.cpp | 29 ++++++++---- plugins/lua/logistics.lua | 17 +++++-- plugins/lua/stockpiles.lua | 89 +++++++++++++++++++++++++++++++++---- 6 files changed, 128 insertions(+), 20 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index ee608652c..1a97e637d 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -56,6 +56,7 @@ Template for new versions: - `preserve-tombs`: tracks tomb assignments to living units and ensures that the tomb stays assigned to them when they die. ## New Features +- `logistics`: ``automelt`` now optionally supports melting masterworks; feature accessible from `stockpiles` overlay ## Fixes diff --git a/docs/plugins/logistics.rst b/docs/plugins/logistics.rst index a65571484..d9aeee067 100644 --- a/docs/plugins/logistics.rst +++ b/docs/plugins/logistics.rst @@ -72,3 +72,7 @@ Options Causes the command to act upon stockpiles with the given names or numbers instead of the stockpile that is currently selected in the UI. Note that the numbers are the stockpile numbers, not the building ids. +``-m``, ``--melt-masterworks`` + If specified with a ``logistics add melt`` command, will configure the + stockpile to allow melting of masterworks. By default, masterworks are not + marked for melting, even if they are in an automelt stockpile. diff --git a/docs/plugins/stockpiles.rst b/docs/plugins/stockpiles.rst index 249a27d13..7d4ec050b 100644 --- a/docs/plugins/stockpiles.rst +++ b/docs/plugins/stockpiles.rst @@ -100,7 +100,13 @@ Overlay This plugin provides a panel that appears when you select a stockpile via an `overlay` widget. You can use it to easily toggle `logistics` plugin features -like autotrade, automelt, or autotrain. +like autotrade, automelt, or autotrain. There are also buttons along the top frame for: + +- minimizing the panel (if it is in the way of the vanilla stockpile + configuration widgets) +- showing help for the overlay widget in `gui/launcher` (this page) +- configuring advanced settings for the stockpile, such as whether automelt + will melt masterworks .. _stockpiles-library: diff --git a/plugins/logistics.cpp b/plugins/logistics.cpp index 86f65d351..d4d2f0afe 100644 --- a/plugins/logistics.cpp +++ b/plugins/logistics.cpp @@ -44,6 +44,7 @@ enum StockpileConfigValues { STOCKPILE_CONFIG_TRADE = 2, STOCKPILE_CONFIG_DUMP = 3, STOCKPILE_CONFIG_TRAIN = 4, + STOCKPILE_CONFIG_MELT_MASTERWORKS = 5, }; static int get_config_val(PersistentDataItem& c, int index) { @@ -81,6 +82,7 @@ static PersistentDataItem& ensure_stockpile_config(color_ostream& out, int stock set_config_bool(c, STOCKPILE_CONFIG_TRADE, false); set_config_bool(c, STOCKPILE_CONFIG_DUMP, false); set_config_bool(c, STOCKPILE_CONFIG_TRAIN, false); + set_config_bool(c, STOCKPILE_CONFIG_MELT_MASTERWORKS, false); return c; } @@ -259,8 +261,8 @@ public: class MeltStockProcessor : public StockProcessor { public: - MeltStockProcessor(int32_t stockpile_number, bool enabled, ProcessorStats &stats) - : StockProcessor("melt", stockpile_number, enabled, stats) { } + MeltStockProcessor(int32_t stockpile_number, bool enabled, ProcessorStats &stats, bool melt_masterworks) + : StockProcessor("melt", stockpile_number, enabled, stats), melt_masterworks(melt_masterworks) { } bool is_designated(color_ostream &out, df::item *item) override { return item->flags.bits.melt; @@ -294,7 +296,9 @@ public: } } - if (item->getQuality() >= df::item_quality::Masterful) + if (!melt_masterworks && item->getQuality() >= df::item_quality::Masterful) + return false; + if (item->flags.bits.artifact) return false; return true; @@ -305,6 +309,9 @@ public: item->flags.bits.melt = 1; return true; } + + private: + const bool melt_masterworks; }; class TradeStockProcessor: public StockProcessor { @@ -519,11 +526,12 @@ static void do_cycle(color_ostream& out, int32_t& melt_count, int32_t& trade_cou int32_t stockpile_number = bld->stockpile_number; bool melt = get_config_bool(c, STOCKPILE_CONFIG_MELT); + bool melt_masterworks = get_config_bool(c, STOCKPILE_CONFIG_MELT_MASTERWORKS); bool trade = get_config_bool(c, STOCKPILE_CONFIG_TRADE); bool dump = get_config_bool(c, STOCKPILE_CONFIG_DUMP); bool train = get_config_bool(c, STOCKPILE_CONFIG_TRAIN); - MeltStockProcessor melt_stock_processor(stockpile_number, melt, melt_stats); + MeltStockProcessor melt_stock_processor(stockpile_number, melt, melt_stats, melt_masterworks); TradeStockProcessor trade_stock_processor(stockpile_number, trade, trade_stats); DumpStockProcessor dump_stock_processor(stockpile_number, dump, dump_stats); TrainStockProcessor train_stock_processor(stockpile_number, train, train_stats); @@ -555,7 +563,7 @@ static int logistics_getStockpileData(lua_State *L) { for (auto bld : df::global::world->buildings.other.STOCKPILE) { int32_t stockpile_number = bld->stockpile_number; - MeltStockProcessor melt_stock_processor(stockpile_number, false, melt_stats); + MeltStockProcessor melt_stock_processor(stockpile_number, false, melt_stats, false); TradeStockProcessor trade_stock_processor(stockpile_number, false, trade_stats); DumpStockProcessor dump_stock_processor(stockpile_number, false, dump_stats); TrainStockProcessor train_stock_processor(stockpile_number, false, train_stats); @@ -581,12 +589,14 @@ static int logistics_getStockpileData(lua_State *L) { PersistentDataItem &c = entry.second; bool melt = get_config_bool(c, STOCKPILE_CONFIG_MELT); + bool melt_masterworks = get_config_bool(c, STOCKPILE_CONFIG_MELT_MASTERWORKS); bool trade = get_config_bool(c, STOCKPILE_CONFIG_TRADE); bool dump = get_config_bool(c, STOCKPILE_CONFIG_DUMP); bool train = get_config_bool(c, STOCKPILE_CONFIG_TRAIN); unordered_map config; config.emplace("melt", melt ? "true" : "false"); + config.emplace("melt_masterworks", melt_masterworks ? "true" : "false"); config.emplace("trade", trade ? "true" : "false"); config.emplace("dump", dump ? "true" : "false"); config.emplace("train", train ? "true" : "false"); @@ -633,11 +643,13 @@ static unordered_map get_stockpile_config(int32_t stockpile_number) if (watched_stockpiles.count(stockpile_number)) { PersistentDataItem &c = watched_stockpiles[stockpile_number]; stockpile_config.emplace("melt", get_config_bool(c, STOCKPILE_CONFIG_MELT)); + stockpile_config.emplace("melt_masterworks", get_config_bool(c, STOCKPILE_CONFIG_MELT_MASTERWORKS)); stockpile_config.emplace("trade", get_config_bool(c, STOCKPILE_CONFIG_TRADE)); stockpile_config.emplace("dump", get_config_bool(c, STOCKPILE_CONFIG_DUMP)); stockpile_config.emplace("train", get_config_bool(c, STOCKPILE_CONFIG_TRAIN)); } else { stockpile_config.emplace("melt", false); + stockpile_config.emplace("melt_masterworks", false); stockpile_config.emplace("trade", false); stockpile_config.emplace("dump", false); stockpile_config.emplace("train", false); @@ -666,9 +678,9 @@ static int logistics_getStockpileConfigs(lua_State *L) { return 1; } -static void logistics_setStockpileConfig(color_ostream& out, int stockpile_number, bool melt, bool trade, bool dump, bool train) { - DEBUG(status, out).print("entering logistics_setStockpileConfig stockpile_number=%d, melt=%d, trade=%d, dump=%d, train=%d\n", - stockpile_number, melt, trade, dump, train); +static void logistics_setStockpileConfig(color_ostream& out, int stockpile_number, bool melt, bool trade, bool dump, bool train, bool melt_masterworks) { + DEBUG(status, out).print("entering logistics_setStockpileConfig stockpile_number=%d, melt=%d, trade=%d, dump=%d, train=%d, melt_masterworks=%d\n", + stockpile_number, melt, trade, dump, train, melt_masterworks); if (!find_stockpile(stockpile_number)) { out.printerr("invalid stockpile number: %d\n", stockpile_number); @@ -677,6 +689,7 @@ static void logistics_setStockpileConfig(color_ostream& out, int stockpile_numbe auto &c = ensure_stockpile_config(out, stockpile_number); set_config_bool(c, STOCKPILE_CONFIG_MELT, melt); + set_config_bool(c, STOCKPILE_CONFIG_MELT_MASTERWORKS, melt_masterworks); set_config_bool(c, STOCKPILE_CONFIG_TRADE, trade); set_config_bool(c, STOCKPILE_CONFIG_DUMP, dump); set_config_bool(c, STOCKPILE_CONFIG_TRAIN, train); diff --git a/plugins/lua/logistics.lua b/plugins/lua/logistics.lua index 0231ce593..2f260cc59 100644 --- a/plugins/lua/logistics.lua +++ b/plugins/lua/logistics.lua @@ -29,6 +29,7 @@ function getStockpileData() trade=make_stat('trade', stockpile_number, stats, configs), dump=make_stat('dump', stockpile_number, stats, configs), train=make_stat('train', stockpile_number, stats, configs), + melt_masterworks=configs[stockpile_number] and configs[stockpile_number].melt_masterworks == 'true', }) end table.sort(data, function(a, b) return a.sort_key < b.sort_key end) @@ -41,16 +42,24 @@ local function print_stockpile_data(data) name_len = math.min(40, math.max(name_len, #sp.name)) end + local has_melt_mastworks = false + print('Designated/designatable items in stockpiles:') print() local fmt = '%6s %-' .. name_len .. 's %4s %10s %5s %11s %4s %10s %5s %11s'; print(fmt:format('number', 'name', 'melt', 'melt items', 'trade', 'trade items', 'dump', 'dump items', 'train', 'train items')) local function uline(len) return ('-'):rep(len) end print(fmt:format(uline(6), uline(name_len), uline(4), uline(10), uline(5), uline(11), uline(4), uline(10), uline(5), uline(11))) - local function get_enab(stats) return ('[%s]'):format(stats.enabled and 'x' or ' ') end + local function get_enab(stats, ch) return ('[%s]'):format(stats.enabled and (ch or 'x') or ' ') end local function get_dstat(stats) return ('%d/%d'):format(stats.designated, stats.designated + stats.can_designate) end for _,sp in ipairs(data) do - print(fmt:format(sp.stockpile_number, sp.name, get_enab(sp.melt), get_dstat(sp.melt), get_enab(sp.trade), get_dstat(sp.trade), get_enab(sp.dump), get_dstat(sp.dump), get_enab(sp.train), get_dstat(sp.train))) + has_melt_mastworks = has_melt_mastworks or sp.melt_masterworks + print(fmt:format(sp.stockpile_number, sp.name, get_enab(sp.melt, sp.melt_masterworks and 'X'), get_dstat(sp.melt), + get_enab(sp.trade), get_dstat(sp.trade), get_enab(sp.dump), get_dstat(sp.dump), get_enab(sp.train), get_dstat(sp.train))) + end + if has_melt_mastworks then + print() + print('An "X" in the "melt" column indicates that masterworks in the stockpile will be melted.') end end @@ -101,7 +110,8 @@ local function do_add_stockpile_config(features, opts) features.melt or config.melt == 1, features.trade or config.trade == 1, features.dump or config.dump == 1, - features.train or config.train == 1) + features.train or config.train == 1, + not not opts.melt_masterworks) end end end) @@ -125,6 +135,7 @@ local function process_args(opts, args) return argparse.processArgsGetopt(args, { {'h', 'help', handler=function() opts.help = true end}, + {'m', 'melt-masterworks', handler=function() opts.melt_masterworks = true end}, {'s', 'stockpile', hasArg=true, handler=function(arg) opts.sp = arg end}, }) end diff --git a/plugins/lua/stockpiles.lua b/plugins/lua/stockpiles.lua index 4707c97ad..f25205a9c 100644 --- a/plugins/lua/stockpiles.lua +++ b/plugins/lua/stockpiles.lua @@ -4,6 +4,7 @@ local argparse = require('argparse') local gui = require('gui') local logistics = require('plugins.logistics') local overlay = require('plugins.overlay') +local textures = require('gui.textures') local widgets = require('gui.widgets') local STOCKPILES_DIR = 'dfhack-config/stockpiles' @@ -262,6 +263,45 @@ local function do_export() export_view = export_view and export_view:raise() or StockpilesExportScreen{}:show() end +-------------------- +-- ConfigModal +-------------------- + +ConfigModal = defclass(ConfigModal, gui.ZScreenModal) +ConfigModal.ATTRS{ + focus_path='stockpiles_config', + on_close=DEFAULT_NIL, +} + +function ConfigModal:init() + local sp = dfhack.gui.getSelectedStockpile(true) + local cur_setting = false + if sp then + local config = logistics.logistics_getStockpileConfigs(sp.stockpile_number)[1] + cur_setting = config.melt_masterworks == 1 + end + + self:addviews{ + widgets.Window{ + frame={w=35, h=10}, + frame_title='Advanced logistics settings', + subviews={ + widgets.ToggleHotkeyLabel{ + view_id='melt_masterworks', + frame={l=0, t=0}, + key='CUSTOM_M', + label='Melt masterworks', + initial_option=cur_setting, + }, + }, + }, + } +end + +function ConfigModal:onDismiss() + self.on_close{melt_masterworks=self.subviews.melt_masterworks:getOptionValue()} +end + -------------------- -- MinimizeButton -------------------- @@ -368,9 +408,7 @@ function StockpilesOverlay:init() view_id='main', frame_style=gui.MEDIUM_FRAME, frame_background=gui.CLEAR_PEN, - visible=function() - return not self.minimized - end, + visible=function() return not self.minimized end, subviews={ -- widgets.HotkeyLabel{ -- frame={t=0, l=0}, @@ -439,14 +477,40 @@ function StockpilesOverlay:init() }, } + local button_pen_left = dfhack.pen.parse{fg=COLOR_CYAN, + tile=curry(textures.tp_control_panel, 7) or nil, ch=string.byte('[')} + local button_pen_right = dfhack.pen.parse{fg=COLOR_CYAN, + tile=curry(textures.tp_control_panel, 8) or nil, ch=string.byte(']')} + local help_pen_center = dfhack.pen.parse{ + tile=curry(textures.tp_control_panel, 9) or nil, ch=string.byte('?')} + local configure_pen_center = dfhack.pen.parse{ + tile=curry(textures.tp_control_panel, 10) or nil, ch=15} -- gear/masterwork symbol + self:addviews{ - main_panel, MinimizeButton{ + main_panel, + MinimizeButton{ frame={t=0, r=9}, - get_minimized_fn=function() - return self.minimized - end, + get_minimized_fn=function() return self.minimized end, on_click=self:callback('toggleMinimized'), }, + widgets.Label{ + frame={t=0, r=5, w=3}, + text={ + {tile=button_pen_left}, + {tile=configure_pen_center}, + {tile=button_pen_right}, + }, + on_click=function() ConfigModal{on_close=self:callback('on_custom_config')}:show() end, + }, + widgets.Label{ + frame={t=0, r=1, w=3}, + text={ + {tile=button_pen_left}, + {tile=help_pen_center}, + {tile=button_pen_right}, + }, + on_click=function() dfhack.run_command('gui/launcher', 'stockpiles ') end, + }, } end @@ -475,7 +539,16 @@ function StockpilesOverlay:toggleLogisticsFeature(feature) -- logical xor logistics.logistics_setStockpileConfig(config.stockpile_number, (feature == 'melt') ~= (config.melt == 1), (feature == 'trade') ~= (config.trade == 1), - (feature == 'dump') ~= (config.dump == 1), (feature == 'train') ~= (config.train == 1)) + (feature == 'dump') ~= (config.dump == 1), (feature == 'train') ~= (config.train == 1), + config.melt_masterworks == 1) +end + +function StockpilesOverlay:on_custom_config(custom) + local sp = dfhack.gui.getSelectedStockpile(true) + if not sp then return end + local config = logistics.logistics_getStockpileConfigs(sp.stockpile_number)[1] + logistics.logistics_setStockpileConfig(config.stockpile_number, + config.melt == 1, config.trade == 1, config.dump == 1, config.train == 1, custom.melt_masterworks) end function StockpilesOverlay:toggleMinimized() From 16eea7c8d45582cf2430e5e5131f1983df8e175f Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 7 Oct 2023 06:33:42 +0000 Subject: [PATCH 694/851] 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 aeab463a0..e49ebc338 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit aeab463a0d35ac9ff896db840735cabfa12df712 +Subproject commit e49ebc3380fd376d85e8d42accb68b25c4bc969c diff --git a/scripts b/scripts index d76ac0b71..740683792 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit d76ac0b710f989a8581d6f1a5c4afb70a99fee1a +Subproject commit 740683792d2e4bbdbb6d008f1dab1a1c07b9ce40 From a3cd847181b3f02f865b1bc7508f039320b4f449 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 7 Oct 2023 07:21:47 +0000 Subject: [PATCH 695/851] 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 e49ebc338..ff278cfe3 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e49ebc3380fd376d85e8d42accb68b25c4bc969c +Subproject commit ff278cfe3b98f6f6a36c7a4be19884677b753a8d diff --git a/scripts b/scripts index 740683792..728d90271 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 740683792d2e4bbdbb6d008f1dab1a1c07b9ce40 +Subproject commit 728d902712655592ec4385e88fd36077641ccfb1 From c4b31176a96fd1e579c029a7315465c43adc2cc9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 7 Oct 2023 00:46:42 -0700 Subject: [PATCH 696/851] remove outdated info for persistence API --- docs/dev/Lua API.rst | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 49f0b3633..9f9a3e374 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -684,7 +684,7 @@ Persistent configuration storage -------------------------------- This api is intended for storing configuration options in the world itself. -It probably should be restricted to data that is world-dependent. +It is intended for data that is world-dependent. Entries are identified by a string ``key``, but it is also possible to manage multiple entries with the same key; their identity is determined by ``entry_id``. @@ -717,10 +717,8 @@ Every entry has a mutable string ``value``, and an array of 7 mutable ``ints``. otherwise the existing one is simply updated. Returns *entry, did_create_new* -Since the data is hidden in data structures owned by the DF world, -and automatically stored in the save game, these save and retrieval -functions can just copy values in memory without doing any actual I/O. -However, currently every entry has a 180+-byte dead-weight overhead. +The data is kept in memory, so no I/O occurs when getting or saving keys. It is +all written to a json file in the game save directory when the game is saved. It is also possible to associate one bit per map tile with an entry, using these two methods: From ae16b65c890e41297aeea4c7223a5239a4a53193 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 7 Oct 2023 12:10:13 -0700 Subject: [PATCH 697/851] process keys before cursor dragging so a held mouse button doesn't inhibit text input --- library/lua/gui/widgets.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 05d237f35..34b154bf8 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -739,12 +739,6 @@ function EditField:onInput(keys) end end return not not self.key - elseif keys._MOUSE_L_DOWN then - local mouse_x = self:getMousePos() - if mouse_x then - self:setCursor(self.start_pos + mouse_x - (self.text_offset or 0)) - return true - end elseif keys._STRING then local old = self.text if keys._STRING == 0 then @@ -795,6 +789,12 @@ function EditField:onInput(keys) elseif keys.CUSTOM_CTRL_V then self:insert(dfhack.internal.getClipboardTextCp437()) return true + elseif keys._MOUSE_L_DOWN then + local mouse_x = self:getMousePos() + if mouse_x then + self:setCursor(self.start_pos + mouse_x - (self.text_offset or 0)) + return true + end end -- if we're modal, then unconditionally eat all the input From 37ad0c3e6f29b4a5a1d16ab7e0a8d39f03852c28 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 7 Oct 2023 12:10:52 -0700 Subject: [PATCH 698/851] add more focus string details for info panels --- library/modules/Gui.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 58763262f..a53876d8a 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -240,7 +240,14 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) switch(game->main_interface.info.current_mode) { case df::enums::info_interface_mode_type::CREATURES: - newFocusString += '/' + enum_item_key(game->main_interface.info.creatures.current_mode); + if (game->main_interface.info.creatures.showing_overall_training) + newFocusString += "/OverallTraining"; + else if (game->main_interface.info.creatures.showing_activity_details) + newFocusString += "/ActivityDetails"; + else if (game->main_interface.info.creatures.adding_trainer) + newFocusString += "/AddingTrainer"; + else + newFocusString += '/' + enum_item_key(game->main_interface.info.creatures.current_mode); break; case df::enums::info_interface_mode_type::BUILDINGS: newFocusString += '/' + enum_item_key(game->main_interface.info.buildings.mode); From ae1d6f98f64210751b9e420fe1e4b0be65bd02f6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 7 Oct 2023 12:11:24 -0700 Subject: [PATCH 699/851] add basic framework for info search widget --- plugins/lua/sort.lua | 14 ++-- plugins/lua/sort/creatures.lua | 139 +++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 plugins/lua/sort/creatures.lua diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 6d8c8a298..1159ce56e 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1,5 +1,6 @@ local _ENV = mkmodule('plugins.sort') +local creatures = require('plugins.sort.creatures') local gui = require('gui') local overlay = require('plugins.overlay') local setbelief = reqscript('modtools/set-belief') @@ -275,29 +276,29 @@ local function get_ranged_skill_effectiveness_rating(unit) return get_rating(ranged_skill_effectiveness(unit), 0, 800000, 72, 52, 31, 11) end -local function make_sort_by_ranged_skill_effectiveness_desc(list) +local function make_sort_by_ranged_skill_effectiveness_desc() return function(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = ranged_skill_effectiveness(unit1, list) - local rating2 = ranged_skill_effectiveness(unit2, list) + local rating1 = ranged_skill_effectiveness(unit1) + local rating2 = ranged_skill_effectiveness(unit2) if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end return utils.compare(rating2, rating1) end end -local function make_sort_by_ranged_skill_effectiveness_asc(list) +local function make_sort_by_ranged_skill_effectiveness_asc() return function(unit_id_1, unit_id_2) if unit_id_1 == unit_id_2 then return 0 end local unit1 = df.unit.find(unit_id_1) local unit2 = df.unit.find(unit_id_2) if not unit1 then return -1 end if not unit2 then return 1 end - local rating1 = ranged_skill_effectiveness(unit1, list) - local rating2 = ranged_skill_effectiveness(unit2, list) + local rating1 = ranged_skill_effectiveness(unit1) + local rating2 = ranged_skill_effectiveness(unit2) if rating1 == rating2 then return sort_by_name_desc(unit_id_1, unit_id_2) end return utils.compare(rating1, rating2) end @@ -1261,6 +1262,7 @@ end OVERLAY_WIDGETS = { squad_assignment=SquadAssignmentOverlay, squad_annotation=SquadAnnotationOverlay, + creatures=creatures.InfoOverlay, } dfhack.onStateChange[GLOBAL_KEY] = function(sc) diff --git a/plugins/lua/sort/creatures.lua b/plugins/lua/sort/creatures.lua new file mode 100644 index 000000000..adf6b3fe9 --- /dev/null +++ b/plugins/lua/sort/creatures.lua @@ -0,0 +1,139 @@ +local _ENV = mkmodule('plugins.sort.creatures') + +local overlay = require('plugins.overlay') +local widgets = require('gui.widgets') + +local creatures = df.global.game.main_interface.info.creatures + +-- ---------------------- +-- InfoOverlay +-- + +InfoOverlay = defclass(InfoOverlay, overlay.OverlayWidget) +InfoOverlay.ATTRS{ + default_pos={x=64, y=9}, + default_enabled=true, + viewscreens={ + 'dwarfmode/Info/CREATURES/CITIZEN', + 'dwarfmode/Info/CREATURES/PET', + 'dwarfmode/Info/CREATURES/OverallTraining', + 'dwarfmode/Info/CREATURES/AddingTrainer', + 'dwarfmode/Info/CREATURES/OTHER', + 'dwarfmode/Info/CREATURES/DECEASED', + }, + hotspot=true, + overlay_onupdate_max_freq_seconds=0, + frame={w=40, h=3}, +} + +function InfoOverlay:init() + self.state = {} + + self:addviews{ + widgets.BannerPanel{ + view_id='panel', + frame={l=0, t=0, r=0, h=1}, + subviews={ + widgets.EditField{ + view_id='search', + frame={l=1, t=0, r=1}, + label_text="Search: ", + key='CUSTOM_ALT_S', + on_change=self:callback('text_input'), + }, + }, + }, + } +end + +function InfoOverlay:overlay_onupdate(scr) + if next(self.state) and not dfhack.gui.matchFocusString('dwarfmode/Info', scr) then + -- TODO: add dynamically allocated elements that were not visible at the time of + -- closure back to the list so they can be properly disposed of + self.state = {} + self.subviews.search:setText('') + self.subviews.search:setFocus(false) + self.overlay_onupdate_max_freq_seconds = 60 + end +end + +local function are_tabs_in_two_rows() + local pen = dfhack.screen.readTile(64, 6, false) -- tile is occupied iff tabs are in one row + return pen.ch == 0 +end + +local function resize_overlay(self) + local sw = dfhack.screen.getWindowSize() + local overlay_width = math.min(40, sw-(self.frame_rect.x1 + 30)) + if overlay_width ~= self.frame.w then + self.frame.w = overlay_width + return true + end +end + +function InfoOverlay:updateFrames() + local ret = resize_overlay(self) + local two_rows = are_tabs_in_two_rows() + if (self.two_rows == two_rows) then return ret end + self.two_rows = two_rows + self.subviews.panel.frame.t = two_rows and 2 or 0 + return true +end + +local function get_key() + if creatures.current_mode == df.unit_list_mode_type.PET then + if creatures.showing_overall_training then + return 'PET_OT' + elseif creatures.adding_trainer then + return 'PET_AT' + end + end + return df.unit_list_mode_type[creatures.current_mode] +end + +local function check_context(self) + local key = get_key() + if self.state.prev_key ~= key then + self.state.prev_key = key + local prev_text = ensure_key(self.state, key).prev_text + self.subviews.search:setText(prev_text or '') + end +end + +function InfoOverlay:onRenderBody(dc) + if next(self.state) then + check_context(self) + end + if self:updateFrames() then + self:updateLayout() + end + self.overlay_onupdate_max_freq_seconds = 0 + InfoOverlay.super.onRenderBody(self, dc) +end + +function InfoOverlay:text_input(text) + if not next(self.state) and text == '' then return end + -- the EditField state is guaranteed to be consistent with the current + -- context since when clicking to switch tabs, onRenderBody is always called + -- before this text_input callback, even if a key is pressed before the next + -- graphical frame would otherwise be printed. if this ever becomes untrue, + -- then we can add an on_char handler to the EditField that also calls + -- check_context. + local key = get_key() + local prev_text = ensure_key(self.state, key).prev_text + if text == prev_text then return end + if prev_text and text:startswith(prev_text) then + -- TODO: search + print('performing incremental search; text:', text, 'key:', key) + else + -- TODO: save list if not already saved + -- TODO: else restore list from saved list + -- TODO: if text ~= '' then search + -- TODO: sort according to vanilla sort widget state + print('performing full search; text:', text, 'key:', key) + end + -- TODO: save visible list + self.state[key].prev_text = text +end + +return _ENV From 673287d0a4bbf15940e29dcd3d53a4102e6013a1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 7 Oct 2023 18:40:47 -0700 Subject: [PATCH 700/851] implement search logic --- plugins/lua/sort/creatures.lua | 199 ++++++++++++++++++++++++++++++--- 1 file changed, 183 insertions(+), 16 deletions(-) diff --git a/plugins/lua/sort/creatures.lua b/plugins/lua/sort/creatures.lua index adf6b3fe9..563bd3cca 100644 --- a/plugins/lua/sort/creatures.lua +++ b/plugins/lua/sort/creatures.lua @@ -2,9 +2,168 @@ local _ENV = mkmodule('plugins.sort.creatures') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') +local utils = require('utils') local creatures = df.global.game.main_interface.info.creatures +-- these sort functions attempt to match the vanilla sort behavior, which is not +-- quite the same as the rest of DFHack. For example, in other DFHack sorts, +-- we'd always sort by name descending as a secondary sort. To match vanilla sorting, +-- if the primary sort is ascending, the secondary name sort will also be ascending. +-- +-- also note that vanilla sorts are not stable, so there might still be some jitter +-- if the player clicks one of the vanilla sort widgets after searching +local function sort_by_name_desc(a, b) + return a.sort_name < b.sort_name +end + +local function sort_by_name_asc(a, b) + return a.sort_name > b.sort_name +end + +local function sort_by_prof_desc(a, b) + if a.profession_list_order1 == b.profession_list_order1 then + return sort_by_name_desc(a, b) + end + return a.profession_list_order1 < b.profession_list_order1 +end + +local function sort_by_prof_asc(a, b) + if a.profession_list_order1 == b.profession_list_order1 then + return sort_by_name_asc(a, b) + end + return a.profession_list_order1 > b.profession_list_order1 +end + +local function sort_by_job_name_desc(a, b) + if a.job_sort_name == b.job_sort_name then + return sort_by_name_desc(a, b) + end + return a.job_sort_name < b.job_sort_name +end + +local function sort_by_job_name_asc(a, b) + if a.job_sort_name == b.job_sort_name then + -- use descending tertiary sort for visual stability + return sort_by_name_desc(a, b) + end + return a.job_sort_name > b.job_sort_name +end + +local function sort_by_job_desc(a, b) + if not not a.jb == not not b.jb then + return sort_by_job_name_desc(a, b) + end + return not not a.jb +end + +local function sort_by_job_asc(a, b) + if not not a.jb == not not b.jb then + return sort_by_job_name_asc(a, b) + end + return not not b.jb +end + +local function sort_by_stress_desc(a, b) + if a.stress == b.stress then + return sort_by_name_desc(a, b) + end + return a.stress > b.stress +end + +local function sort_by_stress_asc(a, b) + if a.stress == b.stress then + return sort_by_name_asc(a, b) + end + return a.stress < b.stress +end + +local function get_sort() + if creatures.sorting_cit_job then + return creatures.sorting_cit_job_is_ascending and sort_by_job_asc or sort_by_job_desc + elseif creatures.sorting_cit_stress then + return creatures.sorting_cit_stress_is_ascending and sort_by_stress_asc or sort_by_stress_desc + elseif creatures.sorting_cit_nameprof_doing_prof then + return creatures.sorting_cit_nameprof_is_ascending and sort_by_prof_asc or sort_by_prof_desc + else + return creatures.sorting_cit_nameprof_is_ascending and sort_by_name_asc or sort_by_name_desc + end +end + +local function copy_to_lua_table(vec) + local tab = {} + for k,v in ipairs(vec) do + tab[k+1] = v + end + return tab +end + +local function general_search(vec, get_search_key_fn, get_sort_fn, data, filter, incremental) + if not data.saved_original then + data.saved_original = copy_to_lua_table(vec) + elseif not incremental then + vec:assign(data.saved_original) + end + if filter ~= '' then + local search_tokens = filter:split() + for idx = #vec-1,0,-1 do + local search_key = get_search_key_fn(vec[idx]) + if search_key and not utils.search_text(search_key, search_tokens) then + vec:erase(idx) + end + end + end + data.saved_visible = copy_to_lua_table(vec) + if get_sort_fn then + table.sort(data.saved_visible, get_sort_fn()) + vec:assign(data.saved_visible) + end +end + +-- add dynamically allocated elements that were not visible at the time of +-- closure back to the vector so they can be cleaned up when it is next initialized +local function cri_unitst_cleanup(vec, data) + if not data.saved_visible or not data.saved_original then return end + for _,elem in ipairs(data.saved_original) do + if not utils.linear_index(data.saved_visible, elem) then + vec:insert('#', elem) + end + end +end + +local function make_cri_unitst_handlers(vec) + return { + search_fn=curry(general_search, vec, + function(elem) return elem.sort_name end, + get_sort), + cleanup_fn=curry(cri_unitst_cleanup, vec), + } +end + +local function overall_training_search(data, filter, incremental) + general_search(creatures.atk_index, function(elem) + local raw = df.creature_raw.find(elem) + if not raw then return '' end + return raw.name[1] + end, nil, data, filter, incremental) +end + +local function assign_trainer_search(data, filter, incremental) + general_search(creatures.trainer, function(elem) + if not elem then return nil end + return ('%s %s'):format(dfhack.TranslateName(elem.name), dfhack.units.getProfessionName(elem)) + end, nil, data, filter, incremental) +end + +local HANDLERS = { + CITIZEN=make_cri_unitst_handlers(creatures.cri_unit.CITIZEN), + PET=make_cri_unitst_handlers(creatures.cri_unit.PET), + OTHER=make_cri_unitst_handlers(creatures.cri_unit.OTHER), + DECEASED=make_cri_unitst_handlers(creatures.cri_unit.DECEASED), + PET_OT={search_fn=overall_training_search}, + PET_AT={search_fn=assign_trainer_search}, +} + -- ---------------------- -- InfoOverlay -- @@ -46,10 +205,18 @@ function InfoOverlay:init() } end -function InfoOverlay:overlay_onupdate(scr) - if next(self.state) and not dfhack.gui.matchFocusString('dwarfmode/Info', scr) then - -- TODO: add dynamically allocated elements that were not visible at the time of - -- closure back to the list so they can be properly disposed of +local function cleanup(state) + for k,v in pairs(state) do + local cleanup_fn = safe_index(HANDLERS, k, 'cleanup_fn') + if cleanup_fn then cleanup_fn(v) end + end +end + +function InfoOverlay:overlay_onupdate() + if next(self.state) and + not dfhack.gui.matchFocusString('dwarfmode/Info', dfhack.gui.getDFViewscreen(true)) + then + cleanup(self.state) self.state = {} self.subviews.search:setText('') self.subviews.search:setFocus(false) @@ -121,19 +288,19 @@ function InfoOverlay:text_input(text) -- check_context. local key = get_key() local prev_text = ensure_key(self.state, key).prev_text - if text == prev_text then return end - if prev_text and text:startswith(prev_text) then - -- TODO: search - print('performing incremental search; text:', text, 'key:', key) - else - -- TODO: save list if not already saved - -- TODO: else restore list from saved list - -- TODO: if text ~= '' then search - -- TODO: sort according to vanilla sort widget state - print('performing full search; text:', text, 'key:', key) - end - -- TODO: save visible list + -- some screens reset their contents between context switches; regardless + -- a switch back to the context should results in an incremental search + local incremental = prev_text and text:startswith(prev_text) + HANDLERS[key].search_fn(self.state[key], text, incremental) self.state[key].prev_text = text end +function InfoOverlay:onInput(keys) + if keys._MOUSE_R and self.subviews.search.focus then + self.subviews.search:setFocus(false) + return true + end + return InfoOverlay.super.onInput(self, keys) +end + return _ENV From 504948333035af6be03d98bb532c04fe44e5930b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 7 Oct 2023 18:55:39 -0700 Subject: [PATCH 701/851] refactor text search routine out into utils fn --- docs/changelog.txt | 2 ++ docs/dev/Lua API.rst | 21 +++++++++++++--- library/lua/gui/widgets.lua | 29 +--------------------- library/lua/utils.lua | 26 +++++++++++++++++++ plugins/lua/buildingplan/itemselection.lua | 1 - 5 files changed, 46 insertions(+), 33 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1a97e637d..57b78c087 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -67,8 +67,10 @@ Template for new versions: ## API ## Lua +- ``utils.search_text``: text search routine (generalized from ``widgets.FilteredList``) ## Removed +- ``FILTER_FULL_TEXT``: moved from ``gui.widgets`` to ``utils``; if your full text search preference is lost, please reset it in `gui/control-panel` # 50.11-r1 diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 9f9a3e374..f5314e4fb 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3337,6 +3337,20 @@ utils Exactly like ``erase_sorted_key``, but if field is specified, takes the key from ``item[field]``. +* ``utils.search_text(text,search_tokens)`` + + Returns true if all the search tokens are found within ``text``. The text and + search tokens are normalized to lower case and special characters (e.g. ``A`` + with a circle on it) are converted to their "basic" forms (e.g. ``a``). + ``search_tokens`` can be a string or a table of strings. If it is a string, + it is split into space-separated tokens before matching. The search tokens + are treated literally, so any special regular expression characters do not + need to be escaped. If ``utils.FILTER_FULL_TEXT`` is ``true``, then the + search tokens can match any part of ``text``. If it is ``false``, then the + matches must happen at the beginning of words within ``text``. You can change + the value of ``utils.FILTER_FULL_TEXT`` in `gui/control-panel` on the + "Preferences" tab. + * ``utils.call_with_string(obj,methodname,...)`` Allocates a temporary string object, calls ``obj:method(tmp,...)``, and @@ -5291,12 +5305,11 @@ FilteredList class ------------------ This widget combines List, EditField and Label into a combo-box like -construction that allows filtering the list by subwords of its items. +construction that allows filtering the list. In addition to passing through all attributes supported by List, it supports: -:case_sensitive: If ``true``, matching is case sensitive. Defaults to ``false``. :edit_pen: If specified, used instead of ``cursor_pen`` for the edit field. :edit_below: If true, the edit field is placed below the list instead of above. :edit_key: If specified, the edit field is disabled until this key is pressed. @@ -5345,9 +5358,9 @@ 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:: +substring across the full text with a command like:: - :lua require('gui.widgets').FILTER_FULL_TEXT=true + :lua require('utils').FILTER_FULL_TEXT=true TabBar class ------------ diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 05d237f35..61da7af65 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -2017,12 +2017,9 @@ end -- Filtered List -- ------------------- -FILTER_FULL_TEXT = false - FilteredList = defclass(FilteredList, Widget) FilteredList.ATTRS { - case_sensitive = false, edit_below = false, edit_key = DEFAULT_NIL, edit_ignore_keys = DEFAULT_NIL, @@ -2172,7 +2169,6 @@ function FilteredList:setFilter(filter, pos) pos = nil for i,v in ipairs(self.choices) do - local ok = true local search_key = v.search_key if not search_key then if type(v.text) ~= 'table' then @@ -2187,30 +2183,7 @@ function FilteredList:setFilter(filter, pos) search_key = table.concat(texts, ' ') end end - for _,key in ipairs(tokens) do - key = key:escape_pattern() - if key ~= '' then - search_key = dfhack.toSearchNormalized(search_key) - key = dfhack.toSearchNormalized(key) - if not self.case_sensitive then - search_key = string.lower(search_key) - key = string.lower(key) - end - - -- 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 - if ok then + if utils.search_text(search_key, tokens) then table.insert(choices, v) cidx[#choices] = i if ipos == i then diff --git a/library/lua/utils.lua b/library/lua/utils.lua index 3883439f1..fb41835da 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -460,6 +460,32 @@ function erase_sorted(vector,item,field,cmp) return erase_sorted_key(vector,key,field,cmp) end +FILTER_FULL_TEXT = false + +function search_text(text, search_tokens) + text = dfhack.toSearchNormalized(text) + if type(search_tokens) ~= 'table' then + search_tokens = search_tokens:split() + end + + for _,search_token in ipairs(search_tokens) do + if search_token == '' then goto continue end + search_token = dfhack.toSearchNormalized(search_token:escape_pattern()) + + -- 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 text:match('%f[^%p\x00]'..search_token) + and not text:match('%f[^%s\x00]'..search_token) then + return false + elseif FILTER_FULL_TEXT and not text:find(search_token) then + return false + end + ::continue:: + end + return true +end + -- Calls a method with a string temporary function call_with_string(obj,methodname,...) return dfhack.with_temp_object( diff --git a/plugins/lua/buildingplan/itemselection.lua b/plugins/lua/buildingplan/itemselection.lua index 9dfd0cc69..4b8ee73d8 100644 --- a/plugins/lua/buildingplan/itemselection.lua +++ b/plugins/lua/buildingplan/itemselection.lua @@ -151,7 +151,6 @@ function ItemSelection:init() widgets.FilteredList{ view_id='flist', frame={t=0, b=0}, - case_sensitive=false, choices=choices, icon_width=2, on_submit=self:callback('toggle_group'), From 8184a093d9b0f76a33dbef94c5ec68c00c79f5a4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 7 Oct 2023 19:00:26 -0700 Subject: [PATCH 702/851] support dynamic onupdate frequency adjustments set to 0 for an immediate burst of high frequency calls --- docs/changelog.txt | 1 + docs/dev/overlay-dev-guide.rst | 5 ++++- plugins/lua/overlay.lua | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1a97e637d..ba05e6e87 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -61,6 +61,7 @@ Template for new versions: ## Fixes ## Misc Improvements +- `overlay`: allow ``overlay_onupdate_max_freq_seconds`` to be dynamically set to 0 for a burst of high-frequency updates ## Documentation diff --git a/docs/dev/overlay-dev-guide.rst b/docs/dev/overlay-dev-guide.rst index 54e200700..b5b6cf0e3 100644 --- a/docs/dev/overlay-dev-guide.rst +++ b/docs/dev/overlay-dev-guide.rst @@ -135,7 +135,10 @@ The ``overlay.OverlayWidget`` superclass defines the following class attributes: seconds) that your widget can take to react to changes in information and not annoy the player. Set to 0 to be called at the maximum rate. Be aware that running more often than you really need to will impact game FPS, - especially if your widget can run while the game is unpaused. + especially if your widget can run while the game is unpaused. If you change + the value of this attribute dynamically, it may not be noticed until the + previous timeout expires. However, if you need a burst of high-frequency + updates, set it to ``0`` and it will be noticed immediately. Registering a widget with the overlay framework *********************************************** diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index 9751561a8..d8b3c4f81 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -433,8 +433,12 @@ end -- reduces the next call by a small random amount to introduce jitter into the -- widget processing timings local function do_update(name, db_entry, now_ms, vs) - if db_entry.next_update_ms > now_ms then return end local w = db_entry.widget + if w.overlay_onupdate_max_freq_seconds ~= 0 and + db_entry.next_update_ms > now_ms + then + return + end db_entry.next_update_ms = get_next_onupdate_timestamp(now_ms, w) if detect_frame_change(w, function() return w:overlay_onupdate(vs) end) then if register_trigger_lock_screen(w:overlay_trigger(), name) then From d0ffd78479e5e6e29d2f08751df7113e0e999e92 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 7 Oct 2023 19:04:19 -0700 Subject: [PATCH 703/851] more focus string details for location selector --- library/modules/Gui.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 58763262f..50a878070 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -556,7 +556,13 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) } if (game->main_interface.location_selector.open) { newFocusString = baseFocus; - newFocusString += "/LocationSelector"; + newFocusString += "/LocationSelector/"; + if (game->main_interface.location_selector.choosing_temple_religious_practice) + newFocusString += "Temple"; + else if (game->main_interface.location_selector.choosing_craft_guild) + newFocusString += "Guildhall"; + else + newFocusString += "Default"; focusStrings.push_back(newFocusString); } if (game->main_interface.location_details.open) { From f8a95667ee81c6471ee31f0e84789a7c13d48d99 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 7 Oct 2023 19:12:53 -0700 Subject: [PATCH 704/851] succumb to american spelling --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 3 +++ library/lua/dfhack.lua | 3 +++ 3 files changed, 7 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1a97e637d..7693052d9 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -67,6 +67,7 @@ Template for new versions: ## API ## Lua +- added ``GRAY`` color aliases for ``GREY`` colors ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 9f9a3e374..781ba6819 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -3081,6 +3081,9 @@ environment by the mandatory init file dfhack.lua: COLOR_LIGHTBLUE, COLOR_LIGHTGREEN, COLOR_LIGHTCYAN, COLOR_LIGHTRED, COLOR_LIGHTMAGENTA, COLOR_YELLOW, COLOR_WHITE + ``COLOR_GREY`` and ``COLOR_DARKGREY`` can also be spelled ``COLOR_GRAY`` and + ``COLOR_DARKGRAY``. + * State change event codes, used by ``dfhack.onStateChange`` Available only in the `core context `, as is the event itself: diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 8ea5e9dac..059c008d2 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -38,6 +38,9 @@ COLOR_LIGHTMAGENTA = 13 COLOR_YELLOW = 14 COLOR_WHITE = 15 +COLOR_GRAY = COLOR_GREY +COLOR_DARKGRAY = COLOR_DARKGREY + -- Events if dfhack.is_core_context then From 53c29a05c96513de26168882af209c6f2ada4aa4 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 8 Oct 2023 02:19:08 +0000 Subject: [PATCH 705/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 728d90271..0759b6b7d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 728d902712655592ec4385e88fd36077641ccfb1 +Subproject commit 0759b6b7dde184c3bf36669f92138748a0e2382b From 2accc5ff569d6445f7dd409f1e4182c2e14162b4 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 8 Oct 2023 02:48:53 +0000 Subject: [PATCH 706/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 0759b6b7d..20d54145e 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 0759b6b7dde184c3bf36669f92138748a0e2382b +Subproject commit 20d54145e97fbae58cda391f66e6a32c7ee20330 From 9865eda9848c3543ae5d51728777bed7610adcb6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 7 Oct 2023 20:29:51 -0700 Subject: [PATCH 707/851] add changelog for #3849 --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index a985793a4..feda83f2c 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,6 +57,7 @@ Template for new versions: ## New Features - `logistics`: ``automelt`` now optionally supports melting masterworks; feature accessible from `stockpiles` overlay +- `sort`: new search widgets for all the "Creatures" tabs on the info panel, e.g. "Citizens", "Pets", etc. This includes the assign trainers and view species training knowledge screens as well ## Fixes From 8886cd7e79c3e347993a6758f1ac1bd833b53aec Mon Sep 17 00:00:00 2001 From: Myk Date: Sat, 7 Oct 2023 20:51:11 -0700 Subject: [PATCH 708/851] Allow searching for job --- plugins/lua/sort/creatures.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/plugins/lua/sort/creatures.lua b/plugins/lua/sort/creatures.lua index 563bd3cca..eeab12087 100644 --- a/plugins/lua/sort/creatures.lua +++ b/plugins/lua/sort/creatures.lua @@ -134,7 +134,9 @@ end local function make_cri_unitst_handlers(vec) return { search_fn=curry(general_search, vec, - function(elem) return elem.sort_name end, + function(elem) + return ('%s %s'):format(elem.sort_name, elem.job_sort_name) + end, get_sort), cleanup_fn=curry(cri_unitst_cleanup, vec), } From ab386a0ed23e2a1921b6341ad4e116986e1c246b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 7 Oct 2023 22:50:31 -0700 Subject: [PATCH 709/851] add docs for creatures search overlay --- docs/plugins/sort.rst | 8 ++++++++ plugins/lua/sort/creatures.lua | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 31ab2d3fc..8ea9e114c 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -91,3 +91,11 @@ and "ranged combat potential" are explained in detail here: https://www.reddit.com/r/dwarffortress/comments/163kczo/enhancing_military_candidate_selection_part_3/ "Mental stability" is explained here: https://www.reddit.com/r/dwarffortress/comments/1617s11/enhancing_military_candidate_selection_part_2/ + +Creatures overlay +----------------- + +The search widget that appears on the "Creatures" info panel sub-tabs (e.g. +"Citizens", "Pets", etc.) can search the lists by name and other shown +attibutes. For example, searching for ``caged`` will show all caged prisoners +on the "Other" tab. diff --git a/plugins/lua/sort/creatures.lua b/plugins/lua/sort/creatures.lua index eeab12087..692855679 100644 --- a/plugins/lua/sort/creatures.lua +++ b/plugins/lua/sort/creatures.lua @@ -145,14 +145,14 @@ end local function overall_training_search(data, filter, incremental) general_search(creatures.atk_index, function(elem) local raw = df.creature_raw.find(elem) - if not raw then return '' end + if not raw then return end return raw.name[1] end, nil, data, filter, incremental) end local function assign_trainer_search(data, filter, incremental) general_search(creatures.trainer, function(elem) - if not elem then return nil end + if not elem then return end return ('%s %s'):format(dfhack.TranslateName(elem.name), dfhack.units.getProfessionName(elem)) end, nil, data, filter, incremental) end From a063c0cf4193e4ce604770f6b42e36e6f9f03627 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 8 Oct 2023 09:47:40 -0700 Subject: [PATCH 710/851] only recheck orders that have conditions --- docs/changelog.txt | 1 + docs/plugins/orders.rst | 13 +++++++------ plugins/lua/orders.lua | 16 ++++++++-------- plugins/orders.cpp | 12 ++++++++---- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index feda83f2c..3dcf287cb 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -63,6 +63,7 @@ Template for new versions: ## Misc Improvements - `overlay`: allow ``overlay_onupdate_max_freq_seconds`` to be dynamically set to 0 for a burst of high-frequency updates +- `orders`: ``recheck`` command now only resets orders that have conditions that can be rechecked ## Documentation diff --git a/docs/plugins/orders.rst b/docs/plugins/orders.rst index acb25fe99..32708b4c8 100644 --- a/docs/plugins/orders.rst +++ b/docs/plugins/orders.rst @@ -18,12 +18,13 @@ Usage ``orders clear`` Deletes all manager orders in the current embark. ``orders recheck [this]`` - Sets the status to ``Checking`` (from ``Active``) for all work orders. if the - "this" option is passed, only sets the status for the workorder whose condition - details page is open. This makes the manager reevaluate its conditions. - This is especially useful for an order that had its conditions met when it - was started, but the requisite items have since disappeared and the workorder - is now generating job cancellation spam. + Sets the status to ``Checking`` (from ``Active``) for all work orders that + have conditions that can be re-checked. If the "this" option is passed, + only sets the status for the workorder whose condition details page is + open. This makes the manager reevaluate its conditions. This is especially + useful for an order that had its conditions met when it was started, but + the requisite items have since disappeared and the workorder is now + generating job cancellation spam. ``orders sort`` Sorts current manager orders by repeat frequency so repeating orders don't prevent one-time orders from ever being completed. The sorting order is: diff --git a/plugins/lua/orders.lua b/plugins/lua/orders.lua index 102580fab..0eeb327fc 100644 --- a/plugins/lua/orders.lua +++ b/plugins/lua/orders.lua @@ -71,7 +71,7 @@ OrdersOverlay.ATTRS{ default_pos={x=53,y=-6}, default_enabled=true, viewscreens='dwarfmode/Info/WORK_ORDERS/Default', - frame={w=46, h=4}, + frame={w=43, h=4}, } function OrdersOverlay:init() @@ -99,7 +99,7 @@ function OrdersOverlay:init() }, widgets.HotkeyLabel{ frame={t=0, l=15}, - label='recheck', + label='recheck conditions', key='CUSTOM_CTRL_K', auto_width=true, on_activate=do_recheck, @@ -112,7 +112,7 @@ function OrdersOverlay:init() on_activate=do_sort, }, widgets.HotkeyLabel{ - frame={t=0, l=31}, + frame={t=1, l=28}, label='clear', key='CUSTOM_CTRL_C', auto_width=true, @@ -179,10 +179,10 @@ local function set_current_inactive() end end -local function is_current_active() +local function can_recheck() local scrConditions = df.global.game.main_interface.info.work_orders.conditions local order = scrConditions.wq - return order.status.active + return order.status.active and #order.item_conditions > 0 end -- ------------------- @@ -197,7 +197,7 @@ RecheckOverlay.ATTRS{ default_enabled=true, viewscreens=focusString, -- width is the sum of lengths of `[` + `Ctrl+A` + `: ` + button.label + `]` - frame={w=1 + 6 + 2 + 16 + 1, h=3}, + frame={w=1 + 6 + 2 + 19 + 1, h=3}, } local function areTabsInTwoRows() @@ -226,10 +226,10 @@ function RecheckOverlay:init() widgets.TextButton{ view_id = 'button', -- frame={t=0, l=0, r=0, h=1}, -- is set in `updateTextButtonFrame()` - label='request re-check', + label='re-check conditions', key='CUSTOM_CTRL_A', on_activate=set_current_inactive, - enabled=is_current_active, + enabled=can_recheck, }, } diff --git a/plugins/orders.cpp b/plugins/orders.cpp index a84f14172..4b4c0ed4f 100644 --- a/plugins/orders.cpp +++ b/plugins/orders.cpp @@ -1036,11 +1036,15 @@ static command_result orders_sort_command(color_ostream & out) static command_result orders_recheck_command(color_ostream & out) { - for (auto it : world->manager_orders) - { - it->status.bits.active = false; - it->status.bits.validated = false; + size_t count = 0; + for (auto it : world->manager_orders) { + if (it->item_conditions.size() && it->status.bits.active) { + ++count; + it->status.bits.active = false; + it->status.bits.validated = false; + } } + out << "Re-checking conditions for " << count << " manager orders." << std::endl; return CR_OK; } From 420e0d0952af6d46814d21e4eec186e5d17f5d50 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 8 Oct 2023 11:30:57 -0700 Subject: [PATCH 711/851] add search support for info objects tabs --- docs/changelog.txt | 2 +- plugins/lua/sort/creatures.lua | 66 +++++++++++++++++++++++----------- 2 files changed, 47 insertions(+), 21 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 3dcf287cb..fa6db90ad 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,7 +57,7 @@ Template for new versions: ## New Features - `logistics`: ``automelt`` now optionally supports melting masterworks; feature accessible from `stockpiles` overlay -- `sort`: new search widgets for all the "Creatures" tabs on the info panel, e.g. "Citizens", "Pets", etc. This includes the assign trainers and view species training knowledge screens as well +- `sort`: new search widgets for all the "Creatures" and "Objects" tabs on the info panel ## Fixes diff --git a/plugins/lua/sort/creatures.lua b/plugins/lua/sort/creatures.lua index 692855679..7fc0ca766 100644 --- a/plugins/lua/sort/creatures.lua +++ b/plugins/lua/sort/creatures.lua @@ -4,10 +4,12 @@ local overlay = require('plugins.overlay') local widgets = require('gui.widgets') local utils = require('utils') -local creatures = df.global.game.main_interface.info.creatures +local info = df.global.game.main_interface.info +local creatures = info.creatures +local objects = info.artifacts --- these sort functions attempt to match the vanilla sort behavior, which is not --- quite the same as the rest of DFHack. For example, in other DFHack sorts, +-- these sort functions attempt to match the vanilla info panelsort behavior, which +-- is not quite the same as the rest of DFHack. For example, in other DFHack sorts, -- we'd always sort by name descending as a secondary sort. To match vanilla sorting, -- if the primary sort is ascending, the secondary name sort will also be ascending. -- @@ -165,6 +167,16 @@ local HANDLERS = { PET_OT={search_fn=overall_training_search}, PET_AT={search_fn=assign_trainer_search}, } +for idx,name in ipairs(df.artifacts_mode_type) do + if idx < 0 then goto continue end + HANDLERS[name] = { + search_fn=curry(general_search, objects.list[idx], + function(elem) + return ('%s %s'):format(dfhack.TranslateName(elem.name), dfhack.TranslateName(elem.name, true)) + end, nil) + } + ::continue:: +end -- ---------------------- -- InfoOverlay @@ -172,7 +184,7 @@ local HANDLERS = { InfoOverlay = defclass(InfoOverlay, overlay.OverlayWidget) InfoOverlay.ATTRS{ - default_pos={x=64, y=9}, + default_pos={x=64, y=8}, default_enabled=true, viewscreens={ 'dwarfmode/Info/CREATURES/CITIZEN', @@ -181,10 +193,14 @@ InfoOverlay.ATTRS{ 'dwarfmode/Info/CREATURES/AddingTrainer', 'dwarfmode/Info/CREATURES/OTHER', 'dwarfmode/Info/CREATURES/DECEASED', + 'dwarfmode/Info/ARTIFACTS/ARTIFACTS', + 'dwarfmode/Info/ARTIFACTS/SYMBOLS', + 'dwarfmode/Info/ARTIFACTS/NAMED_OBJECTS', + 'dwarfmode/Info/ARTIFACTS/WRITTEN_CONTENT', }, hotspot=true, overlay_onupdate_max_freq_seconds=0, - frame={w=40, h=3}, + frame={w=40, h=4}, } function InfoOverlay:init() @@ -226,11 +242,6 @@ function InfoOverlay:overlay_onupdate() end end -local function are_tabs_in_two_rows() - local pen = dfhack.screen.readTile(64, 6, false) -- tile is occupied iff tabs are in one row - return pen.ch == 0 -end - local function resize_overlay(self) local sw = dfhack.screen.getWindowSize() local overlay_width = math.min(40, sw-(self.frame_rect.x1 + 30)) @@ -240,24 +251,39 @@ local function resize_overlay(self) end end +local function get_panel_offsets() + local tabs_in_two_rows = dfhack.screen.readTile(64, 6, false).ch == 0 + local is_objects = info.current_mode == df.info_interface_mode_type.ARTIFACTS + local l_offset = (not tabs_in_two_rows and is_objects) and 4 or 0 + local t_offset = 1 + if tabs_in_two_rows then + t_offset = is_objects and 0 or 3 + end + return l_offset, t_offset +end + function InfoOverlay:updateFrames() local ret = resize_overlay(self) - local two_rows = are_tabs_in_two_rows() - if (self.two_rows == two_rows) then return ret end - self.two_rows = two_rows - self.subviews.panel.frame.t = two_rows and 2 or 0 + local l, t = get_panel_offsets() + local frame = self.subviews.panel.frame + if (frame.l == l and frame.t == t) then return ret end + frame.l, frame.t = l, t return true end local function get_key() - if creatures.current_mode == df.unit_list_mode_type.PET then - if creatures.showing_overall_training then - return 'PET_OT' - elseif creatures.adding_trainer then - return 'PET_AT' + if info.current_mode == df.info_interface_mode_type.CREATURES then + if creatures.current_mode == df.unit_list_mode_type.PET then + if creatures.showing_overall_training then + return 'PET_OT' + elseif creatures.adding_trainer then + return 'PET_AT' + end end + return df.unit_list_mode_type[creatures.current_mode] + elseif info.current_mode == df.info_interface_mode_type.ARTIFACTS then + return df.artifacts_mode_type[objects.mode] end - return df.unit_list_mode_type[creatures.current_mode] end local function check_context(self) From 0ad61ccf26718caef87b33140159a3d41794a4a2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 8 Oct 2023 13:44:09 -0700 Subject: [PATCH 712/851] rename file to reflect the more general usage --- plugins/lua/sort.lua | 4 ++-- plugins/lua/sort/{creatures.lua => info.lua} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename plugins/lua/sort/{creatures.lua => info.lua} (99%) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 1159ce56e..23ba83feb 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1,6 +1,6 @@ local _ENV = mkmodule('plugins.sort') -local creatures = require('plugins.sort.creatures') +local info = require('plugins.sort.info') local gui = require('gui') local overlay = require('plugins.overlay') local setbelief = reqscript('modtools/set-belief') @@ -1262,7 +1262,7 @@ end OVERLAY_WIDGETS = { squad_assignment=SquadAssignmentOverlay, squad_annotation=SquadAnnotationOverlay, - creatures=creatures.InfoOverlay, + info=info.InfoOverlay, } dfhack.onStateChange[GLOBAL_KEY] = function(sc) diff --git a/plugins/lua/sort/creatures.lua b/plugins/lua/sort/info.lua similarity index 99% rename from plugins/lua/sort/creatures.lua rename to plugins/lua/sort/info.lua index 7fc0ca766..de6017f4e 100644 --- a/plugins/lua/sort/creatures.lua +++ b/plugins/lua/sort/info.lua @@ -1,4 +1,4 @@ -local _ENV = mkmodule('plugins.sort.creatures') +local _ENV = mkmodule('plugins.sort.info') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') From 34bbf4cce9b7e247cc2001ca8b69874959697c91 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 8 Oct 2023 13:44:45 -0700 Subject: [PATCH 713/851] add more focus strings for justice screens --- library/modules/Gui.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index f315573c3..3e4281c29 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -259,7 +259,12 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) newFocusString += '/' + enum_item_key(game->main_interface.info.artifacts.mode); break; case df::enums::info_interface_mode_type::JUSTICE: - newFocusString += '/' + enum_item_key(game->main_interface.info.justice.current_mode); + if (game->main_interface.info.justice.interrogating) + newFocusString += "/Interrogating"; + else if (game->main_interface.info.justice.convicting) + newFocusString += "/Convicting"; + else + newFocusString += '/' + enum_item_key(game->main_interface.info.justice.current_mode); break; case df::enums::info_interface_mode_type::WORK_ORDERS: if (game->main_interface.info.work_orders.conditions.open) From c1531ae64635e63bd880cb308f1142dcb1aa16cf Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 8 Oct 2023 15:49:11 -0700 Subject: [PATCH 714/851] prototype justice overlay --- plugins/lua/sort.lua | 1 + plugins/lua/sort/info.lua | 103 +++++++++++++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 23ba83feb..174c7005e 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1263,6 +1263,7 @@ OVERLAY_WIDGETS = { squad_assignment=SquadAssignmentOverlay, squad_annotation=SquadAnnotationOverlay, info=info.InfoOverlay, + interrogation=info.InterrogationOverlay, } dfhack.onStateChange[GLOBAL_KEY] = function(sc) diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index de6017f4e..a82b5b842 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -1,5 +1,6 @@ local _ENV = mkmodule('plugins.sort.info') +local gui = require('gui') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') local utils = require('utils') @@ -7,6 +8,7 @@ local utils = require('utils') local info = df.global.game.main_interface.info local creatures = info.creatures local objects = info.artifacts +local justice = info.justice -- these sort functions attempt to match the vanilla info panelsort behavior, which -- is not quite the same as the rest of DFHack. For example, in other DFHack sorts, @@ -159,6 +161,9 @@ local function assign_trainer_search(data, filter, incremental) end, nil, data, filter, incremental) end +local function interrogation_search(data, filter, incremental) +end + local HANDLERS = { CITIZEN=make_cri_unitst_handlers(creatures.cri_unit.CITIZEN), PET=make_cri_unitst_handlers(creatures.cri_unit.PET), @@ -166,6 +171,7 @@ local HANDLERS = { DECEASED=make_cri_unitst_handlers(creatures.cri_unit.DECEASED), PET_OT={search_fn=overall_training_search}, PET_AT={search_fn=assign_trainer_search}, + INTERROGATING={search_fn=interrogation_search}, } for idx,name in ipairs(df.artifacts_mode_type) do if idx < 0 then goto continue end @@ -251,8 +257,12 @@ local function resize_overlay(self) end end +local function is_tabs_in_two_rows() + return dfhack.screen.readTile(64, 6, false).ch == 0 +end + local function get_panel_offsets() - local tabs_in_two_rows = dfhack.screen.readTile(64, 6, false).ch == 0 + local tabs_in_two_rows = is_tabs_in_two_rows() local is_objects = info.current_mode == df.info_interface_mode_type.ARTIFACTS local l_offset = (not tabs_in_two_rows and is_objects) and 4 or 0 local t_offset = 1 @@ -331,4 +341,95 @@ function InfoOverlay:onInput(keys) return InfoOverlay.super.onInput(self, keys) end +-- ---------------------- +-- InterrogationOverlay +-- + +InterrogationOverlay = defclass(InterrogationOverlay, overlay.OverlayWidget) +InterrogationOverlay.ATTRS{ + default_pos={x=47, y=10}, + default_enabled=true, + viewscreens={ + 'dwarfmode/Info/JUSTICE/Interrogating', + 'dwarfmode/Info/JUSTICE/Convicting', + }, + frame={w=27, h=9}, +} + +function InterrogationOverlay:init() + self:addviews{ + widgets.Panel{ + view_id='panel', + frame={l=0, t=4, h=5, r=0}, + frame_background=gui.CLEAR_PEN, + frame_style=gui.FRAME_MEDIUM, + subviews={ + widgets.EditField{ + view_id='search', + frame={l=0, t=0, r=0}, + label_text="Search: ", + key='CUSTOM_ALT_S', + }, + widgets.CycleHotkeyLabel{ + view_id='subset', + frame={l=0, t=1, w=24}, + key='CUSTOM_SHIFT_F', + label='Show:', + options={ + {label='All', value='all', pen=COLOR_GREEN}, + {label='Undead visitors', value='undead', pen=COLOR_RED}, + {label='Other visitors', value='visitors', pen=COLOR_LIGHTRED}, + {label='Residents', value='residents', pen=COLOR_YELLOW}, + {label='Citizens', value='citizens', pen=COLOR_CYAN}, + {label='Animals', value='animals', pen=COLOR_MAGENTA}, + {label='Deceased', value='deceased', pen=COLOR_BLUE}, + }, + }, + widgets.ToggleHotkeyLabel{ + view_id='include_interviewed', + frame={l=0, t=2, w=23}, + key='CUSTOM_SHIFT_I', + label='Interviewed:', + options={ + {label='Include', value=true, pen=COLOR_GREEN}, + {label='Exclude', value=false, pen=COLOR_RED}, + }, + initial_option=true, + }, + }, + }, + } +end + +function InterrogationOverlay:render(dc) + local sw = dfhack.screen.getWindowSize() + local info_panel_border = 31 -- from edges of panel to screen edges + local info_panel_width = sw - info_panel_border + local info_panel_center = info_panel_width // 2 + local panel_x_offset = (info_panel_center + 5) - self.frame_rect.x1 + local frame_w = math.min(panel_x_offset + 37, info_panel_width - 56) + local panel_l = panel_x_offset + local panel_t = is_tabs_in_two_rows() and 4 or 0 + + if self.frame.w ~= frame_w or + self.subviews.panel.frame.l ~= panel_l or + self.subviews.panel.frame.t ~= panel_t + then + self.frame.w = frame_w + self.subviews.panel.frame.l = panel_l + self.subviews.panel.frame.t = panel_t + self:updateLayout() + end + + InterrogationOverlay.super.render(self, dc) +end + +function InterrogationOverlay:onInput(keys) + if keys._MOUSE_R and self.subviews.search.focus then + self.subviews.search:setFocus(false) + return true + end + return InfoOverlay.super.onInput(self, keys) +end + return _ENV From 060becec7ccd347ff22f454e403755e9a3019c31 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 8 Oct 2023 16:28:02 -0700 Subject: [PATCH 715/851] implement search for conviction screen --- plugins/lua/sort/info.lua | 139 +++++++++++++++++++++++--------------- 1 file changed, 83 insertions(+), 56 deletions(-) diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index a82b5b842..633006d9a 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -10,6 +10,8 @@ local creatures = info.creatures local objects = info.artifacts local justice = info.justice +local state = {} + -- these sort functions attempt to match the vanilla info panelsort behavior, which -- is not quite the same as the rest of DFHack. For example, in other DFHack sorts, -- we'd always sort by name descending as a secondary sort. To match vanilla sorting, @@ -161,7 +163,15 @@ local function assign_trainer_search(data, filter, incremental) end, nil, data, filter, incremental) end -local function interrogation_search(data, filter, incremental) +local function interrogating_search(data, filter, incremental) +end + +local function convicting_search(data, filter, incremental) + general_search(justice.conviction_list, function(elem) + return ('%s %s'):format( + dfhack.units.getReadableName(elem), + dfhack.units.getProfessionName(elem)) + end, nil, data, filter, incremental) end local HANDLERS = { @@ -171,7 +181,8 @@ local HANDLERS = { DECEASED=make_cri_unitst_handlers(creatures.cri_unit.DECEASED), PET_OT={search_fn=overall_training_search}, PET_AT={search_fn=assign_trainer_search}, - INTERROGATING={search_fn=interrogation_search}, + INTERROGATING={search_fn=interrogating_search}, + CONVICTING={search_fn=convicting_search}, } for idx,name in ipairs(df.artifacts_mode_type) do if idx < 0 then goto continue end @@ -184,6 +195,54 @@ for idx,name in ipairs(df.artifacts_mode_type) do ::continue:: end +local function get_key() + if info.current_mode == df.info_interface_mode_type.JUSTICE then + if justice.interrogating then + return 'INTERROGATING' + elseif justice.convicting then + return 'CONVICTING' + end + elseif info.current_mode == df.info_interface_mode_type.CREATURES then + if creatures.current_mode == df.unit_list_mode_type.PET then + if creatures.showing_overall_training then + return 'PET_OT' + elseif creatures.adding_trainer then + return 'PET_AT' + end + end + return df.unit_list_mode_type[creatures.current_mode] + elseif info.current_mode == df.info_interface_mode_type.ARTIFACTS then + return df.artifacts_mode_type[objects.mode] + end +end + +local function check_context(self) + local key = get_key() + if state.prev_key ~= key then + state.prev_key = key + local prev_text = key and ensure_key(state, key).prev_text or '' + self.subviews.search:setText(prev_text) + end +end + +local function do_search(self, text) + if not next(state) and text == '' then return end + -- the EditField state is guaranteed to be consistent with the current + -- context since when clicking to switch tabs, onRenderBody is always called + -- before this text_input callback, even if a key is pressed before the next + -- graphical frame would otherwise be printed. if this ever becomes untrue, + -- then we can add an on_char handler to the EditField that also calls + -- check_context. + local key = get_key() + if not key then return end + local prev_text = ensure_key(state, key).prev_text + -- some screens reset their contents between context switches; regardless + -- a switch back to the context should results in an incremental search + local incremental = prev_text and text:startswith(prev_text) + HANDLERS[key].search_fn(state[key], text, incremental) + state[key].prev_text = text +end + -- ---------------------- -- InfoOverlay -- @@ -210,8 +269,6 @@ InfoOverlay.ATTRS{ } function InfoOverlay:init() - self.state = {} - self:addviews{ widgets.BannerPanel{ view_id='panel', @@ -222,14 +279,14 @@ function InfoOverlay:init() frame={l=1, t=0, r=1}, label_text="Search: ", key='CUSTOM_ALT_S', - on_change=self:callback('text_input'), + on_change=curry(do_search, self), }, }, }, } end -local function cleanup(state) +local function cleanup() for k,v in pairs(state) do local cleanup_fn = safe_index(HANDLERS, k, 'cleanup_fn') if cleanup_fn then cleanup_fn(v) end @@ -237,11 +294,11 @@ local function cleanup(state) end function InfoOverlay:overlay_onupdate() - if next(self.state) and + if next(state) and not dfhack.gui.matchFocusString('dwarfmode/Info', dfhack.gui.getDFViewscreen(true)) then - cleanup(self.state) - self.state = {} + cleanup() + state = {} self.subviews.search:setText('') self.subviews.search:setFocus(false) self.overlay_onupdate_max_freq_seconds = 60 @@ -281,32 +338,8 @@ function InfoOverlay:updateFrames() return true end -local function get_key() - if info.current_mode == df.info_interface_mode_type.CREATURES then - if creatures.current_mode == df.unit_list_mode_type.PET then - if creatures.showing_overall_training then - return 'PET_OT' - elseif creatures.adding_trainer then - return 'PET_AT' - end - end - return df.unit_list_mode_type[creatures.current_mode] - elseif info.current_mode == df.info_interface_mode_type.ARTIFACTS then - return df.artifacts_mode_type[objects.mode] - end -end - -local function check_context(self) - local key = get_key() - if self.state.prev_key ~= key then - self.state.prev_key = key - local prev_text = ensure_key(self.state, key).prev_text - self.subviews.search:setText(prev_text or '') - end -end - function InfoOverlay:onRenderBody(dc) - if next(self.state) then + if next(state) then check_context(self) end if self:updateFrames() then @@ -316,23 +349,6 @@ function InfoOverlay:onRenderBody(dc) InfoOverlay.super.onRenderBody(self, dc) end -function InfoOverlay:text_input(text) - if not next(self.state) and text == '' then return end - -- the EditField state is guaranteed to be consistent with the current - -- context since when clicking to switch tabs, onRenderBody is always called - -- before this text_input callback, even if a key is pressed before the next - -- graphical frame would otherwise be printed. if this ever becomes untrue, - -- then we can add an on_char handler to the EditField that also calls - -- check_context. - local key = get_key() - local prev_text = ensure_key(self.state, key).prev_text - -- some screens reset their contents between context switches; regardless - -- a switch back to the context should results in an incremental search - local incremental = prev_text and text:startswith(prev_text) - HANDLERS[key].search_fn(self.state[key], text, incremental) - self.state[key].prev_text = text -end - function InfoOverlay:onInput(keys) if keys._MOUSE_R and self.subviews.search.focus then self.subviews.search:setFocus(false) @@ -349,13 +365,15 @@ InterrogationOverlay = defclass(InterrogationOverlay, overlay.OverlayWidget) InterrogationOverlay.ATTRS{ default_pos={x=47, y=10}, default_enabled=true, - viewscreens={ - 'dwarfmode/Info/JUSTICE/Interrogating', - 'dwarfmode/Info/JUSTICE/Convicting', - }, + viewscreens='dwarfmode/Info/JUSTICE', frame={w=27, h=9}, } +local function is_interrogate_or_convict() + local key = get_key() + return key == 'INTERROGATING' or key == 'CONVICTING' +end + function InterrogationOverlay:init() self:addviews{ widgets.Panel{ @@ -363,12 +381,14 @@ function InterrogationOverlay:init() frame={l=0, t=4, h=5, r=0}, frame_background=gui.CLEAR_PEN, frame_style=gui.FRAME_MEDIUM, + visible=is_interrogate_or_convict, subviews={ widgets.EditField{ view_id='search', frame={l=0, t=0, r=0}, label_text="Search: ", key='CUSTOM_ALT_S', + on_change=curry(do_search, self), }, widgets.CycleHotkeyLabel{ view_id='subset', @@ -424,12 +444,19 @@ function InterrogationOverlay:render(dc) InterrogationOverlay.super.render(self, dc) end +function InterrogationOverlay:onRenderBody(dc) + if next(state) then + check_context(self) + end + InterrogationOverlay.super.onRenderBody(self, dc) +end + function InterrogationOverlay:onInput(keys) if keys._MOUSE_R and self.subviews.search.focus then self.subviews.search:setFocus(false) return true end - return InfoOverlay.super.onInput(self, keys) + return InterrogationOverlay.super.onInput(self, keys) end return _ENV From 06faeb669b0183b09efa674804726db51fd623a2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 9 Oct 2023 01:10:32 -0700 Subject: [PATCH 716/851] add support for work details and interrogation --- plugins/lua/sort/info.lua | 237 ++++++++++++++++++++++++++++---------- 1 file changed, 173 insertions(+), 64 deletions(-) diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index 633006d9a..f8833a642 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -7,8 +7,9 @@ local utils = require('utils') local info = df.global.game.main_interface.info local creatures = info.creatures -local objects = info.artifacts local justice = info.justice +local objects = info.artifacts +local work_details = info.labor.work_details local state = {} @@ -104,17 +105,19 @@ local function copy_to_lua_table(vec) return tab end -local function general_search(vec, get_search_key_fn, get_sort_fn, data, filter, incremental) +local function general_search(vec, get_search_key_fn, get_sort_fn, matches_filters_fn, data, filter, incremental) if not data.saved_original then data.saved_original = copy_to_lua_table(vec) elseif not incremental then vec:assign(data.saved_original) end - if filter ~= '' then + if matches_filters_fn ~= DEFAULT_NIL or filter ~= '' then local search_tokens = filter:split() for idx = #vec-1,0,-1 do local search_key = get_search_key_fn(vec[idx]) - if search_key and not utils.search_text(search_key, search_tokens) then + if (search_key and not utils.search_text(search_key, search_tokens)) or + (matches_filters_fn ~= DEFAULT_NIL and not matches_filters_fn(vec[idx])) + then vec:erase(idx) end end @@ -148,30 +151,76 @@ local function make_cri_unitst_handlers(vec) } end -local function overall_training_search(data, filter, incremental) +local function overall_training_search(matches_filters_fn, data, filter, incremental) general_search(creatures.atk_index, function(elem) local raw = df.creature_raw.find(elem) if not raw then return end return raw.name[1] - end, nil, data, filter, incremental) + end, nil, matches_filters_fn, data, filter, incremental) end -local function assign_trainer_search(data, filter, incremental) +local function assign_trainer_search(matches_filters_fn, data, filter, incremental) general_search(creatures.trainer, function(elem) if not elem then return end return ('%s %s'):format(dfhack.TranslateName(elem.name), dfhack.units.getProfessionName(elem)) - end, nil, data, filter, incremental) + end, nil, matches_filters_fn, data, filter, incremental) end -local function interrogating_search(data, filter, incremental) +local function get_unit_search_key(unit) + return ('%s %s %s'):format( + dfhack.units.getReadableName(unit), -- last name is in english + dfhack.units.getProfessionName(unit), + dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name end -local function convicting_search(data, filter, incremental) - general_search(justice.conviction_list, function(elem) - return ('%s %s'):format( - dfhack.units.getReadableName(elem), - dfhack.units.getProfessionName(elem)) - end, nil, data, filter, incremental) +local function work_details_search(matches_filters_fn, data, filter, incremental) + if work_details.selected_work_detail_index ~= data.selected then + data.saved_original = nil + data.selected = work_details.selected_work_detail_index + end + general_search(work_details.assignable_unit, get_unit_search_key, + nil, matches_filters_fn, data, filter, incremental) +end + +-- independent implementation of search algorithm since we need to +-- keep two vectors in sync +local function interrogating_search(matches_filters_fn, data, filter, incremental) + local vec, flags_vec = justice.interrogation_list, justice.interrogation_list_flag + if not data.saved_original then + data.saved_original = copy_to_lua_table(vec) + data.saved_flags = copy_to_lua_table(flags_vec) + data.saved_idx_map = {} + for idx, unit in ipairs(data.saved_original) do + data.saved_idx_map[unit.id] = idx -- 1-based idx + end + else -- sync flag changes to saved vector + for idx, unit in ipairs(vec) do -- 0-based idx + data.saved_flags[data.saved_idx_map[unit.id]] = flags_vec[idx] + end + end + + if not incremental then + vec:assign(data.saved_original) + flags_vec:assign(data.saved_flags) + end + + if matches_filters_fn or filter ~= '' then + local search_tokens = filter:split() + for idx = #vec-1,0,-1 do + local search_key = get_unit_search_key(vec[idx]) + if (search_key and not utils.search_text(search_key, search_tokens)) or + (matches_filters_fn and not matches_filters_fn(vec[idx], idx)) + then + vec:erase(idx) + flags_vec:erase(idx) + end + end + end +end + +local function convicting_search(matches_filters_fn, data, filter, incremental) + general_search(justice.conviction_list, get_unit_search_key, + nil, matches_filters_fn, data, filter, incremental) end local HANDLERS = { @@ -181,6 +230,7 @@ local HANDLERS = { DECEASED=make_cri_unitst_handlers(creatures.cri_unit.DECEASED), PET_OT={search_fn=overall_training_search}, PET_AT={search_fn=assign_trainer_search}, + WORK_DETAILS={search_fn=work_details_search}, INTERROGATING={search_fn=interrogating_search}, CONVICTING={search_fn=convicting_search}, } @@ -213,6 +263,10 @@ local function get_key() return df.unit_list_mode_type[creatures.current_mode] elseif info.current_mode == df.info_interface_mode_type.ARTIFACTS then return df.artifacts_mode_type[objects.mode] + elseif info.current_mode == df.info_interface_mode_type.LABOR then + if info.labor.mode == df.labor_mode_type.WORK_DETAILS then + return 'WORK_DETAILS' + end end end @@ -225,8 +279,8 @@ local function check_context(self) end end -local function do_search(self, text) - if not next(state) and text == '' then return end +local function do_search(matches_filters_fn, text, force_full_search) + if not force_full_search and not next(state) and text == '' then return end -- the EditField state is guaranteed to be consistent with the current -- context since when clicking to switch tabs, onRenderBody is always called -- before this text_input callback, even if a key is pressed before the next @@ -238,11 +292,34 @@ local function do_search(self, text) local prev_text = ensure_key(state, key).prev_text -- some screens reset their contents between context switches; regardless -- a switch back to the context should results in an incremental search - local incremental = prev_text and text:startswith(prev_text) - HANDLERS[key].search_fn(state[key], text, incremental) + local incremental = not force_full_search and prev_text and text:startswith(prev_text) + HANDLERS[key].search_fn(matches_filters_fn, state[key], text, incremental) state[key].prev_text = text end +local function on_update(self) + if self.overlay_onupdate_max_freq_seconds == 0 and + not dfhack.gui.matchFocusString('dwarfmode/Info', dfhack.gui.getDFViewscreen(true)) + then + for k,v in pairs(state) do + local cleanup_fn = safe_index(HANDLERS, k, 'cleanup_fn') + if cleanup_fn then cleanup_fn(v) end + end + state = {} + self.subviews.search:setText('') + self.subviews.search:setFocus(false) + self.overlay_onupdate_max_freq_seconds = 60 + end +end + +local function on_input(self, clazz, keys) + if keys._MOUSE_R and self.subviews.search.focus then + self.subviews.search:setFocus(false) + return true + end + return clazz.super.onInput(self, keys) +end + -- ---------------------- -- InfoOverlay -- @@ -262,6 +339,7 @@ InfoOverlay.ATTRS{ 'dwarfmode/Info/ARTIFACTS/SYMBOLS', 'dwarfmode/Info/ARTIFACTS/NAMED_OBJECTS', 'dwarfmode/Info/ARTIFACTS/WRITTEN_CONTENT', + 'dwarfmode/Info/LABOR/WORK_DETAILS', }, hotspot=true, overlay_onupdate_max_freq_seconds=0, @@ -279,30 +357,15 @@ function InfoOverlay:init() frame={l=1, t=0, r=1}, label_text="Search: ", key='CUSTOM_ALT_S', - on_change=curry(do_search, self), + on_change=curry(do_search, DEFAULT_NIL), }, }, }, } end -local function cleanup() - for k,v in pairs(state) do - local cleanup_fn = safe_index(HANDLERS, k, 'cleanup_fn') - if cleanup_fn then cleanup_fn(v) end - end -end - function InfoOverlay:overlay_onupdate() - if next(state) and - not dfhack.gui.matchFocusString('dwarfmode/Info', dfhack.gui.getDFViewscreen(true)) - then - cleanup() - state = {} - self.subviews.search:setText('') - self.subviews.search:setFocus(false) - self.overlay_onupdate_max_freq_seconds = 60 - end + on_update(self) end local function resize_overlay(self) @@ -320,11 +383,12 @@ end local function get_panel_offsets() local tabs_in_two_rows = is_tabs_in_two_rows() - local is_objects = info.current_mode == df.info_interface_mode_type.ARTIFACTS - local l_offset = (not tabs_in_two_rows and is_objects) and 4 or 0 + local shift_right = info.current_mode == df.info_interface_mode_type.ARTIFACTS or + info.current_mode == df.info_interface_mode_type.LABOR + local l_offset = (not tabs_in_two_rows and shift_right) and 4 or 0 local t_offset = 1 if tabs_in_two_rows then - t_offset = is_objects and 0 or 3 + t_offset = shift_right and 0 or 3 end return l_offset, t_offset end @@ -345,16 +409,19 @@ function InfoOverlay:onRenderBody(dc) if self:updateFrames() then self:updateLayout() end + if self.refresh_search then + self.refresh_search = nil + do_search(DEFAULT_NIL, self.subviews.search.text) + end self.overlay_onupdate_max_freq_seconds = 0 InfoOverlay.super.onRenderBody(self, dc) end function InfoOverlay:onInput(keys) - if keys._MOUSE_R and self.subviews.search.focus then - self.subviews.search:setFocus(false) - return true + if keys._MOUSE_L and get_key() == 'WORK_DETAILS' then + self.refresh_search = true end - return InfoOverlay.super.onInput(self, keys) + return on_input(self, InfoOverlay, keys) end -- ---------------------- @@ -367,8 +434,14 @@ InterrogationOverlay.ATTRS{ default_enabled=true, viewscreens='dwarfmode/Info/JUSTICE', frame={w=27, h=9}, + hotspot=true, + overlay_onupdate_max_freq_seconds=0, } +function InterrogationOverlay:overlay_onupdate() + on_update(self) +end + local function is_interrogate_or_convict() local key = get_key() return key == 'INTERROGATING' or key == 'CONVICTING' @@ -388,39 +461,75 @@ function InterrogationOverlay:init() frame={l=0, t=0, r=0}, label_text="Search: ", key='CUSTOM_ALT_S', - on_change=curry(do_search, self), + on_change=curry(do_search, self:callback('matches_filters')), + }, + widgets.ToggleHotkeyLabel{ + view_id='include_interviewed', + frame={l=0, t=1, w=23}, + key='CUSTOM_SHIFT_I', + label='Interviewed:', + options={ + {label='Include', value=true, pen=COLOR_GREEN}, + {label='Exclude', value=false, pen=COLOR_RED}, + }, + visible=function() return justice.interrogating end, + on_change=function() + do_search(self:callback('matches_filters'), self.subviews.search.text, true) + end, }, widgets.CycleHotkeyLabel{ view_id='subset', - frame={l=0, t=1, w=24}, + frame={l=0, t=2, w=28}, key='CUSTOM_SHIFT_F', label='Show:', options={ {label='All', value='all', pen=COLOR_GREEN}, - {label='Undead visitors', value='undead', pen=COLOR_RED}, + {label='Risky visitors', value='risky', pen=COLOR_RED}, {label='Other visitors', value='visitors', pen=COLOR_LIGHTRED}, {label='Residents', value='residents', pen=COLOR_YELLOW}, {label='Citizens', value='citizens', pen=COLOR_CYAN}, - {label='Animals', value='animals', pen=COLOR_MAGENTA}, - {label='Deceased', value='deceased', pen=COLOR_BLUE}, - }, - }, - widgets.ToggleHotkeyLabel{ - view_id='include_interviewed', - frame={l=0, t=2, w=23}, - key='CUSTOM_SHIFT_I', - label='Interviewed:', - options={ - {label='Include', value=true, pen=COLOR_GREEN}, - {label='Exclude', value=false, pen=COLOR_RED}, + {label='Animals', value='animals', pen=COLOR_BLUE}, + {label='Deceased or missing', value='deceased', pen=COLOR_MAGENTA}, + {label='Others', value='others', pen=COLOR_GRAY}, }, - initial_option=true, + on_change=function() + do_search(self:callback('matches_filters'), self.subviews.search.text, true) + end, }, }, }, } end +local function is_risky(unit) + return false +end + +function InterrogationOverlay:matches_filters(unit, idx) + if justice.interrogating then + local include_interviewed = self.subviews.include_interviewed:getOptionValue() + if not include_interviewed and justice.interrogation_list_flag[idx] == 2 then + return false + end + end + local subset = self.subviews.subset:getOptionValue() + if subset == 'all' then + return true + elseif dfhack.units.isDead(unit) or not dfhack.units.isActive(unit) then + return subset == 'deceased' + elseif dfhack.units.isVisiting(unit) then + local risky = is_risky(unit) + return (subset == 'risky' and risky) or (subset == 'visitors' and not risky) + elseif dfhack.units.isAnimal(unit) then + return subset == 'animals' + elseif dfhack.units.isCitizen(unit) then + return subset == 'citizens' + elseif dfhack.units.isOwnGroup(unit) then + return subset == 'residents' + end + return subset == 'others' +end + function InterrogationOverlay:render(dc) local sw = dfhack.screen.getWindowSize() local info_panel_border = 31 -- from edges of panel to screen edges @@ -447,16 +556,16 @@ end function InterrogationOverlay:onRenderBody(dc) if next(state) then check_context(self) + else + self.subviews.include_interviewed:setOption(true, false) + self.subviews.subset:setOption('all') end + self.overlay_onupdate_max_freq_seconds = 0 InterrogationOverlay.super.onRenderBody(self, dc) end function InterrogationOverlay:onInput(keys) - if keys._MOUSE_R and self.subviews.search.focus then - self.subviews.search:setFocus(false) - return true - end - return InterrogationOverlay.super.onInput(self, keys) + return on_input(self, InterrogationOverlay, keys) end return _ENV From a575727c09a32b9eb7399ee121ee6a23604196c4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 9 Oct 2023 01:44:21 -0700 Subject: [PATCH 717/851] add support for searching jobs (tasks) --- plugins/lua/sort/info.lua | 68 +++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index f8833a642..8afe5e02b 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -9,11 +9,12 @@ local info = df.global.game.main_interface.info local creatures = info.creatures local justice = info.justice local objects = info.artifacts +local tasks = info.jobs local work_details = info.labor.work_details local state = {} --- these sort functions attempt to match the vanilla info panelsort behavior, which +-- these sort functions attempt to match the vanilla info panel sort behavior, which -- is not quite the same as the rest of DFHack. For example, in other DFHack sorts, -- we'd always sort by name descending as a secondary sort. To match vanilla sorting, -- if the primary sort is ascending, the secondary name sort will also be ascending. @@ -140,13 +141,22 @@ local function cri_unitst_cleanup(vec, data) end end -local function make_cri_unitst_handlers(vec) +local function get_unit_search_key(unit) + return ('%s %s %s'):format( + dfhack.units.getReadableName(unit), -- last name is in english + dfhack.units.getProfessionName(unit), + dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name +end + +local function make_cri_unitst_handlers(vec, sort_fn) return { search_fn=curry(general_search, vec, function(elem) - return ('%s %s'):format(elem.sort_name, elem.job_sort_name) + return ('%s %s'):format( + elem.un and get_unit_search_key(elem.un) or '', + elem.job_sort_name) end, - get_sort), + sort_fn), cleanup_fn=curry(cri_unitst_cleanup, vec), } end @@ -166,13 +176,6 @@ local function assign_trainer_search(matches_filters_fn, data, filter, increment end, nil, matches_filters_fn, data, filter, incremental) end -local function get_unit_search_key(unit) - return ('%s %s %s'):format( - dfhack.units.getReadableName(unit), -- last name is in english - dfhack.units.getProfessionName(unit), - dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name -end - local function work_details_search(matches_filters_fn, data, filter, incremental) if work_details.selected_work_detail_index ~= data.selected then data.saved_original = nil @@ -224,12 +227,13 @@ local function convicting_search(matches_filters_fn, data, filter, incremental) end local HANDLERS = { - CITIZEN=make_cri_unitst_handlers(creatures.cri_unit.CITIZEN), - PET=make_cri_unitst_handlers(creatures.cri_unit.PET), - OTHER=make_cri_unitst_handlers(creatures.cri_unit.OTHER), - DECEASED=make_cri_unitst_handlers(creatures.cri_unit.DECEASED), + CITIZEN=make_cri_unitst_handlers(creatures.cri_unit.CITIZEN, get_sort), + PET=make_cri_unitst_handlers(creatures.cri_unit.PET, get_sort), + OTHER=make_cri_unitst_handlers(creatures.cri_unit.OTHER, get_sort), + DECEASED=make_cri_unitst_handlers(creatures.cri_unit.DECEASED, get_sort), PET_OT={search_fn=overall_training_search}, PET_AT={search_fn=assign_trainer_search}, + JOBS=make_cri_unitst_handlers(tasks.cri_job), WORK_DETAILS={search_fn=work_details_search}, INTERROGATING={search_fn=interrogating_search}, CONVICTING={search_fn=convicting_search}, @@ -261,6 +265,8 @@ local function get_key() end end return df.unit_list_mode_type[creatures.current_mode] + elseif info.current_mode == df.info_interface_mode_type.JOBS then + return 'JOBS' elseif info.current_mode == df.info_interface_mode_type.ARTIFACTS then return df.artifacts_mode_type[objects.mode] elseif info.current_mode == df.info_interface_mode_type.LABOR then @@ -320,6 +326,11 @@ local function on_input(self, clazz, keys) return clazz.super.onInput(self, keys) end +local function is_interrogate_or_convict() + local key = get_key() + return key == 'INTERROGATING' or key == 'CONVICTING' +end + -- ---------------------- -- InfoOverlay -- @@ -328,19 +339,7 @@ InfoOverlay = defclass(InfoOverlay, overlay.OverlayWidget) InfoOverlay.ATTRS{ default_pos={x=64, y=8}, default_enabled=true, - viewscreens={ - 'dwarfmode/Info/CREATURES/CITIZEN', - 'dwarfmode/Info/CREATURES/PET', - 'dwarfmode/Info/CREATURES/OverallTraining', - 'dwarfmode/Info/CREATURES/AddingTrainer', - 'dwarfmode/Info/CREATURES/OTHER', - 'dwarfmode/Info/CREATURES/DECEASED', - 'dwarfmode/Info/ARTIFACTS/ARTIFACTS', - 'dwarfmode/Info/ARTIFACTS/SYMBOLS', - 'dwarfmode/Info/ARTIFACTS/NAMED_OBJECTS', - 'dwarfmode/Info/ARTIFACTS/WRITTEN_CONTENT', - 'dwarfmode/Info/LABOR/WORK_DETAILS', - }, + viewscreens='dwarfmode/Info', hotspot=true, overlay_onupdate_max_freq_seconds=0, frame={w=40, h=4}, @@ -351,13 +350,14 @@ function InfoOverlay:init() widgets.BannerPanel{ view_id='panel', frame={l=0, t=0, r=0, h=1}, + visible=function() return get_key() and not is_interrogate_or_convict() end, subviews={ widgets.EditField{ view_id='search', frame={l=1, t=0, r=1}, label_text="Search: ", key='CUSTOM_ALT_S', - on_change=curry(do_search, DEFAULT_NIL), + on_change=function(text) do_search(DEFAULT_NIL, text) end, }, }, }, @@ -390,6 +390,9 @@ local function get_panel_offsets() if tabs_in_two_rows then t_offset = shift_right and 0 or 3 end + if info.current_mode == df.info_interface_mode_type.JOBS then + t_offset = t_offset - 1 + end return l_offset, t_offset end @@ -442,11 +445,6 @@ function InterrogationOverlay:overlay_onupdate() on_update(self) end -local function is_interrogate_or_convict() - local key = get_key() - return key == 'INTERROGATING' or key == 'CONVICTING' -end - function InterrogationOverlay:init() self:addviews{ widgets.Panel{ @@ -461,7 +459,7 @@ function InterrogationOverlay:init() frame={l=0, t=0, r=0}, label_text="Search: ", key='CUSTOM_ALT_S', - on_change=curry(do_search, self:callback('matches_filters')), + on_change=function(text) do_search(self:callback('matches_filters'), text) end, }, widgets.ToggleHotkeyLabel{ view_id='include_interviewed', From cfae6065b88fdbc562b07aefdc0f26f1dadb14e2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 9 Oct 2023 01:46:34 -0700 Subject: [PATCH 718/851] update changelog --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fa6db90ad..fbe37deff 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,7 +57,7 @@ Template for new versions: ## New Features - `logistics`: ``automelt`` now optionally supports melting masterworks; feature accessible from `stockpiles` overlay -- `sort`: new search widgets for all the "Creatures" and "Objects" tabs on the info panel +- `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", the "Work details" subtab under "Labor", and the "Interrogate" and "Convict" screens under "Justice" ## Fixes From 9f9d8ff74bde790008d22e20d2b7bec957bd2a45 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 9 Oct 2023 02:25:45 -0700 Subject: [PATCH 719/851] implement risky visitor detection, refine algorithm --- plugins/lua/sort/info.lua | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index 8afe5e02b..62c24d228 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -207,12 +207,12 @@ local function interrogating_search(matches_filters_fn, data, filter, incrementa flags_vec:assign(data.saved_flags) end - if matches_filters_fn or filter ~= '' then + if matches_filters_fn ~= DEFAULT_NIL or filter ~= '' then local search_tokens = filter:split() for idx = #vec-1,0,-1 do local search_key = get_unit_search_key(vec[idx]) if (search_key and not utils.search_text(search_key, search_tokens)) or - (matches_filters_fn and not matches_filters_fn(vec[idx], idx)) + (matches_filters_fn ~= DEFAULT_NIL and not matches_filters_fn(vec[idx], idx)) then vec:erase(idx) flags_vec:erase(idx) @@ -276,10 +276,10 @@ local function get_key() end end -local function check_context(self) +local function check_context(self, key_ctx) local key = get_key() - if state.prev_key ~= key then - state.prev_key = key + if state[key_ctx] ~= key then + state[key_ctx] = key local prev_text = key and ensure_key(state, key).prev_text or '' self.subviews.search:setText(prev_text) end @@ -407,7 +407,7 @@ end function InfoOverlay:onRenderBody(dc) if next(state) then - check_context(self) + check_context(self, InfoOverlay) end if self:updateFrames() then self:updateLayout() @@ -499,8 +499,18 @@ function InterrogationOverlay:init() } end +local RISKY_PROFESSIONS = utils.invert{ + df.profession.THIEF, + df.profession.MASTER_THIEF, + df.profession.CRIMINAL, +} + local function is_risky(unit) - return false + if RISKY_PROFESSIONS[unit.profession] or RISKY_PROFESSIONS[unit.profession2] then + return true + end + if dfhack.units.getReadableName(unit):endswith('necromancer') then return true end + return not dfhack.units.isAlive(unit) -- detect intelligent undead end function InterrogationOverlay:matches_filters(unit, idx) @@ -522,10 +532,10 @@ function InterrogationOverlay:matches_filters(unit, idx) return subset == 'animals' elseif dfhack.units.isCitizen(unit) then return subset == 'citizens' - elseif dfhack.units.isOwnGroup(unit) then - return subset == 'residents' + elseif unit.flags2.roaming_wilderness_population_source then + return subset == 'others' end - return subset == 'others' + return subset == 'residents' end function InterrogationOverlay:render(dc) @@ -553,7 +563,7 @@ end function InterrogationOverlay:onRenderBody(dc) if next(state) then - check_context(self) + check_context(self, InterrogationOverlay) else self.subviews.include_interviewed:setOption(true, false) self.subviews.subset:setOption('all') From 98b44ea8f0f7cda6f151d4a6312ec049074f9c43 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 9 Oct 2023 02:32:26 -0700 Subject: [PATCH 720/851] allow right click exit when search is focused but screen isn't a search-enabled screen --- plugins/lua/sort/info.lua | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index 62c24d228..861b44484 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -319,7 +319,7 @@ local function on_update(self) end local function on_input(self, clazz, keys) - if keys._MOUSE_R and self.subviews.search.focus then + if keys._MOUSE_R and self.subviews.search.focus and self:get_handled_key() then self.subviews.search:setFocus(false) return true end @@ -350,7 +350,7 @@ function InfoOverlay:init() widgets.BannerPanel{ view_id='panel', frame={l=0, t=0, r=0, h=1}, - visible=function() return get_key() and not is_interrogate_or_convict() end, + visible=self:callback('get_handled_key'), subviews={ widgets.EditField{ view_id='search', @@ -368,6 +368,10 @@ function InfoOverlay:overlay_onupdate() on_update(self) end +function InfoOverlay:get_handled_key() + return not is_interrogate_or_convict() and get_key() or nil +end + local function resize_overlay(self) local sw = dfhack.screen.getWindowSize() local overlay_width = math.min(40, sw-(self.frame_rect.x1 + 30)) @@ -445,6 +449,10 @@ function InterrogationOverlay:overlay_onupdate() on_update(self) end +function InterrogationOverlay:get_handled_key() + return is_interrogate_or_convict() and get_key() or nil +end + function InterrogationOverlay:init() self:addviews{ widgets.Panel{ From bd1381bbf3c75d679003dfd1058951411b563ab2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 9 Oct 2023 02:37:32 -0700 Subject: [PATCH 721/851] clean up whitespace --- plugins/lua/sort/info.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index 861b44484..b732e504f 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -1,6 +1,6 @@ local _ENV = mkmodule('plugins.sort.info') -local gui = require('gui') +local gui = require('gui') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') local utils = require('utils') From e7c07a2494bb58272c9c1f2b9b28cf4cdfef1ea0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 9 Oct 2023 03:09:30 -0700 Subject: [PATCH 722/851] update docs for info overlay --- docs/plugins/sort.rst | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 8ea9e114c..70e101b3f 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -92,10 +92,23 @@ https://www.reddit.com/r/dwarffortress/comments/163kczo/enhancing_military_candi "Mental stability" is explained here: https://www.reddit.com/r/dwarffortress/comments/1617s11/enhancing_military_candidate_selection_part_2/ -Creatures overlay ------------------ - -The search widget that appears on the "Creatures" info panel sub-tabs (e.g. -"Citizens", "Pets", etc.) can search the lists by name and other shown -attibutes. For example, searching for ``caged`` will show all caged prisoners -on the "Other" tab. +Info overlay +------------ + +The Info overlay adds search support to many of the fort-wide "Info" panels +(e.g. "Creatures", "Tasks", etc.). When searching for units, you can search by +name (with either English or native language last names), profession, or +special status (like "necromancer"). If there is text in the second column, you +can search for that text as well. This is often a job name or a status, like +"caged". + +In the interrogation and conviction screens under the "Justice" tab, you can +also filter by the classification of the unit. The classification groups are +ordered by how likely a member of that group is to be involved in a plot. The +groups are: All, Risky visitors, Other visitors, Residents, Citizens, Animals, +Deceased, and Others. "Risky" visitors are those who are especially likely to +be involved in plots, such as criminals, necromancers, necromancer experiments, +and intelligent undead. + +On the interrogations screen, you can also filter units by whether they have +already been interrogated. From 3ee059317f5cca16eb915c651418fd4bae8e4b58 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 9 Oct 2023 03:45:53 -0700 Subject: [PATCH 723/851] add help button to squad panel --- docs/changelog.txt | 1 + plugins/lua/sort.lua | 34 +++++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fbe37deff..56a1237c1 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -64,6 +64,7 @@ Template for new versions: ## Misc Improvements - `overlay`: allow ``overlay_onupdate_max_freq_seconds`` to be dynamically set to 0 for a burst of high-frequency updates - `orders`: ``recheck`` command now only resets orders that have conditions that can be rechecked +- `sort`: added help button for squad assignment search/filter/sort ## Documentation diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 174c7005e..52bfac7aa 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -4,6 +4,7 @@ local info = require('plugins.sort.info') local gui = require('gui') local overlay = require('plugins.overlay') local setbelief = reqscript('modtools/set-belief') +local textures = require('gui.textures') local utils = require('utils') local widgets = require('gui.widgets') @@ -631,10 +632,6 @@ SquadAssignmentOverlay.ATTRS{ viewscreens='dwarfmode/UnitSelector/SQUAD_FILL_POSITION', version='2', frame={w=38, h=31}, - frame_style=gui.FRAME_PANEL, - frame_background=gui.CLEAR_PEN, - autoarrange_subviews=true, - autoarrange_gap=1, } -- allow initial spacebar or two successive spacebars to fall through and @@ -661,7 +658,14 @@ function SquadAssignmentOverlay:init() }) end - self:addviews{ + local main_panel = widgets.Panel{ + frame={l=0, r=0, t=0, b=0}, + frame_style=gui.FRAME_PANEL, + frame_background=gui.CLEAR_PEN, + autoarrange_subviews=true, + autoarrange_gap=1, + } + main_panel:addviews{ widgets.EditField{ view_id='search', frame={l=0}, @@ -940,6 +944,26 @@ function SquadAssignmentOverlay:init() on_change=function() self:refresh_list() end, }, } + + local button_pen_left = dfhack.pen.parse{fg=COLOR_CYAN, + tile=curry(textures.tp_control_panel, 7) or nil, ch=string.byte('[')} + local button_pen_right = dfhack.pen.parse{fg=COLOR_CYAN, + tile=curry(textures.tp_control_panel, 8) or nil, ch=string.byte(']')} + local help_pen_center = dfhack.pen.parse{ + tile=curry(textures.tp_control_panel, 9) or nil, ch=string.byte('?')} + + self:addviews{ + main_panel, + widgets.Label{ + frame={t=0, r=1, w=3}, + text={ + {tile=button_pen_left}, + {tile=help_pen_center}, + {tile=button_pen_right}, + }, + on_click=function() dfhack.run_command('gui/launcher', 'sort ') end, + }, + } end local function normalize_search_key(search_key) From 61e44324245a026b895121e4295545ad49a37c31 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 9 Oct 2023 17:24:13 -0700 Subject: [PATCH 724/851] label war and hunt trained animals in readable names --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 3 ++- library/modules/Units.cpp | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fbe37deff..8c99c2b57 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -64,6 +64,7 @@ Template for new versions: ## Misc Improvements - `overlay`: allow ``overlay_onupdate_max_freq_seconds`` to be dynamically set to 0 for a burst of high-frequency updates - `orders`: ``recheck`` command now only resets orders that have conditions that can be rechecked +- `zone`: animals trained for war or hunting are now labeled as such in animal assignment screens ## Documentation diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 1d8c2beb6..fd56a11ed 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1609,7 +1609,8 @@ Units module * ``dfhack.units.getReadableName(unit)`` Returns a string that includes the language name of the unit (if any), the - race of the unit, and any syndrome-given descriptions (such as "necromancer"). + race of the unit, whether it is trained for war or hunting, and any + syndrome-given descriptions (such as "necromancer"). * ``dfhack.units.getStressCategory(unit)`` diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index ebfd13b5e..83554ef78 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -1267,6 +1267,10 @@ static string get_caste_name(df::unit* unit) { string Units::getReadableName(df::unit* unit) { string race_name = isChild(unit) ? getRaceChildName(unit) : get_caste_name(unit); + if (isHunter(unit)) + race_name = "hunter " + race_name; + if (isWar(unit)) + race_name = "war " + race_name; string name = Translation::TranslateName(getVisibleName(unit)); if (name.empty()) { name = race_name; From 640c77dc48f8933eeb06c1efbdd15c07e0a55940 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 9 Oct 2023 17:31:50 -0700 Subject: [PATCH 725/851] dungeon cages/retraints aren't assignable --- docs/changelog.txt | 1 + plugins/lua/zone.lua | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index fbe37deff..59868e902 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -60,6 +60,7 @@ Template for new versions: - `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", the "Work details" subtab under "Labor", and the "Interrogate" and "Convict" screens under "Justice" ## Fixes +- `zone`: don't show animal assignment link for dungeon cages/restraints ## Misc Improvements - `overlay`: allow ``overlay_onupdate_max_freq_seconds`` to be dynamically set to 0 for a burst of high-frequency updates diff --git a/plugins/lua/zone.lua b/plugins/lua/zone.lua index 13182cef1..eb984093b 100644 --- a/plugins/lua/zone.lua +++ b/plugins/lua/zone.lua @@ -961,9 +961,13 @@ CageChainOverlay.ATTRS{ local function is_valid_building() local bld = dfhack.gui.getSelectedBuilding(true) - return bld and bld:getBuildStage() == bld:getMaxBuildStage() and - (bld:getType() == df.building_type.Cage or - bld:getType() == df.building_type.Chain) + if not bld or bld:getBuildStage() ~= bld:getMaxBuildStage() then return false end + local bt = bld:getType() + if bt ~= df.building_type.Cage and bt ~= df.building_type.Chain then return false end + for _,zone in ipairs(bld.relations) do + if zone.type == df.civzone_type.Dungeon then return false end + end + return true end local function is_cage_selected() From a085e5ef2871d7cd7363682dda45ceab48f8d620 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 10 Oct 2023 02:33:47 -0700 Subject: [PATCH 726/851] add support for location selector that is, guildhalls and temples also start refactoring code for better reuse --- plugins/lua/sort.lua | 2 + plugins/lua/sort/locationselector.lua | 67 ++++++++++ plugins/lua/sort/sortoverlay.lua | 169 ++++++++++++++++++++++++++ 3 files changed, 238 insertions(+) create mode 100644 plugins/lua/sort/locationselector.lua create mode 100644 plugins/lua/sort/sortoverlay.lua diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 52bfac7aa..ce9eb1f9e 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -2,6 +2,7 @@ local _ENV = mkmodule('plugins.sort') local info = require('plugins.sort.info') local gui = require('gui') +local locationselector = require('plugins.sort.locationselector') local overlay = require('plugins.overlay') local setbelief = reqscript('modtools/set-belief') local textures = require('gui.textures') @@ -1288,6 +1289,7 @@ OVERLAY_WIDGETS = { squad_annotation=SquadAnnotationOverlay, info=info.InfoOverlay, interrogation=info.InterrogationOverlay, + location_selector=locationselector.LocationSelectorOverlay, } dfhack.onStateChange[GLOBAL_KEY] = function(sc) diff --git a/plugins/lua/sort/locationselector.lua b/plugins/lua/sort/locationselector.lua new file mode 100644 index 000000000..8092db1e2 --- /dev/null +++ b/plugins/lua/sort/locationselector.lua @@ -0,0 +1,67 @@ +local _ENV = mkmodule('plugins.sort.locationselector') + +local sortoverlay = require('plugins.sort.sortoverlay') +local widgets = require('gui.widgets') + +local location_selector = df.global.game.main_interface.location_selector + +-- ---------------------- +-- LocationSelectorOverlay +-- + +LocationSelectorOverlay = defclass(LocationSelectorOverlay, sortoverlay.SortOverlay) +LocationSelectorOverlay.ATTRS{ + default_pos={x=48, y=7}, + viewscreens='dwarfmode/LocationSelector', + frame={w=26, h=1}, +} + +local function get_religion_string(religion_id, religion_type) + if religion_id == -1 then return end + local entity + if religion_type == 0 then + entity = df.historical_figure.find(religion_id) + elseif religion_type == 1 then + entity = df.historical_entity.find(religion_id) + end + if not entity then return end + return dfhack.TranslateName(entity.name, true) +end + +local function get_profession_string(profession) + return df.profession[profession]:gsub('_', ' ') +end + +function LocationSelectorOverlay:init() + self:addviews{ + widgets.BannerPanel{ + frame={l=0, t=0, r=0, h=1}, + visible=self:callback('get_key'), + subviews={ + widgets.EditField{ + view_id='search', + frame={l=1, t=0, r=1}, + label_text="Search: ", + key='CUSTOM_ALT_S', + on_change=function(text) self:do_search(text) end, + }, + }, + }, + } + + self:register_handler('TEMPLE', location_selector.valid_religious_practice_id, + curry(sortoverlay.flags_vector_search, {get_search_key_fn=get_religion_string}, + location_selector.valid_religious_practice)) + self:register_handler('GUILDHALL', location_selector.valid_craft_guild_type, + curry(sortoverlay.single_vector_search, {get_search_key_fn=get_profession_string})) +end + +function LocationSelectorOverlay:get_key() + if location_selector.choosing_temple_religious_practice then + return 'TEMPLE' + elseif location_selector.choosing_craft_guild then + return 'GUILDHALL' + end +end + +return _ENV diff --git a/plugins/lua/sort/sortoverlay.lua b/plugins/lua/sort/sortoverlay.lua new file mode 100644 index 000000000..96c0f8ecc --- /dev/null +++ b/plugins/lua/sort/sortoverlay.lua @@ -0,0 +1,169 @@ +local _ENV = mkmodule('plugins.sort.sortoverlay') + +local overlay = require('plugins.overlay') +local utils = require('utils') + +local function copy_to_lua_table(vec) + local tab = {} + for k,v in ipairs(vec) do + tab[k+1] = v + end + return tab +end + +-- ---------------------- +-- SortOverlay +-- + +SortOverlay = defclass(SortOverlay, overlay.OverlayWidget) +SortOverlay.ATTRS{ + default_enabled=true, + hotspot=true, + overlay_onupdate_max_freq_seconds=0, + -- subclasses expected to provide default_pos, viewscreens (single string), and frame +} + +function SortOverlay:init() + self.state = {} + self.handlers = {} + -- subclasses expected to provide an EditField widget with view_id='search' +end + +function SortOverlay:register_handler(key, vec, search_fn, restore_filtered_on_cleanup) + self.handlers[key] = { + vec=vec, + search_fn=search_fn, + restore_filtered_on_cleanup=restore_filtered_on_cleanup + } +end + +local function restore_filtered(vec, data) + if not data.saved_visible or not data.saved_original then return end + for _,elem in ipairs(data.saved_original) do + if not utils.linear_index(data.saved_visible, elem) then + vec:insert('#', elem) + end + end +end + +-- handles reset and clean up when the player exits the handled scope +function SortOverlay:overlay_onupdate() + if self.overlay_onupdate_max_freq_seconds == 0 and + not dfhack.gui.matchFocusString(self.viewscreens, dfhack.gui.getDFViewscreen(true)) + then + for key,data in pairs(self.state) do + if safe_index(self.handlers, key, 'restore_filtered_on_cleanup') then + restore_filtered(self.handlers[key].vec, data) + end + end + self.state = {} + self.subviews.search:setText('') + self.subviews.search:setFocus(false) + self.overlay_onupdate_max_freq_seconds = 300 + end +end + +-- returns the current context key for dereferencing the handler +-- subclasses must override +function SortOverlay:get_key() + return nil +end + +-- handles saving/restoring search strings when the player moves between different contexts +function SortOverlay:onRenderBody(dc) + if next(self.state) then + local key = self:get_key() + if self.state.cur_key ~= key then + self.state.cur_key = key + local prev_text = key and ensure_key(self.state, key).prev_text or '' + self.subviews.search:setText(prev_text) + end + end + self.overlay_onupdate_max_freq_seconds = 0 + SortOverlay.super.onRenderBody(self, dc) +end + +function SortOverlay:onInput(keys) + if keys._MOUSE_R and self.subviews.search.focus and self:get_key() then + self.subviews.search:setFocus(false) + return true + end + return SortOverlay.super.onInput(self, keys) +end + +function SortOverlay:do_search(text, force_full_search) + if not force_full_search and not next(self.state) and text == '' then return end + -- the EditField state is guaranteed to be consistent with the current + -- context since when clicking to switch tabs, onRenderBody is always called + -- before this text_input callback, even if a key is pressed before the next + -- graphical frame would otherwise be printed. if this ever becomes untrue, + -- then we can add an on_char handler to the EditField that also checks for + -- context transitions. + local key = self:get_key() + if not key then return end + local prev_text = ensure_key(self.state, key).prev_text + -- some screens reset their contents between context switches; regardless, + -- a switch back to the context should results in an incremental search + local incremental = not force_full_search and prev_text and text:startswith(prev_text) + local handler = self.handlers[key] + handler.search_fn(handler.vec, self.state[key], text, incremental) + self.state[key].prev_text = text +end + +local function filter_vec(fns, flags_vec, vec, text, erase_fn) + if fns.matches_filters_fn or text ~= '' then + local search_tokens = text:split() + for idx = #vec-1,0,-1 do + local flag = flags_vec and flags_vec[idx] or nil + local search_key = fns.get_search_key_fn(vec[idx], flag) + if (search_key and not utils.search_text(search_key, search_tokens)) or + (fns.matches_filters_fn and not fns.matches_filters_fn(vec[idx], flag)) + then + erase_fn(idx) + end + end + end +end + +function single_vector_search(fns, vec, data, text, incremental) + if not data.saved_original then + data.saved_original = copy_to_lua_table(vec) + elseif not incremental then + vec:assign(data.saved_original) + end + filter_vec(fns, nil, vec, text, function(idx) vec:erase(idx) end) + data.saved_visible = copy_to_lua_table(vec) + if fns.get_sort_fn then + table.sort(data.saved_visible, fns.get_sort_fn()) + vec:assign(data.saved_visible) + end +end + +-- doesn't support cleanup since nothing that uses this needs it yet +function flags_vector_search(fns, flags_vec, vec, data, text, incremental) + local get_elem_id_fn = fns.get_elem_id_fn and fns.get_elem_id_fn(elem) or function(elem) return elem end + if not data.saved_original then + data.saved_original = copy_to_lua_table(vec) + data.saved_flags = copy_to_lua_table(flags_vec) + data.saved_idx_map = {} + for idx,elem in ipairs(data.saved_original) do + data.saved_idx_map[get_elem_id_fn(elem)] = idx -- 1-based idx + end + else -- sync flag changes to saved vector + for idx,elem in ipairs(vec) do -- 0-based idx + data.saved_flags[data.saved_idx_map[get_elem_id_fn(elem)]] = flags_vec[idx] + end + end + + if not incremental then + vec:assign(data.saved_original) + flags_vec:assign(data.saved_flags) + end + + filter_vec(fns, flags_vec, vec, text, function(idx) + vec:erase(idx) + flags_vec:erase(idx) + end) +end + +return _ENV From 9acf81d3a0fa2c1493d2d06057bb5dc5f84d0420 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 10 Oct 2023 03:57:03 -0700 Subject: [PATCH 727/851] port info widgets to unified superclass --- plugins/lua/sort/info.lua | 397 ++++++++------------------ plugins/lua/sort/locationselector.lua | 2 +- plugins/lua/sort/sortoverlay.lua | 13 +- 3 files changed, 130 insertions(+), 282 deletions(-) diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index b732e504f..7e759bd10 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -1,7 +1,7 @@ local _ENV = mkmodule('plugins.sort.info') local gui = require('gui') -local overlay = require('plugins.overlay') +local sortoverlay = require('plugins.sort.sortoverlay') local widgets = require('gui.widgets') local utils = require('utils') @@ -12,8 +12,6 @@ local objects = info.artifacts local tasks = info.jobs local work_details = info.labor.work_details -local state = {} - -- these sort functions attempt to match the vanilla info panel sort behavior, which -- is not quite the same as the rest of DFHack. For example, in other DFHack sorts, -- we'd always sort by name descending as a secondary sort. To match vanilla sorting, @@ -98,49 +96,6 @@ local function get_sort() end end -local function copy_to_lua_table(vec) - local tab = {} - for k,v in ipairs(vec) do - tab[k+1] = v - end - return tab -end - -local function general_search(vec, get_search_key_fn, get_sort_fn, matches_filters_fn, data, filter, incremental) - if not data.saved_original then - data.saved_original = copy_to_lua_table(vec) - elseif not incremental then - vec:assign(data.saved_original) - end - if matches_filters_fn ~= DEFAULT_NIL or filter ~= '' then - local search_tokens = filter:split() - for idx = #vec-1,0,-1 do - local search_key = get_search_key_fn(vec[idx]) - if (search_key and not utils.search_text(search_key, search_tokens)) or - (matches_filters_fn ~= DEFAULT_NIL and not matches_filters_fn(vec[idx])) - then - vec:erase(idx) - end - end - end - data.saved_visible = copy_to_lua_table(vec) - if get_sort_fn then - table.sort(data.saved_visible, get_sort_fn()) - vec:assign(data.saved_visible) - end -end - --- add dynamically allocated elements that were not visible at the time of --- closure back to the vector so they can be cleaned up when it is next initialized -local function cri_unitst_cleanup(vec, data) - if not data.saved_visible or not data.saved_original then return end - for _,elem in ipairs(data.saved_original) do - if not utils.linear_index(data.saved_visible, elem) then - vec:insert('#', elem) - end - end -end - local function get_unit_search_key(unit) return ('%s %s %s'):format( dfhack.units.getReadableName(unit), -- last name is in english @@ -148,200 +103,46 @@ local function get_unit_search_key(unit) dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name end -local function make_cri_unitst_handlers(vec, sort_fn) - return { - search_fn=curry(general_search, vec, - function(elem) - return ('%s %s'):format( - elem.un and get_unit_search_key(elem.un) or '', - elem.job_sort_name) - end, - sort_fn), - cleanup_fn=curry(cri_unitst_cleanup, vec), - } +local function get_cri_unit_search_key(cri_unit) + return ('%s %s'):format( + cri_unit.un and get_unit_search_key(cri_unit.un) or '', + cri_unit.job_sort_name) +end + +local function get_race_name(raw_id) + local raw = df.creature_raw.find(raw_id) + if not raw then return end + return raw.name[1] end -local function overall_training_search(matches_filters_fn, data, filter, incremental) - general_search(creatures.atk_index, function(elem) - local raw = df.creature_raw.find(elem) - if not raw then return end - return raw.name[1] - end, nil, matches_filters_fn, data, filter, incremental) +local function get_trainer_search_key(unit) + if not unit then return end + return ('%s %s'):format(dfhack.TranslateName(unit.name), dfhack.units.getProfessionName(unit)) end -local function assign_trainer_search(matches_filters_fn, data, filter, incremental) - general_search(creatures.trainer, function(elem) - if not elem then return end - return ('%s %s'):format(dfhack.TranslateName(elem.name), dfhack.units.getProfessionName(elem)) - end, nil, matches_filters_fn, data, filter, incremental) +-- get name in both dwarvish and English +local function get_artifact_search_key(artifact) + return ('%s %s'):format(dfhack.TranslateName(artifact.name), dfhack.TranslateName(artifact.name, true)) end -local function work_details_search(matches_filters_fn, data, filter, incremental) +local function work_details_search(vec, data, text, incremental) if work_details.selected_work_detail_index ~= data.selected then data.saved_original = nil data.selected = work_details.selected_work_detail_index end - general_search(work_details.assignable_unit, get_unit_search_key, - nil, matches_filters_fn, data, filter, incremental) -end - --- independent implementation of search algorithm since we need to --- keep two vectors in sync -local function interrogating_search(matches_filters_fn, data, filter, incremental) - local vec, flags_vec = justice.interrogation_list, justice.interrogation_list_flag - if not data.saved_original then - data.saved_original = copy_to_lua_table(vec) - data.saved_flags = copy_to_lua_table(flags_vec) - data.saved_idx_map = {} - for idx, unit in ipairs(data.saved_original) do - data.saved_idx_map[unit.id] = idx -- 1-based idx - end - else -- sync flag changes to saved vector - for idx, unit in ipairs(vec) do -- 0-based idx - data.saved_flags[data.saved_idx_map[unit.id]] = flags_vec[idx] - end - end - - if not incremental then - vec:assign(data.saved_original) - flags_vec:assign(data.saved_flags) - end - - if matches_filters_fn ~= DEFAULT_NIL or filter ~= '' then - local search_tokens = filter:split() - for idx = #vec-1,0,-1 do - local search_key = get_unit_search_key(vec[idx]) - if (search_key and not utils.search_text(search_key, search_tokens)) or - (matches_filters_fn ~= DEFAULT_NIL and not matches_filters_fn(vec[idx], idx)) - then - vec:erase(idx) - flags_vec:erase(idx) - end - end - end -end - -local function convicting_search(matches_filters_fn, data, filter, incremental) - general_search(justice.conviction_list, get_unit_search_key, - nil, matches_filters_fn, data, filter, incremental) -end - -local HANDLERS = { - CITIZEN=make_cri_unitst_handlers(creatures.cri_unit.CITIZEN, get_sort), - PET=make_cri_unitst_handlers(creatures.cri_unit.PET, get_sort), - OTHER=make_cri_unitst_handlers(creatures.cri_unit.OTHER, get_sort), - DECEASED=make_cri_unitst_handlers(creatures.cri_unit.DECEASED, get_sort), - PET_OT={search_fn=overall_training_search}, - PET_AT={search_fn=assign_trainer_search}, - JOBS=make_cri_unitst_handlers(tasks.cri_job), - WORK_DETAILS={search_fn=work_details_search}, - INTERROGATING={search_fn=interrogating_search}, - CONVICTING={search_fn=convicting_search}, -} -for idx,name in ipairs(df.artifacts_mode_type) do - if idx < 0 then goto continue end - HANDLERS[name] = { - search_fn=curry(general_search, objects.list[idx], - function(elem) - return ('%s %s'):format(dfhack.TranslateName(elem.name), dfhack.TranslateName(elem.name, true)) - end, nil) - } - ::continue:: -end - -local function get_key() - if info.current_mode == df.info_interface_mode_type.JUSTICE then - if justice.interrogating then - return 'INTERROGATING' - elseif justice.convicting then - return 'CONVICTING' - end - elseif info.current_mode == df.info_interface_mode_type.CREATURES then - if creatures.current_mode == df.unit_list_mode_type.PET then - if creatures.showing_overall_training then - return 'PET_OT' - elseif creatures.adding_trainer then - return 'PET_AT' - end - end - return df.unit_list_mode_type[creatures.current_mode] - elseif info.current_mode == df.info_interface_mode_type.JOBS then - return 'JOBS' - elseif info.current_mode == df.info_interface_mode_type.ARTIFACTS then - return df.artifacts_mode_type[objects.mode] - elseif info.current_mode == df.info_interface_mode_type.LABOR then - if info.labor.mode == df.labor_mode_type.WORK_DETAILS then - return 'WORK_DETAILS' - end - end -end - -local function check_context(self, key_ctx) - local key = get_key() - if state[key_ctx] ~= key then - state[key_ctx] = key - local prev_text = key and ensure_key(state, key).prev_text or '' - self.subviews.search:setText(prev_text) - end -end - -local function do_search(matches_filters_fn, text, force_full_search) - if not force_full_search and not next(state) and text == '' then return end - -- the EditField state is guaranteed to be consistent with the current - -- context since when clicking to switch tabs, onRenderBody is always called - -- before this text_input callback, even if a key is pressed before the next - -- graphical frame would otherwise be printed. if this ever becomes untrue, - -- then we can add an on_char handler to the EditField that also calls - -- check_context. - local key = get_key() - if not key then return end - local prev_text = ensure_key(state, key).prev_text - -- some screens reset their contents between context switches; regardless - -- a switch back to the context should results in an incremental search - local incremental = not force_full_search and prev_text and text:startswith(prev_text) - HANDLERS[key].search_fn(matches_filters_fn, state[key], text, incremental) - state[key].prev_text = text -end - -local function on_update(self) - if self.overlay_onupdate_max_freq_seconds == 0 and - not dfhack.gui.matchFocusString('dwarfmode/Info', dfhack.gui.getDFViewscreen(true)) - then - for k,v in pairs(state) do - local cleanup_fn = safe_index(HANDLERS, k, 'cleanup_fn') - if cleanup_fn then cleanup_fn(v) end - end - state = {} - self.subviews.search:setText('') - self.subviews.search:setFocus(false) - self.overlay_onupdate_max_freq_seconds = 60 - end -end - -local function on_input(self, clazz, keys) - if keys._MOUSE_R and self.subviews.search.focus and self:get_handled_key() then - self.subviews.search:setFocus(false) - return true - end - return clazz.super.onInput(self, keys) -end - -local function is_interrogate_or_convict() - local key = get_key() - return key == 'INTERROGATING' or key == 'CONVICTING' + sortoverlay.single_vector_search( + {get_search_key_fn=get_unit_search_key}, + vec, data, text, incremental) end -- ---------------------- -- InfoOverlay -- -InfoOverlay = defclass(InfoOverlay, overlay.OverlayWidget) +InfoOverlay = defclass(InfoOverlay, sortoverlay.SortOverlay) InfoOverlay.ATTRS{ default_pos={x=64, y=8}, - default_enabled=true, viewscreens='dwarfmode/Info', - hotspot=true, - overlay_onupdate_max_freq_seconds=0, frame={w=40, h=4}, } @@ -350,26 +151,71 @@ function InfoOverlay:init() widgets.BannerPanel{ view_id='panel', frame={l=0, t=0, r=0, h=1}, - visible=self:callback('get_handled_key'), + visible=self:callback('get_key'), subviews={ widgets.EditField{ view_id='search', frame={l=1, t=0, r=1}, label_text="Search: ", key='CUSTOM_ALT_S', - on_change=function(text) do_search(DEFAULT_NIL, text) end, + on_change=function(text) self:do_search(text) end, }, }, }, } -end -function InfoOverlay:overlay_onupdate() - on_update(self) -end - -function InfoOverlay:get_handled_key() - return not is_interrogate_or_convict() and get_key() or nil + local CRI_UNIT_VECS = { + CITIZEN=creatures.cri_unit.CITIZEN, + PET=creatures.cri_unit.PET, + OTHER=creatures.cri_unit.OTHER, + DECEASED=creatures.cri_unit.DECEASED, + } + for key,vec in pairs(CRI_UNIT_VECS) do + self:register_handler(key, vec, + curry(sortoverlay.single_vector_search, + { + get_search_key_fn=get_cri_unit_search_key, + get_sort_fn=get_sort + }), + true) + end + + self:register_handler('JOBS', tasks.cri_job, + curry(sortoverlay.single_vector_search, {get_search_key_fn=get_cri_unit_search_key}), + true) + self:register_handler('PET_OT', creatures.atk_index, + curry(sortoverlay.single_vector_search, {get_search_key_fn=get_race_name})) + self:register_handler('PET_AT', creatures.trainer, + curry(sortoverlay.single_vector_search, {get_search_key_fn=get_trainer_search_key})) + self:register_handler('WORK_DETAILS', work_details.assignable_unit, work_details_search) + + for idx,name in ipairs(df.artifacts_mode_type) do + if idx < 0 then goto continue end + self:register_handler(name, objects.list[idx], + curry(sortoverlay.single_vector_search, {get_search_key_fn=get_artifact_search_key})) + ::continue:: + end +end + +function InfoOverlay:get_key() + if info.current_mode == df.info_interface_mode_type.CREATURES then + if creatures.current_mode == df.unit_list_mode_type.PET then + if creatures.showing_overall_training then + return 'PET_OT' + elseif creatures.adding_trainer then + return 'PET_AT' + end + end + return df.unit_list_mode_type[creatures.current_mode] + elseif info.current_mode == df.info_interface_mode_type.JOBS then + return 'JOBS' + elseif info.current_mode == df.info_interface_mode_type.ARTIFACTS then + return df.artifacts_mode_type[objects.mode] + elseif info.current_mode == df.info_interface_mode_type.LABOR then + if info.labor.mode == df.labor_mode_type.WORK_DETAILS then + return 'WORK_DETAILS' + end + end end local function resize_overlay(self) @@ -410,49 +256,34 @@ function InfoOverlay:updateFrames() end function InfoOverlay:onRenderBody(dc) - if next(state) then - check_context(self, InfoOverlay) - end + InfoOverlay.super.onRenderBody(self, dc) if self:updateFrames() then self:updateLayout() end if self.refresh_search then self.refresh_search = nil - do_search(DEFAULT_NIL, self.subviews.search.text) + self:do_search(self.subviews.search.text) end - self.overlay_onupdate_max_freq_seconds = 0 - InfoOverlay.super.onRenderBody(self, dc) end function InfoOverlay:onInput(keys) - if keys._MOUSE_L and get_key() == 'WORK_DETAILS' then + if keys._MOUSE_L and self:get_key() == 'WORK_DETAILS' then self.refresh_search = true end - return on_input(self, InfoOverlay, keys) + return InfoOverlay.super.onInput(self, keys) end -- ---------------------- -- InterrogationOverlay -- -InterrogationOverlay = defclass(InterrogationOverlay, overlay.OverlayWidget) +InterrogationOverlay = defclass(InterrogationOverlay, sortoverlay.SortOverlay) InterrogationOverlay.ATTRS{ default_pos={x=47, y=10}, - default_enabled=true, viewscreens='dwarfmode/Info/JUSTICE', frame={w=27, h=9}, - hotspot=true, - overlay_onupdate_max_freq_seconds=0, } -function InterrogationOverlay:overlay_onupdate() - on_update(self) -end - -function InterrogationOverlay:get_handled_key() - return is_interrogate_or_convict() and get_key() or nil -end - function InterrogationOverlay:init() self:addviews{ widgets.Panel{ @@ -460,14 +291,14 @@ function InterrogationOverlay:init() frame={l=0, t=4, h=5, r=0}, frame_background=gui.CLEAR_PEN, frame_style=gui.FRAME_MEDIUM, - visible=is_interrogate_or_convict, + visible=self:callback('get_key'), subviews={ widgets.EditField{ view_id='search', frame={l=0, t=0, r=0}, label_text="Search: ", key='CUSTOM_ALT_S', - on_change=function(text) do_search(self:callback('matches_filters'), text) end, + on_change=function(text) self:do_search(text) end, }, widgets.ToggleHotkeyLabel{ view_id='include_interviewed', @@ -479,9 +310,7 @@ function InterrogationOverlay:init() {label='Exclude', value=false, pen=COLOR_RED}, }, visible=function() return justice.interrogating end, - on_change=function() - do_search(self:callback('matches_filters'), self.subviews.search.text, true) - end, + on_change=function() self:do_search(self.subviews.search.text, true) end, }, widgets.CycleHotkeyLabel{ view_id='subset', @@ -498,13 +327,40 @@ function InterrogationOverlay:init() {label='Deceased or missing', value='deceased', pen=COLOR_MAGENTA}, {label='Others', value='others', pen=COLOR_GRAY}, }, - on_change=function() - do_search(self:callback('matches_filters'), self.subviews.search.text, true) - end, + on_change=function() self:do_search(self.subviews.search.text, true) end, }, }, }, } + + self:register_handler('INTERROGATING', justice.interrogation_list, + curry(sortoverlay.flags_vector_search, + { + get_search_key_fn=get_unit_search_key, + get_elem_id_fn=function(unit) return unit.id end, + matches_filters_fn=self:callback('matches_filters'), + }, + justice.interrogation_list_flag)) + self:register_handler('CONVICTING', justice.conviction_list, + curry(sortoverlay.single_vector_search, + { + get_search_key_fn=get_unit_search_key, + matches_filters_fn=self:callback('matches_filters'), + })) +end + +function InterrogationOverlay:reset() + InterrogationOverlay.super.reset(self) + self.subviews.include_interviewed:setOption(true, false) + self.subviews.subset:setOption('all') +end + +function InterrogationOverlay:get_key() + if justice.interrogating then + return 'INTERROGATING' + elseif justice.convicting then + return 'CONVICTING' + end end local RISKY_PROFESSIONS = utils.invert{ @@ -521,18 +377,20 @@ local function is_risky(unit) return not dfhack.units.isAlive(unit) -- detect intelligent undead end -function InterrogationOverlay:matches_filters(unit, idx) +function InterrogationOverlay:matches_filters(unit, flag) if justice.interrogating then local include_interviewed = self.subviews.include_interviewed:getOptionValue() - if not include_interviewed and justice.interrogation_list_flag[idx] == 2 then - return false - end + if not include_interviewed and flag == 2 then return false end end local subset = self.subviews.subset:getOptionValue() if subset == 'all' then return true elseif dfhack.units.isDead(unit) or not dfhack.units.isActive(unit) then return subset == 'deceased' + elseif dfhack.units.isInvader(unit) or dfhack.units.isOpposedToLife(unit) + or unit.flags2.visitor_uninvited or unit.flags4.agitated_wilderness_creature + then + return subset == 'others' elseif dfhack.units.isVisiting(unit) then local risky = is_risky(unit) return (subset == 'risky' and risky) or (subset == 'visitors' and not risky) @@ -569,19 +427,4 @@ function InterrogationOverlay:render(dc) InterrogationOverlay.super.render(self, dc) end -function InterrogationOverlay:onRenderBody(dc) - if next(state) then - check_context(self, InterrogationOverlay) - else - self.subviews.include_interviewed:setOption(true, false) - self.subviews.subset:setOption('all') - end - self.overlay_onupdate_max_freq_seconds = 0 - InterrogationOverlay.super.onRenderBody(self, dc) -end - -function InterrogationOverlay:onInput(keys) - return on_input(self, InterrogationOverlay, keys) -end - return _ENV diff --git a/plugins/lua/sort/locationselector.lua b/plugins/lua/sort/locationselector.lua index 8092db1e2..8a79a9d8f 100644 --- a/plugins/lua/sort/locationselector.lua +++ b/plugins/lua/sort/locationselector.lua @@ -51,7 +51,7 @@ function LocationSelectorOverlay:init() self:register_handler('TEMPLE', location_selector.valid_religious_practice_id, curry(sortoverlay.flags_vector_search, {get_search_key_fn=get_religion_string}, - location_selector.valid_religious_practice)) + location_selector.valid_religious_practice)) self:register_handler('GUILDHALL', location_selector.valid_craft_guild_type, curry(sortoverlay.single_vector_search, {get_search_key_fn=get_profession_string})) end diff --git a/plugins/lua/sort/sortoverlay.lua b/plugins/lua/sort/sortoverlay.lua index 96c0f8ecc..b3067a8ba 100644 --- a/plugins/lua/sort/sortoverlay.lua +++ b/plugins/lua/sort/sortoverlay.lua @@ -56,13 +56,17 @@ function SortOverlay:overlay_onupdate() restore_filtered(self.handlers[key].vec, data) end end - self.state = {} - self.subviews.search:setText('') - self.subviews.search:setFocus(false) + self:reset() self.overlay_onupdate_max_freq_seconds = 300 end end +function SortOverlay:reset() + self.state = {} + self.subviews.search:setText('') + self.subviews.search:setFocus(false) +end + -- returns the current context key for dereferencing the handler -- subclasses must override function SortOverlay:get_key() @@ -77,6 +81,7 @@ function SortOverlay:onRenderBody(dc) self.state.cur_key = key local prev_text = key and ensure_key(self.state, key).prev_text or '' self.subviews.search:setText(prev_text) + self:do_search(self.subviews.search.text, true) end end self.overlay_onupdate_max_freq_seconds = 0 @@ -141,7 +146,7 @@ end -- doesn't support cleanup since nothing that uses this needs it yet function flags_vector_search(fns, flags_vec, vec, data, text, incremental) - local get_elem_id_fn = fns.get_elem_id_fn and fns.get_elem_id_fn(elem) or function(elem) return elem end + local get_elem_id_fn = fns.get_elem_id_fn or function(elem) return elem end if not data.saved_original then data.saved_original = copy_to_lua_table(vec) data.saved_flags = copy_to_lua_table(flags_vec) From f282efd4d4a7aa5911a22f5b1a39eac800ad2979 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 10 Oct 2023 04:06:00 -0700 Subject: [PATCH 728/851] update docs --- docs/changelog.txt | 1 + docs/plugins/sort.rst | 24 ++++++++++++++++-------- plugins/lua/sort/sortoverlay.lua | 2 ++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 8a740a670..589952305 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,6 +58,7 @@ Template for new versions: ## New Features - `logistics`: ``automelt`` now optionally supports melting masterworks; feature accessible from `stockpiles` overlay - `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", the "Work details" subtab under "Labor", and the "Interrogate" and "Convict" screens under "Justice" +- `sort`: new search widgets for location selection screen (when you're choosing what kind of guildhall or temple to dedicate) ## Fixes - `zone`: don't show animal assignment link for dungeon cages/restraints diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 70e101b3f..21a2acacf 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -92,8 +92,8 @@ https://www.reddit.com/r/dwarffortress/comments/163kczo/enhancing_military_candi "Mental stability" is explained here: https://www.reddit.com/r/dwarffortress/comments/1617s11/enhancing_military_candidate_selection_part_2/ -Info overlay ------------- +Info tabs overlay +----------------- The Info overlay adds search support to many of the fort-wide "Info" panels (e.g. "Creatures", "Tasks", etc.). When searching for units, you can search by @@ -102,13 +102,21 @@ special status (like "necromancer"). If there is text in the second column, you can search for that text as well. This is often a job name or a status, like "caged". +Interrogation overlay +--------------------- + In the interrogation and conviction screens under the "Justice" tab, you can -also filter by the classification of the unit. The classification groups are -ordered by how likely a member of that group is to be involved in a plot. The -groups are: All, Risky visitors, Other visitors, Residents, Citizens, Animals, -Deceased, and Others. "Risky" visitors are those who are especially likely to -be involved in plots, such as criminals, necromancers, necromancer experiments, -and intelligent undead. +search for units by name. You can also filter by the classification of the +unit. The classification groups are ordered by how likely a member of that +group is to be involved in a plot. The groups are: All, Risky visitors, Other +visitors, Residents, Citizens, Animals, Deceased, and Others. "Risky" visitors are those who are especially likely to be involved in plots, such as criminals, +necromancers, necromancer experiments, and intelligent undead. On the interrogations screen, you can also filter units by whether they have already been interrogated. + +Location selection overlay +-------------------------- + +When choosing the type of guildhall or temple to dedicate, you can search for +the relevant profession, religion, or deity by name. diff --git a/plugins/lua/sort/sortoverlay.lua b/plugins/lua/sort/sortoverlay.lua index b3067a8ba..229fd2559 100644 --- a/plugins/lua/sort/sortoverlay.lua +++ b/plugins/lua/sort/sortoverlay.lua @@ -21,6 +21,8 @@ SortOverlay.ATTRS{ hotspot=true, overlay_onupdate_max_freq_seconds=0, -- subclasses expected to provide default_pos, viewscreens (single string), and frame + -- viewscreens should be the top-level scope within which the search widget state is maintained + -- once the player leaves that scope, widget state will be reset } function SortOverlay:init() From 09e3ed427a2967682d54cc3a607028402c658ef9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 10 Oct 2023 05:03:59 -0700 Subject: [PATCH 729/851] add search functionality for burrows assignment screen --- docs/changelog.txt | 1 + plugins/lua/sort.lua | 9 +++-- plugins/lua/sort/burrows.lua | 70 ++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 plugins/lua/sort/burrows.lua diff --git a/docs/changelog.txt b/docs/changelog.txt index 589952305..f79cbdd28 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -59,6 +59,7 @@ Template for new versions: - `logistics`: ``automelt`` now optionally supports melting masterworks; feature accessible from `stockpiles` overlay - `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", the "Work details" subtab under "Labor", and the "Interrogate" and "Convict" screens under "Justice" - `sort`: new search widgets for location selection screen (when you're choosing what kind of guildhall or temple to dedicate) +- `sort`: new search widgets for burrow assignment screen ## Fixes - `zone`: don't show animal assignment link for dungeon cages/restraints diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index ce9eb1f9e..3bc97cb74 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1,8 +1,6 @@ local _ENV = mkmodule('plugins.sort') -local info = require('plugins.sort.info') local gui = require('gui') -local locationselector = require('plugins.sort.locationselector') local overlay = require('plugins.overlay') local setbelief = reqscript('modtools/set-belief') local textures = require('gui.textures') @@ -1287,9 +1285,10 @@ end OVERLAY_WIDGETS = { squad_assignment=SquadAssignmentOverlay, squad_annotation=SquadAnnotationOverlay, - info=info.InfoOverlay, - interrogation=info.InterrogationOverlay, - location_selector=locationselector.LocationSelectorOverlay, + info=require('plugins.sort.info').InfoOverlay, + interrogation=require('plugins.sort.info').InterrogationOverlay, + location_selector=require('plugins.sort.locationselector').LocationSelectorOverlay, + burrows=require('plugins.sort.burrows').BurrowOverlay, } dfhack.onStateChange[GLOBAL_KEY] = function(sc) diff --git a/plugins/lua/sort/burrows.lua b/plugins/lua/sort/burrows.lua new file mode 100644 index 000000000..fe2b8ec8e --- /dev/null +++ b/plugins/lua/sort/burrows.lua @@ -0,0 +1,70 @@ +local _ENV = mkmodule('plugins.sort.burrows') + +local sortoverlay = require('plugins.sort.sortoverlay') +local widgets = require('gui.widgets') + +local unit_selector = df.global.game.main_interface.unit_selector + +-- ---------------------- +-- BurrowOverlay +-- + +BurrowOverlay = defclass(BurrowOverlay, sortoverlay.SortOverlay) +BurrowOverlay.ATTRS{ + default_pos={x=62, y=6}, + viewscreens='dwarfmode/UnitSelector/BURROW_ASSIGNMENT', + frame={w=26, h=1}, +} + +local function get_unit_id_search_key(unit_id) + local unit = df.unit.find(unit_id) + if not unit then return end + return ('%s %s %s'):format( + dfhack.units.getReadableName(unit), -- last name is in english + dfhack.units.getProfessionName(unit), + dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name +end + +function BurrowOverlay:init() + self:addviews{ + widgets.BannerPanel{ + frame={l=0, t=0, r=0, h=1}, + subviews={ + widgets.EditField{ + view_id='search', + frame={l=1, t=0, r=1}, + label_text="Search: ", + key='CUSTOM_ALT_S', + on_change=function(text) self:do_search(text) end, + }, + }, + }, + } + + self:register_handler('BURROW', unit_selector.unid, + curry(sortoverlay.flags_vector_search, {get_search_key_fn=get_unit_id_search_key}, + unit_selector.selected)) +end + +function BurrowOverlay:get_key() + if unit_selector.context == df.unit_selector_context_type.BURROW_ASSIGNMENT then + return 'BURROW' + end +end + +function BurrowOverlay:onRenderBody(dc) + BurrowOverlay.super.onRenderBody(self, dc) + if self.refresh_search then + self.refresh_search = nil + self:do_search(self.subviews.search.text) + end +end + +function BurrowOverlay:onInput(keys) + if keys._MOUSE_L then + self.refresh_search = true + end + return BurrowOverlay.super.onInput(self, keys) +end + +return _ENV From e41017a26b4eabe3d6fa8014173fc274dc17deb2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 10 Oct 2023 06:03:06 -0700 Subject: [PATCH 730/851] generalize burrow code to other unit assignment screens --- docs/changelog.txt | 2 +- plugins/lua/sort.lua | 2 +- plugins/lua/sort/burrows.lua | 70 ------------------------ plugins/lua/sort/unitselector.lua | 91 +++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 72 deletions(-) delete mode 100644 plugins/lua/sort/burrows.lua create mode 100644 plugins/lua/sort/unitselector.lua diff --git a/docs/changelog.txt b/docs/changelog.txt index f79cbdd28..6b9b1e597 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -59,7 +59,7 @@ Template for new versions: - `logistics`: ``automelt`` now optionally supports melting masterworks; feature accessible from `stockpiles` overlay - `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", the "Work details" subtab under "Labor", and the "Interrogate" and "Convict" screens under "Justice" - `sort`: new search widgets for location selection screen (when you're choosing what kind of guildhall or temple to dedicate) -- `sort`: new search widgets for burrow assignment screen +- `sort`: new search widgets for burrow assignment screen and other unit assignment dialogs ## Fixes - `zone`: don't show animal assignment link for dungeon cages/restraints diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 3bc97cb74..0fc6932c4 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1288,7 +1288,7 @@ OVERLAY_WIDGETS = { info=require('plugins.sort.info').InfoOverlay, interrogation=require('plugins.sort.info').InterrogationOverlay, location_selector=require('plugins.sort.locationselector').LocationSelectorOverlay, - burrows=require('plugins.sort.burrows').BurrowOverlay, + unit_selector=require('plugins.sort.unitselector').UnitSelectorOverlay, } dfhack.onStateChange[GLOBAL_KEY] = function(sc) diff --git a/plugins/lua/sort/burrows.lua b/plugins/lua/sort/burrows.lua deleted file mode 100644 index fe2b8ec8e..000000000 --- a/plugins/lua/sort/burrows.lua +++ /dev/null @@ -1,70 +0,0 @@ -local _ENV = mkmodule('plugins.sort.burrows') - -local sortoverlay = require('plugins.sort.sortoverlay') -local widgets = require('gui.widgets') - -local unit_selector = df.global.game.main_interface.unit_selector - --- ---------------------- --- BurrowOverlay --- - -BurrowOverlay = defclass(BurrowOverlay, sortoverlay.SortOverlay) -BurrowOverlay.ATTRS{ - default_pos={x=62, y=6}, - viewscreens='dwarfmode/UnitSelector/BURROW_ASSIGNMENT', - frame={w=26, h=1}, -} - -local function get_unit_id_search_key(unit_id) - local unit = df.unit.find(unit_id) - if not unit then return end - return ('%s %s %s'):format( - dfhack.units.getReadableName(unit), -- last name is in english - dfhack.units.getProfessionName(unit), - dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name -end - -function BurrowOverlay:init() - self:addviews{ - widgets.BannerPanel{ - frame={l=0, t=0, r=0, h=1}, - subviews={ - widgets.EditField{ - view_id='search', - frame={l=1, t=0, r=1}, - label_text="Search: ", - key='CUSTOM_ALT_S', - on_change=function(text) self:do_search(text) end, - }, - }, - }, - } - - self:register_handler('BURROW', unit_selector.unid, - curry(sortoverlay.flags_vector_search, {get_search_key_fn=get_unit_id_search_key}, - unit_selector.selected)) -end - -function BurrowOverlay:get_key() - if unit_selector.context == df.unit_selector_context_type.BURROW_ASSIGNMENT then - return 'BURROW' - end -end - -function BurrowOverlay:onRenderBody(dc) - BurrowOverlay.super.onRenderBody(self, dc) - if self.refresh_search then - self.refresh_search = nil - self:do_search(self.subviews.search.text) - end -end - -function BurrowOverlay:onInput(keys) - if keys._MOUSE_L then - self.refresh_search = true - end - return BurrowOverlay.super.onInput(self, keys) -end - -return _ENV diff --git a/plugins/lua/sort/unitselector.lua b/plugins/lua/sort/unitselector.lua new file mode 100644 index 000000000..b5423acee --- /dev/null +++ b/plugins/lua/sort/unitselector.lua @@ -0,0 +1,91 @@ +local _ENV = mkmodule('plugins.sort.unitselector') + +local sortoverlay = require('plugins.sort.sortoverlay') +local widgets = require('gui.widgets') + +local unit_selector = df.global.game.main_interface.unit_selector + +-- pen, pit, chain, and cage assignment are handled by dedicated screens +-- squad fill position screen has a specialized overlay +-- we *could* add search functionality to vanilla screens for pit and cage, +-- but then we'd have to handle the itemid vector +local HANDLED_SCREENS = { + ZONE_BEDROOM_ASSIGNMENT='already', + ZONE_OFFICE_ASSIGNMENT='already', + ZONE_DINING_HALL_ASSIGNMENT='already', + ZONE_TOMB_ASSIGNMENT='already', + -- this one should technically appear further to the left, but when the screen + -- gets small enough that that matters, the vanilla widgets are unreadable + WORKER_ASSIGNMENT='selected', + OCCUPATION_ASSIGNMENT='selected', + BURROW_ASSIGNMENT='selected', + SQUAD_KILL_ORDER='selected', +} + +-- ---------------------- +-- UnitSelectorOverlay +-- + +UnitSelectorOverlay = defclass(UnitSelectorOverlay, sortoverlay.SortOverlay) +UnitSelectorOverlay.ATTRS{ + default_pos={x=62, y=6}, + viewscreens='dwarfmode/UnitSelector', + frame={w=26, h=1}, +} + +local function get_unit_id_search_key(unit_id) + local unit = df.unit.find(unit_id) + if not unit then return end + return ('%s %s %s'):format( + dfhack.units.getReadableName(unit), -- last name is in english + dfhack.units.getProfessionName(unit), + dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name +end + +function UnitSelectorOverlay:init() + self:addviews{ + widgets.BannerPanel{ + frame={l=0, t=0, r=0, h=1}, + visible=self:callback('get_key'), + subviews={ + widgets.EditField{ + view_id='search', + frame={l=1, t=0, r=1}, + label_text="Search: ", + key='CUSTOM_ALT_S', + on_change=function(text) self:do_search(text) end, + }, + }, + }, + } + + for name,flags_vec in pairs(HANDLED_SCREENS) do + self:register_handler(name, unit_selector.unid, + curry(sortoverlay.flags_vector_search, {get_search_key_fn=get_unit_id_search_key}, + unit_selector[flags_vec])) + end +end + +function UnitSelectorOverlay:get_key() + local key = df.unit_selector_context_type[unit_selector.context] + if HANDLED_SCREENS[key] then + return key + end +end + +function UnitSelectorOverlay:onRenderBody(dc) + UnitSelectorOverlay.super.onRenderBody(self, dc) + if self.refresh_search then + self.refresh_search = nil + self:do_search(self.subviews.search.text) + end +end + +function UnitSelectorOverlay:onInput(keys) + if keys._MOUSE_L then + self.refresh_search = true + end + return UnitSelectorOverlay.super.onInput(self, keys) +end + +return _ENV From 75e7e6462dd99d2c82b43ab3b816cee698f7aa10 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 10 Oct 2023 16:40:20 -0700 Subject: [PATCH 731/851] add focus strings for viewscreen_worldst --- library/modules/Gui.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 3e4281c29..728786d30 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -89,6 +89,7 @@ using namespace DFHack; #include "df/viewscreen_new_regionst.h" #include "df/viewscreen_setupdwarfgamest.h" #include "df/viewscreen_titlest.h" +#include "df/viewscreen_worldst.h" #include "df/world.h" const size_t MAX_REPORTS_SIZE = 3000; // DF clears old reports to maintain this vector size @@ -224,6 +225,11 @@ DEFINE_GET_FOCUS_STRING_HANDLER(legends) focusStrings.push_back(baseFocus + '/' + screen->page[screen->active_page_index]->header); } +DEFINE_GET_FOCUS_STRING_HANDLER(world) +{ + focusStrings.push_back(baseFocus + '/' + enum_item_key(screen->view_mode)); +} + DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) { std::string newFocusString; From 60818e2194f31549c663ec3df98fb8e4d91bd1ee Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 10 Oct 2023 16:41:02 -0700 Subject: [PATCH 732/851] support search on the world artifacts screen --- plugins/lua/sort.lua | 1 + plugins/lua/sort/info.lua | 13 ++++- plugins/lua/sort/sortoverlay.lua | 30 ++++++----- plugins/lua/sort/world.lua | 87 ++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 16 deletions(-) create mode 100644 plugins/lua/sort/world.lua diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 0fc6932c4..2a98ff42c 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1289,6 +1289,7 @@ OVERLAY_WIDGETS = { interrogation=require('plugins.sort.info').InterrogationOverlay, location_selector=require('plugins.sort.locationselector').LocationSelectorOverlay, unit_selector=require('plugins.sort.unitselector').UnitSelectorOverlay, + world=require('plugins.sort.world').WorldOverlay, } dfhack.onStateChange[GLOBAL_KEY] = function(sc) diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index 7e759bd10..90a4e2348 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -135,6 +135,15 @@ local function work_details_search(vec, data, text, incremental) vec, data, text, incremental) end +local function cleanup_cri_unit(vec, data) + if not data.saved_visible or not data.saved_original then return end + for _,elem in ipairs(data.saved_original) do + if not utils.linear_index(data.saved_visible, elem) then + vec:insert('#', elem) + end + end +end + -- ---------------------- -- InfoOverlay -- @@ -177,12 +186,12 @@ function InfoOverlay:init() get_search_key_fn=get_cri_unit_search_key, get_sort_fn=get_sort }), - true) + curry(cleanup_cri_unit, vec)) end self:register_handler('JOBS', tasks.cri_job, curry(sortoverlay.single_vector_search, {get_search_key_fn=get_cri_unit_search_key}), - true) + curry(cleanup_cri_unit, vec)) self:register_handler('PET_OT', creatures.atk_index, curry(sortoverlay.single_vector_search, {get_search_key_fn=get_race_name})) self:register_handler('PET_AT', creatures.trainer, diff --git a/plugins/lua/sort/sortoverlay.lua b/plugins/lua/sort/sortoverlay.lua index 229fd2559..0a6d04bfd 100644 --- a/plugins/lua/sort/sortoverlay.lua +++ b/plugins/lua/sort/sortoverlay.lua @@ -31,31 +31,23 @@ function SortOverlay:init() -- subclasses expected to provide an EditField widget with view_id='search' end -function SortOverlay:register_handler(key, vec, search_fn, restore_filtered_on_cleanup) +function SortOverlay:register_handler(key, vec, search_fn, cleanup_fn) self.handlers[key] = { vec=vec, search_fn=search_fn, - restore_filtered_on_cleanup=restore_filtered_on_cleanup + cleanup_fn=cleanup_fn } end -local function restore_filtered(vec, data) - if not data.saved_visible or not data.saved_original then return end - for _,elem in ipairs(data.saved_original) do - if not utils.linear_index(data.saved_visible, elem) then - vec:insert('#', elem) - end - end -end - -- handles reset and clean up when the player exits the handled scope function SortOverlay:overlay_onupdate() if self.overlay_onupdate_max_freq_seconds == 0 and not dfhack.gui.matchFocusString(self.viewscreens, dfhack.gui.getDFViewscreen(true)) then for key,data in pairs(self.state) do - if safe_index(self.handlers, key, 'restore_filtered_on_cleanup') then - restore_filtered(self.handlers[key].vec, data) + local cleanup_fn = safe_index(self.handlers, key, 'cleanup_fn') + if cleanup_fn then + cleanup_fn(data) end end self:reset() @@ -133,25 +125,33 @@ local function filter_vec(fns, flags_vec, vec, text, erase_fn) end function single_vector_search(fns, vec, data, text, incremental) + vec = utils.getval(vec) if not data.saved_original then data.saved_original = copy_to_lua_table(vec) + data.saved_original_size = #vec elseif not incremental then vec:assign(data.saved_original) + vec:resize(data.saved_original_size) end filter_vec(fns, nil, vec, text, function(idx) vec:erase(idx) end) data.saved_visible = copy_to_lua_table(vec) if fns.get_sort_fn then table.sort(data.saved_visible, fns.get_sort_fn()) vec:assign(data.saved_visible) + vec:resize(data.saved_visible_size) end end --- doesn't support cleanup since nothing that uses this needs it yet +-- doesn't support sorting since nothing that uses this needs it yet function flags_vector_search(fns, flags_vec, vec, data, text, incremental) local get_elem_id_fn = fns.get_elem_id_fn or function(elem) return elem end + flags_vec, vec = utils.getval(flags_vec), utils.getval(vec) if not data.saved_original then + -- we save the sizes since trailing nils get lost in the lua -> vec assignment data.saved_original = copy_to_lua_table(vec) + data.saved_original_size = #vec data.saved_flags = copy_to_lua_table(flags_vec) + data.saved_flags_size = #flags_vec data.saved_idx_map = {} for idx,elem in ipairs(data.saved_original) do data.saved_idx_map[get_elem_id_fn(elem)] = idx -- 1-based idx @@ -164,7 +164,9 @@ function flags_vector_search(fns, flags_vec, vec, data, text, incremental) if not incremental then vec:assign(data.saved_original) + vec:resize(data.saved_original_size) flags_vec:assign(data.saved_flags) + flags_vec:resize(data.saved_flags_size) end filter_vec(fns, flags_vec, vec, text, function(idx) diff --git a/plugins/lua/sort/world.lua b/plugins/lua/sort/world.lua new file mode 100644 index 000000000..c056840d3 --- /dev/null +++ b/plugins/lua/sort/world.lua @@ -0,0 +1,87 @@ +local _ENV = mkmodule('plugins.sort.world') + +local sortoverlay = require('plugins.sort.sortoverlay') +local widgets = require('gui.widgets') + +-- ---------------------- +-- WorldOverlay +-- + +WorldOverlay = defclass(WorldOverlay, sortoverlay.SortOverlay) +WorldOverlay.ATTRS{ + default_pos={x=-18, y=2}, + viewscreens='world/ARTIFACTS', + frame={w=40, h=1}, +} + +local function get_world_artifact_search_key(artifact, rumor) + local search_key = ('%s %s'):format(dfhack.TranslateName(artifact.name, true), + dfhack.items.getDescription(artifact.item, 0)) + if rumor then + local hf = df.historical_figure.find(rumor.hfid) + if hf then + search_key = ('%s %s %s'):format(search_key, + dfhack.TranslateName(hf.name), + dfhack.TranslateName(hf.name, true)) + end + local ws = df.world_site.find(rumor.stid) + if ws then + search_key = ('%s %s'):format(search_key, + dfhack.TranslateName(ws.name, true)) + end + else + local hf = df.historical_figure.find(artifact.holder_hf) + if hf then + local unit = df.unit.find(hf.unit_id) + if unit then + search_key = ('%s %s'):format(search_key, + dfhack.units.getReadableName(unit)) + end + end + end + return search_key +end + +local function cleanup_artifact_vectors(data) + print('cleanng up') + local vs_world = dfhack.gui.getDFViewscreen(true) + vs_world.artifact:assign(data.saved_original) + vs_world.artifact_arl:assign(data.saved_flags) +end + +function WorldOverlay:init() + self:addviews{ + widgets.BannerPanel{ + frame={l=0, t=0, r=0, h=1}, + visible=self:callback('get_key'), + subviews={ + widgets.EditField{ + view_id='search', + frame={l=1, t=0, r=1}, + label_text="Search: ", + key='CUSTOM_ALT_S', + on_change=function(text) self:do_search(text) end, + }, + }, + }, + } + + self:register_handler('ARTIFACTS', + function() return dfhack.gui.getDFViewscreen(true).artifact end, + curry(sortoverlay.flags_vector_search, + { + get_search_key_fn=get_world_artifact_search_key, + get_elem_id_fn=function(artifact_record) return artifact_record.id end, + }, + function() return dfhack.gui.getDFViewscreen(true).artifact_arl end), + cleanup_artifact_vectors) +end + +function WorldOverlay:get_key() + local scr = dfhack.gui.getDFViewscreen(true) + if scr.view_mode == df.world_view_mode_type.ARTIFACTS then + return 'ARTIFACTS' + end +end + +return _ENV From 276e5a35232c5975d701164ffe469e25526a1351 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 10 Oct 2023 16:42:05 -0700 Subject: [PATCH 733/851] update docs --- docs/changelog.txt | 1 + docs/plugins/sort.rst | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 6b9b1e597..56523fac2 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -60,6 +60,7 @@ Template for new versions: - `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", the "Work details" subtab under "Labor", and the "Interrogate" and "Convict" screens under "Justice" - `sort`: new search widgets for location selection screen (when you're choosing what kind of guildhall or temple to dedicate) - `sort`: new search widgets for burrow assignment screen and other unit assignment dialogs +- `sort`: new search widgets for artifacts on the world/raid screen ## Fixes - `zone`: don't show animal assignment link for dungeon cages/restraints diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 21a2acacf..fd8d5102e 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -120,3 +120,9 @@ Location selection overlay When choosing the type of guildhall or temple to dedicate, you can search for the relevant profession, religion, or deity by name. + +World overlay +------------- + +Searching is supported for the Artifacts list when viewing the world map (where +you can initiate raids). From 40f9b0484666458a301314bb486604013f50d94b Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 11 Oct 2023 01:14:43 +0000 Subject: [PATCH 734/851] 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 ff278cfe3..a598bc677 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ff278cfe3b98f6f6a36c7a4be19884677b753a8d +Subproject commit a598bc6770199e9b965e00d0eade3f8400c4be9e From 2e2773b6abee7fbf58e4d81ab1dd25ac056587c6 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 12 Oct 2023 07:13:36 +0000 Subject: [PATCH 735/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 20d54145e..4e8ad9d87 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 20d54145e97fbae58cda391f66e6a32c7ee20330 +Subproject commit 4e8ad9d8711c4b5262b3806c4a5e563985fd8728 From f14f55a520ab5e71aa718f2eb4aa4963a687ae39 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 12 Oct 2023 01:21:23 -0700 Subject: [PATCH 736/851] add missing storage of visible vec length --- plugins/lua/sort/sortoverlay.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/lua/sort/sortoverlay.lua b/plugins/lua/sort/sortoverlay.lua index 0a6d04bfd..18b4877b3 100644 --- a/plugins/lua/sort/sortoverlay.lua +++ b/plugins/lua/sort/sortoverlay.lua @@ -135,6 +135,7 @@ function single_vector_search(fns, vec, data, text, incremental) end filter_vec(fns, nil, vec, text, function(idx) vec:erase(idx) end) data.saved_visible = copy_to_lua_table(vec) + data.saved_visible_size = #vec if fns.get_sort_fn then table.sort(data.saved_visible, fns.get_sort_fn()) vec:assign(data.saved_visible) From 99e437e7826368d544e783862ca5ba68612d24bc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 12 Oct 2023 11:01:05 -0700 Subject: [PATCH 737/851] changelog edits --- docs/changelog.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 56523fac2..2163305cf 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -52,18 +52,19 @@ Template for new versions: # Future ## New Tools -- `spectate`: automatically follow productive dwarves (returned to availability) -- `preserve-tombs`: tracks tomb assignments to living units and ensures that the tomb stays assigned to them when they die. +- `spectate`: (reinstated) automatically follow dwarves, cycling among interesting ones +- `preserve-tombs`: keep tombs assigned to units when they die ## New Features -- `logistics`: ``automelt`` now optionally supports melting masterworks; feature accessible from `stockpiles` overlay -- `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", the "Work details" subtab under "Labor", and the "Interrogate" and "Convict" screens under "Justice" +- `logistics`: ``automelt`` now optionally supports melting masterworks; click on gear icon on `stockpiles` overlay frame +- `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", and the "Work details" subtab under "Labor" +- `sort`: new search and filter widgets for the "Interrogate" and "Convict" screens under "Justice" - `sort`: new search widgets for location selection screen (when you're choosing what kind of guildhall or temple to dedicate) - `sort`: new search widgets for burrow assignment screen and other unit assignment dialogs - `sort`: new search widgets for artifacts on the world/raid screen ## Fixes -- `zone`: don't show animal assignment link for dungeon cages/restraints +- `zone`: don't show animal assignment link for cages and restraints linked to dungeon zones (which aren't normally assignable) ## Misc Improvements - `overlay`: allow ``overlay_onupdate_max_freq_seconds`` to be dynamically set to 0 for a burst of high-frequency updates @@ -77,7 +78,7 @@ Template for new versions: ## Lua - added ``GRAY`` color aliases for ``GREY`` colors -- ``utils.search_text``: text search routine (generalized from ``widgets.FilteredList``) +- ``utils.search_text``: text search routine (generalized from internal ``widgets.FilteredList`` logic) ## Removed - ``FILTER_FULL_TEXT``: moved from ``gui.widgets`` to ``utils``; if your full text search preference is lost, please reset it in `gui/control-panel` From 448dd5fa19f77910d7b9c5043809dd4c9100cc70 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 12 Oct 2023 11:33:22 -0700 Subject: [PATCH 738/851] clean up artifact search code --- plugins/lua/sort/world.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/lua/sort/world.lua b/plugins/lua/sort/world.lua index c056840d3..a4cf6c0e5 100644 --- a/plugins/lua/sort/world.lua +++ b/plugins/lua/sort/world.lua @@ -43,10 +43,11 @@ local function get_world_artifact_search_key(artifact, rumor) end local function cleanup_artifact_vectors(data) - print('cleanng up') local vs_world = dfhack.gui.getDFViewscreen(true) vs_world.artifact:assign(data.saved_original) + vs_world.artifact:resize(data.saved_original_size) vs_world.artifact_arl:assign(data.saved_flags) + vs_world.artifact_arl:resize(data.saved_flags_size) end function WorldOverlay:init() From db08110e56c825a6244330915afd8c2eaab573d5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 12 Oct 2023 11:48:40 -0700 Subject: [PATCH 739/851] bump release version to 50.11-r2rc1 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c09fc6b71..5ec38b28a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.11") -set(DFHACK_RELEASE "r1") -set(DFHACK_PRERELEASE FALSE) +set(DFHACK_RELEASE "r2rc1") +set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_ABI_VERSION 1) From ee78f4fbdfd36b282d1b27eaa5a65edf804b8032 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Oct 2023 12:37:11 -0700 Subject: [PATCH 740/851] support searching for spheres on the religion selector --- docs/plugins/sort.rst | 4 +++- plugins/lua/sort/locationselector.lua | 24 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index fd8d5102e..0ffe5118b 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -119,7 +119,9 @@ Location selection overlay -------------------------- When choosing the type of guildhall or temple to dedicate, you can search for -the relevant profession, religion, or deity by name. +the relevant profession, religion, or deity by name. For temples, you can also +search for the "spheres" associated with the deity or religion, such as +"wealth" or "lies". World overlay ------------- diff --git a/plugins/lua/sort/locationselector.lua b/plugins/lua/sort/locationselector.lua index 8a79a9d8f..d91c536ac 100644 --- a/plugins/lua/sort/locationselector.lua +++ b/plugins/lua/sort/locationselector.lua @@ -16,16 +16,38 @@ LocationSelectorOverlay.ATTRS{ frame={w=26, h=1}, } +local function add_spheres(hf, spheres) + if not hf then return end + for _, sphere in ipairs(hf.info.spheres.spheres) do + spheres[sphere] = true + end +end + +local function stringify_spheres(spheres) + local strs = {} + for sphere in pairs(spheres) do + table.insert(strs, df.sphere_type[sphere]) + end + return table.concat(strs, ' ') +end + local function get_religion_string(religion_id, religion_type) if religion_id == -1 then return end local entity + local spheres = {} if religion_type == 0 then entity = df.historical_figure.find(religion_id) + add_spheres(entity, spheres) elseif religion_type == 1 then entity = df.historical_entity.find(religion_id) + if entity then + for _, deity in ipairs(entity.relations.deities) do + add_spheres(df.historical_figure.find(deity), spheres) + end + end end if not entity then return end - return dfhack.TranslateName(entity.name, true) + return ('%s %s'):format(dfhack.TranslateName(entity.name, true), stringify_spheres(spheres)) end local function get_profession_string(profession) From 43b0c3e10dfc44ddcd92b34698b0ca3e52ba8bd3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Oct 2023 14:33:06 -0700 Subject: [PATCH 741/851] add more detailed focus strings for the nobles info screen --- library/modules/Gui.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 728786d30..500676983 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -280,6 +280,14 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) else newFocusString += "/Default"; break; + case df::enums::info_interface_mode_type::ADMINISTRATORS: + if (game->main_interface.info.administrators.choosing_candidate) + newFocusString += "/Candidates"; + else if (game->main_interface.info.administrators.assigning_symbol) + newFocusString += "/Symbols"; + else + newFocusString += "/Default"; + break; default: break; } From d739d9c1ef85ef9f8afcede8e8b2ac9ca08bda70 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Oct 2023 14:33:22 -0700 Subject: [PATCH 742/851] add search support for noble candidates --- docs/changelog.txt | 2 +- docs/plugins/sort.rst | 9 +++++ plugins/lua/sort.lua | 1 + plugins/lua/sort/info.lua | 83 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 90 insertions(+), 5 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 2163305cf..5d83dc4cf 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,7 +57,7 @@ Template for new versions: ## New Features - `logistics`: ``automelt`` now optionally supports melting masterworks; click on gear icon on `stockpiles` overlay frame -- `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", and the "Work details" subtab under "Labor" +- `sort`: new search widgets for Info panel tabs, including all "Creatures" subtabs, all "Objects" subtabs, "Tasks", candidate assignment on the "Noble" subtab, and the "Work details" subtab under "Labor" - `sort`: new search and filter widgets for the "Interrogate" and "Convict" screens under "Justice" - `sort`: new search widgets for location selection screen (when you're choosing what kind of guildhall or temple to dedicate) - `sort`: new search widgets for burrow assignment screen and other unit assignment dialogs diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 0ffe5118b..4350a4cb0 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -115,6 +115,15 @@ necromancers, necromancer experiments, and intelligent undead. On the interrogations screen, you can also filter units by whether they have already been interrogated. +Candidates overlay +------------------ + +When you select the button to choose a candidate to assign to a noble role on +the nobles screen, you can search for units by name, profession, or any of the +skills in which they have achieved at least "novice" level. For example, when +assigning a broker, you can search for "appraisal" to find candidates that have +at least some appraisal skill. + Location selection overlay -------------------------- diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 2a98ff42c..58974a357 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1286,6 +1286,7 @@ OVERLAY_WIDGETS = { squad_assignment=SquadAssignmentOverlay, squad_annotation=SquadAnnotationOverlay, info=require('plugins.sort.info').InfoOverlay, + candidates=require('plugins.sort.info').CandidatesOverlay, interrogation=require('plugins.sort.info').InterrogationOverlay, location_selector=require('plugins.sort.locationselector').LocationSelectorOverlay, unit_selector=require('plugins.sort.unitselector').UnitSelectorOverlay, diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index 90a4e2348..1f15d643b 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -6,6 +6,7 @@ local widgets = require('gui.widgets') local utils = require('utils') local info = df.global.game.main_interface.info +local administrators = info.administrators local creatures = info.creatures local justice = info.justice local objects = info.artifacts @@ -135,7 +136,7 @@ local function work_details_search(vec, data, text, incremental) vec, data, text, incremental) end -local function cleanup_cri_unit(vec, data) +local function restore_allocated_data(vec, data) if not data.saved_visible or not data.saved_original then return end for _,elem in ipairs(data.saved_original) do if not utils.linear_index(data.saved_visible, elem) then @@ -144,6 +145,26 @@ local function cleanup_cri_unit(vec, data) end end +local function serialize_skills(unit) + if not unit or not unit.status or not unit.status.current_soul then + return '' + end + local skills = {} + for _, skill in ipairs(unit.status.current_soul.skills) do + if skill.rating > 0 then -- ignore dabbling + table.insert(skills, df.job_skill[skill.id]) + end + end + return table.concat(skills, ' ') +end + +local function get_candidate_search_key(cand) + if not cand.un then return end + return ('%s %s'):format( + get_unit_search_key(cand.un), + serialize_skills(cand.un)) +end + -- ---------------------- -- InfoOverlay -- @@ -186,12 +207,12 @@ function InfoOverlay:init() get_search_key_fn=get_cri_unit_search_key, get_sort_fn=get_sort }), - curry(cleanup_cri_unit, vec)) + curry(restore_allocated_data, vec)) end self:register_handler('JOBS', tasks.cri_job, curry(sortoverlay.single_vector_search, {get_search_key_fn=get_cri_unit_search_key}), - curry(cleanup_cri_unit, vec)) + curry(restore_allocated_data, tasks.cri_job)) self:register_handler('PET_OT', creatures.atk_index, curry(sortoverlay.single_vector_search, {get_search_key_fn=get_race_name})) self:register_handler('PET_AT', creatures.trainer, @@ -259,7 +280,7 @@ function InfoOverlay:updateFrames() local ret = resize_overlay(self) local l, t = get_panel_offsets() local frame = self.subviews.panel.frame - if (frame.l == l and frame.t == t) then return ret end + if frame.l == l and frame.t == t then return ret end frame.l, frame.t = l, t return true end @@ -282,6 +303,60 @@ function InfoOverlay:onInput(keys) return InfoOverlay.super.onInput(self, keys) end +-- ---------------------- +-- CandidatesOverlay +-- + +CandidatesOverlay = defclass(CandidatesOverlay, sortoverlay.SortOverlay) +CandidatesOverlay.ATTRS{ + default_pos={x=54, y=8}, + viewscreens='dwarfmode/Info/ADMINISTRATORS/Candidates', + frame={w=27, h=3}, +} + +function CandidatesOverlay:init() + self:addviews{ + widgets.BannerPanel{ + view_id='panel', + frame={l=0, t=0, r=0, h=1}, + subviews={ + widgets.EditField{ + view_id='search', + frame={l=1, t=0, r=1}, + label_text="Search: ", + key='CUSTOM_ALT_S', + on_change=function(text) self:do_search(text) end, + }, + }, + }, + } + + self:register_handler('CANDIDATE', administrators.candidate, + curry(sortoverlay.single_vector_search, {get_search_key_fn=get_candidate_search_key}), + curry(restore_allocated_data, administrators.candidate)) +end + +function CandidatesOverlay:get_key() + if administrators.choosing_candidate then + return 'CANDIDATE' + end +end + +function CandidatesOverlay:updateFrames() + local t = is_tabs_in_two_rows() and 2 or 0 + local frame = self.subviews.panel.frame + if frame.t == t then return end + frame.t = t + return true +end + +function CandidatesOverlay:onRenderBody(dc) + CandidatesOverlay.super.onRenderBody(self, dc) + if self:updateFrames() then + self:updateLayout() + end +end + -- ---------------------- -- InterrogationOverlay -- From 0323055e0d4eb77c8207e412607808450181b2f8 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Oct 2023 14:48:44 -0700 Subject: [PATCH 743/851] better panel alignment on small screen sizes for worker assignment screen --- plugins/lua/sort.lua | 1 + plugins/lua/sort/unitselector.lua | 50 ++++++++++++++++++------------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 58974a357..9be0848c5 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1290,6 +1290,7 @@ OVERLAY_WIDGETS = { interrogation=require('plugins.sort.info').InterrogationOverlay, location_selector=require('plugins.sort.locationselector').LocationSelectorOverlay, unit_selector=require('plugins.sort.unitselector').UnitSelectorOverlay, + worker_assignment=require('plugins.sort.unitselector').WorkerAssignmentOverlay, world=require('plugins.sort.world').WorldOverlay, } diff --git a/plugins/lua/sort/unitselector.lua b/plugins/lua/sort/unitselector.lua index b5423acee..a904d2f29 100644 --- a/plugins/lua/sort/unitselector.lua +++ b/plugins/lua/sort/unitselector.lua @@ -5,23 +5,6 @@ local widgets = require('gui.widgets') local unit_selector = df.global.game.main_interface.unit_selector --- pen, pit, chain, and cage assignment are handled by dedicated screens --- squad fill position screen has a specialized overlay --- we *could* add search functionality to vanilla screens for pit and cage, --- but then we'd have to handle the itemid vector -local HANDLED_SCREENS = { - ZONE_BEDROOM_ASSIGNMENT='already', - ZONE_OFFICE_ASSIGNMENT='already', - ZONE_DINING_HALL_ASSIGNMENT='already', - ZONE_TOMB_ASSIGNMENT='already', - -- this one should technically appear further to the left, but when the screen - -- gets small enough that that matters, the vanilla widgets are unreadable - WORKER_ASSIGNMENT='selected', - OCCUPATION_ASSIGNMENT='selected', - BURROW_ASSIGNMENT='selected', - SQUAD_KILL_ORDER='selected', -} - -- ---------------------- -- UnitSelectorOverlay -- @@ -30,7 +13,8 @@ UnitSelectorOverlay = defclass(UnitSelectorOverlay, sortoverlay.SortOverlay) UnitSelectorOverlay.ATTRS{ default_pos={x=62, y=6}, viewscreens='dwarfmode/UnitSelector', - frame={w=26, h=1}, + frame={w=31, h=1}, + handled_screens=DEFAULT_NIL, } local function get_unit_id_search_key(unit_id) @@ -59,7 +43,21 @@ function UnitSelectorOverlay:init() }, } - for name,flags_vec in pairs(HANDLED_SCREENS) do + -- pen, pit, chain, and cage assignment are handled by dedicated screens + -- squad fill position screen has a specialized overlay + -- we *could* add search functionality to vanilla screens for pit and cage, + -- but then we'd have to handle the itemid vector + self.handled_screens = self.handled_screens or { + ZONE_BEDROOM_ASSIGNMENT='already', + ZONE_OFFICE_ASSIGNMENT='already', + ZONE_DINING_HALL_ASSIGNMENT='already', + ZONE_TOMB_ASSIGNMENT='already', + OCCUPATION_ASSIGNMENT='selected', + BURROW_ASSIGNMENT='selected', + SQUAD_KILL_ORDER='selected', + } + + for name,flags_vec in pairs(self.handled_screens) do self:register_handler(name, unit_selector.unid, curry(sortoverlay.flags_vector_search, {get_search_key_fn=get_unit_id_search_key}, unit_selector[flags_vec])) @@ -68,7 +66,7 @@ end function UnitSelectorOverlay:get_key() local key = df.unit_selector_context_type[unit_selector.context] - if HANDLED_SCREENS[key] then + if self.handled_screens[key] then return key end end @@ -88,4 +86,16 @@ function UnitSelectorOverlay:onInput(keys) return UnitSelectorOverlay.super.onInput(self, keys) end +-- ---------------------- +-- WorkerAssignmentOverlay +-- + +WorkerAssignmentOverlay = defclass(WorkerAssignmentOverlay, UnitSelectorOverlay) +WorkerAssignmentOverlay.ATTRS{ + default_pos={x=6, y=6}, + viewscreens='dwarfmode/UnitSelector', + frame={w=31, h=1}, + handled_screens={WORKER_ASSIGNMENT='selected'}, +} + return _ENV From cd935dcdcbaf34f081a2c348c26119cc603cb136 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Oct 2023 23:30:09 -0700 Subject: [PATCH 744/851] properly initialize job id when linking into world --- docs/changelog.txt | 1 + plugins/lua/dwarfvet.lua | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 5d83dc4cf..017d61645 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -65,6 +65,7 @@ Template for new versions: ## Fixes - `zone`: don't show animal assignment link for cages and restraints linked to dungeon zones (which aren't normally assignable) +- `dwarfvet`: fix invalid job id assigned to ``Rest`` job, which could cause crashes on reload ## Misc Improvements - `overlay`: allow ``overlay_onupdate_max_freq_seconds`` to be dynamically set to 0 for a burst of high-frequency updates diff --git a/plugins/lua/dwarfvet.lua b/plugins/lua/dwarfvet.lua index a976b91c8..2bda976b7 100644 --- a/plugins/lua/dwarfvet.lua +++ b/plugins/lua/dwarfvet.lua @@ -92,13 +92,12 @@ function HospitalZone:assign_spot(unit, unit_pos) local pos = self:find_spot(unit_pos) if not pos then return false end local job = df.new(df.job) - dfhack.job.linkIntoWorld(job) + dfhack.job.linkIntoWorld(job, true) job.pos.x = pos.x job.pos.y = pos.y job.pos.z = pos.z job.flags.special = true job.job_type = df.job_type.Rest - job.wait_timer = 1600 local gref = df.new(df.general_ref_unit_workerst) gref.unit_id = unit.id job.general_refs:insert('#', gref) From cac17bd8fa0735ac8e84ba0f059230159714b4b8 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 14 Oct 2023 07:11:50 +0000 Subject: [PATCH 745/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 4e8ad9d87..6166bb73d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 4e8ad9d8711c4b5262b3806c4a5e563985fd8728 +Subproject commit 6166bb73dc9ae19a51780ecf026d92f2fffd277f From 87af3281fb9db399953bf77d5f7efff8822a6095 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Oct 2023 04:22:43 -0700 Subject: [PATCH 746/851] use generic baby/child names when race doesn't have something specific --- docs/changelog.txt | 1 + library/modules/Units.cpp | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 5d83dc4cf..a196691af 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -64,6 +64,7 @@ Template for new versions: - `sort`: new search widgets for artifacts on the world/raid screen ## Fixes +- `zone`: races without specific child or baby names will now get generic child/baby names instead of an empty string - `zone`: don't show animal assignment link for cages and restraints linked to dungeon zones (which aren't normally assignable) ## Misc Improvements diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 83554ef78..a9d361706 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -1225,8 +1225,12 @@ string Units::getRaceBabyNameById(int32_t id) if (id >= 0 && (size_t)id < world->raws.creatures.all.size()) { df::creature_raw* raw = world->raws.creatures.all[id]; - if (raw) - return raw->general_baby_name[0]; + if (raw) { + string & baby_name = raw->general_baby_name[0]; + if (!baby_name.empty()) + return baby_name; + return getRaceReadableNameById(id) + " baby"; + } } return ""; } @@ -1242,8 +1246,12 @@ string Units::getRaceChildNameById(int32_t id) if (id >= 0 && (size_t)id < world->raws.creatures.all.size()) { df::creature_raw* raw = world->raws.creatures.all[id]; - if (raw) - return raw->general_child_name[0]; + if (raw) { + string & child_name = raw->general_child_name[0]; + if (!child_name.empty()) + return child_name; + return getRaceReadableNameById(id) + " child"; + } } return ""; } @@ -1266,7 +1274,10 @@ static string get_caste_name(df::unit* unit) { } string Units::getReadableName(df::unit* unit) { - string race_name = isChild(unit) ? getRaceChildName(unit) : get_caste_name(unit); + string race_name = isBaby(unit) ? getRaceBabyName(unit) : + (isChild(unit) ? getRaceChildName(unit) : get_caste_name(unit)); + if (race_name.empty()) + race_name = getRaceReadableName(unit); if (isHunter(unit)) race_name = "hunter " + race_name; if (isWar(unit)) From 6cba299551d6534714a16577dd5fd633879ea5d9 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 14 Oct 2023 19:01:52 +0000 Subject: [PATCH 747/851] 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 a598bc677..2469d0ede 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit a598bc6770199e9b965e00d0eade3f8400c4be9e +Subproject commit 2469d0edea90044d969f5b686bf0eaf73a879063 From 4d35f82e2c81d18fc7173e44a7e1d010a20b33f4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Oct 2023 13:00:15 -0700 Subject: [PATCH 748/851] sync tags from spreadsheet --- docs/plugins/3dveins.rst | 2 +- docs/plugins/design.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/3dveins.rst b/docs/plugins/3dveins.rst index 3112934ab..96fbcf836 100644 --- a/docs/plugins/3dveins.rst +++ b/docs/plugins/3dveins.rst @@ -3,7 +3,7 @@ .. dfhack-tool:: :summary: Rewrite layer veins to expand in 3D space. - :tags: unavailable fort gameplay map + :tags: fort gameplay map Existing, flat veins are removed and new 3D veins that naturally span z-levels are generated in their place. The transformation preserves the mineral counts diff --git a/docs/plugins/design.rst b/docs/plugins/design.rst index 0a6d0ad01..3cb48343c 100644 --- a/docs/plugins/design.rst +++ b/docs/plugins/design.rst @@ -3,7 +3,7 @@ design .. dfhack-tool:: :summary: Draws designations in shapes. - :tags: fort dev design map + :tags: fort design dev map :no-command: This plugin provides a Lua API, but no direct commands. See `gui/design` for From d59170a798dd14406da6cf9d1f288d436c30858c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Oct 2023 13:24:50 -0700 Subject: [PATCH 749/851] remove tags from unavailable tools --- docs/plugins/autogems.rst | 2 +- docs/plugins/building-hacks.rst | 2 +- docs/plugins/burrows.rst | 2 +- docs/plugins/digFlood.rst | 2 +- docs/plugins/diggingInvaders.rst | 2 +- docs/plugins/dwarfmonitor.rst | 2 +- docs/plugins/embark-assistant.rst | 2 +- docs/plugins/embark-tools.rst | 2 +- docs/plugins/fix-unit-occupancy.rst | 2 +- docs/plugins/fixveins.rst | 2 +- docs/plugins/follow.rst | 2 +- docs/plugins/forceequip.rst | 2 +- docs/plugins/generated-creature-renamer.rst | 2 +- docs/plugins/infiniteSky.rst | 2 +- docs/plugins/isoworldremote.rst | 2 +- docs/plugins/jobutils.rst | 2 +- docs/plugins/labormanager.rst | 2 +- docs/plugins/manipulator.rst | 2 +- docs/plugins/map-render.rst | 2 +- docs/plugins/mode.rst | 2 +- docs/plugins/mousequery.rst | 2 +- docs/plugins/petcapRemover.rst | 2 +- docs/plugins/plants.rst | 2 +- docs/plugins/power-meter.rst | 2 +- docs/plugins/rename.rst | 2 +- docs/plugins/rendermax.rst | 2 +- docs/plugins/search.rst | 2 +- docs/plugins/siege-engine.rst | 2 +- docs/plugins/steam-engine.rst | 2 +- docs/plugins/stockflow.rst | 2 +- docs/plugins/stocks.rst | 2 +- docs/plugins/title-folder.rst | 2 +- docs/plugins/trackstop.rst | 2 +- docs/plugins/tweak.rst | 2 +- docs/plugins/workflow.rst | 2 +- docs/plugins/zone.rst | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/docs/plugins/autogems.rst b/docs/plugins/autogems.rst index 6135b39d2..5beb7260e 100644 --- a/docs/plugins/autogems.rst +++ b/docs/plugins/autogems.rst @@ -3,7 +3,7 @@ autogems .. dfhack-tool:: :summary: Automatically cut rough gems. - :tags: unavailable fort auto workorders + :tags: unavailable :no-command: .. dfhack-command:: autogems-reload diff --git a/docs/plugins/building-hacks.rst b/docs/plugins/building-hacks.rst index b45b23be4..ae38cb3d9 100644 --- a/docs/plugins/building-hacks.rst +++ b/docs/plugins/building-hacks.rst @@ -3,7 +3,7 @@ building-hacks .. dfhack-tool:: :summary: Provides a Lua API for creating powered workshops. - :tags: unavailable fort gameplay buildings + :tags: unavailable :no-command: See `building-hacks-api` for more details. diff --git a/docs/plugins/burrows.rst b/docs/plugins/burrows.rst index 299656cf5..b1c966ea2 100644 --- a/docs/plugins/burrows.rst +++ b/docs/plugins/burrows.rst @@ -3,7 +3,7 @@ burrows .. dfhack-tool:: :summary: Auto-expand burrows as you dig. - :tags: unavailable fort auto design productivity map units + :tags: unavailable :no-command: .. dfhack-command:: burrow diff --git a/docs/plugins/digFlood.rst b/docs/plugins/digFlood.rst index ee502371a..e98b65382 100644 --- a/docs/plugins/digFlood.rst +++ b/docs/plugins/digFlood.rst @@ -3,7 +3,7 @@ digFlood .. dfhack-tool:: :summary: Digs out veins as they are discovered. - :tags: unavailable fort auto map + :tags: unavailable Once you register specific vein types, this tool will automatically designate tiles of those types of veins for digging as your miners complete adjacent diff --git a/docs/plugins/diggingInvaders.rst b/docs/plugins/diggingInvaders.rst index 001636709..46db313c6 100644 --- a/docs/plugins/diggingInvaders.rst +++ b/docs/plugins/diggingInvaders.rst @@ -3,7 +3,7 @@ diggingInvaders .. dfhack-tool:: :summary: Invaders dig and destroy to get to your dwarves. - :tags: unavailable fort gameplay military units + :tags: unavailable Usage ----- diff --git a/docs/plugins/dwarfmonitor.rst b/docs/plugins/dwarfmonitor.rst index 45a5d8f85..cd8867ee5 100644 --- a/docs/plugins/dwarfmonitor.rst +++ b/docs/plugins/dwarfmonitor.rst @@ -3,7 +3,7 @@ dwarfmonitor .. dfhack-tool:: :summary: Report on dwarf preferences and efficiency. - :tags: unavailable fort inspection jobs units + :tags: unavailable It can also show heads-up display widgets with live fort statistics. diff --git a/docs/plugins/embark-assistant.rst b/docs/plugins/embark-assistant.rst index 282d4b122..88c4ffccd 100644 --- a/docs/plugins/embark-assistant.rst +++ b/docs/plugins/embark-assistant.rst @@ -3,7 +3,7 @@ embark-assistant .. dfhack-tool:: :summary: Embark site selection support. - :tags: unavailable embark fort interface + :tags: unavailable Run this command while the pre-embark screen is displayed to show extended (and reasonably correct) resource information for the embark rectangle as well as diff --git a/docs/plugins/embark-tools.rst b/docs/plugins/embark-tools.rst index 0c76b887f..37a7bf43e 100644 --- a/docs/plugins/embark-tools.rst +++ b/docs/plugins/embark-tools.rst @@ -3,7 +3,7 @@ embark-tools .. dfhack-tool:: :summary: Extend the embark screen functionality. - :tags: unavailable embark fort interface + :tags: unavailable Usage ----- diff --git a/docs/plugins/fix-unit-occupancy.rst b/docs/plugins/fix-unit-occupancy.rst index 6ba01b712..5bf504fdc 100644 --- a/docs/plugins/fix-unit-occupancy.rst +++ b/docs/plugins/fix-unit-occupancy.rst @@ -3,7 +3,7 @@ fix-unit-occupancy .. dfhack-tool:: :summary: Fix phantom unit occupancy issues. - :tags: unavailable fort bugfix map + :tags: unavailable If you see "unit blocking tile" messages that you can't account for (:bug:`3499`), this tool can help. diff --git a/docs/plugins/fixveins.rst b/docs/plugins/fixveins.rst index 552c5f8c3..49b2046b6 100644 --- a/docs/plugins/fixveins.rst +++ b/docs/plugins/fixveins.rst @@ -3,7 +3,7 @@ fixveins .. dfhack-tool:: :summary: Restore missing mineral inclusions. - :tags: unavailable fort bugfix map + :tags: unavailable This tool can also remove invalid references to mineral inclusions if you broke your embark with tools like `tiletypes`. diff --git a/docs/plugins/follow.rst b/docs/plugins/follow.rst index e72f79ce0..21b3411a9 100644 --- a/docs/plugins/follow.rst +++ b/docs/plugins/follow.rst @@ -3,7 +3,7 @@ follow .. dfhack-tool:: :summary: Make the screen follow the selected unit. - :tags: unavailable fort interface units + :tags: unavailable Once you exit from the current menu or cursor mode, the screen will stay centered on the unit. Handy for watching dwarves running around. Deactivated by diff --git a/docs/plugins/forceequip.rst b/docs/plugins/forceequip.rst index 2565d12c3..18661195a 100644 --- a/docs/plugins/forceequip.rst +++ b/docs/plugins/forceequip.rst @@ -3,7 +3,7 @@ forceequip .. dfhack-tool:: :summary: Move items into a unit's inventory. - :tags: unavailable adventure fort animals items military units + :tags: unavailable This tool is typically used to equip specific clothing/armor items onto a dwarf, but can also be used to put armor onto a war animal or to add unusual items diff --git a/docs/plugins/generated-creature-renamer.rst b/docs/plugins/generated-creature-renamer.rst index ea386eacf..fc2734d07 100644 --- a/docs/plugins/generated-creature-renamer.rst +++ b/docs/plugins/generated-creature-renamer.rst @@ -3,7 +3,7 @@ generated-creature-renamer .. dfhack-tool:: :summary: Automatically renames generated creatures. - :tags: unavailable adventure fort legends units + :tags: unavailable :no-command: .. dfhack-command:: list-generated diff --git a/docs/plugins/infiniteSky.rst b/docs/plugins/infiniteSky.rst index 789709c9f..0c14804af 100644 --- a/docs/plugins/infiniteSky.rst +++ b/docs/plugins/infiniteSky.rst @@ -3,7 +3,7 @@ infiniteSky .. dfhack-tool:: :summary: Automatically allocate new z-levels of sky - :tags: unavailable fort auto design map + :tags: unavailable If enabled, this plugin will automatically allocate new z-levels of sky at the top of the map as you build up. Or it can allocate one or many additional levels diff --git a/docs/plugins/isoworldremote.rst b/docs/plugins/isoworldremote.rst index b792cb649..82748e36e 100644 --- a/docs/plugins/isoworldremote.rst +++ b/docs/plugins/isoworldremote.rst @@ -3,7 +3,7 @@ isoworldremote .. dfhack-tool:: :summary: Provides a remote API used by Isoworld. - :tags: unavailable dev graphics + :tags: unavailable :no-command: See `remote` for related remote APIs. diff --git a/docs/plugins/jobutils.rst b/docs/plugins/jobutils.rst index 674c6897a..5e8125585 100644 --- a/docs/plugins/jobutils.rst +++ b/docs/plugins/jobutils.rst @@ -5,7 +5,7 @@ jobutils .. dfhack-tool:: :summary: Provides commands for interacting with jobs. - :tags: unavailable fort inspection jobs + :tags: unavailable :no-command: .. dfhack-command:: job diff --git a/docs/plugins/labormanager.rst b/docs/plugins/labormanager.rst index 731f706b8..255de05c4 100644 --- a/docs/plugins/labormanager.rst +++ b/docs/plugins/labormanager.rst @@ -3,7 +3,7 @@ labormanager .. dfhack-tool:: :summary: Automatically manage dwarf labors. - :tags: unavailable fort auto labors + :tags: unavailable Labormanager is derived from `autolabor` but uses a completely different approach to assigning jobs to dwarves. While autolabor tries to keep as many diff --git a/docs/plugins/manipulator.rst b/docs/plugins/manipulator.rst index 734800e77..c1268bda5 100644 --- a/docs/plugins/manipulator.rst +++ b/docs/plugins/manipulator.rst @@ -3,7 +3,7 @@ manipulator .. dfhack-tool:: :summary: An in-game labor management interface. - :tags: unavailable fort productivity labors + :tags: unavailable :no-command: It is equivalent to the popular Dwarf Therapist utility. diff --git a/docs/plugins/map-render.rst b/docs/plugins/map-render.rst index 4f3c6ba72..5dc07c45e 100644 --- a/docs/plugins/map-render.rst +++ b/docs/plugins/map-render.rst @@ -3,7 +3,7 @@ map-render .. dfhack-tool:: :summary: Provides a Lua API for re-rendering portions of the map. - :tags: unavailable dev graphics + :tags: unavailable :no-command: See `map-render-api` for details. diff --git a/docs/plugins/mode.rst b/docs/plugins/mode.rst index 061e3a548..35964b783 100644 --- a/docs/plugins/mode.rst +++ b/docs/plugins/mode.rst @@ -3,7 +3,7 @@ mode .. dfhack-tool:: :summary: See and change the game mode. - :tags: unavailable armok dev gameplay + :tags: unavailable .. warning:: diff --git a/docs/plugins/mousequery.rst b/docs/plugins/mousequery.rst index bff110f0e..38e9266e3 100644 --- a/docs/plugins/mousequery.rst +++ b/docs/plugins/mousequery.rst @@ -3,7 +3,7 @@ mousequery .. dfhack-tool:: :summary: Adds mouse controls to the DF interface. - :tags: unavailable fort productivity interface + :tags: unavailable Adds mouse controls to the DF interface. For example, with ``mousequery`` you can click on buildings to configure them, hold the mouse button to draw dig diff --git a/docs/plugins/petcapRemover.rst b/docs/plugins/petcapRemover.rst index 4f6ea4160..2aef993d0 100644 --- a/docs/plugins/petcapRemover.rst +++ b/docs/plugins/petcapRemover.rst @@ -3,7 +3,7 @@ petcapRemover .. dfhack-tool:: :summary: Modify the pet population cap. - :tags: unavailable fort auto animals + :tags: unavailable In vanilla DF, pets will not reproduce unless the population is below 50 and the number of children of that species is below a certain percentage. This plugin diff --git a/docs/plugins/plants.rst b/docs/plugins/plants.rst index 281b295cf..d35579e1d 100644 --- a/docs/plugins/plants.rst +++ b/docs/plugins/plants.rst @@ -5,7 +5,7 @@ plants .. dfhack-tool:: :summary: Provides commands that interact with plants. - :tags: unavailable adventure fort armok map plants + :tags: unavailable :no-command: .. dfhack-command:: plant diff --git a/docs/plugins/power-meter.rst b/docs/plugins/power-meter.rst index f3a76c60a..d6d4c8272 100644 --- a/docs/plugins/power-meter.rst +++ b/docs/plugins/power-meter.rst @@ -3,7 +3,7 @@ power-meter .. dfhack-tool:: :summary: Allow pressure plates to measure power. - :tags: unavailable fort gameplay buildings + :tags: unavailable :no-command: If you run `gui/power-meter` while building a pressure plate, the pressure diff --git a/docs/plugins/rename.rst b/docs/plugins/rename.rst index 903a1a1d4..a002fc4e4 100644 --- a/docs/plugins/rename.rst +++ b/docs/plugins/rename.rst @@ -3,7 +3,7 @@ rename .. dfhack-tool:: :summary: Easily rename things. - :tags: unavailable adventure fort productivity buildings stockpiles units + :tags: unavailable Use `gui/rename` for an in-game interface. diff --git a/docs/plugins/rendermax.rst b/docs/plugins/rendermax.rst index 91faa6f5c..d09014cb2 100644 --- a/docs/plugins/rendermax.rst +++ b/docs/plugins/rendermax.rst @@ -3,7 +3,7 @@ rendermax .. dfhack-tool:: :summary: Modify the map lighting. - :tags: unavailable adventure fort gameplay graphics + :tags: unavailable This plugin provides a collection of OpenGL lighting filters that affect how the map is drawn to the screen. diff --git a/docs/plugins/search.rst b/docs/plugins/search.rst index c1493f992..e07c81cbf 100644 --- a/docs/plugins/search.rst +++ b/docs/plugins/search.rst @@ -5,7 +5,7 @@ search .. dfhack-tool:: :summary: Adds search capabilities to the UI. - :tags: unavailable fort productivity interface + :tags: unavailable :no-command: Search options are added to the Stocks, Animals, Trading, Stockpile, Noble diff --git a/docs/plugins/siege-engine.rst b/docs/plugins/siege-engine.rst index 57693fa11..4707ad5e8 100644 --- a/docs/plugins/siege-engine.rst +++ b/docs/plugins/siege-engine.rst @@ -3,7 +3,7 @@ siege-engine .. dfhack-tool:: :summary: Extend the functionality and usability of siege engines. - :tags: unavailable fort gameplay buildings + :tags: unavailable :no-command: Siege engines in DF haven't been updated since the game was 2D, and can only aim diff --git a/docs/plugins/steam-engine.rst b/docs/plugins/steam-engine.rst index 532b311d0..5ef4ab873 100644 --- a/docs/plugins/steam-engine.rst +++ b/docs/plugins/steam-engine.rst @@ -3,7 +3,7 @@ steam-engine .. dfhack-tool:: :summary: Allow modded steam engine buildings to function. - :tags: unavailable fort gameplay buildings + :tags: unavailable :no-command: The steam-engine plugin detects custom workshops with the string diff --git a/docs/plugins/stockflow.rst b/docs/plugins/stockflow.rst index 29b7838fc..95eba213c 100644 --- a/docs/plugins/stockflow.rst +++ b/docs/plugins/stockflow.rst @@ -3,7 +3,7 @@ stockflow .. dfhack-tool:: :summary: Queue manager jobs based on free space in stockpiles. - :tags: unavailable fort auto stockpiles workorders + :tags: unavailable With this plugin, the fortress bookkeeper can tally up free space in specific stockpiles and queue jobs through the manager to produce items to fill the free diff --git a/docs/plugins/stocks.rst b/docs/plugins/stocks.rst index f8db4ee67..af5228b12 100644 --- a/docs/plugins/stocks.rst +++ b/docs/plugins/stocks.rst @@ -3,7 +3,7 @@ stocks .. dfhack-tool:: :summary: Enhanced fortress stock management interface. - :tags: unavailable fort productivity items + :tags: unavailable When the plugin is enabled, two new hotkeys become available: diff --git a/docs/plugins/title-folder.rst b/docs/plugins/title-folder.rst index ee4068547..b6a250e73 100644 --- a/docs/plugins/title-folder.rst +++ b/docs/plugins/title-folder.rst @@ -3,7 +3,7 @@ title-folder .. dfhack-tool:: :summary: Displays the DF folder name in the window title bar. - :tags: unavailable interface + :tags: unavailable :no-command: Usage diff --git a/docs/plugins/trackstop.rst b/docs/plugins/trackstop.rst index 041bcac2c..d2011387e 100644 --- a/docs/plugins/trackstop.rst +++ b/docs/plugins/trackstop.rst @@ -3,7 +3,7 @@ trackstop .. dfhack-tool:: :summary: Add dynamic configuration options for track stops. - :tags: unavailable fort gameplay buildings + :tags: unavailable :no-command: When enabled, this plugin adds a :kbd:`q` menu for track stops, which is diff --git a/docs/plugins/tweak.rst b/docs/plugins/tweak.rst index f9467e333..69c93bb60 100644 --- a/docs/plugins/tweak.rst +++ b/docs/plugins/tweak.rst @@ -3,7 +3,7 @@ tweak .. dfhack-tool:: :summary: A collection of tweaks and bugfixes. - :tags: unavailable adventure fort armok bugfix fps interface + :tags: unavailable Usage ----- diff --git a/docs/plugins/workflow.rst b/docs/plugins/workflow.rst index c95054c0e..323dd6ed4 100644 --- a/docs/plugins/workflow.rst +++ b/docs/plugins/workflow.rst @@ -3,7 +3,7 @@ workflow .. dfhack-tool:: :summary: Manage automated item production rules. - :tags: unavailable fort auto jobs + :tags: unavailable Manage repeat jobs according to stock levels. `gui/workflow` provides a simple front-end integrated in the game UI. diff --git a/docs/plugins/zone.rst b/docs/plugins/zone.rst index f1e333126..26e170a58 100644 --- a/docs/plugins/zone.rst +++ b/docs/plugins/zone.rst @@ -3,7 +3,7 @@ zone .. dfhack-tool:: :summary: Manage activity zones, cages, and the animals therein. - :tags: unavailable fort productivity animals buildings interface + :tags: unavailable Usage ----- From 34e3f81108457518cf248388daee7020a1b095eb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Oct 2023 13:46:49 -0700 Subject: [PATCH 750/851] don't list unavailable tools in indices --- docs/Tools.rst | 10 ++++++++-- docs/sphinx_extensions/dfhack/tool_docs.py | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/Tools.rst b/docs/Tools.rst index 401276d7f..67d7edc54 100644 --- a/docs/Tools.rst +++ b/docs/Tools.rst @@ -3,8 +3,8 @@ DFHack tools ============ -DFHack has **a lot** of tools. This page attempts to make it clearer what they -are, how they work, and how to find the ones you want. +DFHack comes with **a lot** of tools. This page attempts to make it clearer +what they are, how they work, and how to find the ones you want. .. contents:: Contents :local: @@ -36,6 +36,12 @@ more than one category. If you already know what you're looking for, try the `search` or Ctrl-F on this page. If you'd like to see the full list of tools in one flat list, please refer to the `annotated index `. +Some tools are part of our back catalog and haven't been updated yet for v50 of +Dwarf Fortress. These tools are tagged as +`unavailable `. They will still appear in the +alphabetical list at the bottom of this page, but unavailable tools will not +listed in any of the indices. + DFHack tools by game mode ------------------------- diff --git a/docs/sphinx_extensions/dfhack/tool_docs.py b/docs/sphinx_extensions/dfhack/tool_docs.py index 836bab217..6c65e5918 100644 --- a/docs/sphinx_extensions/dfhack/tool_docs.py +++ b/docs/sphinx_extensions/dfhack/tool_docs.py @@ -140,7 +140,8 @@ class DFHackToolDirectiveBase(sphinx.directives.ObjectDescription): anchor = to_anchor(self.get_tool_name_from_docname()) tags = self.env.domaindata['tag-repo']['doctags'][docname] indexdata = (name, self.options.get('summary', ''), '', docname, anchor, 0) - self.env.domaindata['all']['objects'].append(indexdata) + if 'unavailable' not in tags: + self.env.domaindata['all']['objects'].append(indexdata) for tag in tags: self.env.domaindata[tag]['objects'].append(indexdata) From fd78783a020dc2d10843bd460771bcc60882679c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Oct 2023 13:51:24 -0700 Subject: [PATCH 751/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0248707d9..bf5415fc9 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -75,6 +75,7 @@ Template for new versions: - `zone`: animals trained for war or hunting are now labeled as such in animal assignment screens ## Documentation +- unavailable tools are no longer listed in the tag indices in the online docs ## API - Translate: will use DF's ``translate_name`` function, if available, instead of the DFHack emulation From 55c2cbae8581bac17844565d27d2ab5c4e42c6cf Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 14 Oct 2023 23:58:54 +0000 Subject: [PATCH 752/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 6166bb73d..7444de2a2 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 6166bb73dc9ae19a51780ecf026d92f2fffd277f +Subproject commit 7444de2a2207d93b00defd7de94bb56d10968ea3 From 11ecc9ce0e046565b1bfe6b0c490ea1381dd7423 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Oct 2023 17:36:48 -0700 Subject: [PATCH 753/851] update image for gui/gm-editor --- docs/images/gm-editor.png | Bin 3370 -> 19814 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/gm-editor.png b/docs/images/gm-editor.png index 24546a7102b93d58cf062e6c427b78284518b2b4..117cb70312298abbba8ca6b3ed8b523adaf5f380 100644 GIT binary patch literal 19814 zcmbSzd0bQ1x^~nmZBc1!3o1ftTSXLtR3S1YTB;}tSU^CgAgRb4A-Y$fgs=e{_aG))_z`YkvHA1Ng+o?MM`O`Q+m9vsegZbF2DqO~$^> zx)8|MkP|;1agFnxe;fAr{0NS>tlGr%t2tou&BOhVFlhmyyI#=I&986femxOo7|?EO zy)D7>{ujB20_ER)^7#Hi>?RRp?bU7B^@%?RZriXS)4A7h?@{kN&ZTq`{wMd0BOmwt zdiieNW|yFVF)Zej+w`>izn%O|$H2tCJmf7~N=|8B9+k~uyO-BFu&b1Os=lP(ho6t- z>p#)gBX4}}n6T1}8u|t@{Hbb+5a*N%nY(Ozph{~z@%|Jf<^{24B)4g)?(}K+$9jIdE z!bB#d_U&@@eJh_N^-z+&lO}1;wx0MzG2>sIQOfJLPdYUrOk@PT7UsMX3c2^PRj_Qn zRFkv4P;2PB=gMCRTO-1;i!Tzj=Aeq9#E8!?8B5^!uwg3$tmlf@CoALT;KFXP1*$aH zVn=~C^WAS_VdgZcZphV0c@a72^GkXXEfRjLGdI@JS7z_M)-T6Ko_}{^Nvf8Qyfq?i zJ;ibqf5H%{LqrRirIrCR!*D|NVNH~V?^z=z9%|CI_9vG6cBiRX@8-y=D5K~k`_;+T zV7gBGQna^r)V7q`%tXEA+k8}zb%qzKrJMYv*2^8f2{T1M=aGD6?K;&TKTn^?+v4Z6 z5yyL!42x=_o$#oiUc1{U=?BGVQrh}#R4_8!Np_Hb7us)WSR`pYp7v@kNmlk{zq$YR zej!6zS>HVzDcWb)g?W52X~LYt^i}QEPpzG*`Mf`in>m5zfWfKnyFYoVp^tYunfyuW zS5@*WrRCY?&YBOs7vSfGnZbqMG3`EEeO#(ry}jTpOJtgiV3d&GxbJhhNg->aPuBD< zuFhSJb-bi_VP)_FwAG>GbZpENAy1r8W)=?|9o~AR3Teq);`!IYctg*x zGvk=gPn#*iulOFo@$z#DYV*pxZY-;Zz`q0Mq-726a+IhmUGvogPm_xil3=d$EcHu4 z8Gj|XCh%2%g0jX_KgVM%-23jcQfZy@b}F62q+svISEw%rIT7o)*^QX)92E-H8Bqtf`< zm4nEP3$^*IGxNh;?a@sU37q~UvSYfw)%-~oT*T0B$4Y(2LYo~=$ppI0MQtUKopcl| z|EKS}+eWz`JzrRP1(h*8Kk_?9_a4JEQspXzp7GkJ8r`@j{7K2}m0g#Nmj$SyFCf^@ zsr!UrQCA-M{K<(+iU?r_a`_#TH*R4;QM8iA6IaiD2J!-g9<}<%VhS~OQE+^t`n~y; zu1~ns=05SG`V z2*RHtCx#^kTHEn-G6!3)n({IWIik_`?ZtO2VHGnG2NPRNrLP$T!7GRB;cn)*BnTw1 zbi~SF96m%!o?NIJJ$hnxWr#~GDkfkmN9`O?ws+{}2U~)Qgc%dNN=4XrFV|by*wpm* z_rJh({xmBs72J9>w<=r%nIrDbxjg`Ps}g6mq<5?hGtlX&DZy>PjcQGe)}BSMjiAh| zkp#SBE*ULu@9L{`#h)PIs*;+Hs%oNkMBIZHYw8qBug70cXX*COlv4MI+x?5;G|f10 zFLDXYd+UWYBt=Y+Rg2rIFLm5(`a1il@MbhP`K-P_h|z<1bXS}4+U9EyVY?&krA2W; z-bHd}>pe7=3E?&Ks7~Lrr*9XyWTOmySp?Y7H7-AELYQ!ngdM~(_xfVxQK4mDf`8*; z)$+cE-Zj*d=Wg&it*aC2o;EOS#Zdxmu^t&jc@hTp6TaG7h@t1Z8(nH?+*E6+==NsOrv`8S{Kn&X9N|4$HrV%ovlJdKEA{ z%t4-Ij`uGsS4XLRU**iI$E>|NSjZXF5ZLTLP<5N-G&kE^;#`z70B>`poL$w8oYk$Z z{k(2o?2-eGYBSr%Y@< zE!JGhAHE5Jym7nTbsfJH=*WI57A@F{r61cB>;Mt($KI%9HcVWLUC{XvUNn__U$7gU z&RDO`2{|uvZsU4m(O=v#-&0c3qx_`bRsD)!K#=A5R5HiMVT7I!?wDwt3l-t8p&BmGz&I zFKfIk{t>>u22?X`45Q5s$l+sxK45IfT17@)G|uxLozyH*0gY zs9&r0ub}vQ&%!dH_+}5Ihp!t>yYp#bSrv?{Fx;AHSTu2H>#fv-I7Id!6m0_km9@vl zOGbB@LO-4fxfwEGMISc}95H}|R`s$if`rd~jI__p4-Bk%qm}wtdcEg_Ja1|l-3)`D zS@ddzFT9&Ij%=7rJP18(HEyFDcnZZhf4TN{DsQwOaTPJ25*fxaD!|+&hIEG7P`@IR z$C9))Re84@da>^^aw?!yQp8tKEi&nD#wauHzSwn|K>7LVT0g66X>G!NnVoZmwU*NR z%nj$?Ga8yOQKcyt-mBp0VA~NMF-|Y|#c4_k2DZTuubmo%&-SX?Dx%-#^w+o3Y<0&ynx1(WB5J)= zLeo#lHon#fec$mnaqdOt_QEf1@WPs6Q>Ri#L;Y%NH;|0Lo%hPyF)Yl;kr)_If9_yQ z*Eiy(prf&b%S zyeD*}lI3QJve{h9v}XzL%m$($PdB}!Pf9ABh6{3&+VQj37?N%>z71fCmSUr>GXQA%g}B#(t3M-y7ebgs3E1$_&LkRkmCsh}scu`(T%)I(!b)*`!z9l`Nolm0%eo?b~aqUn1`f4mTFLRPqM>982M;?ruY zxwV)^|M@s98A^4<&x=emsDj}1g1W4Q!ea7W`(<2Nl2NJDM4O{B-VKS?rxF+oY{kQo zL~2+jX{>bow^oorCsN#J*F4d><7yQC?HPs<^uS3*jS1xZxXrfzJ*z=otWZR zzHjeps6o0WA)16iXPF}RVD=LjiW(ljajl-6H#aS)(t}X)s&Ia2GU}&b5UJJqpYkrM z13t8!vn&`^2$C2G6{nR2|k2G$5Yh(Bpm z(J$NJRq1X$mIGHz2M~Mic8Cb;J<*WjuND{=G3iBIrQ~nvA;p?tFZ40bq-a?X41LJt z%1JtuXxijvR+;;o4m5Q%&Ovs$R(GKG_Z)*u!e5Ay>I?+_jYiD-+bFXGRfBDf$kF>v ztQoyKw#I=DP;E-esmB}}4>0eX{`I3n?zV(&idWv5XtXEBFGvx!J9#E{yrGhc zmHMSNIKLoMw~p>vK)pMk$RP%yAjQHJg%!A~>#SNL`|(pcsHay`3BjoPmC!Ab7lrA~ ziVWzeFa%m7!zB4>=m>^uOrXa#`5OpNLW0lzKEQmFcy)@a|T5q1G;(-t<;TlzRiU zdMs3-+_aQGxcEHLH?HT>*BSo^xRPt3aSU5fi1wbbW4N_5z4dGjsjVGOHS;xR%L*f^ zmMTrXdf;Bj4aRB^CR(QJ7HCcl0*GE*`#{A10@K@a4~g$ux1ZEcM%JEmcN>HbeoDeg zbwP4#AD1e7DU1CYnZ|Q=+2M|HhaiV-Fz>!%i7y0q$r(!J_c1ca(^UFc?vDJ_rOyc1 zvoMD2lqF;?8%OZH%SB3-Gb>pdkSKT@_T{S`kp0P(RO-#Q2*~}$7dcxL)-wYQOYEYB zJ4=O|T!>-)3iSBW>V7^UZQ3qyDZ13?O#WUGU4N1eGLkv^J$0yN1~cumDsYaqPo;5{ zilnNpWuo+k&Vn%dme*3r(%X*$eKT7)Em4~zC}-8IlK5d(QZ<^Z9JucCS8!Gg|1& zIDdpMJcpc)cI{}~ZPPLJ6m^``Qap@&etUHWW;ZBfLlVp-?JTDUvn{(AH37Zf3<9+HR|&^9TU8H&81$>79u$yG+S%n zwU3Kgu;AppoyeXUSLQu)$bNn;l>GiC1<;?R@0%*%|=4 zb8_*DN}q;j&vcNIXUWh0-CEn+bM(!Q94#>O_q#!}2Yv-Ptm!50ZrhE})h8H*wButx zXGB`XLmejNYao|QJGpsVFl!EK7`+^Q=Mi48qOtZJwI1O0`$cD)u+EKd&P8a3y3IEO z^!&ySv;r`X35Or$x7`J3n}~Zl%*ZOSgFTF7S|yf~CM;;=bz#UeD1Lmy4r;yQ!qz~l z3!^gc5D}bt=vCy3Wn%vXe!RtEDc9K%P$VPj_&^r?~QDZfV<-w^H+7C?!TO3*| zn-8UcU!1xMH;{c-x6=d0RMoQvUT&b@-d+&CCu+-2H#ABmmAZ%Oz(Jp;cwVZeO^h&# zn;b5+jQ_HK1IEbr>>pu=K|5TwvGE!fuoram##l$La!Z`g<9!%;gk$(+Z6*JTcK%L39w>LH5TQL^Tpu z!NtqL5trPKv2*8S{t46a6z)3kflItxsdu2NTTu2G`*3rm&Q5eqh`CBeSm5ZMOmeuUnppG%Jp|v4rN6zW zS4ul?CiLr+PED^gnS=5pGYmbIj-vd`AmauAbb0@-agUEWYMV6pU&aNleKozdgt(Jp z+o@1u%vv1uPzMNrKq*K6?);&-$N&^U=A-T&|KF9meh|s44^_VrRn2jSjTGd{Zz%>e ziSv>Q1}IdqR@AHC$6+UoJ*!Va16SYo)%RhNd`5}r(RBClS_HzcU`C-W^7nLWpdKVG zwaoY7yA-HfAs;A~vzGbW3u=3x5vs(NrAdO}x<{N}JDN<5wUt(%xb#OPqCH`XqmAy` z`)FQ|w^2tDY`!892fWwJkr)DYr3~{YOiy7q|4bFL2puqa2@*|}-c$8S+OeGK@z7o&Rd(Qi7Ht=VOWC#OFOP> zrP`ad9O=53dQj=wSZexcmf4r2cRQa@6p>e+-gu^oyD~HEY8YPYTN0D>j_+!1hR@K= zxrc;78s}f7wSn4y$4v62HG%%ZRS#+%+KlY5`cNdonMmT|rWG+nl7^{oLo6VbKauh#WGwXb>mYT*z zC_J$#^o$`PeX?t?yrju;wFZ#8d(SX*s~Ec9UV0lV8#3tZoHH4QvU*0KBTlN3f)T5Z zq7kY*Q-YP)N#^^t5Kmk>6j%E#5c-UC_UPI~-B4yWonwMS6 z?$ES$3wBP~%yr5!=B4IqO^N{s?HuBmNg<2NsM+yB*}kj}1nH z3BQ%|(@YPNmh;SaGh5`Fz}M#mNvi2r-yf*@8%havq(9O^;5PZi z&L~LaltpddN;d@r^7Ld=*Yy$6rW^Mtf~Q!qX!}>V*t`}~hj*$)WA8W*RKX~TIR-O`;vIm%z z-l3bh)-AA}$}bhada`2%Jm$l55WM3=pVK+WA`3PYBI)>pP*LtSyVGXCRjaR(uH{D+ znD~4tvC$S*J)OcvRK8b9Xe~2|8|juNF0+XaYY#(HJohJ4tcO?e=&WElj-kPk)eg8?VDFt&{tl;_;+Dl0nl z=4IrJD#E<#921kPGuwLJXA$jL;%YJo=nCg{Cb_ZNr*MF<<0K6*5>^3=V>)iJtkpFXCbHU#S;I?%zOn@fadtT}n`rfulVG1GJtNVRz!*1xvp;*1Qk zF&-z91)C{v?G$xPoifAUCzg_&7Rc2DS<#L@+6@(f?9xifgRpRayxD4Zycbsk;&V{y z;hw4Svo~RLZJ2zNz!a`?nN7gWifzp1sr(h5Bd;#Vi~)x+8yW-VLh+6ip1VC?ao@|9^MA&%t>zC{Omes*~iWin2o;3BQT_nX0_vKs}|=S)BB=L zrbxoW*lO$Aj%9c7P5GJN!jnmr9;&Q+T#eF|Hxe^sF~uxW5t68$xGCSf+&+0^#QaGB z{~vhsCr9C4L=6hUxf%m$z#KM~wh3~lC%zFoeYT6$}q1Iu*4yWteX_in?UJca@;4xn=RY5n~$l$G5WjX zdEbdUs<97pHv61%IJX72)+~7(ilu^F^gQXq@7jzXMpo`@fJrVnY~$;L;aD?5S?rwh zt;uMSid!B+{aW>BAAHr3YR&!``!JPH(#&$k|A}=UR1;lQsWkujlFk6JbX5E4rbuRN z8ekVdS7ZKdC?Z_tv^=kjZ9!)$+fmYsTfXpD!yvrK9rYBnvFSdt#mm)C!vR-0L5uS^ zIPL#U$!=t;GobtN>EWB3#_Gc|_G-=F;p*`C)|Valk%TyA?1>rW9vV1(ZqrI-=7+_( zNQs@74EC_pYzW|Kc+%pjA%i)0yl}m2GShKhQ^z2Q_uWwJxje6nlm4~<(=_VgK<-g~ zoEMIG`7k|Aqt>BIVLGXN(u_=A0@F`O5K&m9>fco#Pe2`8TKUZTW^ z^#{zaxO&Sz+{0=|s`8N3&fE~lrmY}R>iguqDbH?9V*r0a z)G>W!Y6qAT&+I{5+R&?5%?cY#3TPg{Mr-F-VV39vjeAlTlo2@vG|vgs;* z&K9ZtMP|{2sY&-YpA2sl=z~xRJP*VLmvgpjLpLw01+s(OtNNrLdC!|PGty%x9a zCe0i6>n$MFA{x+H)lqpE73!#d?R*KE&zk$xKM+jf@2#9%{?^MwOUi?sRgjZ7Su`ty z)N3k@tzL`T9zJO{$Na)4P?v~;e(hzTeq73?aeodqdUVOWJ`;3BS=mWXPU;w~Znjky z!X6sOV-|gul2j!=^psc+(#-Q=khLB{WxsX=PwY|)nd5=KSdP=b%Mj2m<7hVET9sQ}5J0qZoKS0NS0DY-vmol)4)B)0$vE zH_)#R1eB-+JW=#P-*)EMdr$tF#^VC510)ylSlIky2XuU3pM{UyBv@qG9r#VMILvWG-XTsya} z8QE2@1QT>9K-k>|8YkJFia5Q@-udc@d8+95VO>-wqcLsYr-y?s0jcw zsYfQvV@WUBx#`iJf>cK30OJ`zJ$xaox@X0p_qqADNU&-k16$?Y*YR`T!pg5_-dQ{; zjN9_rY@F_G*A^YYHyQm?TOrur8}ijF_Rzo;l6L9^!3Izw=GNk;{hQ2@gM<@dGTUF! z2alo-pY*O$H}0Uj59on^By8N+zK`!8h;JL7&#@7pZ?s$*st*TOF|3|;_%2GpGrCx| zXNst&A^BVvtd9NH)Y9si6|C^Dl45@k#*NImq+^Q%kEhmp$D0FV&CNn*IT!MA8 zteTU%>eB%Ty#Nny3i_{zwA&t&mzOv4Dh0z*Pep|nkE#84ZD8&I=AAbBbFf%1`Fzji zPQLg4D6diqZUba=tNbsiPLS*O{c5At@aAzl9Sg9E{5CdW7rz}}`=qFn#ok~PSmz`s zB7ad$M1oQ74(AT9XjTADulQw+nv@urMEk5p=qXBKqK|A*edL2aLULplJO_MqR`;uY z@RJOCEVIFELei9E+^_6fGQ4eVBMj0<=rQmwmKT8+je@L*4SAbU9G5pa?B73 z?{82yVqCppVy_NtBy^&X7#(06@YNNK{)VXu&8P%fl!?EGsI4eKd^yfH=BZ zQ8SGM3U=7tiQ({El==qu!VQE@-5jP*k#?6^wEz|tZN=#80f6>E0yG$C|~+Y%}QagWzQUD@gv4Sm{d(|7habX?0mheL+Kz9-Vk6^V zeYPIfd?!Z9_vcaQJ!wb;sbi`N6$hpn64U!f*Y&gUm(!GoYQfuK9T0oi5@?>i@d{ia zEOl1pB*cFDu|0FTR`+}ApGK9C0#(j^v?li;{XtZEDMf5Ut+=!5gi{$$-J2pFfoTs6 z%$#JImt)u+o1C#rqiUAKG#JmXKiiT{?_7)sLw?0v41)uqcXUJQQ7RSlJ-l(hMkv_< z@sW6qO|nBbhP}y#N|77pt0>Bo6P0N;-40n3D^5GjQcn9~H%(XmT3|tmIY|C$9tlt0 z(M6oWp81Q3LAQp?J|2@ddFK(zl2~Bs5h7TwVORs<>!Z;7F4+?gSpIn1$mO&1QU^Wu zsJwFH3_Itxd##qajbNw3M4P7?77a{s>ozno~h!>AK9W zB%IH8#h+sIIy->tpjre=DoGdjzf`@tz6kqS@Ey=C%P4Kmobo)BBZ)x9`Rx^onJKY~ z7z$wmZ<|;D)-XCQ`YSrq0A4J$Ea=;6M&j8MPnO5c%402B ze49?ToVC=Z=Wi#hcye$uW=!o*Rb3~p$Nmx9M(WX$l@7ilNtC}*+p255Nva=92j%v` zTmdaQsfcqsHBqEx&)G+-^9jcL5LMnq+`4_-@2M-6rSAsWt=5sagyl<&R6aA?>L95) z9ljew@@;mFhaq?AyL;Ciq>d`rk(ISTpQ@aD`J#P9EImgs)_%o?E#xqrw_Z&zqRH)n zc*Gu9tWh^x(LAxin*Xg(Kl$5EMKJ{xE7e zz|M$)Hxe&iou%@@SgJ$NX7twnVr~iZb!}Uk7q9j@$E%z#UFHt$LcZ3c8ctisy!dAo zXjhNb9?xQf#$uAY!JWkD$ZFMLnX4~Ky$XXFUj^dt__mPNoo zWAj$IbBTjUMZ{-tUM0WfpkU^|;Fo@6 znb1p~;|I!OdPSzD zA9B7E_~F)lcGxP%`^Qre1fm6XV1 z)#dIm@1YC%6*KkCrbXS?-MJ^G7*RU{rX;pw9cPLxZOKSTBN~*zr6U5|fsZT4t{Syg zr`JL=uPv_d>wVMe9mqsy)pM9=fd{i+b~5yBpf*l2nq*c-WlIA~f;6OB*cdL@OS7p_ zXpHY@cwLj{a-ep5Hd$n-XPd^aDPt6!vCdEQHqb9gcZe6lK!VIV>!WK?WG&bV8Aby9 zWcJcF{`I;Gfy&c43((-baJLqMeMFU9k=M~fvmUpuPJ5n+pW)vhTv-=Z_^6m*Oav+(dZ4yCou2Xr z6eC`t+EVg&w;jc@NYd38?L4)YNxcVU)~@Mf{U-!};nklA9!%4!UoR7TYr9w34hXl? zYlRk9yaqzw{{d7!N})|ic{QA8lsA}h%i2RN-rb@DJjfsK;@3ll&D0QCq}*_JyO)|* zfcR}!w*!(_B*I6Lw?!;hwwZ!Eet8J^M7=!iIJSYT0P%bxgy>~j>djJz2*SpD zsB)orrZKtO0hL0|?6^R+I`s1n9Pwyw-F0P1#s_OG8cMz6#)Mva`v#CIY>%a!0>t}? z6e9hKcOI}Z}8)VUtpeq;ANs8oX2rTvVlR?Wi~hNPb6^8EnIE;T7@Pk)(qLA4EJj~EyeP12BNnJ_eDbx|F}OoAb4`N}vH zFtg)|`I){Jc#Csm0FUK(LQLlLON}y>(5aIdiMXhrvh8lf&aJ*l$|LGSiy~}>61+WW zE!4N7^nB zzYr)5yPP<-be)({o3pm!NfYH5-&`x~^t(yi#e-@07VF^%rvB4xyGKj(e9@S(itOS!k@}AdDC*x}Ij%@}*#<94P*U0SW0*=|1AFkX=k_w{dhX_v=`F8@0xwLE&Wf zml43=c&mR_PNFzAKTo6#0=@N%26v>mt2Oab5Y%uq##_6ChMi9gUUcD*+twFPyhTzX zs}{|?Z{!pSv;e0D;|jSy^&bmP^1-5kA4T*Ns@!?Z<#r*uv#U3>*%;u+o$AUgEHh5+ zxH=T^q3EmIu~J-BRGuqkwx4=;T~?hge7u?;iy5t9qG}2YzunZ>-Q7L+?p59V>f0R2 zP=%-``A-=|?J#}ukj(qetkyMt6YhN(B5dv9O}LmDz+V1W*gsq-C>{Iqt@ZTq#7ZPZ zX)$+;BwlkrgMuWiflLR#=eCB9vp1eZ@1w2p>yAra1Bp3tyQ|IBkt$vX6O_4wr_mat*#5RvK5^mKvkig=J=qVW(F+1EG~j<<402G2U)tVzRdqNd$I}hydo?ZuY*u*IfEM-XxnxRNfWZqm}&NY z9c_Fk(k0%Ow*2FmU68fC2%W$V`jB*}^`STG-5IHg2Mu8T@_Lf{hR(Nc&DdLw5wR}- zpkfxrnp()zr++rVz_Ff0g;a zZi8SKulP{f0!`O53b!9Qi?Jj_w+OhRzBNRyC1x0aVn8#Z(quYq_ z%NL-wG85sb;Nfl*F(g>-Nls=G=Eu-G;e*FuB+gKl9m~lASkN6#l#c1X`f_ROQW0n+ zR+17A>O(aISv5D9xdgqO#R;Fqu0`O)Fkgy3QJPnAkKtoNTgRey zFMBa{A45mfH=A>IUVN{i#p`{(lMmP3#el&lY<@}EW{D)~vrT(2_Ve=9+=785=P6;t z@NNp4mxm_mFv(`If!;xSm{a54%?YK8-uQH;+kGavwuI~wiGyIj2WnU4#TSV>E$+!N zhg!CFTyxS=9XiZzy6fCiqAe=_eU@-Ls?xdf^~?{f{7B{Kg>XEshX|T3rPFnG&?x4HD%ao0l#lVsrE_l&XO2^KFZh%aj>g zZqMYsi9?x*Qgxsdi-l(-2D=f~FxhitW;^x$j0l;=WCrx`o=ma6frsa@a(gfZd}b$g zLj&j~J^+hLlz+)KlQU_vK610@wSwJ!@~_4Fmm+Jz!#9={E9$*vucvZ=6}v^cUBk0C zq|p_?3&hEY11f}Oq?D4y$g%Ujo2pS$d6*B{iGuC6j=*dTc1-kN>vj^=%#U(>wh&P% z-Dr<;>|h?{SSRY z2e$I>$tbx`*A7MOYOF-Nq^*NAj4p{n`V~$=vjPXm{tM`E$82Ty2`C71xoA9M#I<-% z6XN;jF+>MAsu6*LWL-_eICjSUu@1sbQU9pMaHNcUU7q-?qkvI^S6NPC3lY}m4?Y5h0m7#6wwR@|#E*>>J) zbI?XBz*v%w8%KrcTq%|NypWrdC7yuknl5YubdFKO>vozLZ8~n}6)8ohG78a~>^Zt$ z5Ygx*vf6mGL(ioEI7kaYE8PN!fB6?--)550#E!LHP^}KsJI}ob|2!`W2|0DOA9JLd;=>3nBrqi$X1srCb5H2=$J_xZsF77o$aeNy+-DSty zYV-yMK50^#A>WvWP(~6GR~wEw$Ra3`-#gT@Cr)IBxKoQ6Y5{cmQ=9OyxPCRQ#`Gl& zrl+SLoKw5sQ?%H%>gwlJ*G)Ed{L98P5-|R9U#-Uq^-;4)aC*;Y387-~Fg+h!({s|F zgxj+e`_!H|VS_h9#mth>hDDolkOIA54Nr~efSa=@!DF3YPDCf|K!bN#^RKx-BC`uq z-#S}ot$usdC5I#TY(am|kj~%O$t#s8!BlRQlcT#{`2Vhw?JPQEo+A35&@j{Ab?g(h zvhlcPiy*i98DDb`H|4=0V1D#F1rYPu!9L=*^Izzu%r@+N4H>bAmYE}ChlOYX3L z7>ltlBj};z4adrS=jCP#;)0w40FEo2t&3`LRTri_OLh}p18xYIy4$VH-wlf`@I@Td zjdhSqZzDgb5j`ry;jwQ_UxN(-vWAt{UF?0VV-(Qx)ZCgyyQgD9gyKW=%5ofj;|#d! zP$F=BR`F8r_I*?Q-K4mS9Yc{Oo)1jnu!!R#ocZV3{5(xEV3p_c)mp{Tqv4moV6xW> zb4#)^B?qEawqXgmMaq*A)n7pcxFkHFqecINmd2f+c$_XP6yC2MF1=o&?P!^N|4aAL zx=c_Y-mfy{hk1_xOEN#h-)=U~m>RW%u|sY2m%5lMh;j?_gv}>;CdX+tL}y?hJjJJ{ z!PU?xW?t+*KRtc?6$zN@6Ib4cscGEiXuf<|@^{;bd$8;z6YTkiXzXKHDF28&eWL=(&Vb{u5qlb73bhllj~R)=XpMJ zG&U&7*O4?9@~r_0mBZ=94rFrqNfVr@-nbc$+8ZU^C~L?60z*-{=fW+KMe*%c8=mjp z5q!iQsKjq;V}*6~Z&IpFzk>(%CdYE8gdxu0cCZX;9>&h)8>i@hZeKXt5I3{1^+r-=`7d&AraQCzYbNHx`6pppAyn zn8amNrp$d)+Hyv=dc@dMJ~ClDZH`w2X-WJ~PfJvmiCTDLzp5NSES# zEh1*V@JnKRC2&u-FbUqi<#!5nQGcihJ$VrMo_;GqFAm2XXzNATP!LNi36WA;5axVF zk1poF?VJ1?lLNK|*r51eXAl(Z4BGV{z!Z<%_4iC=egb2JvoROYi4JC)A&qtg7l77; zCA4&bt-(*r|8(<*K2Vc7G|sb9P~Oac zKk`0%zhX)_&%QphIkfMAHsn$t=DoU$6A1XUlZ!;QWPIr%rj$7`U3_+TP2^tcMm zF8|QNjSe$R&i6B+_p?JCmy-KZt#p_gHDJ>-h`M*XHBlj8?!AcWCmRrSENknH-bfnh z8FUw1B7@XgPCk#8U~0z^qwRTH($uv2o0v%9pdkqUsy? z1*dqv8T609*UkH^7{iu!hHY%y&SqKotFCx&A#wW zY>Jy%(E_aT7G5&>RgL~h04|XRgLZ$=LS$M^=9e6R>W_GNZO&)d(+#^NVRhUnXMyTg zrZ8kcX9ouKUKPtyOp?$YIG24hYN}~9*c7mU%NYA|NlK@eES=T&%;6@czX|<^PlzYk zjosvtwS%smzvXY#6Kb~bOZdKJRR4zk8ET-DY8kt356+KqKEFQyUIDVW zQZ`Zx`f?~z9?AQRW$+=(EsSN7s1JlK&LY-9!Ag2*2y#4La7)mIc`ZI*2dY8rou!%) z5xRJ4S9V<~=eBMgoKBfdkT+4H+q5DXm`^RW{QCbDEF~P6U9Zp3(Il+l|L4ROJgDDu z-&{K|?|BX?cw^wV(V;E?Me&^YcR-@!9lHB>PP$P!v3Qt4!rcM>9q{Sk@+z?-Bx4cF z(QJBle*k}-t1<53OkPJ8WLsK{mKY4C+|?MpJJi4O*=X&^>WV#Ybl<-cSbD}nR%%$r=-J}H8vzFWUxbJT!80lUjfT+ z$YyooQhW!L$90&?^(MhRD2F@}JrJAIs#~^VJtq=>3<$L<0Qu)`4E#_ZvooumVLkU! zTH34)5aO!Z+Pgj#_A)X;F?@5mH`7}=JRzL+xZ1ap+{zi=s!;DUMjFJn{BTe5ZgA67 zwwEnSU@yYr5;^;T*`(k`I)I?}Yk=wIhEB-1fAyD6#??RMIfFqE&8F%H7=)anO+CmT z5(5=j+0`y=0k&Ye&qNLTT4uqlmG`=L{1p{NJ~j-Vudp)UECLr5cnTs*mD=eTYtNW9caC652zy;AUrAF%bg@k|ZNm z0s^>cV*b^JKI4Bv=X**VOdISCw%!xAp*rtN6Kcl}U|n*B`iRUHYRaQ)h`EOt9poA0 z`_)0q%jp((;?b{rB`%zPC8*qrVC(4|vak|tjq4|ZJKo9oPnyU-xSCj{jops{)lZ6EvTv92L@MZvRqgaX}D|!3@>RL$2i)1jHx|PJ&J1uDyKPW zRZq^nGtG&SVAr{dn}Vz+$TU>;wjnY8zz_DechgZr{kd62T|+n9$fuff?l{*GDa(vj(Ath7&)qBMgdG2KJ02JUz8`3OzRv?>0gUzUoU`J&%!t~q+ z!)b9{*1u_E*M}j2DLQ`?J^AMnPNXC$$$3Ebrc`Duo{X5Bsa#6;IaG^F$IQs@On?py z3#fs)KPKAMW>5*wMA`Cxrd#**|Caf{&E)^<9=7tEtF5njck|eiXR*SY+1}655j!vT z1i03wH9bpE^2wuxy|uA5EkD1Twm+UO4LoGTYgNCm+~i!bc>iRX+qa${pI`?}4;Axr z1I_{0qBhFjet$dZr}wvD{XaSDdpjeWLE8~ry)y-ag+Bdy_TIWLUg~&?Ox5}CH(fH; zm9GPCK4LK7m(L6M_x1VPAE$sDXlL&Iw3FW|-{*`}EpREJ=uTFzn0oOe#qW&QThwpV z_&=rU-7mTJFwnyO8Q1pN1JmLSQD7W{w%BgHe(%Sgy=8aulatcQHdK}D;i}jBhqTtO zNpDT@#~2-rs~0N*qTXCN63neG>m1Nk{YXYX{&=`FaCQ2EVy@JC5=C47Uikss$R(Sx zUyA?NvuqjQ%6Gr>g)jfGt=#b~5Hu|C)56-?cys#fsZoeUXq&G%`NS_jQ@e2M+sD8p z3tR_kndu|`LFWcAKQvf3VWbk1=XJ%}73{1|GSa#(2E})_Y-R&`U zzh_r&Em^#H=h7XoK3xQjC2oD;3|`pTpu2Q-2XMAEUuoLu^!g_e_ZN1?KR2_F+VA$` z`c4suBfMX>DNXCHOx4`!>ps7?^Vf^x_Q`4I&2%7VVQhH1D~In9uj_Oh|2*c9$BX6v z_tbv4$87!Y()BYw_bhk*I5mIs<^7+{A1i^JEWGQ(%>Q5SycT=!#}oLfeq+VA^WyFO zbx-S-tB9GY{eQ9j-sbv(uaDEz>J>q&xDTZLec1muS=Va2;e~R|lFJKba{@cetwn1m zzjiKuyy<9CVt)Nw`yU4Lihullk4}nLwYyfUA m-U1xTU|_J4-n9M4f5zkqZ=yDByb3xBgeZ|FLVyibk%%-|!IdH66sPj!cqdLp$Lkiu7D`4D@svVd2!!+=ggV8_s%`vz30xk-^^sVyE$T{c1r;O zfH^`Yc>n+$4*)Pj1YB$xgb$&`i@duF<&b#2fB*jWHn6?DO{dd=ZQ!1LY!Lv+j2$7_ zQ{n@c3hb}IO=J+xcJID#hpuBSWaJdm4H2sT1x=BqlwVw?n5nXtLy4rXn7mK6`bTx2 zZv_p=3HDTByKf+gJ2k!$2VQ@UaF0W%p_NBIT#8p$)}Bgp0#)WE>ej}Fazv&@Pr>*F z>A|eJJ9VC;&!C(;rJ^HxpCWfG1vg?(I50bNHixauQu6vXPsz`qYgdWq8+ae?xz9xo zZ`5ft8lPdt8_V&(7#I+9G_|k0nyxM6Sro&IrwmEQJwuMY=DrsRlI`0W5l&`RUs2ZE z<5_ISt;UncS`6G|XS##{`OX#bQS;^7?>>5m8<@O9@9Oq$Ma%6RIexK6#%YCtM_?fo zp8kImpg{+S0Ic^UPw35!_YQpS@6r9Jtl??kwT{lZ>GkBUNmW=j0h@Zz+SXvq-!)VI zpDFz2;qxW^)MD5)GDN9es@I|p^Tx#9CEA{!S`rImr(9{M&t0kurjrYb`TPq(GkF#) zfxnt%>_xIA>vHfvokKcsmLp?4^g?pJ!>N@4{q?~V{RkINtqEp=f5M)|zx?qf>~;K= z-OnquU9fs+WX>e|?4l)pn2qL#vUm^=s$1dUFQjuv5n-1WWm#bt2Nq;ZXdmk)A0A~- z2qVK49m?1@7ymgxvQ^hvmLVKJKdhRZb4qn-Sw{e>t1Pg4{OOz0_&sny2tQ; zivfHc{!s@e0HRr%M8y0{gz~qH%Ja0h$b^wC!X+ z*1;boV~n7*L*6Bai)T!qh(#pupZoRNQukHRc;ivR#?_g-wQG)L)8eVQ%9xg-tw+ z_nQBby5vEs?_@e;Dnl-l)Feb)mjj1W_)Uh9*-AJUvB2}+52U3H9?j3cMBrZE{b$V) zq10OLUP8o+>tiMO2V(o)>;Db>#VqPP$f284v+kkEhim&O2&O6S#mjUTJeb3NqFDWG zqNbuyft_}t3s>O!NExsIU=`kP%py9K%0S|REUC~&Y74i@{JQO*z;b~QBpt$s_KK?$ z=PV24Jp*8crky$#l(DXt_oY(*^;uqDh)a*?s0u$R3GbgNnA?0j9W7BM@JrDWc@B>c?Baz^l3KPlfrD18>~jAC0bL)N=Lq0 zkUVj%$<2@$Rbil_od2q`#w_|qm0-X7SSdtLUcoL4Mcszt3c~EYuF>tdw8GbIkgoX_ zh9F$3@x?K=lnI$Nvc5X`?M7BHkC&g>T+OE?_YaR3<~RO!7wI}UbF7K?EpU(8z{8;o zu&l;9Cto7h&Xib$xwKsHn=YZA|6Rp%^0U@u5x)f~P{;BJY5J#s--9CyV+O{zUuH=- z*<_o9=dBRN;uXKEB>5d1p^luGFW1^XtC2Nf=Rqoj}N}-WRj@_lk%Pfc(sS ziCBqF=dP;F8pbLa(rGrNG;|8PC0U0DjKnF^;Yje!OyXirpG;wL?9BGhJ`a82=M&=}&c&1=A9s2|ZlMtvU+K5!PW9g@MKA;E zVb-p2>j1>tgO507_*UnaRsn7co6Z|uswC3W-6h~~8ExZ%l>t9^?en+?B1 zypMuiezOUZ19QSaP!4M}JlRoV+lT{AOrLNR&{**nUe%=<^-z@YBEauZT)oVMtb zX9h;X3Vxy@`a?ZoJf5-ah*A^0n%@N~v(9~?1WSPI9!qR2da^QNRIuc2ECiahLUcui zo*A=LJQmB9Bu^vB0(o`?`SQ`d-Z&`3lISm{M?mZouh=rr(Ejs5+oT?xz87; zRa$#9uTb?cG6%V$d6bZuJxUo9EQ^vN@k+2aw`m$9i{44-;HN1I(+^$}Pg9e*cRRd{ zDBVPyN6S?F`8$?Dga{4Mi5EkG!ASxz>=F9!NF_jY*oNolwW3?$$U4*x^acsvYxT9A z@nWzOL-6xB`bL--hBJPPXh-|>#f0mqShI2D}^7}R>pI@99H@t>ob{F%tPE&6L(PVK9Z3I#vwVRUo zb2D#l<7N|Y-e-r_L7GMJi6XgW9*xj%SwU-NS7xz?D&L%);N#vDzr5&W_U9enNrP3* zU7>^s>uxlmp5UmcP6n;^T1ANCV#28BmNE-#TUT$zyzY2k{{y6&mRFNN-dH))R^*Tr z2vruuWvZ6{;6x~rAkCTJ5AP5s-tv1b&7_+uZfh%XkMxf7Q6b(!(*vA*8aX(edNtZZ z$nX9ujEZh-<}t-y--uyU5#Ph6EdSC@KOwPbg3mi^P7wNs5QHT^pnnv@T1*?M*N+HI zrSG=-_~MLZt7uQeSWS8aq2Z{qLl|{6K?ylipy)3giuLubGqx57OA>@rwXG{@pFG`v z-ABlT-h@%FetZ=wQ%%cG5V>MWa|Gv%HV!5ZDaMvd2k7b=^TikfZ!E0 z?^(=kqNN9yKB4zE{Lo68`W)MJMd)&^o}g1sjwbJE1V=)q@TtcWh&9C@LdfS*FWW-T*%YkmMVHF@36Cc07Ee z73`m^0hQ`fyLb%p0{0f8SLmSW?AKNl&HWA~E|N71kk~@{7S|h1UUPTDO46GQuegGO zzB@jw^AaE^$M*L-z<{_<7<2h*9kaX<^5V zPb+H9X$*}^kaX~-VN_6)V6acjfX=?&#j;jneTAbSN)i)xMf^lr<(DUX1aq}&4;?YV zH>ceKNtqohSlW9~QvnNOw7*f3v-t@>jX`;O+PG3*)5Wxl0E27X3KQ1?9g41>D$~KY zQ*ic@EV>fN+>Hl=x0`D2?o{l2%FcN&1lb?2s0d&&LkcBtVwi>1H`2Scg9OD; z0fBY(qE=gT>f=K_f0P}wihi)~3vHr3Bl80$d^TDJ3{KHKHWm0*9y?3%)gd@TA=?M- zMv`x)s&5}GQZa%;%6(+YYvDQm^nt5=iv0(m7E7wc%2{|!>4V{E495$ Date: Sun, 15 Oct 2023 00:14:12 -0700 Subject: [PATCH 754/851] add filter for established location types --- docs/plugins/sort.rst | 3 ++ plugins/lua/sort/locationselector.lua | 67 ++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 4350a4cb0..b36e78c17 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -132,6 +132,9 @@ the relevant profession, religion, or deity by name. For temples, you can also search for the "spheres" associated with the deity or religion, such as "wealth" or "lies". +You can also choose whether to filter out temple or guildhall types that you +have already established. + World overlay ------------- diff --git a/plugins/lua/sort/locationselector.lua b/plugins/lua/sort/locationselector.lua index d91c536ac..f282d4561 100644 --- a/plugins/lua/sort/locationselector.lua +++ b/plugins/lua/sort/locationselector.lua @@ -11,9 +11,9 @@ local location_selector = df.global.game.main_interface.location_selector LocationSelectorOverlay = defclass(LocationSelectorOverlay, sortoverlay.SortOverlay) LocationSelectorOverlay.ATTRS{ - default_pos={x=48, y=7}, + default_pos={x=48, y=6}, viewscreens='dwarfmode/LocationSelector', - frame={w=26, h=1}, + frame={w=26, h=3}, } local function add_spheres(hf, spheres) @@ -55,10 +55,12 @@ local function get_profession_string(profession) end function LocationSelectorOverlay:init() - self:addviews{ + local panel = widgets.Panel{ + visible=self:callback('get_key'), + } + panel:addviews{ widgets.BannerPanel{ frame={l=0, t=0, r=0, h=1}, - visible=self:callback('get_key'), subviews={ widgets.EditField{ view_id='search', @@ -69,13 +71,35 @@ function LocationSelectorOverlay:init() }, }, }, + widgets.BannerPanel{ + frame={l=0, t=2, r=0, h=1}, + subviews={ + widgets.ToggleHotkeyLabel{ + view_id='hide_established', + frame={l=1, t=0, r=1}, + label="Hide established:", + key='CUSTOM_SHIFT_E', + initial_option=true, + on_change=function() self:do_search(self.subviews.search.text, true) end, + }, + }, + }, } + self:addviews{panel} self:register_handler('TEMPLE', location_selector.valid_religious_practice_id, - curry(sortoverlay.flags_vector_search, {get_search_key_fn=get_religion_string}, + curry(sortoverlay.flags_vector_search, + { + get_search_key_fn=get_religion_string, + matches_filters_fn=self:callback('matches_temple_filter'), + }, location_selector.valid_religious_practice)) self:register_handler('GUILDHALL', location_selector.valid_craft_guild_type, - curry(sortoverlay.single_vector_search, {get_search_key_fn=get_profession_string})) + curry(sortoverlay.single_vector_search, + { + get_search_key_fn=get_profession_string, + matches_filters_fn=self:callback('matches_guildhall_filter'), + })) end function LocationSelectorOverlay:get_key() @@ -86,4 +110,35 @@ function LocationSelectorOverlay:get_key() end end +function LocationSelectorOverlay:reset() + LocationSelectorOverlay.super.reset(self) + self.cache = nil + self.subviews.hide_established:setOption(true, false) +end + +function LocationSelectorOverlay:get_cache() + if self.cache then return self.cache end + local cache = {} + for _,location in ipairs(df.global.world.world_data.active_site[0].buildings) do + if df.abstract_building_templest:is_instance(location) then + ensure_keys(cache, 'temple', location.deity_type)[location.deity_data.Religion] = true + elseif df.abstract_building_guildhallst:is_instance(location) then + ensure_keys(cache, 'guildhall')[location.contents.profession] = true + end + end + self.cache = cache + return self.cache +end + +function LocationSelectorOverlay:matches_temple_filter(id, flag) + if id == -1 then return true end + local hide_established = self.subviews.hide_established:getOptionValue() + return not hide_established or not safe_index(self:get_cache(), 'temple', flag, id) +end + +function LocationSelectorOverlay:matches_guildhall_filter(id) + local hide_established = self.subviews.hide_established:getOptionValue() + return not hide_established or not safe_index(self:get_cache(), 'guildhall', id) +end + return _ENV From a04623e4fbff6f83d829b5485a64dfee505cf214 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Oct 2023 13:26:25 -0700 Subject: [PATCH 755/851] add search and filter for slab engraving list --- docs/changelog.txt | 1 + docs/plugins/sort.rst | 8 +++ plugins/lua/sort.lua | 1 + plugins/lua/sort/slab.lua | 117 +++++++++++++++++++++++++++++++ plugins/lua/sort/sortoverlay.lua | 2 +- 5 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 plugins/lua/sort/slab.lua diff --git a/docs/changelog.txt b/docs/changelog.txt index bf5415fc9..ee61d6dd6 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,6 +62,7 @@ Template for new versions: - `sort`: new search widgets for location selection screen (when you're choosing what kind of guildhall or temple to dedicate) - `sort`: new search widgets for burrow assignment screen and other unit assignment dialogs - `sort`: new search widgets for artifacts on the world/raid screen +- `sort`: new search widgets for slab engraving menu; can filter for only units that need a slab to prevent rising as a ghost ## Fixes - `zone`: races without specific child or baby names will now get generic child/baby names instead of an empty string diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index b36e78c17..c0111fa0c 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -135,6 +135,14 @@ search for the "spheres" associated with the deity or religion, such as You can also choose whether to filter out temple or guildhall types that you have already established. +Slab engraving overlay +---------------------- + +When choosing a unit to engrave a slab for, you can search for units by name, +either in their native language or in English (though only their native name +will be displayed). This overlay also adds a filter for showing only units that +would need a slab in order to prevent them rising as a ghost. + World overlay ------------- diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 9be0848c5..8f89e54e3 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1291,6 +1291,7 @@ OVERLAY_WIDGETS = { location_selector=require('plugins.sort.locationselector').LocationSelectorOverlay, unit_selector=require('plugins.sort.unitselector').UnitSelectorOverlay, worker_assignment=require('plugins.sort.unitselector').WorkerAssignmentOverlay, + slab=require('plugins.sort.slab').SlabOverlay, world=require('plugins.sort.world').WorldOverlay, } diff --git a/plugins/lua/sort/slab.lua b/plugins/lua/sort/slab.lua new file mode 100644 index 000000000..67cd8f753 --- /dev/null +++ b/plugins/lua/sort/slab.lua @@ -0,0 +1,117 @@ +local _ENV = mkmodule('plugins.sort.slab') + +local gui = require('gui') +local sortoverlay = require('plugins.sort.sortoverlay') +local widgets = require('gui.widgets') + +local building = df.global.game.main_interface.building +local view_sheets = df.global.game.main_interface.view_sheets + +-- ---------------------- +-- SlabOverlay +-- + +SlabOverlay = defclass(SlabOverlay, sortoverlay.SortOverlay) +SlabOverlay.ATTRS{ + default_pos={x=-40, y=12}, + viewscreens='dwarfmode/ViewSheets/BUILDING/Workshop', + frame={w=57, h=3}, +} + +function SlabOverlay:init() + local panel = widgets.Panel{ + frame_background=gui.CLEAR_PEN, + visible=self:callback('get_key'), + } + panel:addviews{ + widgets.BannerPanel{ + frame={l=0, t=0, r=0, h=1}, + subviews={ + widgets.EditField{ + view_id='search', + frame={l=1, t=0, r=1}, + label_text="Search: ", + key='CUSTOM_ALT_S', + on_change=function(text) self:do_search(text) end, + }, + }, + }, + widgets.BannerPanel{ + frame={l=0, t=2, r=0, h=1}, + subviews={ + widgets.ToggleHotkeyLabel{ + view_id='only_needs_slab', + frame={l=1, t=0, r=1}, + label="Show only citizens who need a slab:", + key='CUSTOM_SHIFT_E', + initial_option=false, + on_change=function() self:do_search(self.subviews.search.text, true) end, + }, + }, + }, + } + self:addviews{panel} + + self:register_handler('SLAB', building.filtered_button, + curry(sortoverlay.single_vector_search, + { + get_search_key_fn=self:callback('get_search_key'), + matches_filters_fn=self:callback('matches_filters'), + })) +end + +function SlabOverlay:onInput(keys) + if SlabOverlay.super.onInput(self, keys) then return true end + if keys._MOUSE_L and self:get_key() and self:getMousePos() then + return true + end +end + +function SlabOverlay:get_key() + -- DF fails to set building.category back to NONE if there are no units that + -- can be memorialized, so we have to manually check for a populated button vector + if #building.button > 0 and + building.category == df.interface_category_building.SELECT_MEMORIAL_UNIT + then + return 'SLAB' + else + if safe_index(self.state, 'SLAB', 'saved_original') then + -- elements get freed as soon as the screen changes + self.state.SLAB.saved_original = nil + end + end +end + +function SlabOverlay:reset() + SlabOverlay.super.reset(self) + self.subviews.only_needs_slab:setOption(false, false) +end + +local function get_unit(if_button) + local hf = df.historical_figure.find(if_button.spec_id) + return hf and df.unit.find(hf.unit_id) or nil +end + +function SlabOverlay:get_search_key(if_button) + local unit = get_unit(if_button) + if not unit then return if_button.filter_str end + return ('%s %s'):format( + dfhack.units.getReadableName(unit), -- last name is in english + dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name +end + +local function needs_slab(if_button) + local unit = get_unit(if_button) + if not unit then return false end + if not dfhack.units.isOwnGroup(unit) then return false end + local info = dfhack.toSearchNormalized(if_button.info) + if not info:find('no slabs engraved', 1, true) then return false end + return info:find('not memorialized', 1, true) or info:find('ghost', 1, true) +end + +function SlabOverlay:matches_filters(if_button) + local only_needs_slab = self.subviews.only_needs_slab:getOptionValue() + return not only_needs_slab or needs_slab(if_button) +end + +return _ENV diff --git a/plugins/lua/sort/sortoverlay.lua b/plugins/lua/sort/sortoverlay.lua index 18b4877b3..75e31aa01 100644 --- a/plugins/lua/sort/sortoverlay.lua +++ b/plugins/lua/sort/sortoverlay.lua @@ -114,7 +114,7 @@ local function filter_vec(fns, flags_vec, vec, text, erase_fn) local search_tokens = text:split() for idx = #vec-1,0,-1 do local flag = flags_vec and flags_vec[idx] or nil - local search_key = fns.get_search_key_fn(vec[idx], flag) + local search_key = fns.get_search_key_fn and fns.get_search_key_fn(vec[idx], flag) or nil if (search_key and not utils.search_text(search_key, search_tokens)) or (fns.matches_filters_fn and not fns.matches_filters_fn(vec[idx], flag)) then From 682e9d3a86a058d3f768be2aaa201fb3654ef14e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Oct 2023 14:03:31 -0700 Subject: [PATCH 756/851] filter cages by whether they are occupied --- docs/changelog.txt | 1 + plugins/buildingplan/buildingplan_cycle.cpp | 5 +++++ plugins/lua/buildingplan/planneroverlay.lua | 16 ++++++++++++++++ 3 files changed, 22 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index ee61d6dd6..2bb24e361 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -74,6 +74,7 @@ Template for new versions: - `orders`: ``recheck`` command now only resets orders that have conditions that can be rechecked - `sort`: added help button for squad assignment search/filter/sort - `zone`: animals trained for war or hunting are now labeled as such in animal assignment screens +- `buildingplan`: support filtering cages by whether they are occupied ## Documentation - unavailable tools are no longer listed in the tag indices in the online docs diff --git a/plugins/buildingplan/buildingplan_cycle.cpp b/plugins/buildingplan/buildingplan_cycle.cpp index c6e0fbc9a..6dd69e095 100644 --- a/plugins/buildingplan/buildingplan_cycle.cpp +++ b/plugins/buildingplan/buildingplan_cycle.cpp @@ -119,6 +119,11 @@ bool matchesFilters(df::item * item, const df::job_item * jitem, HeatSafety heat && static_cast(item)->engraving_type != df::slab_engraving_type::Memorial) return false; + if (item->getType() == df::item_type::CAGE && specials.count("empty") + && (Items::getGeneralRef(item, df::general_ref_type::CONTAINS_UNIT) + || Items::getGeneralRef(item, df::general_ref_type::CONTAINS_ITEM))) + return false; + if (!matchesHeatSafety(item->getMaterial(), item->getMaterialIndex(), heat)) return false; diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index 2cc15dfde..bca1c7e0b 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -162,6 +162,10 @@ local function is_slab() return uibs.building_type == df.building_type.Slab end +local function is_cage() + return uibs.building_type == df.building_type.Cage +end + local function is_stairs() return is_construction() and uibs.building_subtype == df.construction_type.UpDownStair @@ -477,6 +481,16 @@ function PlannerOverlay:init() buildingplan.setSpecial(uibs.building_type, uibs.building_subtype, uibs.custom_type, 'engraved', val) end, }, + widgets.ToggleHotkeyLabel { + view_id='empty', + frame={b=4, l=1, w=22}, + key='CUSTOM_T', + label='Empty only:', + visible=is_cage, + on_change=function(val) + buildingplan.setSpecial(uibs.building_type, uibs.building_subtype, uibs.custom_type, 'empty', val) + end, + }, widgets.Label{ frame={b=4, l=23}, text_pen=COLOR_DARKGREY, @@ -847,6 +861,8 @@ function PlannerOverlay:onRenderFrame(dc, rect) local buildingplan = require('plugins.buildingplan') self.subviews.engraved:setOption(buildingplan.getSpecials( uibs.building_type, uibs.building_subtype, uibs.custom_type).engraved or false) + self.subviews.empty:setOption(buildingplan.getSpecials( + uibs.building_type, uibs.building_subtype, uibs.custom_type).empty or false) self.subviews.choose:setOption(buildingplan.getChooseItems( uibs.building_type, uibs.building_subtype, uibs.custom_type)) self.subviews.safety:setOption(buildingplan.getHeatSafetyFilter( From 3ed16306da2d419ff6543405d04ebed87f73974a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Oct 2023 15:21:07 -0700 Subject: [PATCH 757/851] mercenaries aren't appointed officials --- docs/changelog.txt | 1 + plugins/lua/sort.lua | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 2bb24e361..1e2690456 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -67,6 +67,7 @@ Template for new versions: ## Fixes - `zone`: races without specific child or baby names will now get generic child/baby names instead of an empty string - `zone`: don't show animal assignment link for cages and restraints linked to dungeon zones (which aren't normally assignable) +- `sort`: don't count mercenaries as appointed officials in the squad assignment screen - `dwarfvet`: fix invalid job id assigned to ``Rest`` job, which could cause crashes on reload ## Misc Improvements diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 8f89e54e3..b27049e91 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -978,7 +978,11 @@ local function is_in_military(unit) end local function is_elected_or_appointed_official(unit) - if #unit.occupations > 0 then return true end + for _,occupation in ipairs(unit.occupations) do + if occupation.type ~= df.occupation_type.MERCENARY then + return true + end + end for _, noble_pos in ipairs(dfhack.units.getNoblePositions(unit) or {}) do if noble_pos.position.flags.ELECTED or (noble_pos.position.mandate_max == 0 and noble_pos.position.demand_max == 0) From 15ae84a31bbe66003b7942bdc158f316ea3b461b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Oct 2023 17:22:29 -0700 Subject: [PATCH 758/851] framed screen subclasses are modal so they should swallow all input --- library/lua/gui.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 4ee3eba4a..555e060d1 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -1027,6 +1027,11 @@ function FramedScreen:onRenderFrame(dc, rect) paint_frame(dc,rect,self.frame_style,self.frame_title) end +function FramedScreen:onInput(keys) + FramedScreen.super.onInput(self, keys) + return true -- FramedScreens are modal +end + -- Inverts the brightness of the color, optionally taking a "bold" parameter, -- which you should include if you're reading the fg color of a pen. function invert_color(color, bold) From f50c137f32151f9dfbca9f8e085ebdf4f0e9c4ff Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Oct 2023 20:00:14 -0700 Subject: [PATCH 759/851] we can no longer build with ash, coal, or soap --- docs/changelog.txt | 1 + plugins/buildingplan/buildingplan_cycle.cpp | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1e2690456..32eaf8b37 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -65,6 +65,7 @@ Template for new versions: - `sort`: new search widgets for slab engraving menu; can filter for only units that need a slab to prevent rising as a ghost ## Fixes +- `buildingplan`: remove bars of ash, coal, and soap as valid building materials to match v50 rules - `zone`: races without specific child or baby names will now get generic child/baby names instead of an empty string - `zone`: don't show animal assignment link for cages and restraints linked to dungeon zones (which aren't normally assignable) - `sort`: don't count mercenaries as appointed officials in the squad assignment screen diff --git a/plugins/buildingplan/buildingplan_cycle.cpp b/plugins/buildingplan/buildingplan_cycle.cpp index 6dd69e095..c43834b36 100644 --- a/plugins/buildingplan/buildingplan_cycle.cpp +++ b/plugins/buildingplan/buildingplan_cycle.cpp @@ -59,11 +59,28 @@ static bool isAccessible(color_ostream& out, df::item* item) { return is_walkable; } +// as of v50, soap, coal, and ash are no longer valid building materials +static bool isUnusableBar(color_ostream& out, df::item* item) { + if (item->getType() != df::item_type::BAR) + return false; + + MaterialInfo minfo(item); + string token = minfo.getToken(); + if (token.starts_with("COAL:") || token == "ASH") + return true; + + df::job_item_flags2 ok; + df::job_item_flags2 mask; + minfo.getMatchBits(ok, mask); + return ok.bits.soap; +} + bool itemPassesScreen(color_ostream& out, df::item* item) { static const BadFlags bad_flags; return !(item->flags.whole & bad_flags.whole) && !item->isAssignedToStockpile() - && isAccessible(out, item); + && isAccessible(out, item) + && !isUnusableBar(out, item); } bool matchesHeatSafety(int16_t mat_type, int32_t mat_index, HeatSafety heat) { From 45d585cabd250809a6c7fa783db18c92e74b34a7 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Oct 2023 20:12:45 -0700 Subject: [PATCH 760/851] refresh the overlay state when toggling minimize since the items may have changed --- docs/changelog.txt | 1 + plugins/lua/buildingplan/planneroverlay.lua | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 32eaf8b37..e0f3c02d3 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -66,6 +66,7 @@ Template for new versions: ## Fixes - `buildingplan`: remove bars of ash, coal, and soap as valid building materials to match v50 rules +- `buildingplan`: fix incorrect required items being displayed sometimes when switching the planner overlay on and off - `zone`: races without specific child or baby names will now get generic child/baby names instead of an empty string - `zone`: don't show animal assignment link for cages and restraints linked to dungeon zones (which aren't normally assignable) - `sort`: don't count mercenaries as appointed officials in the squad assignment screen diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index bca1c7e0b..bdd0008f8 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -652,6 +652,7 @@ end function PlannerOverlay:toggle_minimized() self.state.minimized = not self.state.minimized config:write() + self:reset() end function PlannerOverlay:draw_divider_h(dc) From 6c1f5f90691ea17be16899ec81e455324267c211 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 16 Oct 2023 03:18:48 +0000 Subject: [PATCH 761/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 7444de2a2..af433af3a 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 7444de2a2207d93b00defd7de94bb56d10968ea3 +Subproject commit af433af3ae34621ab8592d6ee419af347d607aca From eab10080db9e70adfaeaeee5699cee067bc3ff4d Mon Sep 17 00:00:00 2001 From: Myk Date: Sun, 15 Oct 2023 21:54:50 -0700 Subject: [PATCH 762/851] Revert "use df's translate_name function if available" --- docs/changelog.txt | 1 - library/modules/Translation.cpp | 26 +------------------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index e0f3c02d3..b46eddc98 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -83,7 +83,6 @@ Template for new versions: - unavailable tools are no longer listed in the tag indices in the online docs ## API -- Translate: will use DF's ``translate_name`` function, if available, instead of the DFHack emulation ## Lua - added ``GRAY`` color aliases for ``GREY`` colors diff --git a/library/modules/Translation.cpp b/library/modules/Translation.cpp index 8bd79d101..af06eeb49 100644 --- a/library/modules/Translation.cpp +++ b/library/modules/Translation.cpp @@ -27,7 +27,7 @@ distribution. #include #include #include -#include +using namespace std; #include "modules/Translation.h" #include "VersionInfo.h" @@ -36,7 +36,6 @@ distribution. #include "ModuleFactory.h" #include "Core.h" #include "Error.h" -#include "Debug.h" using namespace DFHack; using namespace df::enums; @@ -45,16 +44,10 @@ using namespace df::enums; #include "df/world.h" #include "df/d_init.h" -using std::vector, std::string; - using df::global::world; using df::global::d_init; using df::global::gametype; -namespace DFHack { - DBG_DECLARE(core, translate, DebugCategory::LINFO); -} - bool Translation::IsValid () { return (world && (world->raws.language.words.size() > 0) && (world->raws.language.translations.size() > 0)); @@ -174,23 +167,6 @@ string Translation::TranslateName(const df::language_name * name, bool inEnglish CHECK_NULL_POINTER(name); string out; - - auto fp = df::global::translate_name; - - if (fp) { - DEBUG(translate).print("using df provided translate_name function\n"); - typedef std::function fun_type; - auto f = reinterpret_cast(fp); - try { - (*f)(*name, out, inEnglish, onlyLastPart); - return out; - } - catch (...) { - WARN(translate).print("df provided translate_name function threw an exception, falling back\n"); - } - } - - DEBUG(translate).print("using dfhack fallback translate_name function\n"); string word; if (!onlyLastPart) { From b128b904eb697c82c616bfb121c6e1dfbad671fe Mon Sep 17 00:00:00 2001 From: Myk Date: Sun, 15 Oct 2023 21:56:36 -0700 Subject: [PATCH 763/851] Update Translation.cpp --- library/modules/Translation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/modules/Translation.cpp b/library/modules/Translation.cpp index af06eeb49..8ebae035f 100644 --- a/library/modules/Translation.cpp +++ b/library/modules/Translation.cpp @@ -27,7 +27,6 @@ distribution. #include #include #include -using namespace std; #include "modules/Translation.h" #include "VersionInfo.h" @@ -44,6 +43,8 @@ using namespace df::enums; #include "df/world.h" #include "df/d_init.h" +using std::vector, std::string; + using df::global::world; using df::global::d_init; using df::global::gametype; From 287ed440cec865b4c70efd012927ee3799410fca Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Oct 2023 23:20:31 -0700 Subject: [PATCH 764/851] show how many items you need to make when planning --- docs/changelog.txt | 1 + plugins/buildingplan/buildingplan.cpp | 27 +++++++++++++++++++-- plugins/lua/buildingplan/planneroverlay.lua | 7 ++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index b46eddc98..0121e9e5c 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -78,6 +78,7 @@ Template for new versions: - `sort`: added help button for squad assignment search/filter/sort - `zone`: animals trained for war or hunting are now labeled as such in animal assignment screens - `buildingplan`: support filtering cages by whether they are occupied +- `buildingplan`: show how many items you need to make when planning buildings ## Documentation - unavailable tools are no longer listed in the tag indices in the online docs diff --git a/plugins/buildingplan/buildingplan.cpp b/plugins/buildingplan/buildingplan.cpp index 540420749..9fb5641bb 100644 --- a/plugins/buildingplan/buildingplan.cpp +++ b/plugins/buildingplan/buildingplan.cpp @@ -677,7 +677,7 @@ static int scanAvailableItems(color_ostream &out, df::building_type type, int16_ int32_t custom, int index, bool ignore_filters, vector *item_ids = NULL, map *counts = NULL) { DEBUG(status,out).print( - "entering countAvailableItems building_type=%d subtype=%d custom=%d index=%d\n", + "entering scanAvailableItems building_type=%d subtype=%d custom=%d index=%d\n", type, subtype, custom, index); BuildingTypeKey key(type, subtype, custom); HeatSafety heat = get_heat_safety_filter(key); @@ -755,7 +755,30 @@ static int countAvailableItems(color_ostream &out, df::building_type type, int16 DEBUG(status,out).print( "entering countAvailableItems building_type=%d subtype=%d custom=%d index=%d\n", type, subtype, custom, index); - return scanAvailableItems(out, type, subtype, custom, index, false); + int count = scanAvailableItems(out, type, subtype, custom, index, false); + if (count) + return count; + + // nothing in stock; return how many are waiting in line as a negative + BuildingTypeKey key(type, subtype, custom); + auto &job_items = get_job_items(out, key); + if (index < 0 || job_items.size() <= (size_t)index) + return 0; + auto &jitem = job_items[index]; + + for (auto &entry : planned_buildings) { + auto &pb = entry.second; + // don't actually remove bad buildings from the list while we're + // actively iterating through that list + auto bld = pb.getBuildingIfValidOrRemoveIfNot(out, true); + if (!bld || bld->jobs.size() != 1) + continue; + for (auto pb_jitem : bld->jobs[0]->job_items) { + if (pb_jitem->item_type == jitem->item_type && pb_jitem->item_subtype == jitem->item_subtype) + count -= pb_jitem->quantity; + } + } + return count; } static bool hasFilter(color_ostream &out, df::building_type type, int16_t subtype, int32_t custom, int index) { diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index bdd0008f8..6241ff219 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -295,9 +295,12 @@ function ItemLine:get_item_line_text() if self.available >= quantity then self.note_pen = COLOR_GREEN self.note = ' Available now' + elseif self.available >= 0 then + self.note_pen = COLOR_BROWN + self.note = (' Will link next (need to make %d)'):format(quantity - self.available) else self.note_pen = COLOR_BROWN - self.note = ' Will link later' + self.note = (' Will link later (need to make %d)'):format(-self.available + quantity) end self.note = string.char(192) .. self.note -- character 192 is "└" @@ -318,7 +321,7 @@ function ItemLine:reduce_quantity(used_quantity) if not self.available then return end local filter = get_cur_filters()[self.idx] used_quantity = used_quantity or get_quantity(filter, self.is_hollow_fn()) - self.available = math.max(0, self.available - used_quantity) + self.available = self.available - used_quantity end local function get_placement_errors() From 8d4d8f227d5975e5e88ed5c630fcc6e21371aae5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Oct 2023 23:30:43 -0700 Subject: [PATCH 765/851] ensure modal dialogs behave like modal dialogs that is, don't let clicks and keys propagate to parent screens --- library/lua/gui/buildings.lua | 1 + library/lua/gui/dialogs.lua | 9 ++++++--- library/lua/gui/materials.lua | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/library/lua/gui/buildings.lua b/library/lua/gui/buildings.lua index 433afb1ba..93b0e2182 100644 --- a/library/lua/gui/buildings.lua +++ b/library/lua/gui/buildings.lua @@ -268,6 +268,7 @@ function BuildingDialog:onInput(keys) return true end self:inputToSubviews(keys) + return true end function showBuildingPrompt(title, prompt, on_select, on_cancel, build_filter) diff --git a/library/lua/gui/dialogs.lua b/library/lua/gui/dialogs.lua index 7a0f86b3f..63f9990c1 100644 --- a/library/lua/gui/dialogs.lua +++ b/library/lua/gui/dialogs.lua @@ -66,7 +66,8 @@ function MessageBox:onInput(keys) end return true end - return self:inputToSubviews(keys) + self:inputToSubviews(keys) + return true end function showMessage(title, text, tcolor, on_close) @@ -135,7 +136,8 @@ function InputBox:onInput(keys) end return true end - return self:inputToSubviews(keys) + self:inputToSubviews(keys) + return true end function showInputPrompt(title, text, tcolor, input, on_input, on_cancel, min_width) @@ -236,7 +238,8 @@ function ListBox:onInput(keys) end return true end - return self:inputToSubviews(keys) + self:inputToSubviews(keys) + return true end function showListPrompt(title, text, tcolor, choices, on_select, on_cancel, min_width, filter) diff --git a/library/lua/gui/materials.lua b/library/lua/gui/materials.lua index aa070ea73..112d8f6df 100644 --- a/library/lua/gui/materials.lua +++ b/library/lua/gui/materials.lua @@ -265,7 +265,8 @@ function MaterialDialog:onInput(keys) end return true end - return self:inputToSubviews(keys) + self:inputToSubviews(keys) + return true end function showMaterialPrompt(title, prompt, on_select, on_cancel, mat_filter) From 29ef626889805e031f4088a2de14446b850149f8 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Oct 2023 00:43:58 -0700 Subject: [PATCH 766/851] reuse existing orders if possible --- docs/changelog.txt | 1 + plugins/tailor.cpp | 54 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0121e9e5c..e93977444 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -79,6 +79,7 @@ Template for new versions: - `zone`: animals trained for war or hunting are now labeled as such in animal assignment screens - `buildingplan`: support filtering cages by whether they are occupied - `buildingplan`: show how many items you need to make when planning buildings +- `tailor`: now adds to existing orders if possilbe instead of creating new ones ## Documentation - unavailable tools are no longer listed in the tag indices in the online docs diff --git a/plugins/tailor.cpp b/plugins/tailor.cpp index e74a07330..ac71749ee 100644 --- a/plugins/tailor.cpp +++ b/plugins/tailor.cpp @@ -425,7 +425,6 @@ public: int size = world->raws.creatures.all[race]->adultsize; - auto tt = jobTypeMap.find(o->job_type); if (tt == jobTypeMap.end()) { @@ -441,6 +440,21 @@ public: } + static df::manager_order * get_existing_order(df::job_type ty, int16_t sub, int32_t hfid, df::job_material_category mcat) { + for (auto order : world->manager_orders) { + if (order->job_type == ty && + order->item_type == df::item_type::NONE && + order->item_subtype == sub && + order->mat_type == -1 && + order->mat_index == -1 && + order->hist_figure_id == hfid && + order->material_category.whole == mcat.whole && + order->frequency == df::manager_order::T_frequency::OneTime) + return order; + } + return NULL; + } + int place_orders() { int ordered = 0; @@ -532,21 +546,29 @@ public: } supply[m] -= c; - auto order = new df::manager_order; - order->job_type = ty; - order->item_type = df::item_type::NONE; - order->item_subtype = sub; - order->mat_type = -1; - order->mat_index = -1; - order->amount_left = c; - order->amount_total = c; - order->status.bits.validated = false; - order->status.bits.active = false; - order->id = world->manager_order_next_id++; - order->hist_figure_id = sizes[size]; - order->material_category = m.job_material; - - world->manager_orders.push_back(order); + auto order = get_existing_order(ty, sub, sizes[size], m.job_material); + if (order) { + if (order->amount_total > 0) { + order->amount_left += c; + order->amount_total += c; + } + } else { + order = new df::manager_order; + order->job_type = ty; + order->item_type = df::item_type::NONE; + order->item_subtype = sub; + order->mat_type = -1; + order->mat_index = -1; + order->amount_left = c; + order->amount_total = c; + order->status.bits.validated = false; + order->status.bits.active = false; + order->id = world->manager_order_next_id++; + order->hist_figure_id = sizes[size]; + order->material_category = m.job_material; + + world->manager_orders.push_back(order); + } INFO(cycle).print("tailor: added order #%d for %d %s %s, sized for %s\n", order->id, From 723cd39b99b21281eca6e0e1042959762a0cc974 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Oct 2023 01:30:27 -0700 Subject: [PATCH 767/851] minor updates - add note about possibly delaying pasturing initial animals - add display furniture to guildhall level rooms - add wheelbarrows to caged unit stockpile --- data/blueprints/dreamfort.csv | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/data/blueprints/dreamfort.csv b/data/blueprints/dreamfort.csv index 31ba9512e..2261e7cf0 100644 --- a/data/blueprints/dreamfort.csv +++ b/data/blueprints/dreamfort.csv @@ -413,7 +413,7 @@ corridor_traps/surface_corridor_traps -"#zone label(surface_zones) start(19; 19) hidden() message(Remember to assign your dogs to the pasture surrounding the central stairs, your grazing animals to the large pasture, and your male birds to the zone between the rows of nestboxes.) pastures and training areas" +"#zone label(surface_zones) start(19; 19) hidden() message(Remember to assign your dogs to the pasture surrounding the central stairs, your grazing animals to the large pasture, and your male birds to the zone between the rows of nestboxes. If your wagon is far away, you can let your animals wander closer to the fort before pasturing them to save hauling time.) pastures and training areas" @@ -835,7 +835,7 @@ You might also want to set the ""trade goods quantum"" stockpile to autotrade.) ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` -,,,`,,`,,,,,,,,,,,,,,,,,"a{name=""Pets/Prisoner feeder"" autotrain=true}(9x5)",,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,"a10{name=""Pets/Prisoner feeder"" autotrain=true}(9x5)",,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` ,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` @@ -2452,7 +2452,7 @@ doors/guildhall_doors "#build label(guildhall_furnish) start(15; 15; central stairs) hidden() furnish 4 guildhalls, 3 temples, and a library" -,,`,`,`,`,s,`,`,,,`,s,`,c,`,`,f,,,`,`,s,`,`,`,` +,,F,`,`,`,s,`,`,,,F,s,`,c,`,`,f,,,`,`,s,`,`,`,F ,,`,`,c,`,`,`,`,,,`,`,h,~a,`,`,f,,,`,`,`,`,c,`,` ,,`,c,t,c,`,`,s,,,`,`,`,`,`,`,`,,,s,`,`,c,t,c,` ,,`,`,c,`,c,`,`,,,`,`,`,`,`,`,`,,,`,`,c,`,c,`,` @@ -2467,7 +2467,7 @@ doors/guildhall_doors ,,c,~a,`,`,c,c,`,,~,,`,,`,,`,,~,,`,c,c,`,`,~a,c ,,`,h,`,`,c,c,`,~,`,~,`,,,,`,~,`,~,`,c,c,`,`,h,` ,,s,`,`,`,`,`,`,,,,`,`,`,`,`,,,,`,`,`,`,`,`,s -,,`,`,`,`,`,`,t,,,,,~,,~,,,,,t,`,`,`,`,`,` +,,F,`,`,`,`,`,t,,,,,~,,~,,,,,t,`,`,`,`,`,F ,,,,,,,~,,,,,,`,~,`,,,,,,~ ,,,,,,,~,,,,,,~,,~,,,,,,~ ,,`,`,s,`,`,`,t,,,t,`,`,`,`,`,t,,,t,`,`,`,s,`,` @@ -2476,7 +2476,7 @@ doors/guildhall_doors ,,`,`,c,`,c,`,`,,,t,c,`,`,`,c,t,,,`,`,c,`,c,`,` ,,`,c,t,c,`,`,s,,,t,c,`,`,`,c,t,,,s,`,`,c,t,c,` ,,`,`,c,`,`,`,`,,,`,`,`,`,`,`,`,,,`,`,`,`,c,`,` -,,`,`,`,`,s,`,`,,,h,~c,~c,s,~c,~c,h,,,`,`,s,`,`,`,` +,,F,`,`,`,s,`,`,,,h,~c,~c,s,~c,~c,h,,,`,`,s,`,`,`,F #notes label(beds_help) From b554f7472e8244502c951390b23daa8dfd7bd549 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Oct 2023 01:55:38 -0700 Subject: [PATCH 768/851] add stocks plugin (but comment out contents) --- plugins/CMakeLists.txt | 2 +- plugins/stocks.cpp | 32 +++++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index be690edf1..114386ad3 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -162,7 +162,7 @@ if(BUILD_SUPPORTED) add_subdirectory(spectate) #dfhack_plugin(stockflow stockflow.cpp LINK_LIBRARIES lua) add_subdirectory(stockpiles) - #dfhack_plugin(stocks stocks.cpp) + dfhack_plugin(stocks stocks.cpp LINK_LIBRARIES lua) dfhack_plugin(strangemood strangemood.cpp) dfhack_plugin(tailor tailor.cpp LINK_LIBRARIES lua) dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) diff --git a/plugins/stocks.cpp b/plugins/stocks.cpp index 40ebdc960..771160b4a 100644 --- a/plugins/stocks.cpp +++ b/plugins/stocks.cpp @@ -1,3 +1,13 @@ +#include "PluginManager.h" + +using std::vector; +using std::string; + +using namespace DFHack; + +DFHACK_PLUGIN("stocks"); + +/* #include "uicommon.h" #include "listcolumn.h" @@ -41,12 +51,12 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out ) #define MAX_NAME 30 #define SIDEBAR_WIDTH 30 - +*/ /* * Utility */ - +/* static string get_quality_name(const df::item_quality quality) { if (gps->dimx - SIDEBAR_WIDTH < 60) @@ -66,12 +76,12 @@ static df::item *get_container_of(df::unit *unit) auto ref = Units::getGeneralRef(unit, general_ref_type::CONTAINED_IN_ITEM); return (ref) ? ref->getItem() : nullptr; } - +*/ /* * Trade Info */ - +/* class TradeDepotInfo { public: @@ -168,12 +178,12 @@ private: }; static TradeDepotInfo depot_info; - +*/ /* * Item manipulation */ - +/* static map items_in_cages; static df::job *get_item_job(df::item *item) @@ -950,7 +960,7 @@ public: OutputHotkeyString(x, y, "Min Qual: ", "-+"); OutputString(COLOR_BROWN, x, y, get_quality_name(min_quality), true, left_margin); - OutputHotkeyString(x, y, "Max Qual: ", "/*"); + OutputHotkeyString(x, y, "Max Qual: ", "/ *"); OutputString(COLOR_BROWN, x, y, get_quality_name(max_quality), true, left_margin); OutputHotkeyString(x, y, "Min Wear: ", "Shift-W"); OutputString(COLOR_BROWN, x, y, int_to_string(min_wear), true, left_margin); @@ -1466,19 +1476,22 @@ static command_result stocks_cmd(color_ostream &out, vector & parameter return CR_WRONG_USAGE; } +*/ -DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) +DFhackCExport command_result plugin_init (color_ostream &out, vector &commands) { + /* commands.push_back(PluginCommand( "stocks", "An improved stocks management screen.", stocks_cmd)); ViewscreenStocks::reset(); - + */ return CR_OK; } +/* DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) { switch (event) { @@ -1491,3 +1504,4 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan return CR_OK; } +*/ From 2c626213d85f1b9689347ef9ecc5d89ae5b0d076 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Oct 2023 01:55:55 -0700 Subject: [PATCH 769/851] add overlay for collapsing all categories on stocks screen --- plugins/lua/stocks.lua | 55 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 plugins/lua/stocks.lua diff --git a/plugins/lua/stocks.lua b/plugins/lua/stocks.lua new file mode 100644 index 000000000..b87052530 --- /dev/null +++ b/plugins/lua/stocks.lua @@ -0,0 +1,55 @@ +local _ENV = mkmodule('plugins.stocks') + +local gui = require('gui') +local overlay = require('plugins.overlay') +local widgets = require('gui.widgets') + +local stocks = df.global.game.main_interface.stocks + +local function collapse_all() + local num_sections = #stocks.current_type_a_expanded + for idx=0,num_sections-1 do + stocks.current_type_a_expanded[idx] = false + end + stocks.i_height = num_sections * 3 +end + +-- ------------------- +-- StocksOverlay +-- + +StocksOverlay = defclass(StocksOverlay, overlay.OverlayWidget) +StocksOverlay.ATTRS{ + default_pos={x=-3,y=-20}, + default_enabled=true, + viewscreens='dwarfmode/Stocks', + frame={w=27, h=5}, + frame_style=gui.MEDIUM_FRAME, + frame_background=gui.CLEAR_PEN, +} + +function StocksOverlay:init() + self:addviews{ + widgets.HotkeyLabel{ + frame={t=0, l=0}, + label='collapse all', + key='CUSTOM_CTRL_X', + on_activate=collapse_all, + }, + widgets.Label{ + frame={t=2, l=0}, + text = 'Shift+Scroll', + text_pen=COLOR_LIGHTGREEN, + }, + widgets.Label{ + frame={t=2, l=12}, + text = ': fast scroll', + }, + } +end + +OVERLAY_WIDGETS = { + overlay=StocksOverlay, +} + +return _ENV From d14118216cc36f6dacea03f08b4b74f451c59f82 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Oct 2023 01:56:42 -0700 Subject: [PATCH 770/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0121e9e5c..b1bcbe5b4 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -63,6 +63,7 @@ Template for new versions: - `sort`: new search widgets for burrow assignment screen and other unit assignment dialogs - `sort`: new search widgets for artifacts on the world/raid screen - `sort`: new search widgets for slab engraving menu; can filter for only units that need a slab to prevent rising as a ghost +- `stocks`: hotkey for collapsing all categories on stocks screen ## Fixes - `buildingplan`: remove bars of ash, coal, and soap as valid building materials to match v50 rules From a651f6461b28941a25b2135ecc11b5cd8af6b207 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Oct 2023 03:27:08 -0700 Subject: [PATCH 771/851] add standard HelpButton and ConfigureButton classes and use them across the overlays that need them --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 21 ++++++ docs/plugins/buildingplan.rst | 61 +++++++++-------- library/lua/gui/widgets.lua | 76 ++++++++++++++++++++- plugins/lua/buildingplan/planneroverlay.lua | 10 ++- plugins/lua/orders.lua | 7 +- plugins/lua/sort.lua | 18 +---- plugins/lua/stockpiles.lua | 30 ++------ 8 files changed, 149 insertions(+), 75 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index b1bcbe5b4..0a82859fd 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -75,6 +75,7 @@ Template for new versions: ## Misc Improvements - `overlay`: allow ``overlay_onupdate_max_freq_seconds`` to be dynamically set to 0 for a burst of high-frequency updates +- Help icons added to several complex overlays. clicking the icon runs `gui/launcher` with the help text in the help area - `orders`: ``recheck`` command now only resets orders that have conditions that can be rechecked - `sort`: added help button for squad assignment search/filter/sort - `zone`: animals trained for war or hunting are now labeled as such in animal assignment screens diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index fd56a11ed..c46a9534c 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5207,6 +5207,27 @@ This is a specialized subclass of CycleHotkeyLabel that has two options: ``On`` (with a value of ``true``) and ``Off`` (with a value of ``false``). The ``On`` option is rendered in green. +HelpButton class +---------------- + +A 3x1 tile button with a question mark on it, intended to represent a help +icon. Clicking on the icon will launch `gui/launcher` with a given command +string, showing the help text for that command. + +It has the following attributes: + +:command: The command to load in `gui/launcher`. + +ConfigureButton class +--------------------- + +A 3x1 tile button with a gear mark on it, intended to represent a configure +icon. Clicking on the icon will run the given callback. + +It has the following attributes: + +:on_click: The function on run when the icon is clicked. + BannerPanel class ----------------- diff --git a/docs/plugins/buildingplan.rst b/docs/plugins/buildingplan.rst index 9cc7e68a2..db04a97f7 100644 --- a/docs/plugins/buildingplan.rst +++ b/docs/plugins/buildingplan.rst @@ -19,11 +19,11 @@ periodically scan for appropriate items and attach them to the planned building. Once all items are attached, the construction job will be unsuspended and a dwarf will come and build the building. If you have the `unsuspend` overlay enabled (it is enabled by default), then buildingplan-suspended -buildings will appear with a ``P`` marker on the main map, as opposed to the -usual ``x`` marker for "regular" suspended buildings. If you have -`suspendmanager` running, then buildings will be left suspended when their -items are all attached and ``suspendmanager`` will unsuspend them for -construction when it is safe to do so. +buildings will be tagged with a clock graphic in graphics mode or a ``P`` +marker in ASCII mode, as opposed to the ``x`` marker for "regular" suspended +buildings. If you have `suspendmanager` running, then buildings will be left +suspended when their items are all attached and ``suspendmanager`` will +unsuspend them for construction when it is safe to do so. If you want to impose restrictions on which items are chosen for the buildings, buildingplan has full support for quality and material filters (see `below @@ -45,10 +45,10 @@ from the buildingplan placement UI. One way to integrate buildingplan into your gameplay is to create manager workorders to ensure you always have a few blocks/doors/beds/etc. available. You -can then place as many of each building as you like. Produced items will be used -to build the planned buildings as they are produced, with minimal space -dedicated to stockpiles. The DFHack `orders` library can help with setting -these manager workorders up for you. +can then place as many of each building as you like. Items will be used to +build the planned buildings as they are produced, with minimal space dedicated +to stockpiles. The DFHack `orders` library can help with setting these manager +workorders up for you. If you don't want to use the ``buildingplan`` interface for the building you're currently trying to place, you can hit :kbd:`Alt`:kbd:`M` or click on the @@ -125,16 +125,17 @@ tiles selected in the construction area are not appropriate for building. For example, if you want to fill an area with flooring, you can select the entire area, and any tiles with existing buildings or walls will simply be skipped. -For weapon and spike traps, you can choose how many weapons will be included -on this panel. +Some building types will have other options available as well, such as a +selector for how many weapons you want in weapon traps or whether you want your +built cages to not have any occupants. Setting quality and material filters ++++++++++++++++++++++++++++++++++++ If you want to set restrictions on the items chosen to complete the planned -building, you can click on the "filter" button next to the item name or select -the item with the :kbd:`*` and :kbd:`/` keys and hit :kbd:`f` to bring up the -filter dialog. +building, you can click on the "[any material]" link next to the item name or +select the item with the :kbd:`q` or :kbd:`Q` keys and hit :kbd:`f` to bring up +the filter dialog. You can select whether the item must be decorated, and you can drag the ends of the "Item quality" slider to set your desired quality range. Note that blocks, @@ -147,32 +148,33 @@ You can click on specific materials to allow only items of those materials when building the current type of building. You can also allow or disallow entire categories of materials by clicking on the "Type" options on the left. Note that it is perfectly fine to choose materials that currently show zero quantity. -`buildingplan` will patiently watch for items made of materials you have -selected. +`buildingplan` will patiently wait for items made of materials you have +selected to become available. Choosing specific items +++++++++++++++++++++++ -If you want to choose specific items, click on the "Choose from items" toggle -or hit :kbd:`i` before placing the building. When you click to place the -building, a dialog will come up that allows you choose which items to use. The -list is sorted by most recently used materials for that building type by -default, but you can change to sort by name or by available quantity by -clicking on the "Sort by" selector or hitting :kbd:`R`. The configuration for -whether you would like to choose specific items is saved per building type and -will be restored when you plan more of that building type. +If you want to choose specific items instead of using the filters, click on the +"Choose items" selector or hit :kbd:`z` before placing the building. You can +choose to be prompted for every item ("Manually") or you can have it +automatically select the type of item that you last chose for this building +type. The list you are prompted with is sorted by most recently used materials +for that building type by default, but you can change to sort by name or by +available quantity by clicking on the "Sort by" selector or hitting :kbd:`R`. +The configuration for whether you would like to choose specific items is saved +per building type and will be restored when you plan more of that building type. You can select the maximum quantity of a specified item by clicking on the item name or selecting it with the arrow keys and hitting :kbd:`Enter`. You can instead select items one at a time by Ctrl-clicking (:kbd:`Shift`:kbd:`Right`) to increment or Ctrl-Shift-clicking (:kbd:`Shift`:kbd:`Left`) to decrement. -Once you are satisfied with your choices, click on the "Confirm" button or hit +Once you are satisfied with your choices, click on the large green button or hit :kbd:`C` to continue building. Note that you don't have to select all the items that the building needs. Any remaining items will be automatically chosen from -other available items (or future items if not all items are available yet). If -there are multiple item types to choose for the current building, one dialog -will appear per item type. +other available items (or from items produced in the future if not all items +are available yet). If there are multiple item types to choose for the current +building, one dialog will appear per item type. Building status --------------- @@ -180,7 +182,8 @@ Building status When viewing a planned building, a separate `overlay` widget appears on the building info sheet, showing you which items have been attached and which items are still pending. For a pending item, you can see its position in the -fulfillment queue. If there is a particular building that you need built ASAP, +fulfillment queue. You need to manufacture these items for them to be attached +to the building. If there is a particular building that you need built ASAP, you can click on the "make top priority" button (or hit :kbd:`Ctrl`:kbd:`T`) to bump the items for this building to the front of their respective queues. diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index f12ecff5d..912094fc4 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -4,6 +4,7 @@ local _ENV = mkmodule('gui.widgets') local gui = require('gui') local guidm = require('gui.dwarfmode') +local textures = require('gui.textures') local utils = require('utils') local getval = utils.getval @@ -1110,7 +1111,7 @@ end -- returns it (in parsed pen form) local function make_hpen(pen, hpen) if not hpen then - pen = dfhack.pen.parse(pen) + pen = to_pen(pen) -- Swap the foreground and background hpen = dfhack.pen.make(pen.bg, nil, pen.fg + (pen.bold and 8 or 0)) @@ -1119,7 +1120,7 @@ local function make_hpen(pen, hpen) -- text_hpen needs a character in order to paint the background using -- Painter:fill(), so let's make it paint a space to show the background -- color - local hpen_parsed = dfhack.pen.parse(hpen) + local hpen_parsed = to_pen(hpen) hpen_parsed.ch = string.byte(' ') return hpen_parsed end @@ -1504,6 +1505,77 @@ function HotkeyLabel:onInput(keys) end end +---------------- +-- HelpButton -- +---------------- + +HelpButton = defclass(HelpButton, Panel) + +HelpButton.ATTRS{ + command=DEFAULT_NIL, +} + +local button_pen_left = to_pen{fg=COLOR_CYAN, + tile=curry(textures.tp_control_panel, 7) or nil, ch=string.byte('[')} +local button_pen_right = to_pen{fg=COLOR_CYAN, + tile=curry(textures.tp_control_panel, 8) or nil, ch=string.byte(']')} +local help_pen_center = to_pen{ + tile=curry(textures.tp_control_panel, 9) or nil, ch=string.byte('?')} +local configure_pen_center = dfhack.pen.parse{ + tile=curry(textures.tp_control_panel, 10) or nil, ch=15} -- gear/masterwork symbol + +function HelpButton:preinit(init_table) + init_table.frame = init_table.frame or {} + init_table.frame.h = init_table.frame.h or 1 + init_table.frame.w = init_table.frame.w or 3 +end + +function HelpButton:init() + local command = self.command .. ' ' + + self:addviews{ + Label{ + frame={t=0, l=0, w=3, h=1}, + text={ + {tile=button_pen_left}, + {tile=help_pen_center}, + {tile=button_pen_right}, + }, + on_click=function() dfhack.run_command('gui/launcher', command) end, + }, + } +end + +--------------------- +-- ConfigureButton -- +--------------------- + +ConfigureButton = defclass(ConfigureButton, Panel) + +ConfigureButton.ATTRS{ + on_click=DEFAULT_NIL, +} + +function ConfigureButton:preinit(init_table) + init_table.frame = init_table.frame or {} + init_table.frame.h = init_table.frame.h or 1 + init_table.frame.w = init_table.frame.w or 3 +end + +function ConfigureButton:init() + self:addviews{ + Label{ + frame={t=0, l=0, w=3, h=1}, + text={ + {tile=button_pen_left}, + {tile=configure_pen_center}, + {tile=button_pen_right}, + }, + on_click=self.on_click, + }, + } +end + ----------------- -- BannerPanel -- ----------------- diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index 6241ff219..e5462e9c6 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -358,10 +358,10 @@ function PlannerOverlay:init() } local minimized_panel = widgets.Panel{ - frame={t=0, r=1, w=17, h=1}, + frame={t=0, r=1, w=20, h=1}, subviews={ widgets.Label{ - frame={t=0, r=0, h=1}, + frame={t=0, r=3, h=1}, text={ {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}, @@ -370,7 +370,7 @@ function PlannerOverlay:init() on_click=self:callback('toggle_minimized'), }, widgets.Label{ - frame={t=0, r=0, h=1}, + frame={t=0, r=3, h=1}, text={ {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}, @@ -378,6 +378,10 @@ function PlannerOverlay:init() visible=self:callback('is_not_minimized'), on_click=self:callback('toggle_minimized'), }, + widgets.HelpButton{ + frame={t=0, r=0}, + command='buildingplan', + } }, } diff --git a/plugins/lua/orders.lua b/plugins/lua/orders.lua index 0eeb327fc..d01ad79be 100644 --- a/plugins/lua/orders.lua +++ b/plugins/lua/orders.lua @@ -122,7 +122,7 @@ function OrdersOverlay:init() } local minimized_panel = widgets.Panel{ - frame={t=0, r=0, w=3, h=1}, + frame={t=0, r=4, w=3, h=1}, subviews={ widgets.Label{ frame={t=0, l=0, w=1, h=1}, @@ -149,6 +149,11 @@ function OrdersOverlay:init() self:addviews{ main_panel, minimized_panel, + widgets.HelpButton{ + frame={t=0, r=1}, + command='orders', + visible=function() return not self.minimized end, + }, } end diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index b27049e91..0e9f9256d 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -944,23 +944,11 @@ function SquadAssignmentOverlay:init() }, } - local button_pen_left = dfhack.pen.parse{fg=COLOR_CYAN, - tile=curry(textures.tp_control_panel, 7) or nil, ch=string.byte('[')} - local button_pen_right = dfhack.pen.parse{fg=COLOR_CYAN, - tile=curry(textures.tp_control_panel, 8) or nil, ch=string.byte(']')} - local help_pen_center = dfhack.pen.parse{ - tile=curry(textures.tp_control_panel, 9) or nil, ch=string.byte('?')} - self:addviews{ main_panel, - widgets.Label{ - frame={t=0, r=1, w=3}, - text={ - {tile=button_pen_left}, - {tile=help_pen_center}, - {tile=button_pen_right}, - }, - on_click=function() dfhack.run_command('gui/launcher', 'sort ') end, + widgets.HelpButton{ + frame={t=0, r=1}, + command='sort', }, } end diff --git a/plugins/lua/stockpiles.lua b/plugins/lua/stockpiles.lua index f25205a9c..76e0f800b 100644 --- a/plugins/lua/stockpiles.lua +++ b/plugins/lua/stockpiles.lua @@ -4,7 +4,6 @@ local argparse = require('argparse') local gui = require('gui') local logistics = require('plugins.logistics') local overlay = require('plugins.overlay') -local textures = require('gui.textures') local widgets = require('gui.widgets') local STOCKPILES_DIR = 'dfhack-config/stockpiles' @@ -477,15 +476,6 @@ function StockpilesOverlay:init() }, } - local button_pen_left = dfhack.pen.parse{fg=COLOR_CYAN, - tile=curry(textures.tp_control_panel, 7) or nil, ch=string.byte('[')} - local button_pen_right = dfhack.pen.parse{fg=COLOR_CYAN, - tile=curry(textures.tp_control_panel, 8) or nil, ch=string.byte(']')} - local help_pen_center = dfhack.pen.parse{ - tile=curry(textures.tp_control_panel, 9) or nil, ch=string.byte('?')} - local configure_pen_center = dfhack.pen.parse{ - tile=curry(textures.tp_control_panel, 10) or nil, ch=15} -- gear/masterwork symbol - self:addviews{ main_panel, MinimizeButton{ @@ -493,23 +483,13 @@ function StockpilesOverlay:init() get_minimized_fn=function() return self.minimized end, on_click=self:callback('toggleMinimized'), }, - widgets.Label{ - frame={t=0, r=5, w=3}, - text={ - {tile=button_pen_left}, - {tile=configure_pen_center}, - {tile=button_pen_right}, - }, + widgets.ConfigureButton{ + frame={t=0, r=5}, on_click=function() ConfigModal{on_close=self:callback('on_custom_config')}:show() end, }, - widgets.Label{ - frame={t=0, r=1, w=3}, - text={ - {tile=button_pen_left}, - {tile=help_pen_center}, - {tile=button_pen_right}, - }, - on_click=function() dfhack.run_command('gui/launcher', 'stockpiles ') end, + widgets.HelpButton{ + frame={t=0, r=1}, + command='stockpiles', }, } end From a0d41a78f7a1462246086415e578b6a9291a40ff Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 16 Oct 2023 10:53:25 +0000 Subject: [PATCH 772/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index af433af3a..2932e8ee7 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit af433af3ae34621ab8592d6ee419af347d607aca +Subproject commit 2932e8ee7d3298de09339f2033d5c5ba242659c4 From a09f122d7ea4129a9a17e103fbccb76aa977f46e Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 16 Oct 2023 11:08:36 -0500 Subject: [PATCH 773/851] implement simulated `Items::getCapacity` in support of `combine`, see #3307 --- docs/changelog.txt | 1 + library/LuaApi.cpp | 1 + library/include/modules/Items.h | 2 ++ library/modules/Items.cpp | 37 +++++++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0a82859fd..57a32117e 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -86,6 +86,7 @@ Template for new versions: - unavailable tools are no longer listed in the tag indices in the online docs ## API +- added ``Items::getCapacity``, returns the capacity of an item as a container (reverse-engineered), needed for `combine` ## Lua - added ``GRAY`` color aliases for ``GREY`` colors diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 5faec6d88..870c28697 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2139,6 +2139,7 @@ static const LuaWrapper::FunctionReg dfhack_items_module[] = { WRAPM(Items, markForTrade), WRAPM(Items, isRouteVehicle), WRAPM(Items, isSquadEquipment), + WRAPM(Items, getCapacity), WRAPN(moveToGround, items_moveToGround), WRAPN(moveToContainer, items_moveToContainer), WRAPN(moveToInventory, items_moveToInventory), diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h index 9daac1feb..05d0049cf 100644 --- a/library/include/modules/Items.h +++ b/library/include/modules/Items.h @@ -212,6 +212,8 @@ DFHACK_EXPORT bool isRequestedTradeGood(df::item *item, df::caravan_state *carav DFHACK_EXPORT bool isRouteVehicle(df::item *item); /// Checks whether the item is assigned to a squad DFHACK_EXPORT bool isSquadEquipment(df::item *item); +/// Returns the item's capacity as a storage container +DFHACK_EXPORT int32_t getCapacity(df::item* item); } } diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 983921576..72b96c18a 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -2283,3 +2283,40 @@ bool Items::isSquadEquipment(df::item *item) auto &vec = plotinfo->equipment.items_assigned[item->getType()]; return binsearch_index(vec, item->id) >= 0; } + +// reverse engineered, code reference: 0x140953150 in 50.11-win64-steam +// our name for this function: itemst::getCapacity +// bay12 name for this function: not known + +int32_t Items::getCapacity(df::item* item) +{ + CHECK_NULL_POINTER(item); + + switch (item->getType()) { + case df::enums::item_type::FLASK: + case df::enums::item_type::GOBLET: + return 180; + case df::enums::item_type::CAGE: + case df::enums::item_type::BARREL: + case df::enums::item_type::COFFIN: + case df::enums::item_type::BOX: + case df::enums::item_type::BAG: + case df::enums::item_type::BIN: + case df::enums::item_type::ARMORSTAND: + case df::enums::item_type::WEAPONRACK: + case df::enums::item_type::CABINET: + return 6000; + case df::enums::item_type::BUCKET: + return 600; + case df::enums::item_type::ANIMALTRAP: + case df::enums::item_type::BACKPACK: + return 3000; + case df::enums::item_type::QUIVER: + return 1200; + case df::enums::item_type::TOOL: + auto tool = virtual_cast(item); + if (tool) + return tool->subtype->container_capacity; + } + return 0; +} From 74dffc5f522ca0913e9549aa550a252672dc98b7 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 16 Oct 2023 11:17:33 -0500 Subject: [PATCH 774/851] add a `default:` to make gcc happy --- library/modules/Items.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 72b96c18a..cff4ff411 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -2317,6 +2317,7 @@ int32_t Items::getCapacity(df::item* item) auto tool = virtual_cast(item); if (tool) return tool->subtype->container_capacity; + default: } return 0; } From d859a9f420976d9edd7314e964d64dcaa7037f60 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Mon, 16 Oct 2023 11:27:55 -0500 Subject: [PATCH 775/851] more adjustments to make gcc happy --- library/modules/Items.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index cff4ff411..944334480 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -2314,10 +2314,14 @@ int32_t Items::getCapacity(df::item* item) case df::enums::item_type::QUIVER: return 1200; case df::enums::item_type::TOOL: - auto tool = virtual_cast(item); - if (tool) - return tool->subtype->container_capacity; + { + auto tool = virtual_cast(item); + if (tool) + return tool->subtype->container_capacity; + } + // fall through default: + ; // fall through to default exit } return 0; } From f59b7cb4387f506ebcd47e5b09ee05341e42fc26 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Oct 2023 10:09:01 -0700 Subject: [PATCH 776/851] fix devel/query command formatting --- docs/plugins/autobutcher.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/autobutcher.rst b/docs/plugins/autobutcher.rst index 7e5b6b024..4a0d64ae1 100644 --- a/docs/plugins/autobutcher.rst +++ b/docs/plugins/autobutcher.rst @@ -70,7 +70,7 @@ Usage ``autobutcher list_export`` Print commands required to set the current settings in another fort. -To see a list of all races, run this command: +To see a list of all races, run this command:: devel/query --table df.global.world.raws.creatures.all --search ^creature_id --maxdepth 1 From 94cd152224e2e62d111998dba1445f6bae423674 Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 16 Oct 2023 10:16:32 -0700 Subject: [PATCH 777/851] Update docs/changelog.txt --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 57a32117e..6bd21b8de 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -90,6 +90,7 @@ Template for new versions: ## Lua - added ``GRAY`` color aliases for ``GREY`` colors +- added ``dfhack.items.getCapacity`` to expose the new module API - ``utils.search_text``: text search routine (generalized from internal ``widgets.FilteredList`` logic) ## Removed From 28007199182284a2141dd1707d31348f0bc201b7 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 16 Oct 2023 19:04:07 +0000 Subject: [PATCH 778/851] 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 2469d0ede..b685d71c1 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 2469d0edea90044d969f5b686bf0eaf73a879063 +Subproject commit b685d71c152a05f8dc3752f74e9b7f7e73582468 diff --git a/scripts b/scripts index 2932e8ee7..744b450eb 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 2932e8ee7d3298de09339f2033d5c5ba242659c4 +Subproject commit 744b450eb3d706e3104eb19e07c501c3ffa87501 From 0fc4b15093188342150ee95d20582abd0497ecb0 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 16 Oct 2023 22:56:18 +0000 Subject: [PATCH 779/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 744b450eb..d83b1c970 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 744b450eb3d706e3104eb19e07c501c3ffa87501 +Subproject commit d83b1c97091f52c26db1b68f4050818a2c4ac2f1 From 29d39938f9115895b2fa372bd1901cbd3333dda0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Oct 2023 23:40:07 -0700 Subject: [PATCH 780/851] default the location filter to off to preserve default vanilla behavior --- plugins/lua/sort/locationselector.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/lua/sort/locationselector.lua b/plugins/lua/sort/locationselector.lua index f282d4561..f88095203 100644 --- a/plugins/lua/sort/locationselector.lua +++ b/plugins/lua/sort/locationselector.lua @@ -79,7 +79,7 @@ function LocationSelectorOverlay:init() frame={l=1, t=0, r=1}, label="Hide established:", key='CUSTOM_SHIFT_E', - initial_option=true, + initial_option=false, on_change=function() self:do_search(self.subviews.search.text, true) end, }, }, @@ -113,7 +113,7 @@ end function LocationSelectorOverlay:reset() LocationSelectorOverlay.super.reset(self) self.cache = nil - self.subviews.hide_established:setOption(true, false) + self.subviews.hide_established:setOption(false, false) end function LocationSelectorOverlay:get_cache() From fa78ec5fe84ddc590b2b036b32946c8c31a3a3a5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 17 Oct 2023 01:20:28 -0700 Subject: [PATCH 781/851] bump to 50.11-r2 --- CMakeLists.txt | 4 ++-- docs/changelog.txt | 18 ++++++++++++++++++ library/xml | 2 +- scripts | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ec38b28a..7f61bb111 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,8 +8,8 @@ project(dfhack) # set up versioning. set(DF_VERSION "50.11") -set(DFHACK_RELEASE "r2rc1") -set(DFHACK_PRERELEASE TRUE) +set(DFHACK_RELEASE "r2") +set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_ABI_VERSION 1) diff --git a/docs/changelog.txt b/docs/changelog.txt index 7a7b29391..c5df00ba8 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -51,6 +51,24 @@ Template for new versions: # Future +## New Tools + +## New Features + +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 50.11-r2 + ## New Tools - `spectate`: (reinstated) automatically follow dwarves, cycling among interesting ones - `preserve-tombs`: keep tombs assigned to units when they die diff --git a/library/xml b/library/xml index b685d71c1..b9c0733e9 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit b685d71c152a05f8dc3752f74e9b7f7e73582468 +Subproject commit b9c0733e943fb0d22a6717596128b8d44ba4ce04 diff --git a/scripts b/scripts index d83b1c970..1fcc83838 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit d83b1c97091f52c26db1b68f4050818a2c4ac2f1 +Subproject commit 1fcc83838e471fd8ef50cc6d6cb9259b69f1d847 From 3e35f7d89168046d860563a26a0dc82f9c110c9d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 17 Oct 2023 01:24:20 -0700 Subject: [PATCH 782/851] fix off by one error in template expansion --- .github/workflows/github-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 692897898..0a9768436 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -50,7 +50,7 @@ jobs: head -n $((TOKEN_LINE - 1)) .github/release_template.md > release_body.md CHANGELOG_LINES=$(wc -l <$CHANGELOG_FILE) tail -n $((CHANGELOG_LINES - 3)) $CHANGELOG_FILE >> release_body.md - tail -n 2 .github/release_template.md >> release_body.md + tail -n 1 .github/release_template.md >> release_body.md cat release_body.md - name: Stage release uses: actions/download-artifact@v3 From c6edee06318fe42d3230caf2296307bec3c677b4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 17 Oct 2023 01:39:27 -0700 Subject: [PATCH 783/851] one more off by one --- .github/workflows/github-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 0a9768436..8ce6a3bfa 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -49,7 +49,7 @@ jobs: TOKEN_LINE=$(grep -Fhne '%RELEASE_NOTES%' .github/release_template.md | sed 's/:.*//') head -n $((TOKEN_LINE - 1)) .github/release_template.md > release_body.md CHANGELOG_LINES=$(wc -l <$CHANGELOG_FILE) - tail -n $((CHANGELOG_LINES - 3)) $CHANGELOG_FILE >> release_body.md + tail -n $((CHANGELOG_LINES - 4)) $CHANGELOG_FILE >> release_body.md tail -n 1 .github/release_template.md >> release_body.md cat release_body.md - name: Stage release From ca16620b59f09dd0d335b64c7eeb131dd88915b0 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 19 Oct 2023 09:45:07 -0700 Subject: [PATCH 784/851] fix missing paren in PSA template text --- .github/release_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/release_template.md b/.github/release_template.md index 9431a4e18..5ca0a1983 100644 --- a/.github/release_template.md +++ b/.github/release_template.md @@ -50,7 +50,7 @@ Many DFHack tools that worked in previous (pre-Steam) versions of DF have not be The in-game interface for running DFHack commands (`gui/launcher`) will not show "unavailable" tools by default. You can still run them if you know their names, or you can turn on dev mode by hitting Ctrl-D while in `gui/launcher` and they will be added to the autocomplete list. Some tools do not compile yet and are not available at all, even when in dev mode. -If you see a tool complaining about the lack of a cursor, know that it's referring to the **keyboard** cursor (which used to be the only real option in Dwarf Fortress). You can enable the keyboard cursor by entering mining mode or selecting the dump/forbid tool and hitting Alt-K (the DFHack keybinding for `toggle-kbd-cursor`. We're working on making DFHack tools more mouse-aware and accessible so this step isn't necessary in the future. +If you see a tool complaining about the lack of a cursor, know that it's referring to the **keyboard** cursor (which used to be the only real option in Dwarf Fortress). You can enable the keyboard cursor by entering mining mode or selecting the dump/forbid tool and hitting Alt-K (the DFHack keybinding for `toggle-kbd-cursor`). We're working on making DFHack tools more mouse-aware and accessible so this step isn't necessary in the future. From f0a0814553bcd112bac8605a3cd61d34d2ca046b Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 26 Oct 2023 07:13:14 +0000 Subject: [PATCH 785/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 1fcc83838..5e7718c6d 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 1fcc83838e471fd8ef50cc6d6cb9259b69f1d847 +Subproject commit 5e7718c6db114ea776011d0aa7ca4cd120c149ff From 205d14235d907d2c0438291c276464af9f96c3c1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 26 Oct 2023 08:55:46 -0700 Subject: [PATCH 786/851] hide help and configure buttons when panel is minimized --- docs/changelog.txt | 1 + plugins/lua/stockpiles.lua | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index c5df00ba8..57c60072b 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -56,6 +56,7 @@ Template for new versions: ## New Features ## Fixes +- `stockpiles`: hide configure and help buttons when the overlay panel is minimized ## Misc Improvements diff --git a/plugins/lua/stockpiles.lua b/plugins/lua/stockpiles.lua index 76e0f800b..1173fa2d9 100644 --- a/plugins/lua/stockpiles.lua +++ b/plugins/lua/stockpiles.lua @@ -403,11 +403,15 @@ StockpilesOverlay.ATTRS{ function StockpilesOverlay:init() self.minimized = false + local function is_expanded() + return not self.minimized + end + local main_panel = widgets.Panel{ view_id='main', frame_style=gui.MEDIUM_FRAME, frame_background=gui.CLEAR_PEN, - visible=function() return not self.minimized end, + visible=is_expanded, subviews={ -- widgets.HotkeyLabel{ -- frame={t=0, l=0}, @@ -486,10 +490,12 @@ function StockpilesOverlay:init() widgets.ConfigureButton{ frame={t=0, r=5}, on_click=function() ConfigModal{on_close=self:callback('on_custom_config')}:show() end, + visible=is_expanded, }, widgets.HelpButton{ frame={t=0, r=1}, command='stockpiles', + visible=is_expanded, }, } end From 369ac7821c18ece490396c7dfb8a1de9fee35f88 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 26 Oct 2023 09:19:09 -0700 Subject: [PATCH 787/851] display how many items are available on the planner panel just like we display how many you'd need to make if you don't have enough --- docs/changelog.txt | 1 + plugins/lua/buildingplan/planneroverlay.lua | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index c5df00ba8..9eff28542 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,6 +58,7 @@ Template for new versions: ## Fixes ## Misc Improvements +- `buildingplan`: display how many items are available on the planner panel ## Documentation diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index e5462e9c6..688d3bf74 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -294,7 +294,7 @@ function ItemLine:get_item_line_text() uibs.building_type, uibs.building_subtype, uibs.custom_type, idx - 1) if self.available >= quantity then self.note_pen = COLOR_GREEN - self.note = ' Available now' + self.note = (' %d available now'):format(self.available) elseif self.available >= 0 then self.note_pen = COLOR_BROWN self.note = (' Will link next (need to make %d)'):format(quantity - self.available) From 966762c198f1baab9b9c6abcc3392aae6234976a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 26 Oct 2023 19:24:01 -0700 Subject: [PATCH 788/851] unify unit search key logic so all pages have the same search capabilities --- docs/changelog.txt | 1 + plugins/lua/sort.lua | 7 ++++--- plugins/lua/sort/info.lua | 17 +++++------------ plugins/lua/sort/slab.lua | 5 +---- plugins/lua/sort/sortoverlay.lua | 7 +++++++ plugins/lua/sort/unitselector.lua | 5 +---- 6 files changed, 19 insertions(+), 23 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index a89f59d42..0e21b5d04 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -60,6 +60,7 @@ Template for new versions: ## Misc Improvements - `buildingplan`: display how many items are available on the planner panel +- `sort`: allow searching by profession on the squad assignment page ## Documentation diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 0e9f9256d..604120f97 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -3,7 +3,7 @@ local _ENV = mkmodule('plugins.sort') local gui = require('gui') local overlay = require('plugins.overlay') local setbelief = reqscript('modtools/set-belief') -local textures = require('gui.textures') +local sortoverlay = require('plugins.sort.sortoverlay') local utils = require('utils') local widgets = require('gui.widgets') @@ -1031,7 +1031,7 @@ local function filter_matches(unit_id, filter) if filter.maimed == 'only' and not is_maimed(unit) then return false end if filter.maimed == 'exclude' and is_maimed(unit) then return false end if #filter.search == 0 then return true end - local search_key = dfhack.TranslateName(dfhack.units.getVisibleName(unit)) + local search_key = sortoverlay.get_unit_search_key(unit) return normalize_search_key(search_key):find(dfhack.toSearchNormalized(filter.search)) end @@ -1233,6 +1233,7 @@ local function init_face_tiles() FACE_TILES[idx-1] = face end end +init_face_tiles() function get_stress_face_tile(idx, x, y) local elem = rating_annotations[idx] @@ -1240,7 +1241,7 @@ function get_stress_face_tile(idx, x, y) return x == 0 and y == 1 and DASH_PEN or gui.CLEAR_PEN end local val = math.min(6, elem.val) - return FACE_TILES[val][y][x] + return safe_index(FACE_TILES, val, y, x) end function SquadAnnotationOverlay:init() diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index 1f15d643b..a48b1d986 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -97,16 +97,9 @@ local function get_sort() end end -local function get_unit_search_key(unit) - return ('%s %s %s'):format( - dfhack.units.getReadableName(unit), -- last name is in english - dfhack.units.getProfessionName(unit), - dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name -end - local function get_cri_unit_search_key(cri_unit) return ('%s %s'):format( - cri_unit.un and get_unit_search_key(cri_unit.un) or '', + cri_unit.un and sortoverlay.get_unit_search_key(cri_unit.un) or '', cri_unit.job_sort_name) end @@ -132,7 +125,7 @@ local function work_details_search(vec, data, text, incremental) data.selected = work_details.selected_work_detail_index end sortoverlay.single_vector_search( - {get_search_key_fn=get_unit_search_key}, + {get_search_key_fn=sortoverlay.get_unit_search_key}, vec, data, text, incremental) end @@ -161,7 +154,7 @@ end local function get_candidate_search_key(cand) if not cand.un then return end return ('%s %s'):format( - get_unit_search_key(cand.un), + sortoverlay.get_unit_search_key(cand.un), serialize_skills(cand.un)) end @@ -420,7 +413,7 @@ function InterrogationOverlay:init() self:register_handler('INTERROGATING', justice.interrogation_list, curry(sortoverlay.flags_vector_search, { - get_search_key_fn=get_unit_search_key, + get_search_key_fn=sortoverlay.get_unit_search_key, get_elem_id_fn=function(unit) return unit.id end, matches_filters_fn=self:callback('matches_filters'), }, @@ -428,7 +421,7 @@ function InterrogationOverlay:init() self:register_handler('CONVICTING', justice.conviction_list, curry(sortoverlay.single_vector_search, { - get_search_key_fn=get_unit_search_key, + get_search_key_fn=sortoverlay.get_unit_search_key, matches_filters_fn=self:callback('matches_filters'), })) end diff --git a/plugins/lua/sort/slab.lua b/plugins/lua/sort/slab.lua index 67cd8f753..5945763c9 100644 --- a/plugins/lua/sort/slab.lua +++ b/plugins/lua/sort/slab.lua @@ -5,7 +5,6 @@ local sortoverlay = require('plugins.sort.sortoverlay') local widgets = require('gui.widgets') local building = df.global.game.main_interface.building -local view_sheets = df.global.game.main_interface.view_sheets -- ---------------------- -- SlabOverlay @@ -95,9 +94,7 @@ end function SlabOverlay:get_search_key(if_button) local unit = get_unit(if_button) if not unit then return if_button.filter_str end - return ('%s %s'):format( - dfhack.units.getReadableName(unit), -- last name is in english - dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name + return sortoverlay.get_unit_search_key(unit) end local function needs_slab(if_button) diff --git a/plugins/lua/sort/sortoverlay.lua b/plugins/lua/sort/sortoverlay.lua index 75e31aa01..3d80bb70c 100644 --- a/plugins/lua/sort/sortoverlay.lua +++ b/plugins/lua/sort/sortoverlay.lua @@ -3,6 +3,13 @@ local _ENV = mkmodule('plugins.sort.sortoverlay') local overlay = require('plugins.overlay') local utils = require('utils') +function get_unit_search_key(unit) + return ('%s %s %s'):format( + dfhack.units.getReadableName(unit), -- last name is in english + dfhack.units.getProfessionName(unit), + dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name +end + local function copy_to_lua_table(vec) local tab = {} for k,v in ipairs(vec) do diff --git a/plugins/lua/sort/unitselector.lua b/plugins/lua/sort/unitselector.lua index a904d2f29..806d3ec77 100644 --- a/plugins/lua/sort/unitselector.lua +++ b/plugins/lua/sort/unitselector.lua @@ -20,10 +20,7 @@ UnitSelectorOverlay.ATTRS{ local function get_unit_id_search_key(unit_id) local unit = df.unit.find(unit_id) if not unit then return end - return ('%s %s %s'):format( - dfhack.units.getReadableName(unit), -- last name is in english - dfhack.units.getProfessionName(unit), - dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name + return sortoverlay.get_unit_search_key(unit) end function UnitSelectorOverlay:init() From 0e3e5e6b5ebbb911cdc2d4c4893ac09f11a08b37 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 27 Oct 2023 02:28:05 +0000 Subject: [PATCH 789/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 5e7718c6d..9c5e0fe83 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 5e7718c6db114ea776011d0aa7ca4cd120c149ff +Subproject commit 9c5e0fe836901ecb896fd61e9a2e984b19a5c500 From 435f8590009412ddf11e0c04628cacd6e65b3ff2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 27 Oct 2023 03:06:16 -0700 Subject: [PATCH 790/851] reinstate embark screen estimates --- docs/changelog.txt | 1 + docs/plugins/prospector.rst | 4 ++-- plugins/prospector.cpp | 34 ++++++++++++---------------------- 3 files changed, 15 insertions(+), 24 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0e21b5d04..1c16f3088 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -54,6 +54,7 @@ Template for new versions: ## New Tools ## New Features +- `prospect`: can now give you an estimate of resources from the embark screen. hover the mouse over a potential embark area and run `prospect`. ## Fixes - `stockpiles`: hide configure and help buttons when the overlay panel is minimized diff --git a/docs/plugins/prospector.rst b/docs/plugins/prospector.rst index 4628d11c8..68ec3d9b1 100644 --- a/docs/plugins/prospector.rst +++ b/docs/plugins/prospector.rst @@ -11,8 +11,8 @@ prospector .. dfhack-command:: prospect :summary: Shows a summary of resources that exist on the map. -It can also calculate an estimate of resources available in the selected embark -area. +It can also calculate an estimate of resources available in the currently +highlighted embark area. Usage ----- diff --git a/plugins/prospector.cpp b/plugins/prospector.cpp index 4f74661ba..3091f0703 100644 --- a/plugins/prospector.cpp +++ b/plugins/prospector.cpp @@ -567,26 +567,11 @@ static command_result embark_prospector(color_ostream &out, df::viewscreen_choose_start_sitest *screen, const prospect_options &options) { - out.printerr("prospector at embark is not currently available.\n"); - return CR_FAILURE; - -/* - if (!world || !world->world_data) - { + if (!world->world_data) { out.printerr("World data is not available.\n"); return CR_FAILURE; } - df::world_data *data = world->world_data; - coord2d cur_region = screen->location.region_pos; - auto cur_details = get_details(data, cur_region); - - if (!cur_details) - { - out.printerr("Current region details are not available.\n"); - return CR_FAILURE; - } - // Compute material maps MatMap layerMats; MatMap veinMats; @@ -595,12 +580,18 @@ static command_result embark_prospector(color_ostream &out, // Compute biomes std::map biomes; - for (int x = screen->location.embark_pos_min.x; x <= 15 && x <= screen->location.embark_pos_max.x; x++) - { - for (int y = screen->location.embark_pos_min.y; y <= 15 && y <= screen->location.embark_pos_max.y; y++) - { + int32_t max_x = (world->worldgen.worldgen_parms.dim_x * 16) - 1; + int32_t max_y = (world->worldgen.worldgen_parms.dim_y * 16) - 1; + + for (int x = screen->location.embark_pos_min.x; x <= max_x && x <= screen->location.embark_pos_max.x; ++x) { + for (int y = screen->location.embark_pos_min.y; y <= max_y && y <= screen->location.embark_pos_max.y; ++y) { + auto cur_details = get_details(world->world_data, coord2d(x / 16, y / 16)); + + if (!cur_details) + continue; + EmbarkTileLayout tile; - if (!estimate_underground(out, tile, cur_details, x, y) || + if (!estimate_underground(out, tile, cur_details, x % 16, y % 16) || !estimate_materials(out, tile, layerMats, veinMats)) return CR_FAILURE; @@ -627,7 +618,6 @@ static command_result embark_prospector(color_ostream &out, out << std::endl << "Warning: the above data is only a very rough estimate." << std::endl; return CR_OK; -*/ } static command_result map_prospector(color_ostream &con, From 44ac9f4c8f1e2b29568fa235cb7f79bb4147ba48 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 27 Oct 2023 03:45:31 -0700 Subject: [PATCH 791/851] optionally highlight the zoom target tile --- docs/changelog.txt | 2 ++ docs/dev/Lua API.rst | 10 ++++++---- library/LuaApi.cpp | 10 +++++++++- library/include/modules/Gui.h | 4 ++-- library/modules/Gui.cpp | 10 ++++++++-- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0e21b5d04..603bcadaa 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -65,8 +65,10 @@ Template for new versions: ## Documentation ## API +- ``Gui::revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target ## Lua +- ``dfhack.gui.revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index c46a9534c..4a103ef5e 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1053,11 +1053,13 @@ Fortress mode Same as ``resetDwarfmodeView``, but also recenter if position is valid. If ``pause`` is false, skip pausing. Respects ``RECENTER_INTERFACE_SHUTDOWN_MS`` in DF's ``init.txt`` (the delay before input is recognized when a recenter occurs.) -* ``dfhack.gui.revealInDwarfmodeMap(pos[,center])`` - ``dfhack.gui.revealInDwarfmodeMap(x,y,z[,center])`` +* ``dfhack.gui.revealInDwarfmodeMap(pos[,center[,highlight]])`` + ``dfhack.gui.revealInDwarfmodeMap(x,y,z[,center[,highlight]])`` - Centers the view on the given coordinates. If ``center`` is true, make sure the - position is in the exact center of the view, else just bring it on screen. + Centers the view on the given coordinates. If ``center`` is true, make sure + the position is in the exact center of the view, else just bring it on screen. + If ``highlight`` is true, then mark the target tile with a pulsing highlight + until the player clicks somewhere else. ``pos`` can be a ``df.coord`` instance or a table assignable to a ``df.coord`` (see `lua-api-table-assignment`), e.g.:: diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 870c28697..5469ab2cc 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1660,11 +1660,19 @@ static int gui_revealInDwarfmodeMap(lua_State *state) switch (lua_gettop(state)) { default: + case 5: + rv = Gui::revealInDwarfmodeMap(CheckCoordXYZ(state, 1, false), lua_toboolean(state, 4), lua_toboolean(state, 5)); + break; case 4: rv = Gui::revealInDwarfmodeMap(CheckCoordXYZ(state, 1, false), lua_toboolean(state, 4)); break; case 3: - rv = Gui::revealInDwarfmodeMap(CheckCoordXYZ(state, 1, false)); + if (lua_isboolean(state, 3)) { + Lua::CheckDFAssign(state, &p, 1); + rv = Gui::revealInDwarfmodeMap(p, lua_toboolean(state, 2), lua_toboolean(state, 3)); + } + else + rv = Gui::revealInDwarfmodeMap(CheckCoordXYZ(state, 1, false)); break; case 2: Lua::CheckDFAssign(state, &p, 1); diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h index bbdaa0d39..03ca4a2c1 100644 --- a/library/include/modules/Gui.h +++ b/library/include/modules/Gui.h @@ -165,8 +165,8 @@ namespace DFHack DFHACK_EXPORT DwarfmodeDims getDwarfmodeViewDims(); DFHACK_EXPORT void resetDwarfmodeView(bool pause = false); - DFHACK_EXPORT bool revealInDwarfmodeMap(int32_t x, int32_t y, int32_t z, bool center = false); - DFHACK_EXPORT inline bool revealInDwarfmodeMap(df::coord pos, bool center = false) { return revealInDwarfmodeMap(pos.x, pos.y, pos.z, center); }; + DFHACK_EXPORT bool revealInDwarfmodeMap(int32_t x, int32_t y, int32_t z, bool center = false, bool highlight = false); + DFHACK_EXPORT inline bool revealInDwarfmodeMap(df::coord pos, bool center = false, bool highlight = false) { return revealInDwarfmodeMap(pos.x, pos.y, pos.z, center, highlight); }; DFHACK_EXPORT bool pauseRecenter(int32_t x, int32_t y, int32_t z, bool pause = true); DFHACK_EXPORT inline bool pauseRecenter(df::coord pos, bool pause = true) { return pauseRecenter(pos.x, pos.y, pos.z, pause); }; DFHACK_EXPORT bool refreshSidebar(); diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 500676983..04800779d 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -2094,13 +2094,13 @@ void Gui::resetDwarfmodeView(bool pause) *df::global::pause_state = true; } -bool Gui::revealInDwarfmodeMap(int32_t x, int32_t y, int32_t z, bool center) +bool Gui::revealInDwarfmodeMap(int32_t x, int32_t y, int32_t z, bool center, bool highlight) { // Reverse-engineered from DF announcement and scrolling code using df::global::window_x; using df::global::window_y; using df::global::window_z; - if (!window_x || !window_y || !window_z || !world) + if (!window_x || !window_y || !window_z || !world || !game) return false; auto dims = getDwarfmodeViewDims(); @@ -2137,6 +2137,12 @@ bool Gui::revealInDwarfmodeMap(int32_t x, int32_t y, int32_t z, bool center) game->minimap.update = true; game->minimap.mustmake = true; + if (highlight) { + game->main_interface.recenter_indicator_m.x = x; + game->main_interface.recenter_indicator_m.y = y; + game->main_interface.recenter_indicator_m.z = z; + } + return true; } From 7ff30f7c9eeb316c13e034dfa1f685d84991939e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 27 Oct 2023 04:15:59 -0700 Subject: [PATCH 792/851] rename burrows plugin to burrow to match the command name --- docs/plugins/{burrows.rst => burrow.rst} | 0 plugins/{burrows.cpp => burrow.cpp} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename docs/plugins/{burrows.rst => burrow.rst} (100%) rename plugins/{burrows.cpp => burrow.cpp} (100%) diff --git a/docs/plugins/burrows.rst b/docs/plugins/burrow.rst similarity index 100% rename from docs/plugins/burrows.rst rename to docs/plugins/burrow.rst diff --git a/plugins/burrows.cpp b/plugins/burrow.cpp similarity index 100% rename from plugins/burrows.cpp rename to plugins/burrow.cpp From 5d98282623d634761bf62305712facb1bbd2e9d1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 27 Oct 2023 04:23:02 -0700 Subject: [PATCH 793/851] also rename lua file --- plugins/lua/{burrows.lua => burrow.lua} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename plugins/lua/{burrows.lua => burrow.lua} (100%) diff --git a/plugins/lua/burrows.lua b/plugins/lua/burrow.lua similarity index 100% rename from plugins/lua/burrows.lua rename to plugins/lua/burrow.lua From a962699f98547a1b8857815eb9c0b2e8e34ff6a6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 27 Oct 2023 04:42:47 -0700 Subject: [PATCH 794/851] fix doc reference --- docs/dev/Lua API.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index c46a9534c..b59bfa747 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5601,10 +5601,10 @@ Native functions provided by the `buildingplan` plugin: * ``void doCycle()`` runs a check for whether buildings in the monitor list can be assigned items and unsuspended. This method runs automatically twice a game day, so you only need to call it directly if you want buildingplan to do a check right now. * ``void scheduleCycle()`` schedules a cycle to be run during the next non-paused game frame. Can be called multiple times while the game is paused and only one cycle will be scheduled. -burrows -======= +burrow +====== -The `burrows` plugin implements extended burrow manipulations. +The `burrow` plugin implements extended burrow manipulations. Events: From 4e864ae2dc3f8513b74c8c16514f19bead4a2c14 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 27 Oct 2023 22:23:51 -0700 Subject: [PATCH 795/851] adjust price of vermin swarms --- docs/changelog.txt | 1 + library/modules/Items.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1c0dbd9f2..de74e37b8 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,6 +58,7 @@ Template for new versions: ## Fixes - `stockpiles`: hide configure and help buttons when the overlay panel is minimized +- `caravan`: price of vermin swarms correctly adjusted down. a stack of 10000 is worth 1, not 10000 ## Misc Improvements - `buildingplan`: display how many items are available on the planner panel diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 944334480..1a9ca1fa6 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -2042,8 +2042,12 @@ int Items::getValue(df::item *item, df::caravan_state *caravan) { int divisor = 1; auto creature = vector_get(world->raws.creatures.all, mat_type); - if (creature && size_t(mat_subtype) < creature->caste.size()) - divisor = creature->caste[mat_subtype]->misc.petvalue_divisor; + if (creature) { + if (creature->flags.is_set(df::creature_raw_flags::VERMIN_SOIL_COLONY)) + divisor = 10000; + else if (size_t(mat_subtype) < creature->caste.size()) + divisor = creature->caste[mat_subtype]->misc.petvalue_divisor; + } if (divisor > 1) value /= divisor; } From 7103cd58903a929e54ea1c63f94520519050ac4c Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 28 Oct 2023 07:12:37 +0000 Subject: [PATCH 796/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 9c5e0fe83..996c04010 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 9c5e0fe836901ecb896fd61e9a2e984b19a5c500 +Subproject commit 996c0401051c09f65a3c048f337f891b99aa142c From 5f6cfcdbe7491e453b4ab9e3e9b79e9789f6519e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 28 Oct 2023 10:25:26 -0700 Subject: [PATCH 797/851] don't special case vermin; fallback on caste instead --- library/modules/Items.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 1a9ca1fa6..a91ea3470 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -2043,13 +2043,15 @@ int Items::getValue(df::item *item, df::caravan_state *caravan) int divisor = 1; auto creature = vector_get(world->raws.creatures.all, mat_type); if (creature) { - if (creature->flags.is_set(df::creature_raw_flags::VERMIN_SOIL_COLONY)) - divisor = 10000; - else if (size_t(mat_subtype) < creature->caste.size()) - divisor = creature->caste[mat_subtype]->misc.petvalue_divisor; + size_t caste = std::max(0, mat_subtype); + if (caste < creature->caste.size()) + divisor = creature->caste[caste]->misc.petvalue_divisor; } - if (divisor > 1) + if (divisor > 1) { value /= divisor; + if (!value) + value = 1; + } } // Add in value from units contained in cages From 31b568b2d1214f827ed4cad861b00f90c1774db2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 28 Oct 2023 10:26:55 -0700 Subject: [PATCH 798/851] update changelog --- docs/changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index de74e37b8..d8e4a6ad4 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,7 +58,7 @@ Template for new versions: ## Fixes - `stockpiles`: hide configure and help buttons when the overlay panel is minimized -- `caravan`: price of vermin swarms correctly adjusted down. a stack of 10000 is worth 1, not 10000 +- `caravan`: price of vermin swarms correctly adjusted down. a stack of 10000 bees is worth 10, not 10000 ## Misc Improvements - `buildingplan`: display how many items are available on the planner panel From 19480f41ca2aca062e99967aa94ae25d98ca36d3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 29 Oct 2023 16:36:02 -0700 Subject: [PATCH 799/851] add api for getting the walkability group of a tile --- docs/changelog.txt | 2 ++ docs/dev/Lua API.rst | 11 ++++++++--- library/LuaApi.cpp | 1 + library/include/modules/Maps.h | 1 + library/modules/Maps.cpp | 15 +++++++-------- plugins/buildingplan/buildingplan_cycle.cpp | 13 ++++--------- 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1c0dbd9f2..aaa508018 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -67,9 +67,11 @@ Template for new versions: ## API - ``Gui::revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target +- ``Maps::getWalkableGroup``: get the walkability group of a tile ## Lua - ``dfhack.gui.revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target +- ``dfhack.maps.getWalkableGroup``: get the walkability group of a tile ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 4a103ef5e..202454040 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1912,10 +1912,11 @@ Maps module Returns the plant struct that owns the tile at the specified position. -* ``dfhack.maps.canWalkBetween(pos1, pos2)`` +* ``dfhack.maps.getWalkableGroup(pos)`` - Checks if a dwarf may be able to walk between the two tiles, - using a pathfinding cache maintained by the game. + Returns the walkability group for the given tile position. A return value of + ``0`` indicates that the tile is not walkable. The data comes from a + pathfinding cache maintained by DF. .. note:: This cache is only updated when the game is unpaused, and thus @@ -1924,6 +1925,10 @@ Maps module take into account anything that depends on the actual units, like burrows, or the presence of invaders. +* ``dfhack.maps.canWalkBetween(pos1, pos2)`` + + Checks if both positions are walkable and also share a walkability group. + * ``dfhack.maps.hasTileAssignment(tilemask)`` Checks if the tile_bitmask object is not *nil* and contains any set bits; returns *true* or *false*. diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 5469ab2cc..1fd4b5ecf 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2239,6 +2239,7 @@ static const LuaWrapper::FunctionReg dfhack_maps_module[] = { WRAPM(Maps, enableBlockUpdates), WRAPM(Maps, getGlobalInitFeature), WRAPM(Maps, getLocalInitFeature), + WRAPM(Maps, getWalkableGroup), WRAPM(Maps, canWalkBetween), WRAPM(Maps, spawnFlow), WRAPN(hasTileAssignment, hasTileAssignment), diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index 2b7d768d0..9bb1dda25 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -339,6 +339,7 @@ extern DFHACK_EXPORT bool SortBlockEvents(df::map_block *block, extern DFHACK_EXPORT bool RemoveBlockEvent(int32_t x, int32_t y, int32_t z, df::block_square_event * which ); extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, df::block_square_event * which ); // todo: deprecate me +DFHACK_EXPORT uint16_t getWalkableGroup(df::coord pos); DFHACK_EXPORT bool canWalkBetween(df::coord pos1, df::coord pos2); DFHACK_EXPORT bool canStepBetween(df::coord pos1, df::coord pos2); diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index 2e831075d..a05474fa5 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -622,16 +622,15 @@ bool Maps::ReadGeology(vector > *layer_mats, vector return true; } +uint16_t Maps::getWalkableGroup(df::coord pos) { + auto block = getTileBlock(pos); + return block ? index_tile(block->walkable, pos) : 0; +} + bool Maps::canWalkBetween(df::coord pos1, df::coord pos2) { - auto block1 = getTileBlock(pos1); - auto block2 = getTileBlock(pos2); - - if (!block1 || !block2) - return false; - - auto tile1 = index_tile(block1->walkable, pos1); - auto tile2 = index_tile(block2->walkable, pos2); + auto tile1 = getWalkableGroup(pos1); + auto tile2 = getWalkableGroup(pos2); return tile1 && tile1 == tile2; } diff --git a/plugins/buildingplan/buildingplan_cycle.cpp b/plugins/buildingplan/buildingplan_cycle.cpp index c43834b36..0a3f0d867 100644 --- a/plugins/buildingplan/buildingplan_cycle.cpp +++ b/plugins/buildingplan/buildingplan_cycle.cpp @@ -12,7 +12,6 @@ #include "df/item.h" #include "df/item_slabst.h" #include "df/job.h" -#include "df/map_block.h" #include "df/world.h" #include @@ -48,14 +47,10 @@ struct BadFlags { // 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 "); - } + uint16_t walkability_group = Maps::getWalkableGroup(item_pos); + bool 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; } From 89a649c790bc3faf5e5c0c7c2720e165b97f0c19 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 28 Oct 2023 00:37:02 -0700 Subject: [PATCH 800/851] update docs --- docs/plugins/burrow.rst | 115 +++++++++++++++++++++++++++------------- 1 file changed, 79 insertions(+), 36 deletions(-) diff --git a/docs/plugins/burrow.rst b/docs/plugins/burrow.rst index b1c966ea2..c366b2787 100644 --- a/docs/plugins/burrow.rst +++ b/docs/plugins/burrow.rst @@ -1,46 +1,36 @@ -burrows -======= +burrow +====== .. dfhack-tool:: - :summary: Auto-expand burrows as you dig. - :tags: unavailable - :no-command: + :summary: Quickly adjust burrow tiles and units. + :tags: fort auto design productivity units -.. dfhack-command:: burrow - :summary: Quickly add units/tiles to burrows. +This tool has two modes. When enabled, it monitors burrows with names that end +in ``+``. If a wall at the edge of such a burrow is dug out, the burrow will be +automatically extended to include the newly-revealed adjacent walls. -When a wall inside a burrow with a name ending in ``+`` is dug out, the burrow -will be extended to newly-revealed adjacent walls. +When run as a command, it can quickly adjust which tiles and/or units are +associated with the burrow. Usage ----- -``burrow enable auto-grow`` - When a wall inside a burrow with a name ending in '+' is dug out, the burrow - will be extended to newly-revealed adjacent walls. This final '+' may be - omitted in burrow name args of other ``burrow`` commands. Note that digging - 1-wide corridors with the miner inside the burrow is SLOW. -``burrow disable auto-grow`` - Disables auto-grow processing. -``burrow clear-unit [ ...]`` - Remove all units from the named burrows. -``burrow clear-tiles [ ...]`` - Remove all tiles from the named burrows. -``burrow set-units target-burrow [ ...]`` - Clear all units from the target burrow, then add units from the named source - burrows. -``burrow add-units target-burrow [ ...]`` - Add units from the source burrows to the target. -``burrow remove-units target-burrow [ ...]`` - Remove units in source burrows from the target. -``burrow set-tiles target-burrow [ ...]`` - Clear target burrow tiles and add tiles from the names source burrows. -``burrow add-tiles target-burrow [ ...]`` - Add tiles from the source burrows to the target. -``burrow remove-tiles target-burrow [ ...]`` - Remove tiles in source burrows from the target. - -In place of a source burrow, you can use one of the following keywords: +:: + + enable burrow + burrow tiles|units clear [ ...] [] + burrow tiles|units set|add|remove [...] [] + burrow tiles box-add|box-remove [] [] + burrow tiles flood-add|flood-remove [] + +The burrows can be referenced by name or by the internal numeric burrow ID. If +referenced by name, all burrows that match the name (case sensitive) will be +included. If a burrow name ends in ``+`` (to indicate that it should be +auto-expanded), the final ``+`` does not need to be specified on the +commandline. + +For ``set``, ``add``, or ``remove`` commands, instead of a burrow, you can +specify one of the following all-caps keywords: - ``ABOVE_GROUND`` - ``SUBTERRANEAN`` @@ -51,4 +41,57 @@ In place of a source burrow, you can use one of the following keywords: - ``HIDDEN`` - ``REVEALED`` -to add tiles with the given properties. +to add or remove tiles with the corresponding properties. + +For flood fill, all tiles that match the properties (from the list above) of +the specified start tile will be included. When flood adding, the flood fill +will also stop at any tiles that have already been added to the burrow. +Similarly for flood removing, the flood will also stop at tiles that are not in +the burrow. + +Examples +-------- + +``enable burrow`` + Start monitoring burrows that have names ending in '+' and automatically + expand them when walls that border the burrows are dug out. +``burrow tiles clear Safety`` + Remove all tiles from the burrow named ``Safety`` (in preparation for + adding new tiles elsewhere, presumably). +``burrow units clear Farmhouse Workshops`` + Remove all units from the burrows named ``Farmhouse`` and ``Workshops``. +``multicmd burrow tiles set Inside INSIDE; burrow tiles remove Inside HIDDEN`` + Reset the burrow named ``Inside`` to include all the currently revealed, + interior tiles. +``burrow units set "Core Fort" Peasants Skilled`` + Clear all units from the burrow named ``Core Fort``, then add units + currently assigned to the ``Peasants`` and ``Skilled`` burrows. +``burrow tiles box-add Safety 0,0,0`` + Add all tiles to the burrow named ``Safety`` that are within the volume of + the box starting at coordinate 0, 0, 0 (the upper left corner of the bottom + level) and ending at the current location of the keyboard cursor. +``burrow tiles flood-add Safety --cur-zlevel`` + Flood-add the tiles on the current z-level with the same properties as the + tile under the keyboard cursor to the burrow named ``Safety``. + +Options +------- + +``-c``, ``--cursor `` + Indicate the starting position of the box or flood fill. If not specified, + the position of the keyboard cursor is used. +``-d``, ``--dry-run`` + Report what would be done, but don't actually change anything. +``-z``, ``--cur-zlevel`` + Restricts the operation to the currently visible z-level. + +Note +---- + +If you are auto-expanding a burrow (whose name ends in a ``+``) and the miner +who is digging to expand the burrow is assigned to that burrow, then 1-wide +corridors that expand the burrow will have very slow progress. This is because +the burrow is expanded to include the next dig job only after the miner has +chosen a next tile to dig, which may be far away. 2-wide cooridors are much +more efficient when expanding a burrow since the "next" tile to dig will still +be nearby. From ad998001b601875a08d528a5428d30143a0cc9d2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 28 Oct 2023 00:37:24 -0700 Subject: [PATCH 801/851] implement skeleton for UI handling --- plugins/lua/burrow.lua | 144 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) diff --git a/plugins/lua/burrow.lua b/plugins/lua/burrow.lua index 7c8753bf7..e3c2d0bfa 100644 --- a/plugins/lua/burrow.lua +++ b/plugins/lua/burrow.lua @@ -1,4 +1,4 @@ -local _ENV = mkmodule('plugins.burrows') +local _ENV = mkmodule('plugins.burrow') --[[ @@ -18,6 +18,148 @@ local _ENV = mkmodule('plugins.burrows') --]] +local overlay = require('plugins.overlay') +local widgets = require('gui.widgets') + +local selection_rect = df.global.selection_rect +local if_burrow = df.global.game.main_interface.burrow + +local function is_choosing_area(pos) + return if_burrow.doing_rectangle and + selection_rect.start_x >= 0 and + (pos or dfhack.gui.getMousePos()) +end + +local function reset_selection_rect() + selection_rect.start_x = -30000 + selection_rect.start_y = -30000 + selection_rect.start_z = -30000 +end + +local function get_bounds(pos) + pos = pos or dfhack.gui.getMousePos() + local bounds = { + x1=math.min(selection_rect.start_x, pos.x), + x2=math.max(selection_rect.start_x, pos.x), + y1=math.min(selection_rect.start_y, pos.y), + y2=math.max(selection_rect.start_y, pos.y), + z1=math.min(selection_rect.start_z, pos.z), + z2=math.max(selection_rect.start_z, pos.z), + } + + -- clamp to map edges + bounds = { + x1=math.max(0, bounds.x1), + x2=math.min(df.global.world.map.x_count-1, bounds.x2), + y1=math.max(0, bounds.y1), + y2=math.min(df.global.world.map.y_count-1, bounds.y2), + z1=math.max(0, bounds.z1), + z2=math.min(df.global.world.map.z_count-1, bounds.z2), + } + + return bounds +end + +local function get_cur_area_dims() + local bounds = get_bounds() + return bounds.x2 - bounds.x1 + 1, + bounds.y2 - bounds.y1 + 1, + bounds.z2 - bounds.z1 + 1 +end + +BurrowDesignationOverlay = defclass(BurrowDesignationOverlay, overlay.OverlayWidget) +BurrowDesignationOverlay.ATTRS{ + default_pos={x=6,y=8}, + viewscreens='dwarfmode/Burrow/Paint', + default_enabled=true, + frame={w=30, h=2}, +} + +function BurrowDesignationOverlay:init() + self:addviews{ + widgets.BannerPanel{ + frame={t=0, l=0}, + subviews={ + widgets.Label{ + frame={t=0, l=1}, + text='Double-click to flood fill.', + }, + }, + }, + widgets.BannerPanel{ + frame={t=1, l=0}, + subviews={ + widgets.Label{ + frame={t=0, l=1}, + text_pen=COLOR_DARKGREY, + text={ + 'Selected area: ', + {text=function() return ('%dx%dx%d'):format(get_cur_area_dims()) end}, + }, + }, + }, + visible=is_choosing_area, + }, + } +end + +local function flood_fill(pos, painting_burrow) + print('flood fill, erasing:', if_burrow.erasing) + print('origin pos:') + printall(pos) + reset_selection_rect() +end + +local function box_fill(bounds, painting_burrow) + print('box fill, erasing:', if_burrow.erasing) + print('bounds:') + printall(bounds) + if bounds.z1 == bounds.z2 then return end +end + +function BurrowDesignationOverlay:onInput(keys) + if self:inputToSubviews(keys) then + return true + -- don't perform burrow modifications immediately -- painting_burrow may not yet + -- have been initialized. instead, allow clicks to go through so that vanilla + -- behavior is triggered before we modify the burrow further + elseif keys._MOUSE_L then + local pos = dfhack.gui.getMousePos() + if pos then + local now_ms = dfhack.getTickCount() + if not same_xyz(pos, self.saved_pos) then + self.last_click_ms = now_ms + self.saved_pos = pos + else + if now_ms - self.last_click_ms <= widgets.DOUBLE_CLICK_MS then + self.last_click_ms = 0 + self.pending_fn = curry(flood_fill, pos) + return + else + self.last_click_ms = now_ms + end + end + if is_choosing_area(pos) then + self.pending_fn = curry(box_fill, get_bounds(pos)) + return + end + end + end +end + +function BurrowDesignationOverlay:onRenderBody(dc) + BurrowDesignationOverlay.super.onRenderBody(self, dc) + local pending_fn = self.pending_fn + self.pending_fn = nil + if pending_fn and if_burrow.painting_burrow then + pending_fn(if_burrow.painting_burrow) + end +end + +OVERLAY_WIDGETS = { + designation=BurrowDesignationOverlay, +} + rawset_default(_ENV, dfhack.burrows) return _ENV From 352397519453d918cd4dbed311971fde7c209dae Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 28 Oct 2023 00:37:43 -0700 Subject: [PATCH 802/851] re-add burrow to the build --- plugins/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 114386ad3..efeae25f9 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -90,7 +90,7 @@ if(BUILD_SUPPORTED) dfhack_plugin(autonestbox autonestbox.cpp LINK_LIBRARIES lua) dfhack_plugin(autoslab autoslab.cpp) dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua) - #dfhack_plugin(burrows burrows.cpp LINK_LIBRARIES lua) + dfhack_plugin(burrow burrow.cpp LINK_LIBRARIES lua) #dfhack_plugin(building-hacks building-hacks.cpp LINK_LIBRARIES lua) add_subdirectory(buildingplan) dfhack_plugin(changeitem changeitem.cpp) From cf1e4e69ca94af0d410a96114d883d54704121a3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 28 Oct 2023 19:26:15 -0700 Subject: [PATCH 803/851] basic commandline processing and skeleton lua interface --- docs/plugins/burrow.rst | 6 +- plugins/burrow.cpp | 380 +++++++++++++++++++++++++++++++++++++--- plugins/lua/burrow.lua | 141 ++++++++++++--- 3 files changed, 476 insertions(+), 51 deletions(-) diff --git a/docs/plugins/burrow.rst b/docs/plugins/burrow.rst index c366b2787..b14be928c 100644 --- a/docs/plugins/burrow.rst +++ b/docs/plugins/burrow.rst @@ -20,12 +20,12 @@ Usage enable burrow burrow tiles|units clear [ ...] [] burrow tiles|units set|add|remove [...] [] - burrow tiles box-add|box-remove [] [] + burrow tiles box-add|box-remove [] [] [] burrow tiles flood-add|flood-remove [] The burrows can be referenced by name or by the internal numeric burrow ID. If -referenced by name, all burrows that match the name (case sensitive) will be -included. If a burrow name ends in ``+`` (to indicate that it should be +referenced by name, the first burrow that matches the name (case sensitive) +will be targeted. If a burrow name ends in ``+`` (to indicate that it should be auto-expanded), the final ``+`` does not need to be specified on the commandline. diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index c39253488..4a6d8ee8b 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -1,3 +1,361 @@ +#include "Core.h" +#include "Debug.h" +#include "LuaTools.h" +#include "PluginManager.h" + +#include "modules/Burrows.h" +#include "modules/Persistence.h" +#include "modules/World.h" + +#include "df/burrow.h" +#include "df/world.h" + +using std::vector; +using std::string; +using namespace DFHack; + +DFHACK_PLUGIN("burrow"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + +REQUIRE_GLOBAL(window_z); +REQUIRE_GLOBAL(world); + +// logging levels can be dynamically controlled with the `debugfilter` command. +namespace DFHack { + // for configuration-related logging + DBG_DECLARE(burrow, status, DebugCategory::LINFO); + // for logging during the periodic scan + DBG_DECLARE(burrow, cycle, DebugCategory::LINFO); +} + +static const auto CONFIG_KEY = std::string(plugin_name) + "/config"; +static PersistentDataItem config; +enum ConfigValues { + CONFIG_IS_ENABLED = 0, +}; +static int get_config_val(int index) { + if (!config.isValid()) + return -1; + return config.ival(index); +} +static bool get_config_bool(int index) { + return get_config_val(index) == 1; +} +static void set_config_val(int index, int value) { + if (config.isValid()) + config.ival(index) = value; +} +static void set_config_bool(int index, bool value) { + set_config_val(index, value ? 1 : 0); +} + +static const int32_t CYCLE_TICKS = 100; +static int32_t cycle_timestamp = 0; // world->frame_counter at last cycle + +static command_result do_command(color_ostream &out, vector ¶meters); +static void do_cycle(color_ostream &out); + +DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { + DEBUG(status, out).print("initializing %s\n", plugin_name); + commands.push_back( + PluginCommand("burrow", + "Quickly adjust burrow tiles and units.", + do_command)); + return CR_OK; +} + +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_IS_ENABLED, is_enabled); + if (enable) + do_cycle(out); + } + 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_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_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) { + CoreSuspender suspend; + if (is_enabled && world->frame_counter - cycle_timestamp >= CYCLE_TICKS) + do_cycle(out); + return CR_OK; +} + +static bool call_burrow_lua(color_ostream *out, const char *fn_name, + int nargs = 0, int nres = 0, + Lua::LuaLambda && args_lambda = Lua::DEFAULT_LUA_LAMBDA, + Lua::LuaLambda && res_lambda = Lua::DEFAULT_LUA_LAMBDA) { + DEBUG(status).print("calling %s lua function: '%s'\n", plugin_name, fn_name); + + CoreSuspender guard; + + auto L = Lua::Core::State; + Lua::StackUnwinder top(L); + + if (!out) + out = &Core::getInstance().getConsole(); + + return Lua::CallLuaModuleFunction(*out, L, "plugins.burrow", fn_name, + nargs, nres, + std::forward(args_lambda), + std::forward(res_lambda)); +} + +static command_result do_command(color_ostream &out, vector ¶meters) { + CoreSuspender suspend; + + if (!Core::getInstance().isWorldLoaded()) { + out.printerr("Cannot run %s without a loaded world.\n", plugin_name); + return CR_FAILURE; + } + + bool show_help = false; + if (!call_burrow_lua(&out, "parse_commandline", parameters.size(), 1, + [&](lua_State *L) { + for (const string ¶m : parameters) + Lua::Push(L, param); + }, + [&](lua_State *L) { + show_help = !lua_toboolean(L, -1); + })) { + return CR_FAILURE; + } + + return show_help ? CR_WRONG_USAGE : CR_OK; +} + +///////////////////////////////////////////////////// +// cycle logic +// + +static void do_cycle(color_ostream &out) +{ + // mark that we have recently run + cycle_timestamp = world->frame_counter; + + // TODO +} + +///////////////////////////////////////////////////// +// Lua API +// + +static void get_opts(lua_State *L, int idx, bool &dry_run, bool &cur_zlevel) { + // TODO +} + +static void get_bounds(lua_State *L, int idx, df::coord &pos1, df::coord &pos2) { + // TODO +} + +static int burrow_tiles_clear(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_tiles_clear\n"); + return 0; +} + +static int burrow_tiles_set(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_tiles_set\n"); + return 0; +} + +static int burrow_tiles_add(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_tiles_add\n"); + return 0; +} + +static int burrow_tiles_remove(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_tiles_remove\n"); + return 0; +} + +static int box_fill(lua_State *L, bool enable) { + df::coord pos_start, pos_end; + bool dry_run = false, cur_zlevel = false; + + df::burrow *burrow = NULL; + if (lua_isuserdata(L, 1)) + burrow = Lua::GetDFObject(L, 1); + else if (lua_isstring(L, 1)) + burrow = Burrows::findByName(luaL_checkstring(L, 1)); + else if (lua_isinteger(L, 1)) + burrow = df::burrow::find(luaL_checkinteger(L, 1)); + + if (!burrow) { + luaL_argerror(L, 1, "invalid burrow specifier or burrow not found"); + return 0; + } + + get_bounds(L, 2, pos_start, pos_end); + get_opts(L, 3, dry_run, cur_zlevel); + + if (cur_zlevel) { + pos_start.z = *window_z; + pos_end.z = *window_z; + } + + int32_t count = 0; + for (int32_t z = pos_start.z; z <= pos_end.z; ++z) { + for (int32_t y = pos_start.y; y <= pos_end.y; ++y) { + for (int32_t x = pos_start.x; x <= pos_end.x; ++x) { + df::coord pos(x, y, z); + if (!Burrows::isAssignedTile(burrow, pos)) + ++count; + if (!dry_run) + Burrows::setAssignedTile(burrow, pos, true); + } + } + } + + Lua::Push(L, count); + return 1; +} + +static int burrow_tiles_box_add(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_tiles_box_add\n"); + return box_fill(L, true); +} + +static int burrow_tiles_box_remove(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_tiles_box_remove\n"); + return box_fill(L, false); +} + +static int burrow_tiles_flood_add(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_tiles_flood_add\n"); + return 0; +} + +static int burrow_tiles_flood_remove(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_tiles_flood_remove\n"); + return 0; +} + +static int burrow_units_clear(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_units_clear\n"); + return 0; +} + +static int burrow_units_set(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_units_set\n"); + return 0; +} + +static int burrow_units_add(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_units_add\n"); + return 0; +} + +static int burrow_units_remove(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_units_remove\n"); + return 0; +} + +DFHACK_PLUGIN_LUA_COMMANDS { + DFHACK_LUA_COMMAND(burrow_tiles_clear), + DFHACK_LUA_COMMAND(burrow_tiles_set), + DFHACK_LUA_COMMAND(burrow_tiles_add), + DFHACK_LUA_COMMAND(burrow_tiles_remove), + DFHACK_LUA_COMMAND(burrow_tiles_box_add), + DFHACK_LUA_COMMAND(burrow_tiles_box_remove), + DFHACK_LUA_COMMAND(burrow_tiles_flood_add), + DFHACK_LUA_COMMAND(burrow_tiles_flood_remove), + DFHACK_LUA_COMMAND(burrow_units_clear), + DFHACK_LUA_COMMAND(burrow_units_set), + DFHACK_LUA_COMMAND(burrow_units_add), + DFHACK_LUA_COMMAND(burrow_units_remove), + DFHACK_LUA_END +}; + + + + + + + + + + +/* + + #include "Core.h" #include "Console.h" #include "Export.h" @@ -13,7 +371,6 @@ #include "modules/MapCache.h" #include "modules/World.h" #include "modules/Units.h" -#include "modules/Burrows.h" #include "TileTypes.h" #include "DataDefs.h" @@ -37,26 +394,16 @@ using namespace DFHack; using namespace df::enums; using namespace dfproto; -DFHACK_PLUGIN("burrows"); +DFHACK_PLUGIN("burrow"); REQUIRE_GLOBAL(plotinfo); REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(gamemode); -/* - * Initialization. - */ - -static command_result burrow(color_ostream &out, vector & parameters); - static void init_map(color_ostream &out); static void deinit_map(color_ostream &out); DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { - commands.push_back( - PluginCommand("burrow", - "Quick commands for burrow control.", - burrow)); if (Core::getInstance().isMapLoaded()) init_map(out); @@ -90,10 +437,6 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan return CR_OK; } -/* - * State change tracking. - */ - static int name_burrow_id = -1; static void handle_burrow_rename(color_ostream &out, df::burrow *burrow); @@ -214,10 +557,6 @@ DFhackCExport command_result plugin_onupdate(color_ostream &out) return CR_OK; } -/* - * Config and processing - */ - static std::map name_lookup; static void parse_names() @@ -680,3 +1019,4 @@ static command_result burrow(color_ostream &out, vector ¶meters) return CR_OK; } +*/ diff --git a/plugins/lua/burrow.lua b/plugins/lua/burrow.lua index e3c2d0bfa..536372fae 100644 --- a/plugins/lua/burrow.lua +++ b/plugins/lua/burrow.lua @@ -21,6 +21,10 @@ local _ENV = mkmodule('plugins.burrow') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') +--------------------------------- +-- BurrowDesignationOverlay +-- + local selection_rect = df.global.selection_rect local if_burrow = df.global.game.main_interface.burrow @@ -36,15 +40,16 @@ local function reset_selection_rect() selection_rect.start_z = -30000 end -local function get_bounds(pos) - pos = pos or dfhack.gui.getMousePos() +local function get_bounds(pos1, pos2) + pos1 = pos1 or dfhack.gui.getMousePos() + pos2 = pos2 or xyz2pos(selection_rect.start_x, selection_rect.start_y, selection_rect.start_z) local bounds = { - x1=math.min(selection_rect.start_x, pos.x), - x2=math.max(selection_rect.start_x, pos.x), - y1=math.min(selection_rect.start_y, pos.y), - y2=math.max(selection_rect.start_y, pos.y), - z1=math.min(selection_rect.start_z, pos.z), - z2=math.max(selection_rect.start_z, pos.z), + x1=math.min(pos1.x, pos2.x), + x2=math.max(pos1.x, pos2.x), + y1=math.min(pos1.y, pos2.y), + y2=math.max(pos1.y, pos2.y), + z1=math.min(pos1.z, pos2.z), + z2=math.max(pos1.z, pos2.z), } -- clamp to map edges @@ -69,10 +74,10 @@ end BurrowDesignationOverlay = defclass(BurrowDesignationOverlay, overlay.OverlayWidget) BurrowDesignationOverlay.ATTRS{ - default_pos={x=6,y=8}, + default_pos={x=6,y=9}, viewscreens='dwarfmode/Burrow/Paint', default_enabled=true, - frame={w=30, h=2}, + frame={w=54, h=1}, } function BurrowDesignationOverlay:init() @@ -82,39 +87,41 @@ function BurrowDesignationOverlay:init() subviews={ widgets.Label{ frame={t=0, l=1}, - text='Double-click to flood fill.', + text='Double-click to fill.', + auto_width=true, }, - }, - }, - widgets.BannerPanel{ - frame={t=1, l=0}, - subviews={ widgets.Label{ - frame={t=0, l=1}, + frame={t=0, l=25}, text_pen=COLOR_DARKGREY, text={ 'Selected area: ', {text=function() return ('%dx%dx%d'):format(get_cur_area_dims()) end}, }, + visible=is_choosing_area, }, }, - visible=is_choosing_area, }, } end -local function flood_fill(pos, painting_burrow) - print('flood fill, erasing:', if_burrow.erasing) - print('origin pos:') - printall(pos) +local function flood_fill(pos, erasing, painting_burrow) + if erasing then + burrow_tiles_flood_remove(painting_burrow, pos) + else + burrow_tiles_flood_add(painting_burrow, pos) + end reset_selection_rect() end -local function box_fill(bounds, painting_burrow) - print('box fill, erasing:', if_burrow.erasing) - print('bounds:') - printall(bounds) +local function box_fill(bounds, erasing, painting_burrow) if bounds.z1 == bounds.z2 then return end + local pos1 = xyz2pos(bounds.x1, bounds.y1, bounds.z1) + local pos2 = xyz2pos(bounds.x2, bounds.y2, bounds.z2) + if erasing then + burrow_tiles_box_remove(painting_burrow, pos1, pos2) + else + burrow_tiles_box_add(painting_burrow, pos1, pos2) + end end function BurrowDesignationOverlay:onInput(keys) @@ -133,14 +140,14 @@ function BurrowDesignationOverlay:onInput(keys) else if now_ms - self.last_click_ms <= widgets.DOUBLE_CLICK_MS then self.last_click_ms = 0 - self.pending_fn = curry(flood_fill, pos) + self.pending_fn = curry(flood_fill, pos, if_burrow.erasing) return else self.last_click_ms = now_ms end end if is_choosing_area(pos) then - self.pending_fn = curry(box_fill, get_bounds(pos)) + self.pending_fn = curry(box_fill, get_bounds(pos), if_burrow.erasing) return end end @@ -162,4 +169,82 @@ OVERLAY_WIDGETS = { rawset_default(_ENV, dfhack.burrows) +--------------------------------- +-- commandline handling +-- + +local function set_add_remove(mode, which, params, opts) + local target_burrow = table.remove(params, 1) + return _ENV[('burrow_%s_%s'):format(mode, which)](target_burrow, params, opts) +end + +local function tiles_box_add_remove(which, params, opts) + local target_burrow = table.remove(params, 1) + local pos1 = argparse.coords(params[1] or 'here', 'pos') + local pos2 = opts.cursor or argparse.coords(params[2] or 'here', 'pos') + local bounds = get_bounds(pos1, pos2) + return _ENV['burrow_tiles_box_'..which](target_burrow, bounds, opts) +end + +local function tiles_flood_add_remove(which, params, opts) + local target_burrow = table.remove(params, 1) + local pos = opts.cursor or argparse.coords('here', 'pos') + return _ENV['burrow_tiles_flood_'..which](target_burrow, pos, opts) +end + +local function run_command(mode, command, params, opts) + if mode == 'tiles' then + if command == 'clear' then + return burrow_tiles_clear(params, opts) + elseif command == 'set' or command == 'add' or command == 'remove' then + return set_add_remove('tiles', command, params, opts) + elseif command == 'box-add' or command == 'box-remove' then + return tiles_box_add_remove(command:sub(5), params, opts) + elseif command == 'flood-add' or command == 'flood-remove' then + return tiles_flood_add_remove(command:sub(7), params, opts) + else + return false + end + elseif mode == 'units' then + if command == 'clear' then + return burrow_units_clear(params) + elseif command == 'set' or command == 'add' or command == 'remove' then + return set_add_remove('units', command, params, opts) + else + return false + end + else + return false + end +end + +function parse_commandline(...) + local args, opts = {...}, {} + + if args[1] == 'help' then + return false + end + + local positionals = argparse.processArgsGetopt(args, { + {'c', 'cursor', hasArg=true, + handler=function(optarg) opts.cursor = argparse.coords(optarg, 'cursor') end}, + {'d', 'dry-run', handler=function() opts.dry_run = true end}, + {'h', 'help', handler=function() opts.help = true end}, + {'z', 'cur-zlevel', handler=function() opts.zlevel = true end}, + }) + + if opts.help then + return false + end + + local mode = table.remove(positionals, 1) + local command = table.remove(positionals, 1) + local ret = run_command(mode, command, positionals, opts) + + if not ret then return false end + + print(('%d %s affected'):format(ret, mode)) + return true +end + return _ENV From f5f9f76ee1e03fdabd68ba28d0ca573eb1945f66 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 29 Oct 2023 14:09:42 -0700 Subject: [PATCH 804/851] implement box select from the UI --- plugins/burrow.cpp | 62 +++++++++++++++++++++++++++++++++++------- plugins/lua/burrow.lua | 22 +++++++-------- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index 4a6d8ee8b..33b7cb719 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -182,12 +182,41 @@ static void do_cycle(color_ostream &out) // Lua API // -static void get_opts(lua_State *L, int idx, bool &dry_run, bool &cur_zlevel) { - // TODO +static void get_bool_field(lua_State *L, int idx, const char *name, bool *dest) { + lua_getfield(L, idx, name); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + return; + } + *dest = lua_toboolean(L, -1); + lua_pop(L, 1); } -static void get_bounds(lua_State *L, int idx, df::coord &pos1, df::coord &pos2) { - // TODO +static void get_opts(lua_State *L, int idx, bool &dry_run, bool &zlevel) { + if (lua_gettop(L) < idx) + return; + get_bool_field(L, idx, "dry_run", &dry_run); + get_bool_field(L, idx, "zlevel", &zlevel); +} + +static bool get_int_field(lua_State *L, int idx, const char *name, int16_t *dest) { + lua_getfield(L, idx, name); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + return false; + } + *dest = lua_tointeger(L, -1); + lua_pop(L, 1); + return true; +} + +static bool get_bounds(lua_State *L, int idx, df::coord &pos1, df::coord &pos2) { + return get_int_field(L, idx, "x1", &pos1.x) && + get_int_field(L, idx, "y1", &pos1.y) && + get_int_field(L, idx, "z1", &pos1.z) && + get_int_field(L, idx, "x2", &pos2.x) && + get_int_field(L, idx, "y2", &pos2.y) && + get_int_field(L, idx, "z2", &pos2.z); } static int burrow_tiles_clear(lua_State *L) { @@ -195,6 +224,7 @@ static int burrow_tiles_clear(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_clear\n"); + // TODO return 0; } @@ -203,6 +233,7 @@ static int burrow_tiles_set(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_set\n"); + // TODO return 0; } @@ -211,6 +242,7 @@ static int burrow_tiles_add(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_add\n"); + // TODO return 0; } @@ -219,12 +251,13 @@ static int burrow_tiles_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_remove\n"); + // TODO return 0; } static int box_fill(lua_State *L, bool enable) { df::coord pos_start, pos_end; - bool dry_run = false, cur_zlevel = false; + bool dry_run = false, zlevel = false; df::burrow *burrow = NULL; if (lua_isuserdata(L, 1)) @@ -239,10 +272,13 @@ static int box_fill(lua_State *L, bool enable) { return 0; } - get_bounds(L, 2, pos_start, pos_end); - get_opts(L, 3, dry_run, cur_zlevel); + if (!get_bounds(L, 2, pos_start, pos_end)) { + luaL_argerror(L, 2, "invalid box bounds"); + return 0; + } + get_opts(L, 3, dry_run, zlevel); - if (cur_zlevel) { + if (zlevel) { pos_start.z = *window_z; pos_end.z = *window_z; } @@ -252,10 +288,10 @@ static int box_fill(lua_State *L, bool enable) { for (int32_t y = pos_start.y; y <= pos_end.y; ++y) { for (int32_t x = pos_start.x; x <= pos_end.x; ++x) { df::coord pos(x, y, z); - if (!Burrows::isAssignedTile(burrow, pos)) + if (enable != Burrows::isAssignedTile(burrow, pos)) ++count; if (!dry_run) - Burrows::setAssignedTile(burrow, pos, true); + Burrows::setAssignedTile(burrow, pos, enable); } } } @@ -285,6 +321,7 @@ static int burrow_tiles_flood_add(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_flood_add\n"); + // TODO return 0; } @@ -293,6 +330,7 @@ static int burrow_tiles_flood_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_flood_remove\n"); + // TODO return 0; } @@ -301,6 +339,7 @@ static int burrow_units_clear(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_clear\n"); + // TODO return 0; } @@ -309,6 +348,7 @@ static int burrow_units_set(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_set\n"); + // TODO return 0; } @@ -317,6 +357,7 @@ static int burrow_units_add(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_add\n"); + // TODO return 0; } @@ -325,6 +366,7 @@ static int burrow_units_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_remove\n"); + // TODO return 0; } diff --git a/plugins/lua/burrow.lua b/plugins/lua/burrow.lua index 536372fae..2668cc5e7 100644 --- a/plugins/lua/burrow.lua +++ b/plugins/lua/burrow.lua @@ -87,14 +87,15 @@ function BurrowDesignationOverlay:init() subviews={ widgets.Label{ frame={t=0, l=1}, - text='Double-click to fill.', + text='Double-click to fill. Shift double-click to 3D fill.', auto_width=true, + visible=function() return not is_choosing_area() end, }, widgets.Label{ - frame={t=0, l=25}, + frame={t=0, l=1}, text_pen=COLOR_DARKGREY, text={ - 'Selected area: ', + '3D box select enabled: ', {text=function() return ('%dx%dx%d'):format(get_cur_area_dims()) end}, }, visible=is_choosing_area, @@ -104,23 +105,22 @@ function BurrowDesignationOverlay:init() } end -local function flood_fill(pos, erasing, painting_burrow) +local function flood_fill(pos, erasing, do_3d, painting_burrow) + local opts = {zlevel=not do_3d} if erasing then - burrow_tiles_flood_remove(painting_burrow, pos) + burrow_tiles_flood_remove(painting_burrow, pos, opts) else - burrow_tiles_flood_add(painting_burrow, pos) + burrow_tiles_flood_add(painting_burrow, pos, opts) end reset_selection_rect() end local function box_fill(bounds, erasing, painting_burrow) if bounds.z1 == bounds.z2 then return end - local pos1 = xyz2pos(bounds.x1, bounds.y1, bounds.z1) - local pos2 = xyz2pos(bounds.x2, bounds.y2, bounds.z2) if erasing then - burrow_tiles_box_remove(painting_burrow, pos1, pos2) + burrow_tiles_box_remove(painting_burrow, bounds) else - burrow_tiles_box_add(painting_burrow, pos1, pos2) + burrow_tiles_box_add(painting_burrow, bounds) end end @@ -140,7 +140,7 @@ function BurrowDesignationOverlay:onInput(keys) else if now_ms - self.last_click_ms <= widgets.DOUBLE_CLICK_MS then self.last_click_ms = 0 - self.pending_fn = curry(flood_fill, pos, if_burrow.erasing) + self.pending_fn = curry(flood_fill, pos, if_burrow.erasing, dfhack.internal.getModifiers().shift) return else self.last_click_ms = now_ms From c98da947b83c8be383e43f22f16577557e2193d1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 29 Oct 2023 16:34:18 -0700 Subject: [PATCH 805/851] implement flood fill --- docs/plugins/burrow.rst | 25 ++++++++-- plugins/burrow.cpp | 105 +++++++++++++++++++++++++++++++++++----- 2 files changed, 113 insertions(+), 17 deletions(-) diff --git a/docs/plugins/burrow.rst b/docs/plugins/burrow.rst index b14be928c..9fbd23dc4 100644 --- a/docs/plugins/burrow.rst +++ b/docs/plugins/burrow.rst @@ -43,11 +43,16 @@ specify one of the following all-caps keywords: to add or remove tiles with the corresponding properties. -For flood fill, all tiles that match the properties (from the list above) of -the specified start tile will be included. When flood adding, the flood fill -will also stop at any tiles that have already been added to the burrow. -Similarly for flood removing, the flood will also stop at tiles that are not in -the burrow. +Flood fill selects tiles spreading out from a starting tile if they: + +- match the inside/outside and hidden/revealed properties of the starting tile +- match the walkability group of the starting tile OR (if the starting tile is + walkable) is adjacent to a tile with the same walkability group as the + starting tile + +When flood adding, the flood fill will also stop at any tiles that have already +been added to the burrow. Similarly for flood removing, the flood will also +stop at tiles that are not in the burrow. Examples -------- @@ -95,3 +100,13 @@ the burrow is expanded to include the next dig job only after the miner has chosen a next tile to dig, which may be far away. 2-wide cooridors are much more efficient when expanding a burrow since the "next" tile to dig will still be nearby. + +Overlay +------- + +When painting burrows in the vanilla UI, a few extra mouse operations are +supported. If you box select across multiple z-levels, you will be able to +select the entire volume instead of just the selected area on the z-level that +you are currently looking at. + +In addition, double-clicking will start a flood fill from the target tile. diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index 33b7cb719..a4f96be46 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -2,12 +2,14 @@ #include "Debug.h" #include "LuaTools.h" #include "PluginManager.h" +#include "TileTypes.h" #include "modules/Burrows.h" #include "modules/Persistence.h" #include "modules/World.h" #include "df/burrow.h" +#include "df/tile_designation.h" #include "df/world.h" using std::vector; @@ -255,18 +257,22 @@ static int burrow_tiles_remove(lua_State *L) { return 0; } +static df::burrow* get_burrow(lua_State *L, int idx) { + df::burrow *burrow = NULL; + if (lua_isuserdata(L, idx)) + burrow = Lua::GetDFObject(L, idx); + else if (lua_isstring(L, idx)) + burrow = Burrows::findByName(luaL_checkstring(L, idx)); + else if (lua_isinteger(L, idx)) + burrow = df::burrow::find(luaL_checkinteger(L, idx)); + return burrow; +} + static int box_fill(lua_State *L, bool enable) { df::coord pos_start, pos_end; bool dry_run = false, zlevel = false; - df::burrow *burrow = NULL; - if (lua_isuserdata(L, 1)) - burrow = Lua::GetDFObject(L, 1); - else if (lua_isstring(L, 1)) - burrow = Burrows::findByName(luaL_checkstring(L, 1)); - else if (lua_isinteger(L, 1)) - burrow = df::burrow::find(luaL_checkinteger(L, 1)); - + df::burrow *burrow = get_burrow(L, 1); if (!burrow) { luaL_argerror(L, 1, "invalid burrow specifier or burrow not found"); return 0; @@ -316,13 +322,89 @@ static int burrow_tiles_box_remove(lua_State *L) { return box_fill(L, false); } +static int flood_fill(lua_State *L, bool enable) { + df::coord start_pos; + bool dry_run = false, zlevel = false; + + df::burrow *burrow = get_burrow(L, 1); + if (!burrow) { + luaL_argerror(L, 1, "invalid burrow specifier or burrow not found"); + return 0; + } + + Lua::CheckDFAssign(L, &start_pos, 2); + get_opts(L, 3, dry_run, zlevel); + + // record properties to match + df::tile_designation *start_des = Maps::getTileDesignation(start_pos); + if (!start_des) { + luaL_argerror(L, 2, "invalid starting coordinates"); + return 0; + } + uint16_t start_walk = Maps::getWalkableGroup(start_pos); + + int32_t count = 0; + + std::stack flood; + flood.emplace(start_pos); + + while(!flood.empty()) { + const df::coord pos = flood.top(); + flood.pop(); + + df::tile_designation *des = Maps::getTileDesignation(pos); + if(!des || + des->bits.outside != start_des->bits.outside || + des->bits.hidden != start_des->bits.hidden) + { + continue; + } + + if (!start_walk && Maps::getWalkableGroup(pos)) + continue; + + if (pos != start_pos && enable == Burrows::isAssignedTile(burrow, pos)) + continue; + + ++count; + if (!dry_run) + Burrows::setAssignedTile(burrow, pos, enable); + + // only go one tile outside of a walkability group + if (start_walk && start_walk != Maps::getWalkableGroup(pos)) + continue; + + flood.emplace(pos.x-1, pos.y-1, pos.z); + flood.emplace(pos.x, pos.y-1, pos.z); + flood.emplace(pos.x+1, pos.y-1, pos.z); + flood.emplace(pos.x-1, pos.y, pos.z); + flood.emplace(pos.x+1, pos.y, pos.z); + flood.emplace(pos.x-1, pos.y+1, pos.z); + flood.emplace(pos.x, pos.y+1, pos.z); + flood.emplace(pos.x+1, pos.y+1, pos.z); + + if (!zlevel) { + df::coord pos_above(pos); + ++pos_above.z; + df::tiletype *tt = Maps::getTileType(pos); + df::tiletype *tt_above = Maps::getTileType(pos_above); + if (tt_above && LowPassable(*tt_above)) + flood.emplace(pos_above); + if (tt && LowPassable(*tt)) + flood.emplace(pos.x, pos.y, pos.z-1); + } + } + + Lua::Push(L, count); + return 1; +} + static int burrow_tiles_flood_add(lua_State *L) { color_ostream *out = Lua::GetOutput(L); if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_flood_add\n"); - // TODO - return 0; + return flood_fill(L, true); } static int burrow_tiles_flood_remove(lua_State *L) { @@ -330,8 +412,7 @@ static int burrow_tiles_flood_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_flood_remove\n"); - // TODO - return 0; + return flood_fill(L, false); } static int burrow_units_clear(lua_State *L) { From 8ca03982d5a5a1ea70ea2ff92f55f68503fb393e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 30 Oct 2023 16:27:14 -0700 Subject: [PATCH 806/851] implement clear tiles --- docs/plugins/burrow.rst | 3 +++ plugins/burrow.cpp | 38 +++++++++++++++++++++++++------------- plugins/lua/burrow.lua | 11 +---------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/docs/plugins/burrow.rst b/docs/plugins/burrow.rst index 9fbd23dc4..24f1b72d4 100644 --- a/docs/plugins/burrow.rst +++ b/docs/plugins/burrow.rst @@ -110,3 +110,6 @@ select the entire volume instead of just the selected area on the z-level that you are currently looking at. In addition, double-clicking will start a flood fill from the target tile. + +The box and flood fill actions respect the UI setting for whether the burrow is +being added to or erased. diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index a4f96be46..59da9b929 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -221,13 +221,36 @@ static bool get_bounds(lua_State *L, int idx, df::coord &pos1, df::coord &pos2) get_int_field(L, idx, "z2", &pos2.z); } +static df::burrow* get_burrow(lua_State *L, int idx) { + df::burrow *burrow = NULL; + if (lua_isuserdata(L, idx)) + burrow = Lua::GetDFObject(L, idx); + else if (lua_isstring(L, idx)) + burrow = Burrows::findByName(luaL_checkstring(L, idx)); + else if (lua_isinteger(L, idx)) + burrow = df::burrow::find(luaL_checkinteger(L, idx)); + return burrow; +} + static int burrow_tiles_clear(lua_State *L) { color_ostream *out = Lua::GetOutput(L); if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_clear\n"); - // TODO - return 0; + + int32_t count = 0; + lua_pushnil(L); // first key + while (lua_next(L, 1)) { + df::burrow * burrow = get_burrow(L, -1); + if (burrow) { + count += burrow->block_x.size(); + Burrows::clearTiles(burrow); + } + lua_pop(L, 1); // remove value, leave key + } + + Lua::Push(L, count); + return 1; } static int burrow_tiles_set(lua_State *L) { @@ -257,17 +280,6 @@ static int burrow_tiles_remove(lua_State *L) { return 0; } -static df::burrow* get_burrow(lua_State *L, int idx) { - df::burrow *burrow = NULL; - if (lua_isuserdata(L, idx)) - burrow = Lua::GetDFObject(L, idx); - else if (lua_isstring(L, idx)) - burrow = Burrows::findByName(luaL_checkstring(L, idx)); - else if (lua_isinteger(L, idx)) - burrow = df::burrow::find(luaL_checkinteger(L, idx)); - return burrow; -} - static int box_fill(lua_State *L, bool enable) { df::coord pos_start, pos_end; bool dry_run = false, zlevel = false; diff --git a/plugins/lua/burrow.lua b/plugins/lua/burrow.lua index 2668cc5e7..9b7d8c63d 100644 --- a/plugins/lua/burrow.lua +++ b/plugins/lua/burrow.lua @@ -2,20 +2,11 @@ local _ENV = mkmodule('plugins.burrow') --[[ - Native events: + Provided events: * onBurrowRename(burrow) * onDigComplete(job_type,pos,old_tiletype,new_tiletype) - Native functions: - - * findByName(name) -> burrow - * copyUnits(dest,src,enable) - * copyTiles(dest,src,enable) - * setTilesByKeyword(dest,kwd,enable) -> success - - 'enable' selects between add and remove modes - --]] local overlay = require('plugins.overlay') From 07c12ff808a08a2d8a4b6cbe8c8df7f472aef667 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 31 Oct 2023 07:12:51 +0000 Subject: [PATCH 807/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 996c04010..5c8cdd7ae 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 996c0401051c09f65a3c048f337f891b99aa142c +Subproject commit 5c8cdd7aeb8e921bbbed8c90e7539f8bb88a9a6c From 721800a6fead78031fc011f6a051d9645e32480c Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Tue, 31 Oct 2023 18:50:58 +0000 Subject: [PATCH 808/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 5c8cdd7ae..80487f5ad 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 5c8cdd7aeb8e921bbbed8c90e7539f8bb88a9a6c +Subproject commit 80487f5ad68c83083d67fcf85e6c27066dc5ec66 From c94aa8d28cdc0ec2c14cfd9e45cdd4b93e18f0de Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 31 Oct 2023 16:56:45 -0700 Subject: [PATCH 809/851] prep for more tiles actions --- plugins/burrow.cpp | 124 ++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 64 deletions(-) diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index 59da9b929..5e6158de9 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -8,8 +8,10 @@ #include "modules/Persistence.h" #include "modules/World.h" +#include "df/block_burrow.h" #include "df/burrow.h" #include "df/tile_designation.h" +#include "df/unit.h" #include "df/world.h" using std::vector; @@ -253,6 +255,42 @@ static int burrow_tiles_clear(lua_State *L) { return 1; } +static void copyTiles(df::burrow *target, df::burrow *source, bool enable) +{ + CHECK_NULL_POINTER(target); + CHECK_NULL_POINTER(source); + + if (source == target) { + if (!enable) + Burrows::clearTiles(target); + return; + } + + vector pvec; + Burrows::listBlocks(&pvec, source); + + for (auto block : pvec) { + auto smask = Burrows::getBlockMask(source, block); + if (!smask) + continue; + + auto tmask = Burrows::getBlockMask(target, block, enable); + if (!tmask) + continue; + + if (enable) { + for (int j = 0; j < 16; j++) + tmask->tile_bitmask[j] |= smask->tile_bitmask[j]; + } else { + for (int j = 0; j < 16; j++) + tmask->tile_bitmask[j] &= ~smask->tile_bitmask[j]; + + if (!tmask->has_assignments()) + Burrows::deleteBlockMask(target, block, tmask); + } + } +} + static int burrow_tiles_set(lua_State *L) { color_ostream *out = Lua::GetOutput(L); if (!out) @@ -436,6 +474,28 @@ static int burrow_units_clear(lua_State *L) { return 0; } +static void copyUnits(df::burrow *target, df::burrow *source, bool enable) +{ + CHECK_NULL_POINTER(target); + CHECK_NULL_POINTER(source); + + if (source == target) + { + if (!enable) + Burrows::clearUnits(target); + + return; + } + + for (size_t i = 0; i < source->units.size(); i++) + { + auto unit = df::unit::find(source->units[i]); + + if (unit) + Burrows::setAssignedUnit(target, unit, enable); + } +} + static int burrow_units_set(lua_State *L) { color_ostream *out = Lua::GetOutput(L); if (!out) @@ -892,70 +952,6 @@ static df::burrow *findByName(color_ostream &out, std::string name, bool silent return rv; } -static void copyUnits(df::burrow *target, df::burrow *source, bool enable) -{ - CHECK_NULL_POINTER(target); - CHECK_NULL_POINTER(source); - - if (source == target) - { - if (!enable) - Burrows::clearUnits(target); - - return; - } - - for (size_t i = 0; i < source->units.size(); i++) - { - auto unit = df::unit::find(source->units[i]); - - if (unit) - Burrows::setAssignedUnit(target, unit, enable); - } -} - -static void copyTiles(df::burrow *target, df::burrow *source, bool enable) -{ - CHECK_NULL_POINTER(target); - CHECK_NULL_POINTER(source); - - if (source == target) - { - if (!enable) - Burrows::clearTiles(target); - - return; - } - - std::vector pvec; - Burrows::listBlocks(&pvec, source); - - for (size_t i = 0; i < pvec.size(); i++) - { - auto block = pvec[i]; - auto smask = Burrows::getBlockMask(source, block); - if (!smask) - continue; - - auto tmask = Burrows::getBlockMask(target, block, enable); - if (!tmask) - continue; - - if (enable) - { - for (int j = 0; j < 16; j++) - tmask->tile_bitmask[j] |= smask->tile_bitmask[j]; - } - else - { - for (int j = 0; j < 16; j++) - tmask->tile_bitmask[j] &= ~smask->tile_bitmask[j]; - - if (!tmask->has_assignments()) - Burrows::deleteBlockMask(target, block, tmask); - } - } -} static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mask, df::tile_designation d_value, bool enable) From aa87d7638055e9fd61740c90f6fcc248e1ae8d09 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 31 Oct 2023 18:54:38 -0700 Subject: [PATCH 810/851] implement CLI functions --- docs/plugins/burrow.rst | 4 +- plugins/burrow.cpp | 442 +++++++++++++++------------------------- plugins/lua/burrow.lua | 25 +-- 3 files changed, 178 insertions(+), 293 deletions(-) diff --git a/docs/plugins/burrow.rst b/docs/plugins/burrow.rst index 24f1b72d4..68556053b 100644 --- a/docs/plugins/burrow.rst +++ b/docs/plugins/burrow.rst @@ -85,10 +85,8 @@ Options ``-c``, ``--cursor `` Indicate the starting position of the box or flood fill. If not specified, the position of the keyboard cursor is used. -``-d``, ``--dry-run`` - Report what would be done, but don't actually change anything. ``-z``, ``--cur-zlevel`` - Restricts the operation to the currently visible z-level. + Restricts a flood fill operation to the currently visible z-level. Note ---- diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index 5e6158de9..231cfdf43 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -10,6 +10,7 @@ #include "df/block_burrow.h" #include "df/burrow.h" +#include "df/map_block.h" #include "df/tile_designation.h" #include "df/unit.h" #include "df/world.h" @@ -196,10 +197,9 @@ static void get_bool_field(lua_State *L, int idx, const char *name, bool *dest) lua_pop(L, 1); } -static void get_opts(lua_State *L, int idx, bool &dry_run, bool &zlevel) { +static void get_opts(lua_State *L, int idx, bool &zlevel) { if (lua_gettop(L) < idx) return; - get_bool_field(L, idx, "dry_run", &dry_run); get_bool_field(L, idx, "zlevel", &zlevel); } @@ -234,29 +234,7 @@ static df::burrow* get_burrow(lua_State *L, int idx) { return burrow; } -static int burrow_tiles_clear(lua_State *L) { - color_ostream *out = Lua::GetOutput(L); - if (!out) - out = &Core::getInstance().getConsole(); - DEBUG(status,*out).print("entering burrow_tiles_clear\n"); - - int32_t count = 0; - lua_pushnil(L); // first key - while (lua_next(L, 1)) { - df::burrow * burrow = get_burrow(L, -1); - if (burrow) { - count += burrow->block_x.size(); - Burrows::clearTiles(burrow); - } - lua_pop(L, 1); // remove value, leave key - } - - Lua::Push(L, count); - return 1; -} - -static void copyTiles(df::burrow *target, df::burrow *source, bool enable) -{ +static void copyTiles(df::burrow *target, df::burrow *source, bool enable) { CHECK_NULL_POINTER(target); CHECK_NULL_POINTER(source); @@ -291,12 +269,124 @@ static void copyTiles(df::burrow *target, df::burrow *source, bool enable) } } +static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mask, + df::tile_designation d_value, bool enable) { + CHECK_NULL_POINTER(target); + + auto &blocks = world->map.map_blocks; + + for (auto block : blocks) { + df::block_burrow *mask = NULL; + + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + if ((block->designation[x][y].whole & d_mask.whole) != d_value.whole) + continue; + + if (!mask) + mask = Burrows::getBlockMask(target, block, enable); + if (!mask) + goto next_block; + + mask->setassignment(x, y, enable); + } + } + + if (mask && !enable && !mask->has_assignments()) + Burrows::deleteBlockMask(target, block, mask); + + next_block:; + } +} + +static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable) { + CHECK_NULL_POINTER(target); + + df::tile_designation mask; + df::tile_designation value; + + if (name == "ABOVE_GROUND") + mask.bits.subterranean = true; + else if (name == "SUBTERRANEAN") + mask.bits.subterranean = value.bits.subterranean = true; + else if (name == "LIGHT") + mask.bits.light = value.bits.light = true; + else if (name == "DARK") + mask.bits.light = true; + else if (name == "OUTSIDE") + mask.bits.outside = value.bits.outside = true; + else if (name == "INSIDE") + mask.bits.outside = true; + else if (name == "HIDDEN") + mask.bits.hidden = value.bits.hidden = true; + else if (name == "REVEALED") + mask.bits.hidden = true; + else + return false; + + setTilesByDesignation(target, mask, value, enable); + return true; +} + +static void copyUnits(df::burrow *target, df::burrow *source, bool enable) { + CHECK_NULL_POINTER(target); + CHECK_NULL_POINTER(source); + + if (source == target) { + if (!enable) + Burrows::clearUnits(target); + return; + } + + for (size_t i = 0; i < source->units.size(); i++) { + if (auto unit = df::unit::find(source->units[i])) + Burrows::setAssignedUnit(target, unit, enable); + } +} + +static int burrow_tiles_clear(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + DEBUG(status,*out).print("entering burrow_tiles_clear\n"); + + lua_pushnil(L); // first key + while (lua_next(L, 1)) { + df::burrow * burrow = get_burrow(L, -1); + if (burrow) + Burrows::clearTiles(burrow); + lua_pop(L, 1); // remove value, leave key + } + + return 0; +} + +static void tiles_set_add_remove(lua_State *L, bool do_set, bool enable) { + df::burrow *target = get_burrow(L, 1); + if (!target) { + luaL_argerror(L, 1, "invalid burrow specifier or burrow not found"); + return; + } + + if (do_set) + Burrows::clearTiles(target); + + lua_pushnil(L); // first key + while (lua_next(L, 2)) { + if (!lua_isstring(L, -1) || !setTilesByKeyword(target, luaL_checkstring(L, -1), enable)) { + if (auto burrow = get_burrow(L, -1)) + copyTiles(target, burrow, enable); + } + lua_pop(L, 1); // remove value, leave key + } +} + static int burrow_tiles_set(lua_State *L) { color_ostream *out = Lua::GetOutput(L); if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_set\n"); - // TODO + tiles_set_add_remove(L, true, true); return 0; } @@ -305,7 +395,7 @@ static int burrow_tiles_add(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_add\n"); - // TODO + tiles_set_add_remove(L, false, true); return 0; } @@ -314,46 +404,31 @@ static int burrow_tiles_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_remove\n"); - // TODO + tiles_set_add_remove(L, false, false); return 0; } -static int box_fill(lua_State *L, bool enable) { - df::coord pos_start, pos_end; - bool dry_run = false, zlevel = false; - +static void box_fill(lua_State *L, bool enable) { df::burrow *burrow = get_burrow(L, 1); if (!burrow) { luaL_argerror(L, 1, "invalid burrow specifier or burrow not found"); - return 0; + return; } + df::coord pos_start, pos_end; if (!get_bounds(L, 2, pos_start, pos_end)) { luaL_argerror(L, 2, "invalid box bounds"); - return 0; - } - get_opts(L, 3, dry_run, zlevel); - - if (zlevel) { - pos_start.z = *window_z; - pos_end.z = *window_z; + return; } - int32_t count = 0; for (int32_t z = pos_start.z; z <= pos_end.z; ++z) { for (int32_t y = pos_start.y; y <= pos_end.y; ++y) { for (int32_t x = pos_start.x; x <= pos_end.x; ++x) { df::coord pos(x, y, z); - if (enable != Burrows::isAssignedTile(burrow, pos)) - ++count; - if (!dry_run) - Burrows::setAssignedTile(burrow, pos, enable); + Burrows::setAssignedTile(burrow, pos, enable); } } } - - Lua::Push(L, count); - return 1; } static int burrow_tiles_box_add(lua_State *L) { @@ -361,7 +436,8 @@ static int burrow_tiles_box_add(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_box_add\n"); - return box_fill(L, true); + box_fill(L, true); + return 0; } static int burrow_tiles_box_remove(lua_State *L) { @@ -369,32 +445,30 @@ static int burrow_tiles_box_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_box_remove\n"); - return box_fill(L, false); + box_fill(L, false); + return 0; } -static int flood_fill(lua_State *L, bool enable) { +static void flood_fill(lua_State *L, bool enable) { df::coord start_pos; - bool dry_run = false, zlevel = false; + bool zlevel = false; df::burrow *burrow = get_burrow(L, 1); if (!burrow) { luaL_argerror(L, 1, "invalid burrow specifier or burrow not found"); - return 0; + return; } Lua::CheckDFAssign(L, &start_pos, 2); - get_opts(L, 3, dry_run, zlevel); + get_opts(L, 3, zlevel); - // record properties to match df::tile_designation *start_des = Maps::getTileDesignation(start_pos); if (!start_des) { luaL_argerror(L, 2, "invalid starting coordinates"); - return 0; + return; } uint16_t start_walk = Maps::getWalkableGroup(start_pos); - int32_t count = 0; - std::stack flood; flood.emplace(start_pos); @@ -416,9 +490,7 @@ static int flood_fill(lua_State *L, bool enable) { if (pos != start_pos && enable == Burrows::isAssignedTile(burrow, pos)) continue; - ++count; - if (!dry_run) - Burrows::setAssignedTile(burrow, pos, enable); + Burrows::setAssignedTile(burrow, pos, enable); // only go one tile outside of a walkability group if (start_walk && start_walk != Maps::getWalkableGroup(pos)) @@ -444,9 +516,6 @@ static int flood_fill(lua_State *L, bool enable) { flood.emplace(pos.x, pos.y, pos.z-1); } } - - Lua::Push(L, count); - return 1; } static int burrow_tiles_flood_add(lua_State *L) { @@ -454,7 +523,8 @@ static int burrow_tiles_flood_add(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_flood_add\n"); - return flood_fill(L, true); + flood_fill(L, true); + return 0; } static int burrow_tiles_flood_remove(lua_State *L) { @@ -462,7 +532,8 @@ static int burrow_tiles_flood_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_tiles_flood_remove\n"); - return flood_fill(L, false); + flood_fill(L, false); + return 0; } static int burrow_units_clear(lua_State *L) { @@ -470,29 +541,37 @@ static int burrow_units_clear(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_clear\n"); - // TODO - return 0; -} -static void copyUnits(df::burrow *target, df::burrow *source, bool enable) -{ - CHECK_NULL_POINTER(target); - CHECK_NULL_POINTER(source); + int32_t count = 0; + lua_pushnil(L); // first key + while (lua_next(L, 1)) { + df::burrow * burrow = get_burrow(L, -1); + if (burrow) { + count += burrow->units.size(); + Burrows::clearUnits(burrow); + } + lua_pop(L, 1); // remove value, leave key + } - if (source == target) - { - if (!enable) - Burrows::clearUnits(target); + Lua::Push(L, count); + return 1; +} +static void units_set_add_remove(lua_State *L, bool do_set, bool enable) { + df::burrow *target = get_burrow(L, 1); + if (!target) { + luaL_argerror(L, 1, "invalid burrow specifier or burrow not found"); return; } - for (size_t i = 0; i < source->units.size(); i++) - { - auto unit = df::unit::find(source->units[i]); + if (do_set) + Burrows::clearUnits(target); - if (unit) - Burrows::setAssignedUnit(target, unit, enable); + lua_pushnil(L); // first key + while (lua_next(L, 2)) { + if (auto burrow = get_burrow(L, -1)) + copyUnits(target, burrow, enable); + lua_pop(L, 1); // remove value, leave key } } @@ -501,7 +580,7 @@ static int burrow_units_set(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_set\n"); - // TODO + units_set_add_remove(L, true, true); return 0; } @@ -510,7 +589,7 @@ static int burrow_units_add(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_add\n"); - // TODO + units_set_add_remove(L, false, true); return 0; } @@ -519,7 +598,7 @@ static int burrow_units_remove(lua_State *L) { if (!out) out = &Core::getInstance().getConsole(); DEBUG(status,*out).print("entering burrow_units_remove\n"); - // TODO + units_set_add_remove(L, false, false); return 0; } @@ -540,17 +619,7 @@ DFHACK_PLUGIN_LUA_COMMANDS { }; - - - - - - - - /* - - #include "Core.h" #include "Console.h" #include "Export.h" @@ -952,72 +1021,6 @@ static df::burrow *findByName(color_ostream &out, std::string name, bool silent return rv; } - -static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mask, - df::tile_designation d_value, bool enable) -{ - CHECK_NULL_POINTER(target); - - auto &blocks = world->map.map_blocks; - - for (size_t i = 0; i < blocks.size(); i++) - { - auto block = blocks[i]; - df::block_burrow *mask = NULL; - - for (int x = 0; x < 16; x++) - { - for (int y = 0; y < 16; y++) - { - if ((block->designation[x][y].whole & d_mask.whole) != d_value.whole) - continue; - - if (!mask) - mask = Burrows::getBlockMask(target, block, enable); - if (!mask) - goto next_block; - - mask->setassignment(x, y, enable); - } - } - - if (mask && !enable && !mask->has_assignments()) - Burrows::deleteBlockMask(target, block, mask); - - next_block:; - } -} - -static bool setTilesByKeyword(df::burrow *target, std::string name, bool enable) -{ - CHECK_NULL_POINTER(target); - - df::tile_designation mask; - df::tile_designation value; - - if (name == "ABOVE_GROUND") - mask.bits.subterranean = true; - else if (name == "SUBTERRANEAN") - mask.bits.subterranean = value.bits.subterranean = true; - else if (name == "LIGHT") - mask.bits.light = value.bits.light = true; - else if (name == "DARK") - mask.bits.light = true; - else if (name == "OUTSIDE") - mask.bits.outside = value.bits.outside = true; - else if (name == "INSIDE") - mask.bits.outside = true; - else if (name == "HIDDEN") - mask.bits.hidden = value.bits.hidden = true; - else if (name == "REVEALED") - mask.bits.hidden = true; - else - return false; - - setTilesByDesignation(target, mask, value, enable); - return true; -} - DFHACK_PLUGIN_LUA_FUNCTIONS { DFHACK_LUA_FUNCTION(renameBurrow), DFHACK_LUA_FUNCTION(findByName), @@ -1033,121 +1036,4 @@ DFHACK_PLUGIN_LUA_EVENTS { DFHACK_LUA_END }; -static command_result burrow(color_ostream &out, vector ¶meters) -{ - CoreSuspender suspend; - - if (!active) - { - out.printerr("The plugin cannot be used without map.\n"); - return CR_FAILURE; - } - - string cmd; - if (!parameters.empty()) - cmd = parameters[0]; - - if (cmd == "enable" || cmd == "disable") - { - if (parameters.size() < 2) - return CR_WRONG_USAGE; - - bool state = (cmd == "enable"); - - for (size_t i = 1; i < parameters.size(); i++) - { - string &option = parameters[i]; - - if (option == "auto-grow") - enable_auto_grow(out, state); - else - return CR_WRONG_USAGE; - } - } - else if (cmd == "clear-units") - { - if (parameters.size() < 2) - return CR_WRONG_USAGE; - - for (size_t i = 1; i < parameters.size(); i++) - { - auto target = findByName(out, parameters[i]); - if (!target) - return CR_WRONG_USAGE; - - Burrows::clearUnits(target); - } - } - else if (cmd == "set-units" || cmd == "add-units" || cmd == "remove-units") - { - if (parameters.size() < 3) - return CR_WRONG_USAGE; - - auto target = findByName(out, parameters[1]); - if (!target) - return CR_WRONG_USAGE; - - if (cmd == "set-units") - Burrows::clearUnits(target); - - bool enable = (cmd != "remove-units"); - - for (size_t i = 2; i < parameters.size(); i++) - { - auto source = findByName(out, parameters[i]); - if (!source) - return CR_WRONG_USAGE; - - copyUnits(target, source, enable); - } - } - else if (cmd == "clear-tiles") - { - if (parameters.size() < 2) - return CR_WRONG_USAGE; - - for (size_t i = 1; i < parameters.size(); i++) - { - auto target = findByName(out, parameters[i]); - if (!target) - return CR_WRONG_USAGE; - - Burrows::clearTiles(target); - } - } - else if (cmd == "set-tiles" || cmd == "add-tiles" || cmd == "remove-tiles") - { - if (parameters.size() < 3) - return CR_WRONG_USAGE; - - auto target = findByName(out, parameters[1]); - if (!target) - return CR_WRONG_USAGE; - - if (cmd == "set-tiles") - Burrows::clearTiles(target); - - bool enable = (cmd != "remove-tiles"); - - for (size_t i = 2; i < parameters.size(); i++) - { - if (setTilesByKeyword(target, parameters[i], enable)) - continue; - - auto source = findByName(out, parameters[i]); - if (!source) - return CR_WRONG_USAGE; - - copyTiles(target, source, enable); - } - } - else - { - if (!parameters.empty() && cmd != "?") - out.printerr("Invalid command: %s\n", cmd.c_str()); - return CR_WRONG_USAGE; - } - - return CR_OK; -} */ diff --git a/plugins/lua/burrow.lua b/plugins/lua/burrow.lua index 9b7d8c63d..be4a51dd4 100644 --- a/plugins/lua/burrow.lua +++ b/plugins/lua/burrow.lua @@ -9,6 +9,7 @@ local _ENV = mkmodule('plugins.burrow') --]] +local argparse = require('argparse') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') @@ -164,9 +165,9 @@ rawset_default(_ENV, dfhack.burrows) -- commandline handling -- -local function set_add_remove(mode, which, params, opts) +local function set_add_remove(mode, which, params, _) local target_burrow = table.remove(params, 1) - return _ENV[('burrow_%s_%s'):format(mode, which)](target_burrow, params, opts) + _ENV[('burrow_%s_%s'):format(mode, which)](target_burrow, params) end local function tiles_box_add_remove(which, params, opts) @@ -174,39 +175,40 @@ local function tiles_box_add_remove(which, params, opts) local pos1 = argparse.coords(params[1] or 'here', 'pos') local pos2 = opts.cursor or argparse.coords(params[2] or 'here', 'pos') local bounds = get_bounds(pos1, pos2) - return _ENV['burrow_tiles_box_'..which](target_burrow, bounds, opts) + _ENV['burrow_tiles_box_'..which](target_burrow, bounds) end local function tiles_flood_add_remove(which, params, opts) local target_burrow = table.remove(params, 1) local pos = opts.cursor or argparse.coords('here', 'pos') - return _ENV['burrow_tiles_flood_'..which](target_burrow, pos, opts) + _ENV['burrow_tiles_flood_'..which](target_burrow, pos, opts) end local function run_command(mode, command, params, opts) if mode == 'tiles' then if command == 'clear' then - return burrow_tiles_clear(params, opts) + burrow_tiles_clear(params) elseif command == 'set' or command == 'add' or command == 'remove' then - return set_add_remove('tiles', command, params, opts) + set_add_remove('tiles', command, params, opts) elseif command == 'box-add' or command == 'box-remove' then - return tiles_box_add_remove(command:sub(5), params, opts) + tiles_box_add_remove(command:sub(5), params, opts) elseif command == 'flood-add' or command == 'flood-remove' then - return tiles_flood_add_remove(command:sub(7), params, opts) + tiles_flood_add_remove(command:sub(7), params, opts) else return false end elseif mode == 'units' then if command == 'clear' then - return burrow_units_clear(params) + burrow_units_clear(params) elseif command == 'set' or command == 'add' or command == 'remove' then - return set_add_remove('units', command, params, opts) + set_add_remove('units', command, params, opts) else return false end else return false end + return true end function parse_commandline(...) @@ -219,7 +221,6 @@ function parse_commandline(...) local positionals = argparse.processArgsGetopt(args, { {'c', 'cursor', hasArg=true, handler=function(optarg) opts.cursor = argparse.coords(optarg, 'cursor') end}, - {'d', 'dry-run', handler=function() opts.dry_run = true end}, {'h', 'help', handler=function() opts.help = true end}, {'z', 'cur-zlevel', handler=function() opts.zlevel = true end}, }) @@ -234,7 +235,7 @@ function parse_commandline(...) if not ret then return false end - print(('%d %s affected'):format(ret, mode)) + print('done') return true end From 98bb1d57bbe94ad34f75a9c59fe89597444a2782 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 1 Nov 2023 07:13:44 +0000 Subject: [PATCH 811/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 80487f5ad..887e44324 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 80487f5ad68c83083d67fcf85e6c27066dc5ec66 +Subproject commit 887e44324b4b55c9687fdb5737f6d2ef2b00b19a From 9db479bf3243d8d2b98cb0666c7c6bbf96fa4b37 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 1 Nov 2023 12:54:26 -0700 Subject: [PATCH 812/851] include ramp tops in flood fill --- plugins/burrow.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index 231cfdf43..ef6231990 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -449,6 +449,21 @@ static int burrow_tiles_box_remove(lua_State *L) { return 0; } +// ramp tops inherit walkability group of the tile below +static uint16_t get_walk_group(const df::coord & pos) { + uint16_t walk = Maps::getWalkableGroup(pos); + if (walk) + return walk; + if (auto tt = Maps::getTileType(pos)) { + if (tileShape(*tt) == df::tiletype_shape::RAMP_TOP) { + df::coord pos_below(pos); + --pos_below.z; + walk = Maps::getWalkableGroup(pos_below); + } + } + return walk; +} + static void flood_fill(lua_State *L, bool enable) { df::coord start_pos; bool zlevel = false; @@ -484,7 +499,8 @@ static void flood_fill(lua_State *L, bool enable) { continue; } - if (!start_walk && Maps::getWalkableGroup(pos)) + uint16_t walk = get_walk_group(pos); + if (!start_walk && walk) continue; if (pos != start_pos && enable == Burrows::isAssignedTile(burrow, pos)) @@ -493,7 +509,7 @@ static void flood_fill(lua_State *L, bool enable) { Burrows::setAssignedTile(burrow, pos, enable); // only go one tile outside of a walkability group - if (start_walk && start_walk != Maps::getWalkableGroup(pos)) + if (start_walk && start_walk != walk) continue; flood.emplace(pos.x-1, pos.y-1, pos.z); From 0e00dd8777f1028fbe4f3933eeacdee7112aec28 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 2 Nov 2023 01:03:06 +0000 Subject: [PATCH 813/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 887e44324..d56aac6bc 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 887e44324b4b55c9687fdb5737f6d2ef2b00b19a +Subproject commit d56aac6bcd6628d22420d57b4a96987490e5a11f From 3f069d469d6c75dd43d9b7904eae28b300ab0909 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 1 Nov 2023 18:20:25 -0700 Subject: [PATCH 814/851] add FRAME_THIN --- docs/changelog.txt | 1 + docs/dev/Lua API.rst | 4 ++++ library/lua/gui.lua | 3 +++ 3 files changed, 8 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 850879a3a..19d87faad 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -73,6 +73,7 @@ Template for new versions: ## Lua - ``dfhack.gui.revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target - ``dfhack.maps.getWalkableGroup``: get the walkability group of a tile +- ``gui.FRAME_THIN``: a panel frame suitable for floating tooltips ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 35a604988..eeb0fbda6 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4583,6 +4583,10 @@ There are the following predefined frame style tables: A frame suitable for overlay widget panels. +* ``FRAME_THIN`` + + A frame suitable for floating tooltip panels that need the DFHack signature. + * ``FRAME_BOLD`` A frame suitable for a non-draggable panel meant to capture the user's focus, diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 555e060d1..05d848bb3 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -940,6 +940,9 @@ end function FRAME_BOLD() return make_frame(textures.tp_border_bold, true) end +function FRAME_THIN() + return make_frame(textures.tp_border_thin, false) +end function FRAME_INTERIOR() local frame = make_frame(textures.tp_border_thin, false) frame.signature_pen = false From a6ce29d209642872e27e6695ad4867a9648ac843 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 1 Nov 2023 23:56:56 -0700 Subject: [PATCH 815/851] remove old code for search plugin (now part of sort) --- conf.py | 3 +- docs/about/Removed.rst | 6 + docs/images/search-stockpile.png | Bin 5132 -> 0 bytes docs/images/search.png | Bin 4509 -> 0 bytes docs/plugins/search.rst | 52 - docs/plugins/sort.rst | 8 +- plugins/CMakeLists.txt | 1 - plugins/search.cpp | 2568 ------------------------------ 8 files changed, 12 insertions(+), 2626 deletions(-) delete mode 100644 docs/images/search-stockpile.png delete mode 100644 docs/images/search.png delete mode 100644 docs/plugins/search.rst delete mode 100644 plugins/search.cpp diff --git a/conf.py b/conf.py index 60c3be579..ffcc24b75 100644 --- a/conf.py +++ b/conf.py @@ -78,8 +78,7 @@ def write_tool_docs(): os.makedirs(os.path.join('docs/tools', os.path.dirname(k[0])), mode=0o755, exist_ok=True) with write_file_if_changed('docs/tools/{}.rst'.format(k[0])) as outfile: - if k[0] != 'search': - outfile.write(label) + outfile.write(label) outfile.write(include) diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index 86d7e0f75..67c4530bb 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -220,6 +220,12 @@ ruby Support for the Ruby language in DFHack scripts was removed due to the issues the Ruby library causes when used as an embedded language. +.. _search-plugin: + +search +====== +Functionality was merged into `sort`. + .. _show-unit-syndromes: show-unit-syndromes diff --git a/docs/images/search-stockpile.png b/docs/images/search-stockpile.png deleted file mode 100644 index a0e837875c86685bc421549199ae5f6f7438ff87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5132 zcmZ8lc{J3~+n*T|V;K#~zI@4U##YMSH%11Lec!TFOl2=iG=nUm8Dgj`8AP@;Ox7ZM zqZExLMD}bUX(9RPeb0N&@4Wxq=ibk`_de&I`#hh|b8oVxg)x#tm;(ZVAWd*sYY2n| zfIy&{aFzqa3VSF1zzABNvo#_R2oM6Ht*vc;fByi35Fn8Ke~roFb{_=7_tXS?#x~r2 zHT%Ndc!2Bd3)nPkJSTabb*_2;K7ToV9M%0X@9j1F$K3)I-$^9u6&2%fjgt~f4&Kck zSV&=EJR}@i0+rXfn^a=RHd}}aMv?v46D1!+24W^zmlmpwr8RSI9zWgA$&MP;lWDJ=Lh-3D zp&TTaTyZmF2HmabD5-`cgP&zJOU)=EH`)`(N@%BV$7MElQJ)^lf3N1oMqHD~&?)O} zMh$c4*KjD+I+rIT9MWIDRbz8$C(==FuZ~<#ezSu)=CdPbpg;OFPBih1AV)_?sf0z_ z1Z4iNgV0BgS%7ISBg(&yaV;x}+FT>OOV5NDEQ1@-h8%BtR z=u<+#GEPYNYc`^gG)*ABJM{darIB2HP#jq~7gzVqG2Ip=i?TlR3*IgSAiui#S+1S{ zJ(YTOPhrHCx6ZR)BM;<&ZC$-ALikv>6rRo@3z3<)Zdaw>B7^v+f7L8l+MJ;?pU$Bi z&pb*+e%!H?*!?Ais036tE=D^a3o(q;eW!F|^ZT#6@(#ScK?4tWM2QIOZ}0WgklF4CdHq{+ z(q{rTLJ6LJJ}TC4*!f3SZlx`Jc&WjjHfSpKLV?{@uqQvgrxnNHVPXnZ6W^Mie)Pq?Bx-Id^ydegJq|>M$QEET~jQnkVbE#0_V@%#2>hD_&*+A0V zB!aoMtkXg`u@s+{0+n0jJMh^t2vM7aR zIQxdZ)}lGfbm5uP}T6 zr;IAY@ksg0REkF7;dK);lO=f0aP-;*m`Ms7@3x4Em15_@HYNbmr@|#aIkSxs*%N1- zYxN3b4IaE+CjIQAP`2I1<=m^4zU+aTUtGih=JhX>XCJ-WX7m^6=*N!Vs&{rMEacc* z&2Jyt><7YO&z$**mQjHN^=R@*>9S#~vaz$p)Vr+K9zwu!b$A{Ns%SpK!YT2@efU?f zlHyA|*fjcd{1|sGe;8DLK^rQBcRKehbLLTi0x*3m?XK|!Q@L2)g&kQk-nrX1i=cbD z$%UBER;V{jYd9ORC^#t1n-pH*>=M;49bf&ntPjPs^&GHy_y!n z1%1jCD>2Hs%yGEq{dI9(x-U@`Y1dT%>5?l!0_5xM(4?gaC4aoGZ&+NlE+J5tH-il| z-WbIkcI+Fpq3ECzW3)WR`j1hcS4y;t?ocT@rJ{zW#xn~IX3z4DN&745g(aRAp*t% zMYg2BPYaU4%BwL+pzmJeFUccyW6U#vb^dENe0*IjgJK(FK{GwC*FhNM#lg~ptuXky zE-5cQWL{TSI0oO)Ma_JVHC&A5nx$86@~3RTVGh9amv#*ljWMrh`BRU5wU%7?ajlN$ z8Yn|kUg@Ac-U*tVz>jzj<*oGHu6L9s4>=EGsf8VgR-gDd~7 z)_?%gZ``SyU*Xp0TlQKbp0wC63ZBJYbprBIr6d5AdWol#?zSPY;3z+peXXctA8uKV9XZ2O@5DvpG_nW zF9_}!{R_V}WaM7fP##S&L7YrVn4`=KMjnLaim#Q8HssXlxnU>fQeunl*Cvc+)*+Ls zH)^3tV>{*fkqd$s?_Pktj&z!hwT~@HUe0^h92m&Idpl(9#z(i)$xDdgnYh|+4$3Li zDyvip=Um1sr;S4}QU7KG*fcQTRpBpGYc_NR*-vw`CRv}KCE#88qorTCU6_g}PZTMS zuKg&UJG5iDXHC+!YyX+nH#p8JZfWuwP79QjA+vBj^f@s+{26`Sz1emyB~o}Jt&djH zEpnTi%vOFIk8qrL5Y}{^?UKpTiq&)8zb&yE9x8p1fhewi5k%)Xv4?TBwgDF{WKqOh zuKcUdiS2y0{t*5V=P!wmYRdw+`f1IIwZz=~?x1H4l_y+{wM}MIvp{uaCHKIvmbCC_ zJUXv4TQ4&Z*xIqb;%X0jB?~yq2CM$)yGRXT!{Eavr!~2H^)4h{YcL#m$d18>OcoxJ z@}w4Cx~am=aOB?f%O%gdg6xk~zibnbk%~IcI=T8CLHp6uky3YE0 z7!SeB>T{E`toBr?ulbxp)hpre5R13#u$p~pGHR`J148( zA8l8B!Q$WoNS_^|fp7A@6LF3DWU@%RHSl~@=aJWAMkJJjt~T#y_){%3WlXro_e|;0 zCpii*r}?*qMG9SO-hzAw3?#~dQ0TDF;5B$~iSd&%E z%`%sr^o0~){zX4w%gUvhpvv0E@N+!rn~tgd9s5%)HEE0%gR@$?t*YiIA8Jv9BV-Jx zGZs=NdfuP*PXX0?R3~fC0Ve?0r6zqclh%}TNW3M-Rf{-XEsjyHE)D`n zgh)j$#xD1A&ikTVVjB|C)ALk#>i^}VeyZzv;1z`WTFnD;XCvehMxYLpp%xbXx zc(c&B$xrV>DyPUw0<}ofTx4`Wp26Tt8p_N}wHsJx0swk3hM55Vs>Oh1zK7P_HCcmyFjI^LUn&<&43q8ivrDS7FvB!i z8sZZ{G*C#=$7&>8dHJeHHu6BHG}4V4t|F7!tbucq~gL7eeEGrrLG*aj?DXNn;=gk0i>9;*Lq%xQ7o|P5+ z2}tKZ;)u^QiPUo!d5DMbB$id-S^NOSobV1CAP`P%|N4n=b9bO+`1Q&|ZGkLrL7s!K z8U41R{G)B7r@kM--mCVVGX! z=e?Xio(o%o)c!3gam2lK$j&V{GzmKH&$V zQeBYy^5OxLvH~)^MZQR6beb817if?tU&fem*#1U;?H{t{j>yA^zdI}_)W5eg5+h*8 zmSRXbtplT1?l@~1UEIYW!o`U1{pQ)Yh>zrD6w1l!#0@kt{<2eAE6n=v?>9?AX@r~p z{I*6TK6^&RfSo@PHVc+kl6U*gWlVC8U57?PxC>rmcaGr(z0}YKj`Hp}p%%gRK zqXD?J8`t~4>-|jyrRvcA#!cvwz>LNJa^ia`T?56UxGyg@F zo%FCt2N+Lgqq9|PM%d&C^j{Sug(cC^nT06A-WUc|Lz09Arpl=Lfxwqux4@h|o*GhN zCY}Wvd00*u@f^y-Oi-sB5dfIoR}2Bm;OvNTC>y2^FJVaO%CK%TEYM^b9h^T&O86!e z;J}U$p`%Blxsn?R;7utpM}@Z>&TxZ(dzZ%df}}4LQRZ7ol5~66W>80&=VpV)wS0l` zZ(k0U{F7HAS1B6iCx<4dIaAj46OalVa%>W%c9xDjeJ4+DlY+Aqi|sttKG1?CI+(OU z>po#8efx;#H)6=#^0;GV| z;949{u%$GdE~QiWQE_7nTwT;My84!cI_V8`YOB8=u{->#Qu5s+Z@0VCH<`owfHf=V z=umNEQ!t5n*V((H4p;4Q$eqCuHLNeI+N8R_7q-+WPi%pov|uj@QPZDK#61B9*gsGu z2CHDCEUknn>T_Maus>(D5&}1vMRNt=EYwzie!- z&!B+3IA@s2Kj8mOVUOS4+o~}Tt>u%=^$z{9HDCKknHaUEENr@XvZj7vW-VMtg0}YX zwYYGBm;>JHWlI8>QZ0&4Q&K5v0=#c2bmQ2tRAqPsDPc4EV6BL(zPBJa9E zpN#Ll)DKH)HZ8QGHw%w{kSPxyhLf+YRiE_4j%-=qU|htI zclWsFE`!(V`N)wtomTVwg%NgDRxke>PJpr1(99z7z#S5?-evoGjB~Ep$xxAe_V%%2 zoiDq;!{T__4_kKCM1tH|?hRKMgEt`8nV$y8Z@($5aLrY*#N*C_IUYZ2!D2^X!9=wr zfCZ(%pLFCf;L4;+3_7;lY-xI7n{?f3KgI!%Q)%tbr-z6uUCP7XAil{-&~%W`zcKan zQ`g5krQoJwK z$x+5O>cQqZtF39-5T9Kq!1OfL^Td1F%+(@Fmt3Es)54|iE8Rn`J2O&y5*5Dpm3y3r zN7&khE#XpxLta|JKi|Ei_zD!V!i`v#{GB|G;4Xcgo(0Ik^7BQ9eb9NLVoRN{uXra9 ziKMESl7fCggw|J>)O>}7ll}0kGkWEI)AE0u?k!gS={NH~2B+4cBbTEwDQ^7e4>a}V z{|&pL{o7IdSv4}A_A#v$kDsuv|4fFh@cr~kt*32quTo=L>c2*T#i4Pdk71`nw@}*a z9p92xM0qC75}BT}?HI7>h2awu9b(<9&7j`?pRkD5!vx1mui1Kkk|HX)3Uu8EPFXES zyow;zC6^AUqHuNu_W0-u;7J5S<|^|8uU#6p0>eQ#r3Cf>J0iz z-P^b0q(n=$o}v(?V0yohv<7nSUF+XJE22PP?k$zCBtvb#S>AQLF@iX;-a?W@c}i`} zZXOZNntespV;7bY8P?60kX+8;!|v{^^&@;NXQJnYgM}q8F0ZoO7nE4d0R4;VMC}g8 z93{uu@Q)nd26mpAHWOP;0c$~_L{ZSndiM`CM)$8C)F2%{omoPxnVv8Q4m>LDk$-qL zls_?H@yAOm+8mET$l;U~e*R#DS~RB6MmwpKo5{;pw%;LNgfN6D;iL^_LDzE0r_*l) z5Iu~5OHX`d{_(+orT_o&!QkH!Zc*~Ve;vS8d&@sW^m*1nAJPVWQB{haVZQkAZ)9R* Kfvq<1jQtNc4N)Wj diff --git a/docs/images/search.png b/docs/images/search.png deleted file mode 100644 index 384c3c533214d92769818d9d357293208a11e507..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4509 zcmb_f`8SmB`+w${#TaC4lig#@T9R!j9{VWDGRhWVT97T2-HaxTl%cZkAqrU{T5V-4 z5z(6#G?oe#A!Pe{f6nLo4}8z}ocr9@>-9R<>ps^H*LBWyGi;7q@Zdyo008hv)kOH0en&JM79sQ=;Ae<83d>@omI@jNyM0DPL3 zrbgs2xA_cTpAL2W)r3!wj(Q}Tc7U?5m11K?wz4V|JZdGOA#I$$xZU-5(qi6X`Q_^v zizxr=TRY|?G3xP(=kK^}l~hT&zAN|>ueac%^dH2m;V@z59)q-#EA=w9laFTg)XqaZ2@?nhj?ZX2ydpGoP!mw0Ck}mu+-5=v;ZnFGJAyeQA}>0L2i1f z5U@ma0w_J8yf$&#E*(sJin<|7Ba`@9I$US;m?@68b$_YI)HD}5UFt4X9g((} zz@db0^I?I}EV%J)=RH>5eGEG;H{wziPEXnonw?Q{gejTrHSTkHP>rYE^`IU8g@k5$I_m` zFGdbd-X?nDlMH(~Baq?yuwgq-g_Lb&>IW}BUbxf0nm|!tsI1FB5s5zfv7fOCaUjBkeQqxdrSB^f!+Ta2eB05&XdNE3${So8_|ZMEzcm zaLXH6p+}=DQ=f!$Bz~#q@JUM26VWl-9R7H#tl#=n zznii#mOhBANHuSY<)!?9&s>GcE z{dVwN^DuZ-i1pPMt4hm#YjZ73P6*B@V?&S5xEsaL9^hJqx4lIACn0iusJ6{a|BG9uZUX0?~#i`?X$3gehz1uMK4g&N( z%t_CH!}cAMsOA9q_N2GJ8T{;bldrX~!^uhctT%kwLOlJWAIuIb(YX5QclsdNrvFko z^r_~-`i8x&Sb{fe5QC8)@@XB~uaXow{;=5C$cOnLL62a*P2DSYd!p35X-2!&v$;bS; z-n^leIMA%dn2wQ@hJPG#A{a$r&^h>%BrtgVG$M7CKaq{OK5cPwT`$tPGbRF|!5%Sr z#Qn|{a|MFeR|4H#lwGrm!X2EGa6Um5<{Q(7E?fq)DV(*=?^kOjS*OHZIHxk6AA0R4 z5#JhkCT!uaKYl?@G)z53?++K&%w6qCpuSu(IS4XU`dP?Zd{;_7ctbbG=iz}q0WK%z z#yg3x&uvpz&0Vy%{vh(-CfGOFDtqYS-QCX%JC^U+AS9{=a1`sTF#B|Kj}#48Ng?Ps zE)M!NcLZPhn3wNwI5Q|%QW~xagQ6bmgGRr-yTOw9Jym7_sv1cH7o7_y*W4}&VZdtRPhzwOYM zl(Qkt%<++9ma0uZ+&K0oj~JdW>NYEhl@Hr3YE!cKV(Ew6HyO`fiLWxh8VAwQH=6x> z_@=be(f3pX-jUTZ;j(nI*atK5r@Z`=9iJs%tH>7P!155(bG*Ktyn9x);3o%)?P8sa z3{OecqCsSY>6w9${E2p34Fddjpupcc`w2#-bH*k?+Y2D_*|I6BR=3v84F~#8By!l5 zlm|mH0E1ckEaK+t2PU9Vm7bxrI73mS=cP%LM+yh30SAR7%ACE{?Ffh{pB;#^yJ+8> z0Qotbx-99SV)vRYX=kR?rWs=?CQ)qQ{(8`m?4>wJ(=PWGhTgGhu8%4Al!|w9Q4gFy z#`GjGT-(%ERr1I$HHAgxrxRcb186hljNoWXT(IlDajK#5une=2L%#^=$%S=Djw4s8 z{Tlr(2p`Q{8oSbcUpDq3GLcBX4|+4~8ya($kZp~~61sTaHdWP~_O@;fWIYEt$qkJX z5Md9(6o@->3DF@@iFN3~CUZ|gH7<$o!w_<$;RvQ~No61Hk=m$t%>MZxks_bP938?3 zMR*v*9tai7`uNAqeRip!UJump1GC`m`e5zms&;k!&$h!YPi^-e26TdV9vr?cbVy!t zr`*O*H;|yJbkJ$xK`#Zcr5*u1rF@Cs65{?MK*#H!k!6Zcoyn`yGr#pa>=u)Ba3$4T zD0knruFehxyzQ8{jovCI?LopUr~S<=97-gyWyk8p^7?U@ni3#O9pHlE9R*avx5r4F zvW;kzJx#Uy0sSax)j-;k7vLe~LqGuY?o7 z@*F4Ozab8SjP7cXal&Z*B=Ciiv%wnd=Qa%(H*xGYz#ADD&cUBTXo1$BayUCaKPF07 z<4Yia)_M(1gjMr%}BUhOpZpn)VSKP}OalTafTzO6yA1*|4$=TMYuX1Wt z$Bv1y1mEq%c7~$EN(7#HuSluQA=<{e@uXvpw$_=a3~+f%Cez$Y_Yi7NuH>aFO$s#j zq2klDrAtSd=ywfOrh8t>@IMm@hs&Z#@?D;c4C+Ml@chn>w;6h#~sf9(ID@ay2)sRlSS#MRIDU`Fhup{`uKdMb|l?$RqQ5zziV*_;W4fP z1PPB-!m8x1Q46g42p%QG~F2m;IOMh4~E%1cM+M zBEP}=;s#1;nP7>5bnMV08XxvufovLeO@-}7o8Pd9>gsD09!8z$^Pr8gwvF!caj3MqK%CgCUBIC|KT`jSnvZ=+j!<%`gVH7T-= zjqiV_y(+o2Mftq-v)|0>w2#5=b^@ky(|ON`flgOmW{m!+u$r^tX+}*E*j2laugm-T zUgRf@anpm)toIghiN)ZqI%@s-Yke?-ukV-jx4IQVP*r3B$6lyfvc0L|@y?aijetLM znY&*(x`!~qMt`Gx!r4dqR9=L600e@jFbb7O1^Dp)2VAoMKPD;`i$@@2{-5xr`OH?I zWp!>kkKVQXZ5_Ve>oc>bSQV?$%>_`0db#kOy3g`Acw1d8yyV@_UOT8Gc-cgKXXvw{)hrbGV?~Hq^ zHix2Tj0<_`AS{LT`Umcf6=F38JO#Vj5m>?^j=L7}494IM1iZpAs^~urFrt{F#~cAN z9FG$1`Zcu+a^a?j&1!YAddv?dp5_n|Qzi9UL$~cWTNp^9l35qAa+u`oRs;F56DXw? zCweQC&bA@?Xz_{x9b%))SJ_Q9802QMz zXIP@FqoEcC=Vr>_N8f(68kAYTewCw$JJL&H^b)#cxgNz`TeFr34ew_V0$pPP- zeCm%M5j|O*_NtjDrk3P*}M4F5%-gg9CU)x+GTgdiME=KAeUkoOU&)z>$GKcZLriiyVQ!Z3&7lL$@ zZa781E|w8}Za8_}B0J(Ej|@K89%{CUWGO0>UaB%~OJ3qview; cur; cur = cur->child) - if (cur == screen && cur->breakdown_level == interface_breakdown_types::NONE) - return true; - return false; -} - -static string get_unit_description(df::unit *unit) -{ - if (!unit) - return ""; - string desc; - auto name = Units::getVisibleName(unit); - if (name->has_name) - desc = Translation::TranslateName(name, false); - desc += ", " + Units::getProfessionName(unit); // Check animal type too - - return desc; -} - -static bool cursor_key_pressed (std::set *input, bool in_entry_mode) -{ - if (in_entry_mode) - { - // give text input (e.g. "2") priority over cursor keys - for (auto it = input->begin(); it != input->end(); ++it) - { - if (Screen::keyToChar(*it) != -1) - return false; - } - } - return - input->count(df::interface_key::CURSOR_UP) || - input->count(df::interface_key::CURSOR_DOWN) || - input->count(df::interface_key::CURSOR_LEFT) || - input->count(df::interface_key::CURSOR_RIGHT) || - input->count(df::interface_key::CURSOR_UPLEFT) || - input->count(df::interface_key::CURSOR_UPRIGHT) || - input->count(df::interface_key::CURSOR_DOWNLEFT) || - input->count(df::interface_key::CURSOR_DOWNRIGHT) || - input->count(df::interface_key::CURSOR_UP_FAST) || - input->count(df::interface_key::CURSOR_DOWN_FAST) || - input->count(df::interface_key::CURSOR_LEFT_FAST) || - input->count(df::interface_key::CURSOR_RIGHT_FAST) || - input->count(df::interface_key::CURSOR_UPLEFT_FAST) || - input->count(df::interface_key::CURSOR_UPRIGHT_FAST) || - input->count(df::interface_key::CURSOR_DOWNLEFT_FAST) || - input->count(df::interface_key::CURSOR_DOWNRIGHT_FAST) || - input->count(df::interface_key::CURSOR_UP_Z) || - input->count(df::interface_key::CURSOR_DOWN_Z) || - input->count(df::interface_key::CURSOR_UP_Z_AUX) || - input->count(df::interface_key::CURSOR_DOWN_Z_AUX); -} - -// -// START: Generic Search functionality -// - -template -class search_generic -{ -public: - bool init(S *screen) - { - if (screen != viewscreen && !reset_on_change()) - return false; - - if (!can_init(screen)) - { - if (is_valid()) - { - clear_search(); - reset_all(); - } - - return false; - } - - if (!is_valid()) - { - this->viewscreen = screen; - this->cursor_pos = get_viewscreen_cursor(); - this->primary_list = get_primary_list(); - this->select_key = get_search_select_key(); - select_token = Screen::charToKey(select_key); - shift_select_token = Screen::charToKey(select_key + 'A' - 'a'); - valid = true; - do_post_init(); - } - - return true; - } - - // Called each time you enter or leave a searchable screen. Resets everything. - virtual void reset_all() - { - reset_search(); - valid = false; - primary_list = NULL; - viewscreen = NULL; - select_key = 's'; - } - - bool reset_on_change() - { - if (valid && is_live_screen(viewscreen)) - return false; - - reset_all(); - return true; - } - - bool is_valid() - { - return valid; - } - - // A new keystroke is received in a searchable screen - virtual bool process_input(set *input) - { - // If the page has two search options (Trade screen), only allow one to operate - // at a time - if (lock != NULL && lock != this) - return false; - - // Allows custom preprocessing for each screen - if (!should_check_input(input)) - return false; - - bool key_processed = true; - - if (entry_mode) - { - // Query typing mode - - df::interface_key last_token = get_string_key(input); - int charcode = Screen::keyToChar(last_token); - if (charcode >= 32 && charcode <= 126) - { - // Standard character - search_string += char(charcode); - do_search(); - } - else if (last_token == interface_key::STRING_A000) - { - // Backspace - if (search_string.length() > 0) - { - search_string.erase(search_string.length()-1); - do_search(); - } - } - else if (input->count(interface_key::SELECT) || input->count(interface_key::LEAVESCREEN)) - { - // ENTER or ESC: leave typing mode - end_entry_mode(); - } - else if (cursor_key_pressed(input, entry_mode)) - { - // Arrow key pressed. Leave entry mode and allow screen to process key - end_entry_mode(); - key_processed = false; - } - } - // Not in query typing mode - else if (input->count(select_token)) - { - // Hotkey pressed, enter typing mode - start_entry_mode(); - } - else if (input->count(shift_select_token)) - { - // Shift + Hotkey pressed, clear query - clear_search(); - } - else - { - // Not a key for us, pass it on to the screen - key_processed = false; - } - - return key_processed || entry_mode; // Only pass unrecognized keys down if not in typing mode - } - - // Called after a keystroke has been processed - virtual void do_post_input_feed() - { - } - - static search_generic *lock; - - bool in_entry_mode() - { - return entry_mode; - } - -protected: - virtual string get_element_description(T element) const = 0; - virtual void render() const = 0; - virtual int32_t *get_viewscreen_cursor() = 0; - virtual vector *get_primary_list() = 0; - - search_generic() - { - reset_all(); - } - - virtual bool can_init(S *screen) - { - return true; - } - - virtual void do_post_init() - { - - } - - void start_entry_mode() - { - entry_mode = true; - lock = this; - } - - void end_entry_mode() - { - entry_mode = false; - lock = NULL; - } - - virtual char get_search_select_key() - { - return 's'; - } - - virtual void reset_search() - { - end_entry_mode(); - search_string = ""; - saved_list1.clear(); - } - - // Shortcut to clear the search immediately - virtual void clear_search() - { - if (saved_list1.size() > 0) - { - *primary_list = saved_list1; - saved_list1.clear(); - } - search_string = ""; - } - - virtual void save_original_values() - { - saved_list1 = *primary_list; - } - - virtual void do_pre_incremental_search() - { - - } - - virtual void clear_viewscreen_vectors() - { - primary_list->clear(); - } - - virtual void add_to_filtered_list(size_t i) - { - primary_list->push_back(saved_list1[i]); - } - - virtual void do_post_search() - { - - } - - virtual bool is_valid_for_search(size_t index) - { - return true; - } - - virtual bool force_in_search(size_t index) - { - return false; - } - - // The actual sort - virtual void do_search() - { - if (search_string.length() == 0) - { - clear_search(); - return; - } - - if (saved_list1.size() == 0) - // On first run, save the original list - save_original_values(); - else - do_pre_incremental_search(); - - clear_viewscreen_vectors(); - - string search_string_l = to_search_normalized(search_string); - for (size_t i = 0; i < saved_list1.size(); i++ ) - { - if (force_in_search(i)) - { - add_to_filtered_list(i); - continue; - } - - if (!is_valid_for_search(i)) - continue; - - T element = saved_list1[i]; - string desc = to_search_normalized(get_element_description(element)); - if (desc.find(search_string_l) != string::npos) - { - add_to_filtered_list(i); - } - } - - do_post_search(); - - if (cursor_pos) - *cursor_pos = 0; - } - - virtual bool should_check_input(set *input) - { - return true; - } - - // Display hotkey message - void print_search_option(int x, int y = -1) const - { - auto dim = Screen::getWindowSize(); - if (y == -1) - y = dim.y - 2; - - OutputString((entry_mode) ? 4 : 12, x, y, string(1, select_key)); - OutputString((entry_mode) ? 10 : 15, x, y, ": Search"); - if (search_string.length() > 0 || entry_mode) - OutputString(15, x, y, ": " + search_string); - if (entry_mode) - OutputString(10, x, y, "_"); - } - - S *viewscreen; - vector saved_list1, reference_list, *primary_list; - - //bool redo_search; - string search_string; - -protected: - int *cursor_pos; - char select_key; - bool valid; - bool entry_mode; - - df::interface_key select_token; - df::interface_key shift_select_token; -}; - -template search_generic *search_generic ::lock = NULL; - - -// Search class helper for layered screens -template -class layered_search : public search_generic -{ -protected: - virtual bool can_init(S *screen) - { - auto list = getLayerList(screen); - if (!is_list_valid(screen) || !list || !list->active) - return false; - - return true; - } - - virtual bool is_list_valid(S*) - { - return true; - } - - virtual void do_search() - { - search_generic::do_search(); - auto list = getLayerList(this->viewscreen); - list->num_entries = this->get_primary_list()->size(); - } - - int32_t *get_viewscreen_cursor() - { - auto list = getLayerList(this->viewscreen); - return &list->cursor; - } - - virtual void clear_search() - { - search_generic::clear_search(); - - if (is_list_valid(this->viewscreen)) - { - auto list = getLayerList(this->viewscreen); - list->num_entries = this->get_primary_list()->size(); - } - } - -private: - static df::layer_object_listst *getLayerList(const df::viewscreen_layer *layer) - { - return virtual_cast(vector_get(layer->layer_objects, LIST_ID)); - } -}; - - - -// Parent class for screens that have more than one primary list to synchronise -template < class S, class T, class PARENT = search_generic > -class search_multicolumn_modifiable_generic : public PARENT -{ -protected: - vector reference_list; - vector saved_indexes; - bool read_only; - - virtual void update_saved_secondary_list_item(size_t i, size_t j) = 0; - virtual void save_secondary_values() = 0; - virtual void clear_secondary_viewscreen_vectors() = 0; - virtual void add_to_filtered_secondary_lists(size_t i) = 0; - virtual void clear_secondary_saved_lists() = 0; - virtual void reset_secondary_viewscreen_vectors() = 0; - virtual void restore_secondary_values() = 0; - - virtual void do_post_init() - { - // If true, secondary list isn't modifiable so don't bother synchronising values - read_only = false; - } - - void reset_all() - { - PARENT::reset_all(); - reference_list.clear(); - saved_indexes.clear(); - reset_secondary_viewscreen_vectors(); - } - - void reset_search() - { - PARENT::reset_search(); - reference_list.clear(); - saved_indexes.clear(); - clear_secondary_saved_lists(); - } - - virtual void clear_search() - { - if (this->saved_list1.size() > 0) - { - do_pre_incremental_search(); - restore_secondary_values(); - } - clear_secondary_saved_lists(); - PARENT::clear_search(); - do_post_search(); - } - - virtual bool is_match(T &a, T &b) = 0; - - virtual bool is_match(vector &a, vector &b) = 0; - - void do_pre_incremental_search() - { - PARENT::do_pre_incremental_search(); - if (read_only) - return; - - bool list_has_been_sorted = (this->primary_list->size() == reference_list.size() - && !is_match(*this->primary_list, reference_list)); - - for (size_t i = 0; i < saved_indexes.size(); i++) - { - int adjusted_item_index = i; - if (list_has_been_sorted) - { - for (size_t j = 0; j < this->primary_list->size(); j++) - { - if (is_match((*this->primary_list)[j], reference_list[i])) - { - adjusted_item_index = j; - break; - } - } - } - - update_saved_secondary_list_item(saved_indexes[i], adjusted_item_index); - } - saved_indexes.clear(); - } - - void clear_viewscreen_vectors() - { - search_generic::clear_viewscreen_vectors(); - saved_indexes.clear(); - clear_secondary_viewscreen_vectors(); - } - - void add_to_filtered_list(size_t i) - { - search_generic::add_to_filtered_list(i); - add_to_filtered_secondary_lists(i); - if (!read_only) - saved_indexes.push_back(i); // Used to map filtered indexes back to original, if needed - } - - virtual void do_post_search() - { - if (!read_only) - reference_list = *this->primary_list; - } - - void save_original_values() - { - search_generic::save_original_values(); - save_secondary_values(); - } -}; - -// This basic match function is separated out from the generic multi column class, because the -// pets screen, which uses a union in its primary list, will cause a compile failure if this -// match function exists in the generic class -template < class S, class T, class PARENT = search_generic > -class search_multicolumn_modifiable : public search_multicolumn_modifiable_generic -{ - bool is_match(T &a, T &b) - { - return a == b; - } - - bool is_match(vector &a, vector &b) - { - return a == b; - } -}; - -// General class for screens that have only one secondary list to keep in sync -template < class S, class T, class V, class PARENT = search_generic > -class search_twocolumn_modifiable : public search_multicolumn_modifiable -{ -public: -protected: - virtual vector * get_secondary_list() = 0; - - virtual void do_post_init() - { - search_multicolumn_modifiable::do_post_init(); - secondary_list = get_secondary_list(); - } - - void save_secondary_values() - { - saved_secondary_list = *secondary_list; - } - - void reset_secondary_viewscreen_vectors() - { - secondary_list = NULL; - } - - virtual void update_saved_secondary_list_item(size_t i, size_t j) - { - saved_secondary_list[i] = (*secondary_list)[j]; - } - - void clear_secondary_viewscreen_vectors() - { - secondary_list->clear(); - } - - void add_to_filtered_secondary_lists(size_t i) - { - secondary_list->push_back(saved_secondary_list[i]); - } - - void clear_secondary_saved_lists() - { - saved_secondary_list.clear(); - } - - void restore_secondary_values() - { - *secondary_list = saved_secondary_list; - } - - vector *secondary_list, saved_secondary_list; -}; - - -// Parent struct for the hooks, use optional param D to generate multiple search classes in the same -// viewscreen but different static modules -template -struct generic_search_hook : T -{ - typedef T interpose_base; - - static V module; - - DEFINE_VMETHOD_INTERPOSE(void, feed, (set *input)) - { - if (!module.init(this)) - { - INTERPOSE_NEXT(feed)(input); - return; - } - - if (!module.process_input(input)) - { - INTERPOSE_NEXT(feed)(input); - module.do_post_input_feed(); - } - - } - - DEFINE_VMETHOD_INTERPOSE(void, render, ()) - { - bool ok = module.init(this); - INTERPOSE_NEXT(render)(); - if (ok) - module.render(); - } - - DEFINE_VMETHOD_INTERPOSE(bool, key_conflict, (df::interface_key key)) - { - if (module.in_entry_mode() && (key == interface_key::MOVIES || key == interface_key::HELP)) - return true; - return INTERPOSE_NEXT(key_conflict)(key); - } -}; - -template V generic_search_hook ::module; - - -// Hook definition helpers -#define IMPLEMENT_HOOKS_WITH_ID(screen, module, id, prio) \ - typedef generic_search_hook module##_hook; \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, feed, prio); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, render, prio); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, key_conflict, prio) - -#define IMPLEMENT_HOOKS(screen, module) \ - typedef generic_search_hook module##_hook; \ - template<> IMPLEMENT_VMETHOD_INTERPOSE(module##_hook, feed); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE(module##_hook, render); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE(module##_hook, key_conflict) - -#define IMPLEMENT_HOOKS_PRIO(screen, module, prio) \ - typedef generic_search_hook module##_hook; \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, feed, prio); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, render, prio); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, key_conflict, prio); - -// -// END: Generic Search functionality -// - - -// -// START: Animal screen search -// - -typedef search_multicolumn_modifiable_generic pets_search_base; -class pets_search : public pets_search_base -{ - typedef df::viewscreen_petst::T_animal T_animal; - typedef df::viewscreen_petst::T_mode T_mode; -public: - void render() const - { - print_search_option(25, 4); - } - -private: - bool can_init(df::viewscreen_petst *screen) - { - return pets_search_base::can_init(screen) && screen->mode == T_mode::List; - } - - int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor; - } - - vector *get_primary_list() - { - return &viewscreen->animal; - } - - virtual void do_post_init() - { - is_vermin = &viewscreen->is_vermin; - is_tame = &viewscreen->is_tame; - is_adopting = &viewscreen->is_adopting; - } - - string get_element_description(df::viewscreen_petst::T_animal element) const - { - return get_unit_description(element.unit); - } - - bool should_check_input() - { - return viewscreen->mode == T_mode::List; - } - - bool is_valid_for_search(size_t i) - { - return is_vermin_s[i] == 0; - } - - void save_secondary_values() - { - is_vermin_s = *is_vermin; - is_tame_s = *is_tame; - is_adopting_s = *is_adopting; - } - - void reset_secondary_viewscreen_vectors() - { - is_vermin = NULL; - is_tame = NULL; - is_adopting = NULL; - } - - void update_saved_secondary_list_item(size_t i, size_t j) - { - is_vermin_s[i] = (*is_vermin)[j]; - is_tame_s[i] = (*is_tame)[j]; - is_adopting_s[i] = (*is_adopting)[j]; - } - - void clear_secondary_viewscreen_vectors() - { - is_vermin->clear(); - is_tame->clear(); - is_adopting->clear(); - } - - void add_to_filtered_secondary_lists(size_t i) - { - is_vermin->push_back(is_vermin_s[i]); - is_tame->push_back(is_tame_s[i]); - is_adopting->push_back(is_adopting_s[i]); - } - - void clear_secondary_saved_lists() - { - is_vermin_s.clear(); - is_tame_s.clear(); - is_adopting_s.clear(); - } - - void restore_secondary_values() - { - *is_vermin = is_vermin_s; - *is_tame = is_tame_s; - *is_adopting = is_adopting_s; - } - - bool is_match(T_animal &a, T_animal &b) - { - return a.unit == b.unit; - } - - bool is_match(vector &a, vector &b) - { - for (size_t i = 0; i < a.size(); i++) - { - if (!is_match(a[i], b[i])) - return false; - } - - return true; - } - - std::vector *is_vermin, is_vermin_s; - std::vector *is_tame, is_tame_s; - std::vector *is_adopting, is_adopting_s; -}; - -IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_petst, pets_search, 1, 0); - -// -// END: Animal screen search -// - - -// -// START: Animal knowledge screen search -// - -typedef search_generic animal_knowledge_search_base; -class animal_knowledge_search : public animal_knowledge_search_base -{ - typedef df::viewscreen_petst::T_mode T_mode; - bool can_init(df::viewscreen_petst *screen) - { - return animal_knowledge_search_base::can_init(screen) && screen->mode == T_mode::TrainingKnowledge; - } - -public: - void render() const - { - print_search_option(2, 4); - } - -private: - int32_t *get_viewscreen_cursor() - { - return NULL; - } - - vector *get_primary_list() - { - return &viewscreen->known; - } - - string get_element_description(int32_t id) const - { - auto craw = df::creature_raw::find(id); - string out; - if (craw) - { - for (size_t i = 0; i < 3; ++i) - out += craw->name[i] + " "; - } - return out; - } -}; - -IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_petst, animal_knowledge_search, 2, 0); - -// -// END: Animal knowledge screen search -// - - -// -// START: Animal trainer search -// - -typedef search_twocolumn_modifiable animal_trainer_search_base; -class animal_trainer_search : public animal_trainer_search_base -{ - typedef df::viewscreen_petst::T_mode T_mode; - typedef df::viewscreen_petst::T_trainer_mode T_trainer_mode; - - bool can_init(df::viewscreen_petst *screen) - { - return animal_trainer_search_base::can_init(screen) && screen->mode == T_mode::SelectTrainer; - } - -public: - void render() const - { - Screen::paintTile(Screen::Pen('\xBA', 8, 0), 14, 2); - Screen::paintTile(Screen::Pen('\xBA', 8, 0), gps->dimx - 14, 2); - Screen::paintTile(Screen::Pen('\xC9', 8, 0), 14, 1); - Screen::paintTile(Screen::Pen('\xBB', 8, 0), gps->dimx - 14, 1); - for (int x = 15; x <= gps->dimx - 15; ++x) - { - Screen::paintTile(Screen::Pen('\xCD', 8, 0), x, 1); - Screen::paintTile(Screen::Pen('\x00', 0, 0), x, 2); - } - print_search_option(16, 2); - } - -private: - int32_t *get_viewscreen_cursor() - { - return &viewscreen->trainer_cursor; - } - - vector *get_primary_list() - { - return &viewscreen->trainer_unit; - } - - string get_element_description(df::unit *u) const - { - return get_unit_description(u); - } - - std::vector *get_secondary_list() - { - return &viewscreen->trainer_mode; - } - -public: - bool process_input(set *input) - { - if (input->count(interface_key::SELECT) && viewscreen->trainer_unit.empty() && !in_entry_mode()) - return true; - return animal_trainer_search_base::process_input(input); - } - -}; - -IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_petst, animal_trainer_search, 3, 0); - -// -// END: Animal trainer search -// - - -// -// START: Stocks screen search -// -typedef search_generic stocks_search_base; -class stocks_search : public stocks_search_base -{ -public: - - void render() const - { - if (!viewscreen->in_group_mode) - print_search_option(2); - else - { - auto dim = Screen::getWindowSize(); - int x = 2, y = dim.y - 2; - OutputString(15, x, y, "Tab to enable Search"); - } - } - - bool process_input(set *input) - { - if (viewscreen->in_group_mode) - return false; - - redo_search = false; - - if ((input->count(interface_key::CURSOR_UP) || input->count(interface_key::CURSOR_DOWN)) && !viewscreen->in_right_list) - { - // Redo search if category changes - saved_list1.clear(); - end_entry_mode(); - if (search_string.length() > 0) - redo_search = true; - - return false; - } - - return stocks_search_base::process_input(input); - } - - virtual void do_post_input_feed() - { - if (viewscreen->in_group_mode) - { - // Disable search if item lists are grouped - clear_search(); - reset_search(); - } - else if (redo_search) - { - do_search(); - redo_search = false; - } - } - -private: - int32_t *get_viewscreen_cursor() - { - return &viewscreen->item_cursor; - } - - virtual vector *get_primary_list() - { - return &viewscreen->items; - } - - -private: - string get_element_description(df::item *element) const - { - if (!element) - return ""; - return Items::getDescription(element, 0, true); - } - - bool redo_search; -}; - - -IMPLEMENT_HOOKS_PRIO(df::viewscreen_storesst, stocks_search, 100); - -// -// END: Stocks screen search -// - - -// -// START: Unit screen search -// -typedef search_twocolumn_modifiable unitlist_search_base; -class unitlist_search : public unitlist_search_base -{ -public: - void render() const - { - print_search_option(28); - } - -private: - void do_post_init() - { - unitlist_search_base::do_post_init(); - read_only = true; - } - - static string get_non_work_description(df::unit *unit) - { - if (!unit) - return ""; - for (auto p = unit->status.misc_traits.begin(); p < unit->status.misc_traits.end(); p++) - { - if ((*p)->id == misc_trait_type::Migrant) - { - return ".new arrival.migrant"; - } - } - - if (Units::isBaby(unit) || - Units::isChild(unit) || - unit->profession == profession::DRUNK) - { - return ""; - } - - if (ENUM_ATTR(profession, military, unit->profession)) - return ".military"; - - return ".idle.no job"; - } - - string get_element_description(df::unit *unit) const - { - if (!unit) - return "Inactive"; - string desc = get_unit_description(unit); - if (!unit->job.current_job) - { - desc += get_non_work_description(unit); - } - - return desc; - } - - bool should_check_input(set *input) - { - if (input->count(interface_key::STANDARDSCROLL_LEFT) || - input->count(interface_key::STANDARDSCROLL_RIGHT) || - (!in_entry_mode() && input->count(interface_key::UNITVIEW_PRF_PROF))) - { - if (!in_entry_mode()) - { - // Changing screens, reset search - int32_t *cursor_pos = get_viewscreen_cursor(); - if (cursor_pos && *cursor_pos < 0) - *cursor_pos = 0; - clear_search(); - reset_all(); - return false; - } - else - { - // Ignore cursor keys when typing - input->erase(interface_key::STANDARDSCROLL_LEFT); - input->erase(interface_key::STANDARDSCROLL_RIGHT); - } - } - - return true; - } - - char get_search_select_key() - { - return 'q'; - } - - vector *get_secondary_list() - { - return &viewscreen->jobs[viewscreen->page]; - } - - int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor_pos[viewscreen->page]; - } - - vector *get_primary_list() - { - return &viewscreen->units[viewscreen->page]; - } -}; - -typedef generic_search_hook unitlist_search_hook; -IMPLEMENT_HOOKS_PRIO(df::viewscreen_unitlistst, unitlist_search, 100); - -// -// END: Unit screen search -// - - -// -// START: Trade screen search -// -class trade_search_base : public search_multicolumn_modifiable -{ -protected: - virtual vector *get_selected_list() = 0; - virtual vector *get_count_list() = 0; - -private: - string get_element_description(df::item *element) const - { - if (!element) - return ""; - return Items::getDescription(element, 0, true); - } - - bool should_check_input(set *input) - { - if (in_entry_mode()) - return true; - - if (input->count(interface_key::TRADE_TRADE) || - input->count(interface_key::TRADE_OFFER) || - input->count(interface_key::TRADE_SEIZE)) - { - // Block the keys if were searching - if (!search_string.empty()) - { - input->clear(); - } - - return false; - } - else if (input->count(interface_key::CUSTOM_ALT_C)) - { - clear_search_for_trade(); - return true; - } - - return true; - } - - void clear_search_for_trade() - { - // Trying to trade, reset search - clear_search(); - reset_all(); - } - - void do_post_init() - { - search_multicolumn_modifiable::do_post_init(); - - selected = get_selected_list(); - count = get_count_list(); - } - - void save_secondary_values() - { - selected_s = *selected; - count_s = *count; - } - - void reset_secondary_viewscreen_vectors() - { - selected = NULL; - count = NULL; - } - - void update_saved_secondary_list_item(size_t i, size_t j) - { - selected_s[i] = (*selected)[j]; - count_s[i] = (*count)[j]; - } - - void clear_secondary_viewscreen_vectors() - { - selected->clear(); - count->clear(); - } - - void add_to_filtered_secondary_lists(size_t i) - { - selected->push_back(selected_s[i]); - count->push_back(count_s[i]); - } - - void clear_secondary_saved_lists() - { - selected_s.clear(); - count_s.clear(); - } - - void restore_secondary_values() - { - *selected = selected_s; - *count = count_s; - } - - std::vector *selected, selected_s; - std::vector *count, count_s; -}; - - -class trade_search_merc : public trade_search_base -{ -public: - virtual void render() const - { - if (viewscreen->counteroffer.size() > 0) - { - // The merchant is proposing a counteroffer. - // Not only is there nothing to search, - // but the native hotkeys are where we normally write. - return; - } - - print_search_option(2, -1); - - if (!search_string.empty()) - { - int32_t x = 2; - int32_t y = gps->dimy - 3; - make_text_dim(2, gps->dimx-2, y); - OutputString(COLOR_LIGHTRED, x, y, string(1, select_key + 'A' - 'a')); - OutputString(COLOR_WHITE, x, y, ": Clear search to trade "); - } - } - -private: - int32_t *get_viewscreen_cursor() - { - return &viewscreen->trader_cursor; - } - - vector *get_primary_list() - { - return &viewscreen->trader_items; - } - - vector *get_selected_list() - { - return &viewscreen->trader_selected; - } - - vector *get_count_list() - { - return &viewscreen->trader_count; - } - - char get_search_select_key() - { - return 'q'; - } -}; - -IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_tradegoodsst, trade_search_merc, 1, 100); - - -class trade_search_fort : public trade_search_base -{ -public: - virtual void render() const - { - if (viewscreen->counteroffer.size() > 0) - { - // The merchant is proposing a counteroffer. - // Not only is there nothing to search, - // but the native hotkeys are where we normally write. - return; - } - - int32_t x = gps->dimx / 2 + 2; - print_search_option(x, -1); - - if (!search_string.empty()) - { - int32_t y = gps->dimy - 3; - make_text_dim(2, gps->dimx-2, y); - OutputString(COLOR_LIGHTRED, x, y, string(1, select_key + 'A' - 'a')); - OutputString(COLOR_WHITE, x, y, ": Clear search to trade "); - } - } - -private: - int32_t *get_viewscreen_cursor() - { - return &viewscreen->broker_cursor; - } - - vector *get_primary_list() - { - return &viewscreen->broker_items; - } - - vector *get_selected_list() - { - return &viewscreen->broker_selected; - } - - vector *get_count_list() - { - return &viewscreen->broker_count; - } - - char get_search_select_key() - { - return 'w'; - } -}; - -IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_tradegoodsst, trade_search_fort, 2, 100); - -// -// END: Trade screen search -// - - -// -// START: Stockpile screen search -// -typedef layered_search stocks_layer; -class stockpile_search : public search_twocolumn_modifiable -{ -public: - void update_saved_secondary_list_item(size_t i, size_t j) - { - *saved_secondary_list[i] = *(*secondary_list)[j]; - } - - string get_element_description(string *element) const - { - return *element; - } - - void render() const - { - print_search_option(51, 23); - } - - vector *get_primary_list() - { - return &viewscreen->item_names; - } - - vector *get_secondary_list() - { - return &viewscreen->item_status; - } - - bool should_check_input(set *input) - { - if (input->count(interface_key::STOCKPILE_SETTINGS_DISABLE) && !in_entry_mode() && !search_string.empty()) - { - // Restore original list - clear_search(); - reset_all(); - } - - return true; - } - -}; - -IMPLEMENT_HOOKS(df::viewscreen_layer_stockpilest, stockpile_search); - -// -// END: Stockpile screen search -// - - -// -// START: Military screen search -// -typedef layered_search military_search_base; -class military_search : public military_search_base -{ -public: - - string get_element_description(df::unit *element) const - { - return get_unit_description(element); - } - - void render() const - { - print_search_option(52, 22); - } - - char get_search_select_key() - { - return 'q'; - } - - // When not on the positions page, this list is used for something - // else entirely, so screwing with it seriously breaks stuff. - bool is_list_valid(df::viewscreen_layer_militaryst *screen) - { - if (screen->page != df::viewscreen_layer_militaryst::Positions) - return false; - - return true; - } - - vector *get_primary_list() - { - return &viewscreen->positions.candidates; - } - - bool should_check_input(set *input) - { - if (input->count(interface_key::SELECT) && !in_entry_mode() && !search_string.empty()) - { - // About to make an assignment, so restore original list (it will be changed by the game) - int32_t *cursor = get_viewscreen_cursor(); - auto list = get_primary_list(); - if (size_t(*cursor) >= list->size()) - return false; - df::unit *selected_unit = list->at(*cursor); - clear_search(); - - for (*cursor = 0; size_t(*cursor) < list->size(); (*cursor)++) - { - if (list->at(*cursor) == selected_unit) - break; - } - - reset_all(); - } - - return true; - } -}; - -IMPLEMENT_HOOKS_PRIO(df::viewscreen_layer_militaryst, military_search, 100); - -// -// END: Military screen search -// - - -// -// START: Room list search -// -typedef search_twocolumn_modifiable roomlist_search_base; -class roomlist_search : public roomlist_search_base -{ -public: - void render() const - { - print_search_option(2, 23); - } - -private: - void do_post_init() - { - roomlist_search_base::do_post_init(); - read_only = true; - } - - string get_element_description(df::building *bld) const - { - if (!bld) - return ""; - - string desc; - desc.reserve(100); - if (bld->owner) - desc += get_unit_description(bld->owner); - - desc += "."; - - string room_desc = Buildings::getRoomDescription(bld, nullptr); - desc += room_desc; - if (room_desc.empty()) - { - if (!bld->owner) - desc += "no owner"; - - string name; - bld->getName(&name); - if (!name.empty()) - { - desc += name; - } - } - - return desc; - } - - vector *get_secondary_list() - { - return &viewscreen->room_value; - } - - int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor; - } - - vector *get_primary_list() - { - return &viewscreen->buildings; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_buildinglistst, roomlist_search); - -// -// END: Room list search -// - - - -// -// START: Announcement list search -// -class announcement_search : public search_generic -{ -public: - void render() const - { - print_search_option(2, gps->dimy - 3); - } - -private: - int32_t *get_viewscreen_cursor() - { - return &viewscreen->sel_idx; - } - - virtual vector *get_primary_list() - { - return &viewscreen->reports; - } - - -private: - string get_element_description(df::report *element) const - { - if (!element) - return ""; - return element->text; - } -}; - - -IMPLEMENT_HOOKS(df::viewscreen_announcelistst, announcement_search); - -// -// END: Announcement list search -// - - -// -// START: Nobles search list -// -typedef df::viewscreen_layer_noblelistst::T_candidates T_candidates; -typedef layered_search nobles_search_base; -class nobles_search : public nobles_search_base -{ -public: - - string get_element_description(T_candidates *element) const - { - if (!element->unit) - return ""; - - return get_unit_description(element->unit); - } - - void render() const - { - print_search_option(2, 23); - } - - bool force_in_search(size_t index) - { - return index == 0; // Leave Vacant - } - - bool can_init(df::viewscreen_layer_noblelistst *screen) - { - if (screen->mode != df::viewscreen_layer_noblelistst::Appoint) - return false; - - return nobles_search_base::can_init(screen); - } - - vector *get_primary_list() - { - return &viewscreen->candidates; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_layer_noblelistst, nobles_search); - -// -// END: Nobles search list -// - -// -// START: Workshop profiles search list -// -typedef search_generic profiles_search_base; -class profiles_search : public profiles_search_base -{ -public: - - bool can_init (df::viewscreen_workshop_profilest *screen) - { - return screen->tab == df::viewscreen_workshop_profilest::T_tab::Workers; - } - - string get_element_description(df::unit *element) const - { - return get_unit_description(element); - } - - void render() const - { - print_search_option(2, gps->dimy - 5); - } - - vector *get_primary_list() - { - return &viewscreen->workers; - } - - int32_t *get_viewscreen_cursor() - { - return &viewscreen->worker_idx; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_workshop_profilest, profiles_search); - -// -// END: Workshop profiles search list -// - - -// -// START: Job list search -// -void get_job_details(string &desc, df::job *job) -{ - string job_name = ENUM_KEY_STR(job_type,job->job_type); - for (size_t i = 0; i < job_name.length(); i++) - { - char c = job_name[i]; - if (c >= 'A' && c <= 'Z') - desc += " "; - desc += c; - } - desc += "."; - - df::item_type itype = ENUM_ATTR(job_type, item, job->job_type); - - MaterialInfo mat(job); - if (itype == item_type::FOOD) - mat.decode(-1); - - if (mat.isValid() || job->material_category.whole) - { - desc += mat.toString(); - desc += "."; - if (job->material_category.whole) - { - desc += bitfield_to_string(job->material_category); - desc += "."; - } - } - - if (!job->reaction_name.empty()) - { - for (size_t i = 0; i < job->reaction_name.length(); i++) - { - if (job->reaction_name[i] == '_') - desc += " "; - else - desc += job->reaction_name[i]; - } - - desc += "."; - } - - if (job->flags.bits.suspend) - desc += "suspended."; -} - -typedef search_twocolumn_modifiable joblist_search_base; -class joblist_search : public joblist_search_base -{ -public: - void render() const - { - print_search_option(2); - } - -private: - void do_post_init() - { - joblist_search_base::do_post_init(); - read_only = true; - } - - string get_element_description(df::job *element) const - { - if (!element) - return "no job.idle"; - - string desc; - desc.reserve(100); - get_job_details(desc, element); - df::unit *worker = DFHack::Job::getWorker(element); - if (worker) - desc += get_unit_description(worker); - else - desc += "Inactive"; - - return desc; - } - - char get_search_select_key() - { - return 'q'; - } - - vector *get_secondary_list() - { - return &viewscreen->units; - } - - int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor_pos; - } - - vector *get_primary_list() - { - return &viewscreen->jobs; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_joblistst, joblist_search); - -// -// END: Job list search -// - - -// -// START: Look menu search -// - -typedef search_generic look_menu_search_base; -class look_menu_search : public look_menu_search_base -{ - typedef df::ui_look_list::T_items::T_type elt_type; -public: - bool can_init(df::viewscreen_dwarfmodest *screen) - { - if (plotinfo->main.mode == df::ui_sidebar_mode::LookAround) - { - return look_menu_search_base::can_init(screen); - } - - return false; - } - - string get_element_description(df::ui_look_list::T_items *element) const - { - std::string desc = ""; - switch (element->type) - { - case elt_type::Item: - if (element->data.Item) - desc = Items::getDescription(element->data.Item, 0, true); - break; - case elt_type::Unit: - if (element->data.Unit) - desc = get_unit_description(element->data.Unit); - break; - case elt_type::Building: - if (element->data.Building) - element->data.Building->getName(&desc); - break; - default: - break; - } - return desc; - } - - bool force_in_search (size_t i) - { - df::ui_look_list::T_items *element = saved_list1[i]; - switch (element->type) - { - case elt_type::Item: - case elt_type::Unit: - case elt_type::Building: - return false; - break; - default: - return true; - break; - } - } - - void render() const - { - auto dims = Gui::getDwarfmodeViewDims(); - int left_margin = dims.menu_x1 + 1; - int x = left_margin; - int y = 1; - - print_search_option(x, y); - } - - vector *get_primary_list() - { - return &ui_look_list->items; - } - - virtual int32_t * get_viewscreen_cursor() - { - return ui_look_cursor; - } - - - bool should_check_input(set *input) - { - if (input->count(interface_key::SECONDSCROLL_UP) - || input->count(interface_key::SECONDSCROLL_DOWN) - || input->count(interface_key::SECONDSCROLL_PAGEUP) - || input->count(interface_key::SECONDSCROLL_PAGEDOWN)) - { - end_entry_mode(); - return false; - } - bool hotkey_pressed = - input->lower_bound(interface_key::D_HOTKEY1) != input->upper_bound(interface_key::D_HOTKEY16); - if (cursor_key_pressed(input, in_entry_mode()) || hotkey_pressed) - { - end_entry_mode(); - clear_search(); - return false; - } - - return true; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_dwarfmodest, look_menu_search); - -// -// END: Look menu search -// - - -// -// START: Burrow assignment search -// - -typedef search_twocolumn_modifiable burrow_search_base; -class burrow_search : public burrow_search_base -{ -public: - bool can_init(df::viewscreen_dwarfmodest *screen) - { - if (plotinfo->main.mode == df::ui_sidebar_mode::Burrows && plotinfo->burrows.in_add_units_mode) - { - return burrow_search_base::can_init(screen); - } - - return false; - } - - string get_element_description(df::unit *element) const - { - return get_unit_description(element); - } - - void render() const - { - auto dims = Gui::getDwarfmodeViewDims(); - int left_margin = dims.menu_x1 + 1; - int x = left_margin; - int y = 23; - - print_search_option(x, y); - } - - vector *get_primary_list() - { - return &plotinfo->burrows.list_units; - } - - vector *get_secondary_list() - { - return &plotinfo->burrows.sel_units; - } - - virtual int32_t * get_viewscreen_cursor() - { - return &plotinfo->burrows.unit_cursor_pos; - } - - - bool should_check_input(set *input) - { - if (input->count(interface_key::SECONDSCROLL_UP) || input->count(interface_key::SECONDSCROLL_DOWN) - || input->count(interface_key::SECONDSCROLL_PAGEUP) || input->count(interface_key::SECONDSCROLL_PAGEDOWN)) - { - end_entry_mode(); - return false; - } - - return true; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_dwarfmodest, burrow_search); - -// -// END: Burrow assignment search -// - - -// -// START: Room assignment search -// - -typedef search_generic room_assign_search_base; -class room_assign_search : public room_assign_search_base -{ -public: - bool can_init(df::viewscreen_dwarfmodest *screen) - { - if (plotinfo->main.mode == df::ui_sidebar_mode::QueryBuilding && *ui_building_in_assign) - { - return room_assign_search_base::can_init(screen); - } - - return false; - } - - string get_element_description(df::unit *element) const - { - return element ? get_unit_description(element) : "Nobody"; - } - - void render() const - { - auto dims = Gui::getDwarfmodeViewDims(); - int left_margin = dims.menu_x1 + 1; - int x = left_margin; - int y = 19; - - print_search_option(x, y); - } - - vector *get_primary_list() - { - return ui_building_assign_units; - } - - virtual int32_t * get_viewscreen_cursor() - { - return ui_building_item_cursor; - } - - bool should_check_input(set *input) - { - if (input->count(interface_key::SECONDSCROLL_UP) || input->count(interface_key::SECONDSCROLL_DOWN) - || input->count(interface_key::SECONDSCROLL_PAGEUP) || input->count(interface_key::SECONDSCROLL_PAGEDOWN)) - { - end_entry_mode(); - return false; - } - - return true; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_dwarfmodest, room_assign_search); - -// -// END: Room assignment search -// - -// -// START: Noble suggestion search -// - -typedef search_generic noble_suggest_search_base; -class noble_suggest_search : public noble_suggest_search_base -{ -public: - string get_element_description (int32_t hf_id) const - { - df::historical_figure *histfig = df::historical_figure::find(hf_id); - if (!histfig) - return ""; - df::unit *unit = df::unit::find(histfig->unit_id); - if (!unit) - return ""; - return get_unit_description(unit); - } - - void render() const - { - print_search_option(2, gps->dimy - 4); - } - - vector *get_primary_list() - { - return &viewscreen->candidate_histfig_ids; - } - - virtual int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor; - } - -}; - -IMPLEMENT_HOOKS(df::viewscreen_topicmeeting_fill_land_holder_positionsst, noble_suggest_search); - -// -// END: Noble suggestion search -// - -// -// START: Location occupation assignment search -// - -typedef search_generic location_assign_occupation_search_base; -class location_assign_occupation_search : public location_assign_occupation_search_base -{ -public: - bool can_init (df::viewscreen_locationsst *screen) - { - return screen->menu == df::viewscreen_locationsst::AssignOccupation; - } - - string get_element_description (df::unit *unit) const - { - return unit ? get_unit_description(unit) : "Nobody"; - } - - void render() const - { - print_search_option(37, gps->dimy - 3); - } - - vector *get_primary_list() - { - return &viewscreen->units; - } - - virtual int32_t *get_viewscreen_cursor() - { - return &viewscreen->unit_idx; - } - -}; - -IMPLEMENT_HOOKS(df::viewscreen_locationsst, location_assign_occupation_search); - -// -// END: Location occupation assignment search -// - -// -// START: Kitchen preferences search -// - -typedef search_multicolumn_modifiable kitchen_pref_search_base; -class kitchen_pref_search : public kitchen_pref_search_base -{ -public: - - string get_element_description(string *s) const override - { - return s ? *s : ""; - } - - void render() const override - { - print_search_option(40, gps->dimy - 2); - } - - int32_t *get_viewscreen_cursor() override - { - return &viewscreen->cursor; - } - - vector *get_primary_list() override - { - return &viewscreen->item_str[viewscreen->page]; - } - - bool should_check_input(set *input) override - { - if (input->count(interface_key::CHANGETAB) || input->count(interface_key::SEC_CHANGETAB)) - { - // Restore original list - clear_search(); - reset_all(); - } - - return true; - } - - -#define KITCHEN_VECTORS \ - KVEC(df::item_type, item_type); \ - KVEC(int16_t, item_subtype); \ - KVEC(int16_t, mat_type); \ - KVEC(int32_t, mat_index); \ - KVEC(int32_t, count); \ - KVEC(df::kitchen_pref_flag, forbidden); \ - KVEC(df::kitchen_pref_flag, possible) - - - virtual void do_post_init() - { - kitchen_pref_search_base::do_post_init(); - #define KVEC(type, name) name = &viewscreen->name[viewscreen->page] - KITCHEN_VECTORS; - #undef KVEC - } - - void save_secondary_values() - { - #define KVEC(type, name) name##_s = *name - KITCHEN_VECTORS; - #undef KVEC - } - - void reset_secondary_viewscreen_vectors() - { - #define KVEC(type, name) name = nullptr - KITCHEN_VECTORS; - #undef KVEC - } - - virtual void update_saved_secondary_list_item(size_t i, size_t j) - { - #define KVEC(type, name) name##_s[i] = (*name)[j]; - KITCHEN_VECTORS; - #undef KVEC - } - - void clear_secondary_viewscreen_vectors() - { - #define KVEC(type, name) name->clear() - KITCHEN_VECTORS; - #undef KVEC - } - - void add_to_filtered_secondary_lists(size_t i) - { - #define KVEC(type, name) name->push_back(name##_s[i]) - KITCHEN_VECTORS; - #undef KVEC - } - - void clear_secondary_saved_lists() - { - #define KVEC(type, name) name##_s.clear() - KITCHEN_VECTORS; - #undef KVEC - } - - void restore_secondary_values() - { - #define KVEC(type, name) *name = name##_s - KITCHEN_VECTORS; - #undef KVEC - } - - #define KVEC(type, name) vector *name, name##_s - KITCHEN_VECTORS; - #undef KVEC -#undef KITCHEN_VECTORS -}; - -IMPLEMENT_HOOKS(df::viewscreen_kitchenprefst, kitchen_pref_search); - -// -// END: Kitchen preferences search -// - - -// -// START: Stone status screen search -// -typedef layered_search stone_search_layer; -class stone_search : public search_twocolumn_modifiable -{ - // bool in_update = false; -public: - void render() const override - { - print_search_option(21, 23); - } - - vector *get_primary_list() override - { - return &viewscreen->stone_type[viewscreen->type_tab]; - } - - vector *get_secondary_list() override - { - return &viewscreen->stone_economic[viewscreen->type_tab]; - } - - string get_element_description(int32_t stone_type) const override - { - auto iraw = vector_get(world->raws.inorganics, stone_type); - if (!iraw) - return ""; - return iraw->material.stone_name + " " + iraw->material.state_name[0]; - } - - bool should_check_input(set *input) override - { - // if (in_update) - // return false; - - if (input->count(interface_key::CHANGETAB)) - { - // Restore original list - clear_search(); - reset_all(); - } - - return true; - } - - // virtual void do_post_input_feed() override - // { - // auto *list1 = get_primary_list(); - // auto *list2 = get_secondary_list(); - // bool appended = false; - // if (list1->empty()) - // { - // // Clear uses - // auto *use_list = virtual_cast(viewscreen->layer_objects[4]); - // if (use_list) - // use_list->num_entries = 0; - // return; - // } - // else if (list1->size() == 1) - // { - // list1->push_back(list1->back()); - // list2->push_back(list2->back()); - // appended = true; - // } - - // in_update = true; - // Core::printerr("updating\n"); - // viewscreen->feed_key(interface_key::STANDARDSCROLL_DOWN); - // viewscreen->feed_key(interface_key::STANDARDSCROLL_UP); - // Core::printerr("updating done\n"); - // in_update = false; - - // if (appended) - // { - // list1->pop_back(); - // list2->pop_back(); - // } - // } -}; - -IMPLEMENT_HOOKS(df::viewscreen_layer_stone_restrictionst, stone_search); - -// -// END: Stone status screen search -// - -// -// START: Justice screen conviction search -// - -typedef search_generic justice_conviction_search_base; -class justice_conviction_search : public justice_conviction_search_base -{ -public: - bool can_init (df::viewscreen_justicest *screen) - { - return screen->cur_column == df::viewscreen_justicest::ConvictChoices; - } - - string get_element_description (df::unit *unit) const - { - return get_unit_description(unit); - } - - void render() const - { - print_search_option(37); - } - - vector *get_primary_list() - { - return &viewscreen->convict_choices; - } - - virtual int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor_right; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_justicest, justice_conviction_search); - -// -// END: Justice screen conviction search -// - -// -// START: Justice screen interrogation search -// - -typedef search_generic justice_interrogation_search_base; -class justice_interrogation_search : public justice_interrogation_search_base -{ -public: - bool can_init (df::viewscreen_justicest *screen) - { - return screen->cur_column == df::viewscreen_justicest::InterrogateChoices; - } - - string get_element_description (df::unit *unit) const - { - return get_unit_description(unit); - } - - void render() const - { - print_search_option(37); - } - - vector *get_primary_list() - { - return &viewscreen->interrogate_choices; - } - - virtual int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor_right; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_justicest, justice_interrogation_search); - -// -// END: Justice screen conviction search -// - -#define SEARCH_HOOKS \ - HOOK_ACTION(unitlist_search_hook) \ - HOOK_ACTION(roomlist_search_hook) \ - HOOK_ACTION(trade_search_merc_hook) \ - HOOK_ACTION(trade_search_fort_hook) \ - HOOK_ACTION(stocks_search_hook) \ - HOOK_ACTION(pets_search_hook) \ - HOOK_ACTION(animal_knowledge_search_hook) \ - HOOK_ACTION(animal_trainer_search_hook) \ - HOOK_ACTION(military_search_hook) \ - HOOK_ACTION(nobles_search_hook) \ - HOOK_ACTION(profiles_search_hook) \ - HOOK_ACTION(announcement_search_hook) \ - HOOK_ACTION(joblist_search_hook) \ - HOOK_ACTION(look_menu_search_hook) \ - HOOK_ACTION(burrow_search_hook) \ - HOOK_ACTION(stockpile_search_hook) \ - HOOK_ACTION(room_assign_search_hook) \ - HOOK_ACTION(noble_suggest_search_hook) \ - HOOK_ACTION(location_assign_occupation_search_hook) \ - HOOK_ACTION(kitchen_pref_search_hook) \ - HOOK_ACTION(stone_search_hook) \ - HOOK_ACTION(justice_conviction_search_hook) \ - HOOK_ACTION(justice_interrogation_search_hook) \ - - -DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable) -{ - if (!gps || !gview) - return CR_FAILURE; - - if (is_enabled != enable) - { -#define HOOK_ACTION(hook) \ - !INTERPOSE_HOOK(hook, feed).apply(enable) || \ - !INTERPOSE_HOOK(hook, render).apply(enable) || \ - !INTERPOSE_HOOK(hook, key_conflict).apply(enable) || - - if (SEARCH_HOOKS 0) - return CR_FAILURE; - - is_enabled = enable; - } -#undef HOOK_ACTION - - return CR_OK; -} - -DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) -{ - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ -#define HOOK_ACTION(hook) \ - INTERPOSE_HOOK(hook, feed).remove(); \ - INTERPOSE_HOOK(hook, render).remove(); \ - INTERPOSE_HOOK(hook, key_conflict).remove(); - - SEARCH_HOOKS - -#undef HOOK_ACTION - - return CR_OK; -} - -DFhackCExport command_result plugin_onstatechange ( color_ostream &out, state_change_event event ) -{ -#define HOOK_ACTION(hook) hook::module.reset_on_change(); - - switch (event) { - case SC_VIEWSCREEN_CHANGED: - SEARCH_HOOKS - break; - - default: - break; - } - - return CR_OK; - -#undef HOOK_ACTION -} - -#undef IMPLEMENT_HOOKS -#undef SEARCH_HOOKS From 940f7de0d29a13e67887cb5b903a32b8f55e443f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 2 Nov 2023 12:44:37 -0700 Subject: [PATCH 816/851] implement autogrow and update docs also fix bad state tracking in EventManager for the JobStarted event --- data/init/dfhack.tools.init | 1 + docs/changelog.txt | 2 + docs/dev/Lua API.rst | 45 --- docs/plugins/burrow.rst | 4 +- library/modules/EventManager.cpp | 25 +- plugins/burrow.cpp | 611 ++++++------------------------- plugins/lua/burrow.lua | 9 - 7 files changed, 141 insertions(+), 556 deletions(-) diff --git a/data/init/dfhack.tools.init b/data/init/dfhack.tools.init index 38221883a..02169b526 100644 --- a/data/init/dfhack.tools.init +++ b/data/init/dfhack.tools.init @@ -80,6 +80,7 @@ # Enable system services enable buildingplan +enable burrow enable confirm enable logistics enable overlay diff --git a/docs/changelog.txt b/docs/changelog.txt index 19d87faad..8a06ee1a1 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -52,9 +52,11 @@ Template for new versions: # Future ## New Tools +- `burrow`: (reinstated) automatically expand burrows as you dig ## New Features - `prospect`: can now give you an estimate of resources from the embark screen. hover the mouse over a potential embark area and run `prospect`. +- `burrow`: integrated 3d box fill and 2d/3d flood fill extensions for burrow painting mode ## Fixes - `stockpiles`: hide configure and help buttons when the overlay panel is minimized diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index eeb0fbda6..dd057fe01 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5612,51 +5612,6 @@ Native functions provided by the `buildingplan` plugin: * ``void doCycle()`` runs a check for whether buildings in the monitor list can be assigned items and unsuspended. This method runs automatically twice a game day, so you only need to call it directly if you want buildingplan to do a check right now. * ``void scheduleCycle()`` schedules a cycle to be run during the next non-paused game frame. Can be called multiple times while the game is paused and only one cycle will be scheduled. -burrow -====== - -The `burrow` plugin implements extended burrow manipulations. - -Events: - -* ``onBurrowRename.foo = function(burrow)`` - - Emitted when a burrow might have been renamed either through - the game UI, or ``renameBurrow()``. - -* ``onDigComplete.foo = function(job_type,pos,old_tiletype,new_tiletype,worker)`` - - Emitted when a tile might have been dug out. Only tracked if the - auto-growing burrows feature is enabled. - -Native functions: - -* ``renameBurrow(burrow,name)`` - - Renames the burrow, emitting ``onBurrowRename`` and updating auto-grow state properly. - -* ``findByName(burrow,name)`` - - Finds a burrow by name, using the same rules as the plugin command line interface. - Namely, trailing ``'+'`` characters marking auto-grow burrows are ignored. - -* ``copyUnits(target,source,enable)`` - - Applies units from ``source`` burrow to ``target``. The ``enable`` - parameter specifies if they are to be added or removed. - -* ``copyTiles(target,source,enable)`` - - Applies tiles from ``source`` burrow to ``target``. The ``enable`` - parameter specifies if they are to be added or removed. - -* ``setTilesByKeyword(target,keyword,enable)`` - - Adds or removes tiles matching a predefined keyword. The keyword - set is the same as used by the command line. - -The lua module file also re-exports functions from ``dfhack.burrows``. - .. _cxxrandom-api: cxxrandom diff --git a/docs/plugins/burrow.rst b/docs/plugins/burrow.rst index 68556053b..f84f02989 100644 --- a/docs/plugins/burrow.rst +++ b/docs/plugins/burrow.rst @@ -7,7 +7,9 @@ burrow This tool has two modes. When enabled, it monitors burrows with names that end in ``+``. If a wall at the edge of such a burrow is dug out, the burrow will be -automatically extended to include the newly-revealed adjacent walls. +automatically extended to include the newly-revealed adjacent walls. If a miner +digs into an open space, such as a cavern, the open space will *not* be +included in the burrow. When run as a command, it can quickly adjust which tiles and/or units are associated with the burrow. diff --git a/library/modules/EventManager.cpp b/library/modules/EventManager.cpp index 14fac42b3..e985cfa96 100644 --- a/library/modules/EventManager.cpp +++ b/library/modules/EventManager.cpp @@ -206,6 +206,9 @@ std::array compileManagerArray() { //job initiated static int32_t lastJobId = -1; +//job started +static unordered_set startedJobs; + //job completed static unordered_map prevJobs; @@ -269,6 +272,7 @@ void DFHack::EventManager::onStateChange(color_ostream& out, state_change_event } if ( event == DFHack::SC_MAP_UNLOADED ) { lastJobId = -1; + startedJobs.clear(); for (auto &prevJob : prevJobs) { Job::deleteJobStruct(prevJob.second, true); } @@ -461,29 +465,27 @@ static void manageJobStartedEvent(color_ostream& out) { if (!df::global::world) return; - static unordered_set startedJobs; - - vector new_started_jobs; // iterate event handler callbacks multimap copy(handlers[EventType::JOB_STARTED].begin(), handlers[EventType::JOB_STARTED].end()); + unordered_set newStartedJobs; + for (df::job_list_link* link = &df::global::world->jobs.list; link->next != nullptr; link = link->next) { df::job* job = link->next->item; + if (!job || !Job::getWorker(job)) + continue; + int32_t j_id = job->id; - if (job && Job::getWorker(job) && !startedJobs.count(job->id)) { - startedJobs.emplace(job->id); + newStartedJobs.emplace(j_id); + if (!startedJobs.count(j_id)) { for (auto &[_,handle] : copy) { - // the jobs must have a worker to start DEBUG(log,out).print("calling handler for job started event\n"); handle.eventHandler(out, job); } } - if (link->next == nullptr || link->next->item->id != j_id) { - if ( Once::doOnce("EventManager jobstarted job removed") ) { - out.print("%s,%d: job %u removed from jobs linked list\n", __FILE__, __LINE__, j_id); - } - } } + + startedJobs = newStartedJobs; } //helper function for manageJobCompletedEvent @@ -498,6 +500,7 @@ TODO: consider checking item creation / experience gain just in case static void manageJobCompletedEvent(color_ostream& out) { if (!df::global::world) return; + int32_t tick0 = eventLastTick[EventType::JOB_COMPLETED]; int32_t tick1 = df::global::world->frame_counter; diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index ef6231990..f33e9e910 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -5,12 +5,15 @@ #include "TileTypes.h" #include "modules/Burrows.h" +#include "modules/EventManager.h" +#include "modules/Job.h" #include "modules/Persistence.h" #include "modules/World.h" #include "df/block_burrow.h" #include "df/burrow.h" #include "df/map_block.h" +#include "df/plotinfost.h" #include "df/tile_designation.h" #include "df/unit.h" #include "df/world.h" @@ -22,6 +25,7 @@ using namespace DFHack; DFHACK_PLUGIN("burrow"); DFHACK_PLUGIN_IS_ENABLED(is_enabled); +REQUIRE_GLOBAL(plotinfo); REQUIRE_GLOBAL(window_z); REQUIRE_GLOBAL(world); @@ -30,35 +34,15 @@ namespace DFHack { // for configuration-related logging DBG_DECLARE(burrow, status, DebugCategory::LINFO); // for logging during the periodic scan - DBG_DECLARE(burrow, cycle, DebugCategory::LINFO); -} - -static const auto CONFIG_KEY = std::string(plugin_name) + "/config"; -static PersistentDataItem config; -enum ConfigValues { - CONFIG_IS_ENABLED = 0, -}; -static int get_config_val(int index) { - if (!config.isValid()) - return -1; - return config.ival(index); -} -static bool get_config_bool(int index) { - return get_config_val(index) == 1; -} -static void set_config_val(int index, int value) { - if (config.isValid()) - config.ival(index) = value; -} -static void set_config_bool(int index, bool value) { - set_config_val(index, value ? 1 : 0); + DBG_DECLARE(burrow, event, DebugCategory::LINFO); } -static const int32_t CYCLE_TICKS = 100; -static int32_t cycle_timestamp = 0; // world->frame_counter at last cycle +static std::unordered_map active_dig_jobs; static command_result do_command(color_ostream &out, vector ¶meters); -static void do_cycle(color_ostream &out); +static void init_diggers(color_ostream& out); +static void jobStartedHandler(color_ostream& out, void* ptr); +static void jobCompletedHandler(color_ostream& out, void* ptr); DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { DEBUG(status, out).print("initializing %s\n", plugin_name); @@ -69,18 +53,21 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vectorframe_counter - cycle_timestamp >= CYCLE_TICKS) - do_cycle(out); + if (event == DFHack::SC_WORLD_UNLOADED) + reset(); return CR_OK; } @@ -172,15 +131,107 @@ static command_result do_command(color_ostream &out, vector ¶meters) } ///////////////////////////////////////////////////// -// cycle logic +// listener logic // -static void do_cycle(color_ostream &out) +static void init_diggers(color_ostream& out) { + if (!Core::getInstance().isWorldLoaded()) { + DEBUG(status, out).print("world not yet loaded; not scanning jobs\n"); + return; + } + + std::vector pvec; + int start_id = 0; + if (Job::listNewlyCreated(&pvec, &start_id)) { + for (auto job : pvec) { + if (Job::getWorker(job)) + jobStartedHandler(out, job); + } + } +} + +static void jobStartedHandler(color_ostream& out, void* ptr) { + DEBUG(event, out).print("entering jobStartedHandler\n"); + + df::job *job = (df::job *)ptr; + auto type = ENUM_ATTR(job_type, type, job->job_type); + if (type != job_type_class::Digging) + return; + + const df::coord &pos = job->pos; + DEBUG(event, out).print("dig job started: id=%d, pos=(%d,%d,%d), type=%s\n", + job->id, pos.x, pos.y, pos.z, ENUM_KEY_STR(job_type, job->job_type).c_str()); + df::tiletype *tt = Maps::getTileType(pos); + if (tt) + active_dig_jobs[pos] = *tt; +} + +static void add_walls_to_burrow(color_ostream &out, df::burrow* b, + const df::coord & pos1, const df::coord & pos2) { - // mark that we have recently run - cycle_timestamp = world->frame_counter; + for (int z = pos1.z; z <= pos2.z; z++) { + for (int y = pos1.y; y <= pos2.y; y++) { + for (int x = pos1.x; x <= pos2.x; x++) { + df::coord pos(x,y,z); + df::tiletype *tt = Maps::getTileType(pos); + if (tt && isWallTerrain(*tt)) + Burrows::setAssignedTile(b, pos, true); + } + } + } +} + +static void expand_burrows(color_ostream &out, const df::coord & pos, df::tiletype prev_tt, df::tiletype tt) { + if (!isWalkable(tt)) + return; + + bool changed = false; + for (auto b : plotinfo->burrows.list) { + if (!b->name.ends_with('+') || !Burrows::isAssignedTile(b, pos)) + continue; + + if (!isWalkable(prev_tt)) { + changed = true; + add_walls_to_burrow(out, b, pos+df::coord(-1,-1,0), pos+df::coord(1,1,0)); + + if (isWalkableUp(tt)) + Burrows::setAssignedTile(b, pos+df::coord(0,0,1), true); + + if (tileShape(tt) == tiletype_shape::RAMP) + add_walls_to_burrow(out, b, pos+df::coord(-1,-1,1), pos+df::coord(1,1,1)); + } + + if (LowPassable(tt) && !LowPassable(prev_tt)) { + changed = true; + Burrows::setAssignedTile(b, pos-df::coord(0,0,1), true); + if (tileShape(tt) == tiletype_shape::RAMP_TOP) + add_walls_to_burrow(out, b, pos+df::coord(-1,-1,-1), pos+df::coord(1,1,-1)); + } + } + + if (changed) + Job::checkDesignationsNow(); +} + +static void jobCompletedHandler(color_ostream& out, void* ptr) { + DEBUG(event, out).print("entering jobCompletedHandler\n"); + + df::job *job = (df::job *)ptr; + auto type = ENUM_ATTR(job_type, type, job->job_type); + if (type != job_type_class::Digging) + return; + + const df::coord &pos = job->pos; + DEBUG(event, out).print("dig job completed: id=%d, pos=(%d,%d,%d), type=%s\n", + job->id, pos.x, pos.y, pos.z, ENUM_KEY_STR(job_type, job->job_type).c_str()); + + df::tiletype prev_tt = active_dig_jobs[pos]; + df::tiletype *tt = Maps::getTileType(pos); + + if (tt && *tt && *tt != prev_tt) + expand_burrows(out, pos, prev_tt, *tt); - // TODO + active_dig_jobs.erase(pos); } ///////////////////////////////////////////////////// @@ -633,423 +684,3 @@ DFHACK_PLUGIN_LUA_COMMANDS { DFHACK_LUA_COMMAND(burrow_units_remove), DFHACK_LUA_END }; - - -/* -#include "Core.h" -#include "Console.h" -#include "Export.h" -#include "PluginManager.h" -#include "Error.h" - -#include "DataFuncs.h" -#include "LuaTools.h" - -#include "modules/Gui.h" -#include "modules/Job.h" -#include "modules/Maps.h" -#include "modules/MapCache.h" -#include "modules/World.h" -#include "modules/Units.h" -#include "TileTypes.h" - -#include "DataDefs.h" -#include "df/plotinfost.h" -#include "df/world.h" -#include "df/unit.h" -#include "df/burrow.h" -#include "df/map_block.h" -#include "df/block_burrow.h" -#include "df/job.h" -#include "df/job_list_link.h" - -#include "MiscUtils.h" - -#include - -using std::vector; -using std::string; -using std::endl; -using namespace DFHack; -using namespace df::enums; -using namespace dfproto; - -DFHACK_PLUGIN("burrow"); -REQUIRE_GLOBAL(plotinfo); -REQUIRE_GLOBAL(world); -REQUIRE_GLOBAL(gamemode); - -static void init_map(color_ostream &out); -static void deinit_map(color_ostream &out); - -DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) -{ - - if (Core::getInstance().isMapLoaded()) - init_map(out); - - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ - deinit_map(out); - - return CR_OK; -} - -DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_change_event event) -{ - switch (event) { - case SC_MAP_LOADED: - deinit_map(out); - if (gamemode && - *gamemode == game_mode::DWARF) - init_map(out); - break; - case SC_MAP_UNLOADED: - deinit_map(out); - break; - default: - break; - } - - return CR_OK; -} - -static int name_burrow_id = -1; - -static void handle_burrow_rename(color_ostream &out, df::burrow *burrow); - -DEFINE_LUA_EVENT_1(onBurrowRename, handle_burrow_rename, df::burrow*); - -static void detect_burrow_renames(color_ostream &out) -{ - if (plotinfo->main.mode == ui_sidebar_mode::Burrows && - plotinfo->burrows.in_edit_name_mode && - plotinfo->burrows.sel_id >= 0) - { - name_burrow_id = plotinfo->burrows.sel_id; - } - else if (name_burrow_id >= 0) - { - auto burrow = df::burrow::find(name_burrow_id); - name_burrow_id = -1; - if (burrow) - onBurrowRename(out, burrow); - } -} - -struct DigJob { - int id; - df::job_type job; - df::coord pos; - df::tiletype old_tile; -}; - -static int next_job_id_save = 0; -static std::map diggers; - -static void handle_dig_complete(color_ostream &out, df::job_type job, df::coord pos, - df::tiletype old_tile, df::tiletype new_tile, df::unit *worker); - -DEFINE_LUA_EVENT_5(onDigComplete, handle_dig_complete, - df::job_type, df::coord, df::tiletype, df::tiletype, df::unit*); - -static void detect_digging(color_ostream &out) -{ - for (auto it = diggers.begin(); it != diggers.end();) - { - auto worker = df::unit::find(it->first); - - if (!worker || !worker->job.current_job || - worker->job.current_job->id != it->second.id) - { - //out.print("Dig job %d expired.\n", it->second.id); - - df::coord pos = it->second.pos; - - if (auto block = Maps::getTileBlock(pos)) - { - df::tiletype new_tile = block->tiletype[pos.x&15][pos.y&15]; - - //out.print("Tile %d -> %d\n", it->second.old_tile, new_tile); - - if (new_tile != it->second.old_tile) - { - onDigComplete(out, it->second.job, pos, it->second.old_tile, new_tile, worker); - } - } - - auto cur = it; ++it; diggers.erase(cur); - } - else - ++it; - } - - std::vector jvec; - - if (Job::listNewlyCreated(&jvec, &next_job_id_save)) - { - for (size_t i = 0; i < jvec.size(); i++) - { - auto job = jvec[i]; - auto type = ENUM_ATTR(job_type, type, job->job_type); - if (type != job_type_class::Digging) - continue; - - auto worker = Job::getWorker(job); - if (!worker) - continue; - - df::coord pos = job->pos; - auto block = Maps::getTileBlock(pos); - if (!block) - continue; - - auto &info = diggers[worker->id]; - - //out.print("New dig job %d.\n", job->id); - - info.id = job->id; - info.job = job->job_type; - info.pos = pos; - info.old_tile = block->tiletype[pos.x&15][pos.y&15]; - } - } -} - -DFHACK_PLUGIN_IS_ENABLED(active); - -static bool auto_grow = false; -static std::vector grow_burrows; - -DFhackCExport command_result plugin_onupdate(color_ostream &out) -{ - if (!active) - return CR_OK; - - detect_burrow_renames(out); - - if (auto_grow) - detect_digging(out); - - return CR_OK; -} - -static std::map name_lookup; - -static void parse_names() -{ - auto &list = plotinfo->burrows.list; - - grow_burrows.clear(); - name_lookup.clear(); - - for (size_t i = 0; i < list.size(); i++) - { - auto burrow = list[i]; - - std::string name = burrow->name; - - if (!name.empty()) - { - name_lookup[name] = burrow->id; - - if (name[name.size()-1] == '+') - { - grow_burrows.push_back(burrow->id); - name.resize(name.size()-1); - } - - if (!name.empty()) - name_lookup[name] = burrow->id; - } - } -} - -static void reset_tracking() -{ - diggers.clear(); - next_job_id_save = 0; -} - -static void init_map(color_ostream &out) -{ - auto config = World::GetPersistentData("burrows/config"); - if (config.isValid()) - { - auto_grow = !!(config.ival(0) & 1); - } - - parse_names(); - name_burrow_id = -1; - - reset_tracking(); - active = true; - - if (auto_grow && !grow_burrows.empty()) - out.print("Auto-growing %zu burrows.\n", grow_burrows.size()); -} - -static void deinit_map(color_ostream &out) -{ - active = false; - auto_grow = false; - reset_tracking(); -} - -static PersistentDataItem create_config(color_ostream &out) -{ - bool created; - auto rv = World::GetPersistentData("burrows/config", &created); - if (created && rv.isValid()) - rv.ival(0) = 0; - if (!rv.isValid()) - out.printerr("Could not write configuration."); - return rv; -} - -static void enable_auto_grow(color_ostream &out, bool enable) -{ - if (enable == auto_grow) - return; - - auto config = create_config(out); - if (!config.isValid()) - return; - - if (enable) - config.ival(0) |= 1; - else - config.ival(0) &= ~1; - - auto_grow = enable; - - if (enable) - reset_tracking(); -} - -static void handle_burrow_rename(color_ostream &out, df::burrow *burrow) -{ - parse_names(); -} - -static void add_to_burrows(std::vector &burrows, df::coord pos) -{ - for (size_t i = 0; i < burrows.size(); i++) - Burrows::setAssignedTile(burrows[i], pos, true); -} - -static void add_walls_to_burrows(color_ostream &out, std::vector &burrows, - MapExtras::MapCache &mc, df::coord pos1, df::coord pos2) -{ - for (int x = pos1.x; x <= pos2.x; x++) - { - for (int y = pos1.y; y <= pos2.y; y++) - { - for (int z = pos1.z; z <= pos2.z; z++) - { - df::coord pos(x,y,z); - - auto tile = mc.tiletypeAt(pos); - - if (isWallTerrain(tile)) - add_to_burrows(burrows, pos); - } - } - } -} - -static void handle_dig_complete(color_ostream &out, df::job_type job, df::coord pos, - df::tiletype old_tile, df::tiletype new_tile, df::unit *worker) -{ - if (!isWalkable(new_tile)) - return; - - std::vector to_grow; - - for (size_t i = 0; i < grow_burrows.size(); i++) - { - auto b = df::burrow::find(grow_burrows[i]); - if (b && Burrows::isAssignedTile(b, pos)) - to_grow.push_back(b); - } - - //out.print("%d to grow.\n", to_grow.size()); - - if (to_grow.empty()) - return; - - MapExtras::MapCache mc; - bool changed = false; - - if (!isWalkable(old_tile)) - { - changed = true; - add_walls_to_burrows(out, to_grow, mc, pos+df::coord(-1,-1,0), pos+df::coord(1,1,0)); - - if (isWalkableUp(new_tile)) - add_to_burrows(to_grow, pos+df::coord(0,0,1)); - - if (tileShape(new_tile) == tiletype_shape::RAMP) - { - add_walls_to_burrows(out, to_grow, mc, - pos+df::coord(-1,-1,1), pos+df::coord(1,1,1)); - } - } - - if (LowPassable(new_tile) && !LowPassable(old_tile)) - { - changed = true; - add_to_burrows(to_grow, pos-df::coord(0,0,1)); - - if (tileShape(new_tile) == tiletype_shape::RAMP_TOP) - { - add_walls_to_burrows(out, to_grow, mc, - pos+df::coord(-1,-1,-1), pos+df::coord(1,1,-1)); - } - } - - if (changed && worker && !worker->job.current_job) - Job::checkDesignationsNow(); -} - -static void renameBurrow(color_ostream &out, df::burrow *burrow, std::string name) -{ - CHECK_NULL_POINTER(burrow); - - // The event makes this absolutely necessary - CoreSuspender suspend; - - burrow->name = name; - onBurrowRename(out, burrow); -} - -static df::burrow *findByName(color_ostream &out, std::string name, bool silent = false) -{ - int id = -1; - if (name_lookup.count(name)) - id = name_lookup[name]; - auto rv = df::burrow::find(id); - if (!rv && !silent) - out.printerr("Burrow not found: '%s'\n", name.c_str()); - return rv; -} - -DFHACK_PLUGIN_LUA_FUNCTIONS { - DFHACK_LUA_FUNCTION(renameBurrow), - DFHACK_LUA_FUNCTION(findByName), - DFHACK_LUA_FUNCTION(copyUnits), - DFHACK_LUA_FUNCTION(copyTiles), - DFHACK_LUA_FUNCTION(setTilesByKeyword), - DFHACK_LUA_END -}; - -DFHACK_PLUGIN_LUA_EVENTS { - DFHACK_LUA_EVENT(onBurrowRename), - DFHACK_LUA_EVENT(onDigComplete), - DFHACK_LUA_END -}; - -*/ diff --git a/plugins/lua/burrow.lua b/plugins/lua/burrow.lua index be4a51dd4..5248beb31 100644 --- a/plugins/lua/burrow.lua +++ b/plugins/lua/burrow.lua @@ -1,14 +1,5 @@ local _ENV = mkmodule('plugins.burrow') ---[[ - - Provided events: - - * onBurrowRename(burrow) - * onDigComplete(job_type,pos,old_tiletype,new_tiletype) - ---]] - local argparse = require('argparse') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') From 604eb47f8774159759efac8c14b1d1f4b4296ab8 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 2 Nov 2023 13:55:08 -0700 Subject: [PATCH 817/851] implement burrow name matching with ignoring plus --- docs/dev/Lua API.rst | 6 +++-- library/include/modules/Burrows.h | 2 +- library/modules/Burrows.cpp | 37 +++++++++---------------------- plugins/burrow.cpp | 2 +- 4 files changed, 17 insertions(+), 30 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index dd057fe01..abab94829 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1949,9 +1949,11 @@ Maps module Burrows module -------------- -* ``dfhack.burrows.findByName(name)`` +* ``dfhack.burrows.findByName(name[, ignore_final_plus])`` - Returns the burrow pointer or *nil*. + Returns the burrow pointer or *nil*. if ``ignore_final_plus`` is ``true``, + then ``+`` characters at the end of the names are ignored, both for the + specified ``name`` and the names of the burrows that it matches against. * ``dfhack.burrows.clearUnits(burrow)`` diff --git a/library/include/modules/Burrows.h b/library/include/modules/Burrows.h index 49b7df3c1..b2e3e56b4 100644 --- a/library/include/modules/Burrows.h +++ b/library/include/modules/Burrows.h @@ -45,7 +45,7 @@ namespace DFHack { namespace Burrows { - DFHACK_EXPORT df::burrow *findByName(std::string name); + DFHACK_EXPORT df::burrow *findByName(std::string name, bool ignore_final_plus = false); // Units DFHACK_EXPORT void clearUnits(df::burrow *burrow); diff --git a/library/modules/Burrows.cpp b/library/modules/Burrows.cpp index c2fe45eae..9e63c0dbc 100644 --- a/library/modules/Burrows.cpp +++ b/library/modules/Burrows.cpp @@ -51,13 +51,21 @@ using namespace df::enums; using df::global::world; using df::global::plotinfo; -df::burrow *Burrows::findByName(std::string name) +df::burrow *Burrows::findByName(std::string name, bool ignore_final_plus) { auto &vec = df::burrow::get_vector(); - for (size_t i = 0; i < vec.size(); i++) - if (vec[i]->name == name) + if (ignore_final_plus && name.ends_with('+')) + name = name.substr(0, name.length() - 1); + + for (size_t i = 0; i < vec.size(); i++) { + std::string bname = vec[i]->name; + if (ignore_final_plus && bname.ends_with('+')) + bname = bname.substr(0, bname.length() - 1); + + if (bname == name) return vec[i]; + } return NULL; } @@ -75,18 +83,6 @@ void Burrows::clearUnits(df::burrow *burrow) } burrow->units.clear(); - -/* TODO: understand how this changes for v50 - // Sync plotinfo if active - if (plotinfo && plotinfo->main.mode == ui_sidebar_mode::Burrows && - plotinfo->burrows.in_add_units_mode && plotinfo->burrows.sel_id == burrow->id) - { - auto &sel = plotinfo->burrows.sel_units; - - for (size_t i = 0; i < sel.size(); i++) - sel[i] = false; - } -*/ } bool Burrows::isAssignedUnit(df::burrow *burrow, df::unit *unit) @@ -114,17 +110,6 @@ void Burrows::setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable) erase_from_vector(unit->burrows, burrow->id); erase_from_vector(burrow->units, unit->id); } - -/* TODO: understand how this changes for v50 - // Sync plotinfo if active - if (plotinfo && plotinfo->main.mode == ui_sidebar_mode::Burrows && - plotinfo->burrows.in_add_units_mode && plotinfo->burrows.sel_id == burrow->id) - { - int idx = linear_index(plotinfo->burrows.list_units, unit); - if (idx >= 0) - plotinfo->burrows.sel_units[idx] = enable; - } -*/ } void Burrows::listBlocks(std::vector *pvec, df::burrow *burrow) diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index f33e9e910..413a8eb6e 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -279,7 +279,7 @@ static df::burrow* get_burrow(lua_State *L, int idx) { if (lua_isuserdata(L, idx)) burrow = Lua::GetDFObject(L, idx); else if (lua_isstring(L, idx)) - burrow = Burrows::findByName(luaL_checkstring(L, idx)); + burrow = Burrows::findByName(luaL_checkstring(L, idx), true); else if (lua_isinteger(L, idx)) burrow = df::burrow::find(luaL_checkinteger(L, idx)); return burrow; From 49dcd95a42f01f27d3334345ee0af0b13167d284 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 2 Nov 2023 15:58:00 -0700 Subject: [PATCH 818/851] add focus string for linking levers --- library/modules/Gui.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 04800779d..a6a28239d 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -376,7 +376,9 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) } break; case df::view_sheet_type::BUILDING: - if (auto bld = df::building::find(game->main_interface.view_sheets.viewing_bldid)) + if (game->main_interface.view_sheets.linking_lever) + newFocusString = baseFocus + "/LinkingLever"; + else if (auto bld = df::building::find(game->main_interface.view_sheets.viewing_bldid)) newFocusString += '/' + enum_item_key(bld->getType()); break; default: From 164caaaa20dfcfbe205f8b73413a2c135c36ec64 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 2 Nov 2023 15:58:17 -0700 Subject: [PATCH 819/851] tombstone gui/mechanisms --- docs/about/Removed.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index 67c4530bb..da7d42d37 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -191,6 +191,12 @@ gui/hack-wish ============= Replaced by `gui/create-item`. +.. _gui/mechanisms: + +gui/mechanisms +============== +Linked building interface has been added to the vanilla UI. + .. _gui/no-dfhack-init: gui/no-dfhack-init From f0039ab39dfb90b4a64494bf744709cb8514a4ec Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 2 Nov 2023 16:00:25 -0700 Subject: [PATCH 820/851] update scripts ref --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index d56aac6bc..56874c5fa 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit d56aac6bcd6628d22420d57b4a96987490e5a11f +Subproject commit 56874c5fa0913c598351408c300961b6cc69e0b2 From 322d4fb51f5d15568147d9f469a98153ce828847 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Nov 2023 09:21:14 -0700 Subject: [PATCH 821/851] allow burrows to expand into dug channels --- plugins/burrow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index 413a8eb6e..bf2f6a80b 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -182,7 +182,7 @@ static void add_walls_to_burrow(color_ostream &out, df::burrow* b, } static void expand_burrows(color_ostream &out, const df::coord & pos, df::tiletype prev_tt, df::tiletype tt) { - if (!isWalkable(tt)) + if (!isWalkable(tt) && tileShape(tt) != tiletype_shape::RAMP_TOP) return; bool changed = false; From f09af3c8a2c5efb6d91582fb19883209d13fb479 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 3 Nov 2023 18:02:01 +0000 Subject: [PATCH 822/851] 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 b9c0733e9..a23ec834b 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit b9c0733e943fb0d22a6717596128b8d44ba4ce04 +Subproject commit a23ec834bbbd2a9d47defd0fa1add717c837632a diff --git a/scripts b/scripts index 56874c5fa..f7d6869a6 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 56874c5fa0913c598351408c300961b6cc69e0b2 +Subproject commit f7d6869a60f0bec0ab9f8b3383827c2ab7a1ef0c From dbf1eb1d4203013b3d352afec3d6c37b6068d71e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Nov 2023 02:29:43 -0700 Subject: [PATCH 823/851] add docs for quickfort burrow blueprint mode --- docs/guides/quickfort-user-guide.rst | 49 +++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/docs/guides/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst index c12df3eee..0fc02e6b5 100644 --- a/docs/guides/quickfort-user-guide.rst +++ b/docs/guides/quickfort-user-guide.rst @@ -84,7 +84,7 @@ Feature summary - Configurable zone/location settings, such as the pit/pond toggle or hospital supply quantities -- Build mode +- Build mode - Integrated with DFHack `buildingplan`: you can place buildings before manufacturing building materials and you can use the `buildingplan` UI @@ -108,6 +108,10 @@ Feature summary - Set building properties (such as a name) - Can attach and configure track stops as part of hauling routes +- Burrow mode + + - Supports creating, adding to, and subtracting from burrows. + Introduction to blueprints -------------------------- @@ -866,6 +870,35 @@ names an existing route, the stop will be added to that route:: These two track stops (which do not dump their contents) simply exist on a common route at the ends of a connected carved track. +#burrow mode +------------ + +``#burrow`` mode can create, extend, and remove tiles from burrows. + +Burrow designation syntax +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The syntax should look familiar by now:: + + symbol{properties}(expansion) + +See the `#burrow mode reference`_ for symbol and property definitions. + +Here's how to create (or add to, if a burrow by that name already exists) a +5x5 burrow named ``Inside+``:: + + #burrow + a{create=true name=Inside+}(5x5) + +Why the trailing ``+``? That's to indicate to the `burrow` plugin that the +burrow should grow as adjacent tiles are dug out. + +Similarly, here is how to erase a tile from all burrows that currently include +it:: + + #burrow + e + .. _quickfort-modeline: Modeline markers @@ -2199,3 +2232,17 @@ Symbol Type Properties ``trackrampSEW`` track ramp tee to the S, E, W ``trackrampNSEW`` track ramp cross ================= ============================= ========== + +#burrow mode reference +~~~~~~~~~~~~~~~~~~~~~~ + +====== ======= ========== +Symbol Meaning Properties +====== ======= ========== +``a`` add ``name``: if set, will add to an existing burrow of this name. + ``create``: if set to ``true``, will create a burrow with the + specified ``name`` if it doesn't already exist. +``e`` erase ``name``: if set, will only affect the first burrow of the given + name. if not set, will affect all burrows that cover the given + tiles. +====== ======= ========== From f2cbc2d3e56f6f1345bef93b3b72b0f4d0fc3a16 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Nov 2023 02:50:25 -0700 Subject: [PATCH 824/851] document civalert property --- docs/guides/quickfort-user-guide.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/guides/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst index 0fc02e6b5..f104a1124 100644 --- a/docs/guides/quickfort-user-guide.rst +++ b/docs/guides/quickfort-user-guide.rst @@ -885,10 +885,11 @@ The syntax should look familiar by now:: See the `#burrow mode reference`_ for symbol and property definitions. Here's how to create (or add to, if a burrow by that name already exists) a -5x5 burrow named ``Inside+``:: +5x5 burrow named ``Inside+``. It will also register this burrow with +`gui/civ-alert` if no burrow has yet been registered:: #burrow - a{create=true name=Inside+}(5x5) + a{create=true name=Inside+ civalert=true}(5x5) Why the trailing ``+``? That's to indicate to the `burrow` plugin that the burrow should grow as adjacent tiles are dug out. @@ -2242,6 +2243,8 @@ Symbol Meaning Properties ``a`` add ``name``: if set, will add to an existing burrow of this name. ``create``: if set to ``true``, will create a burrow with the specified ``name`` if it doesn't already exist. + ``civalert``: if set to ``true``, will register this burrow with + `gui/civ-alert` if no burrow has already been registered. ``e`` erase ``name``: if set, will only affect the first burrow of the given name. if not set, will affect all burrows that cover the given tiles. From 4d9e6d53f58adf101ad1f351f93558fc064dfef1 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Nov 2023 11:33:43 -0700 Subject: [PATCH 825/851] document autochop properties --- docs/guides/quickfort-user-guide.rst | 6 ++++++ plugins/lua/autochop.lua | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/guides/quickfort-user-guide.rst b/docs/guides/quickfort-user-guide.rst index f104a1124..e4b337cc4 100644 --- a/docs/guides/quickfort-user-guide.rst +++ b/docs/guides/quickfort-user-guide.rst @@ -2245,6 +2245,12 @@ Symbol Meaning Properties specified ``name`` if it doesn't already exist. ``civalert``: if set to ``true``, will register this burrow with `gui/civ-alert` if no burrow has already been registered. + ``autochop_clear``: if set to ``true``, register the burrow with + `autochop` so that all trees in the burrow are immediately + chopped down, regardless of how many logs are in stock. + ``autochop_chop``: if set to ``true``, register the burrow with + ``autochop`` so that woodcutting activity is constrained to this + burrow (and others marked for ``chop``). ``e`` erase ``name``: if set, will only affect the first burrow of the given name. if not set, will affect all burrows that cover the given tiles. diff --git a/plugins/lua/autochop.lua b/plugins/lua/autochop.lua index cda91b32d..239db9ec8 100644 --- a/plugins/lua/autochop.lua +++ b/plugins/lua/autochop.lua @@ -51,7 +51,7 @@ function parse_commandline(...) local args, opts = {...}, {} local positionals = process_args(opts, args) - if opts.help then + if opts.help or not positionals then return false end From 5b96ab0c42a8b139a3319efd9852c251d35a80be Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Nov 2023 11:33:56 -0700 Subject: [PATCH 826/851] add burrow blueprints to dreamfort --- data/blueprints/dreamfort.csv | 91 ++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/data/blueprints/dreamfort.csv b/data/blueprints/dreamfort.csv index 2261e7cf0..22b78230a 100644 --- a/data/blueprints/dreamfort.csv +++ b/data/blueprints/dreamfort.csv @@ -20,7 +20,7 @@ "Dreamfort blueprints take care of everything to get the fort up and running. You don't need to clear any extra trees or create any extra buildings or stockpiles (though of course you are free to do so). Blueprints that do require manual steps, like 'assign minecart to hauling route', will leave a message telling you so when you run them. Note that blueprints will designate buildings to build even if you don't have the materials needed to build them. You can use the ""o"" hotkey to automatically create the manager orders for all the needed items when you have a blueprint loaded in gui/quickfort. Make sure your manager is available to validate all the incoming work orders!" "" "There are some tasks common to all forts that Dreamfort doesn't specifically handle for you. For example, Dreamfort sets up a barracks, but managing squads is up to you. Here are some other common tasks that may need to be done manually (or with some other tool):" -- Exploratory mining for specific resources like iron +- Exploratory mining for specific resources like iron (see gui/design for help with this) "- Filling the well system with water (if you have a light aquifer, see library/aquifer_tap.csv for help with this)" - Bringing magma up to the industry level to power magma forges/furnaces (see library/pump_stack.csv for help with this) - Manufacturing trade goods @@ -70,7 +70,7 @@ gui/quickfort,/farming1,,Dig out the farming level. Run when channels on the sur gui/quickfort,/farming2,,Build farming level. Run as soon as the farming level has been completely dug out. gui/quickfort,/surface3,,Cover the miasma vents and start protecting the central staircase from early invasions. Run right after /farming2. gui/quickfort,/industry2,,Build industry level. Run as soon as the industry level has been completely 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. 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!**" +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 surface workshops before deconstructing them, otherwise you'll get canceled jobs!" gui/quickfort,/surface4,,Finish protecting the staircase and lay flooring for future buildings. Run after the walls and floors around the staircase are built and you have moved production from the surface to the industry level. gui/quickfort,/industry3,,Build the rest of the industry level. Run once /surface4 is mostly complete. orders import library/basic,,,"Run after the first migration wave, so you have dwarves to do all the basic tasks. Note that this is the ""orders"" plugin, not the ""quickfort orders"" command." @@ -145,9 +145,6 @@ On the work details screen (Labor -> Work details) In standing orders (Labor -> Standing orders): " - Change ""Automatically weave all thread"" to ""No automatic weaving"" so the hospital always has thread -- we'll be managing cloth production with automated orders" "- On the ""Other"" tab, change ""Everybody harvests"" to ""Only farmers harvest""" -"" -"Finally, in the burrows screen:" -"- 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." "#meta label(dig_all) start(central stairs on industry level) dig industry, services, guildhall, suites, apartments, and crypt levels. does not include farming." # Note that this blueprint will only work for the unified dreamfort.csv. It won't work for the individual .xlsx files (since #meta blueprints can't cross file boundaries). "" @@ -249,6 +246,8 @@ Features: - Optional extended trap hallways (to handle larger sieges with a smaller/no military) "- Protected trade depot, with separate trade goods stockpiles for organics and inorganics (for easy elven trading)" - A grid of small farm plots for lucrative surface farming +"- A burrow named ""Inside+"" that grows with your fort as you dig it out. It is pre-registered as a civilian alert burrow so you can use it to get your civilians to safety during sieges." +"- A burrow named ""Clearcutting area"" that is automatically registered with autochop (if you have it enabled) to keep the area around your fort clear of trees" "" Manual steps you have to take: "- Assign grazing livestock to the large pasture, dogs to the pasture over the central stairs, and male birds to the zone between the rows of nestboxes (DFHack's autonestbox will auto-assign the female egg-laying birds to the nestbox zones)" @@ -281,11 +280,11 @@ Surface Walkthrough: 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"" pasture is) or the trapped hallways." +"- Your ""Inside+"" burrow will automatically grow with your fort and should include only safe areas of your fort. In particular, it should not include the ""atrium"" area (where the ""siege bait"" pasture is) or the trapped hallways." "" -"- When a siege begins, set your civilian alert (attach the alert to your ""Inside"" burrow if it isn't already) to ensure all your civilians stay out of danger. Immediately pull the lever to close the outer main gate. It is also wise to close the trade depot and inner main gate as well. That way, if enemies get past the traps, they'll have to go through the soldiers in your barracks (assuming you have a military)." +"- When a siege begins, set your civilian alert (attach the alert to your ""Inside+"" burrow if it isn't already) to ensure all your civilians stay out of danger. Immediately pull the lever to close the outer main gate. It is also wise to close the trade depot and inner main gate as well. That way, if enemies get past the traps, they'll have to go through the soldiers in your barracks (assuming you have a military)." "" -"- During a siege, 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." +"- During a siege, you can use the levers to control how attackers path through the trapped corridors. If there are more enemies than cage traps, time your lever pulling so that the inner gates snap closed before your last cage trap is sprung. Then the remaining attackers will have to backtrack and go through the other trap-filled hallway. You can also choose *not* to use the trap hallways and meet the siege with your military. It's up to you!" "" "- If your cage traps fill up, ensure your hallways are free of uncaged attackers, then close the trap hallway outer gates and open the inner gates. Clear the civilian alert and allow your dwarves to reset all the traps -- make some extra cages in preparation for this! Then re-enable the civilian alert and open the trap hallway outer gates." "" @@ -293,13 +292,13 @@ Here are some tips and procedures for handling seiges -- including how to clean "" "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 ""stripcaged all"" in DFHack's gui/launcher." +"- Once the prisoners are hauled to the ""prisoner quantum"" stockpile in the barracks, run ""stripcaged all"" in DFHack's gui/launcher." "" "- After all the prisoners' items have been confiscated, bring your military dwarves to the barracks (if they aren't already there)." "" - Assign a group of prisoners to the pasture that overlaps the prisoner quantum stockpile "" -"- Hauler dwarves will come and release prisoners one by one. Your military dwarves will immediately pounce on the released prisoner and chop them to bits, saving the hauler dwarves from being attacked. Repeat until all prisoners have been ""processed""." +"- Hauler dwarves will come and release prisoners one by one. Your military dwarves will immediately pounce on the released prisoners and chop them to bits, saving the hauler dwarves from being attacked. Repeat until all prisoners have been ""processed"". Some prisoners are not directly hostile (like cavern-caught gorlaks) and you may need to be target them explicitly to get your soldiers to attack them." #dig label(central_stairs_odd) start(2;2) hidden() carved spiral stairs odd levels `,j6,` u,`,u @@ -331,6 +330,7 @@ message(Once the central stairs are mined out deeply enough, you should start di If your wagon is within the fort perimeter, deconstruct it to get it out of the way. Once the marked trees are all chopped down (if any), continue with /surface2.) clear trees and set up pastures" clear_small/surface_clear_small +burrow_start/surface_burrow_start zones/surface_zones #> central_stairs/central_stairs repeat(down 10) @@ -368,7 +368,8 @@ traps/surface_traps clear_large/surface_clear_large "" "#meta label(surface7) start(central stairs (on ground level)) message(Remember to enqueue manager orders for this blueprint. -For extra security, you can run /surface8 at any time to extend the trap corridors.) build roof" +For extra security, you can run /surface8 at any time to extend the trap corridors.) expand Inside+ burrow to safe surface areas and build roof" +burrows/surface_burrows #< roof/surface_roof roof2/surface_roof2 @@ -413,6 +414,40 @@ corridor_traps/surface_corridor_traps +#burrow label(surface_burrow_start) start(19; 19) hidden() create safety burrow that will grow with your fort + + + +,,,`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,,`,`,,` +,,,`,,`,,`,,,,,,,,`,a{name=Inside+ create=true civalert=true}(5x5),,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,~,,~,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,,`,`,`,`,,`,,`,`,`,`,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` + + + "#zone label(surface_zones) start(19; 19) hidden() message(Remember to assign your dogs to the pasture surrounding the central stairs, your grazing animals to the large pasture, and your male birds to the zone between the rows of nestboxes. If your wagon is far away, you can let your animals wander closer to the fort before pasturing them to save hauling time.) pastures and training areas" @@ -1029,6 +1064,40 @@ t1(37x33) ,,,,,,,,,,,,,Tc,Tc,,,,,,,,Tc,Tc ,,,,,,,,,,,,,Tc,Tc,,,,,,,,Tc,Tc +#burrow label(surface_burrows) start(19; 19) hidden() extend safety burrow to newly safe surface areas and set up surrounding clearcutting area + + +,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(-10x-10)","a{name=""Clearcutting area"" create=true autochop_clear=true}(32x-10)",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(10x-10)" +,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(-10x27)",`,,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,`,,`,"a{name=""Clearcutting area"" create=true autochop_clear=true}(10x27)" +,,,`,,`,a{name=Inside+}(25x17),,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,,`,`,`,`,`,`,,`,,`,`,`,`,`,,`,`,`,,`,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,`,,~,,~,,`,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,`,,,,,,,,`,,,,,,`,,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,a{name=Inside+},`,`,`,`,,`,,`,`,`,`,a{name=Inside+}(7x6),,,,,,,`,,` +,,,`,,`,a{name=Inside+}(7x5),,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,,,,,,,,,,,,,,,,,,`,,` +,,,`,,`,,,,,,,,,`,,,,,,,,`,,,,,,,,,`,,` +,,,`,,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,,` +,,,`,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,` +,,,`,`,`,`,`,`,`,`,`,`,`,`,,,,,,,,`,`,`,`,`,`,`,`,`,`,`,` +,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(-10x10)","a{name=""Clearcutting area"" create=true autochop_clear=true}(32x10)",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"a{name=""Clearcutting area"" create=true autochop_clear=true}(10x10)" + + #build label(surface_roof) start(19; 19) hidden() roof hatch and adjacent tiles From a19545dcec6e6726e1fc38d84cb0dca0bc9dbf1f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Nov 2023 11:54:08 -0700 Subject: [PATCH 827/851] don't unregister handlers on world unload we still need them for the next world! --- plugins/burrow.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index bf2f6a80b..743035fbb 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -54,7 +54,6 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector Date: Fri, 3 Nov 2023 20:09:59 +0000 Subject: [PATCH 828/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index f7d6869a6..2382a3343 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit f7d6869a60f0bec0ab9f8b3383827c2ab7a1ef0c +Subproject commit 2382a334367b7a46a1ddeefc0e43a63491d6062c From e4f986d53be37289c730511ed277a7e4c07355aa Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Nov 2023 13:31:58 -0700 Subject: [PATCH 829/851] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 8a06ee1a1..f4860efc0 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -65,6 +65,7 @@ Template for new versions: ## Misc Improvements - `buildingplan`: display how many items are available on the planner panel - `sort`: allow searching by profession on the squad assignment page +- `dreamfort`: Inside+ and Clearcutting burrows now automatically created and managed ## Documentation From 74464f3b61e7e9734b4da22b5f944e974237c950 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Nov 2023 11:02:43 -0700 Subject: [PATCH 830/851] mock out potential UI --- plugins/lua/buildingplan.lua | 3 ++ plugins/lua/buildingplan/mechanisms.lua | 69 +++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 plugins/lua/buildingplan/mechanisms.lua diff --git a/plugins/lua/buildingplan.lua b/plugins/lua/buildingplan.lua index d64317eb0..7e034b988 100644 --- a/plugins/lua/buildingplan.lua +++ b/plugins/lua/buildingplan.lua @@ -14,6 +14,7 @@ local _ENV = mkmodule('plugins.buildingplan') local argparse = require('argparse') local inspector = require('plugins.buildingplan.inspectoroverlay') +local mechanisms = require('plugins.buildingplan.mechanisms') local pens = require('plugins.buildingplan.pens') local planner = require('plugins.buildingplan.planneroverlay') require('dfhack.buildings') @@ -134,12 +135,14 @@ function reload_modules() reload('plugins.buildingplan.itemselection') reload('plugins.buildingplan.planneroverlay') reload('plugins.buildingplan.inspectoroverlay') + reload('plugins.buildingplan.mechanisms') reload('plugins.buildingplan') end OVERLAY_WIDGETS = { planner=planner.PlannerOverlay, inspector=inspector.InspectorOverlay, + mechanisms=mechanisms.MechanismOverlay, } return _ENV diff --git a/plugins/lua/buildingplan/mechanisms.lua b/plugins/lua/buildingplan/mechanisms.lua new file mode 100644 index 000000000..b3475be2b --- /dev/null +++ b/plugins/lua/buildingplan/mechanisms.lua @@ -0,0 +1,69 @@ +local _ENV = mkmodule('plugins.buildingplan.mechanisms') + +local overlay = require('plugins.overlay') +local widgets = require('gui.widgets') + +-------------------------------- +-- MechanismOverlay +-- + +MechanismOverlay = defclass(MechanismOverlay, overlay.OverlayWidget) +MechanismOverlay.ATTRS{ + default_pos={x=5,y=5}, + default_enabled=true, + viewscreens='dwarfmode/LinkingLever', + frame={w=57, h=13}, +} + +function MechanismOverlay:init() + self:addviews{ + widgets.CycleHotkeyLabel{ + view_id='safety1', + frame={t=4, l=4, w=40}, + key='CUSTOM_G', + label='Lever mechanism safety:', + options={ + {label='Any', value=0}, + {label='Magma', value=2, pen=COLOR_RED}, + {label='Fire', value=1, pen=COLOR_LIGHTRED}, + }, + initial_option=0, + }, + widgets.CycleHotkeyLabel{ + view_id='safety2', + frame={t=5, l=4, w=40}, + key='CUSTOM_SHIFT_G', + label='Target mechanism safety:', + options={ + {label='Any', value=0}, + {label='Magma', value=2, pen=COLOR_RED}, + {label='Fire', value=1, pen=COLOR_LIGHTRED}, + }, + initial_option=0, + }, + widgets.HotkeyLabel{ + frame={t=6, l=9, w=48, h=3}, + key='CUSTOM_M', + label='Choose', + auto_height=false, + on_activate=function() end, + }, + widgets.HotkeyLabel{ + frame={t=9, l=9, w=48, h=3}, + key='CUSTOM_SHIFT_M', + label='Choose', + auto_height=false, + on_activate=function() end, + }, + } +end + +function MechanismOverlay:onInput(keys) + if keys._MOUSE_L and self:getMousePos() then + MechanismOverlay.super.onInput(self, keys) + -- don't let clicks bleed through the panel + return true + end +end + +return _ENV From f0badc63e4ca62b2fd6f50511dcd8d3f39a2f9ac Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Nov 2023 16:33:08 -0700 Subject: [PATCH 831/851] implement mechanism selection for lever linking --- docs/changelog.txt | 1 + plugins/buildingplan/buildingplan.cpp | 36 +++++- plugins/lua/buildingplan/itemselection.lua | 40 ++++-- plugins/lua/buildingplan/mechanisms.lua | 128 +++++++++++++++++--- plugins/lua/buildingplan/planneroverlay.lua | 6 +- 5 files changed, 180 insertions(+), 31 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index f4860efc0..7a13ba6f4 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -57,6 +57,7 @@ Template for new versions: ## New Features - `prospect`: can now give you an estimate of resources from the embark screen. hover the mouse over a potential embark area and run `prospect`. - `burrow`: integrated 3d box fill and 2d/3d flood fill extensions for burrow painting mode +- `buildingplan`: allow specific mechanisms to be selected when linking levers ## Fixes - `stockpiles`: hide configure and help buttons when the overlay panel is minimized diff --git a/plugins/buildingplan/buildingplan.cpp b/plugins/buildingplan/buildingplan.cpp index 9fb5641bb..7a1416855 100644 --- a/plugins/buildingplan/buildingplan.cpp +++ b/plugins/buildingplan/buildingplan.cpp @@ -674,13 +674,14 @@ static void scheduleCycle(color_ostream &out) { } static int scanAvailableItems(color_ostream &out, df::building_type type, int16_t subtype, - int32_t custom, int index, bool ignore_filters, vector *item_ids = NULL, - map *counts = NULL) { + int32_t custom, int index, bool ignore_filters, bool ignore_quality, HeatSafety *heat_override = NULL, + vector *item_ids = NULL, map *counts = NULL) +{ DEBUG(status,out).print( "entering scanAvailableItems building_type=%d subtype=%d custom=%d index=%d\n", type, subtype, custom, index); BuildingTypeKey key(type, subtype, custom); - HeatSafety heat = get_heat_safety_filter(key); + HeatSafety heat = heat_override ? *heat_override : get_heat_safety_filter(key); auto &job_items = get_job_items(out, key); if (index < 0 || job_items.size() <= (size_t)index) return 0; @@ -703,6 +704,10 @@ static int scanAvailableItems(color_ostream &out, df::building_type type, int16_ filter.setMaterials(set()); special.clear(); } + if (ignore_quality) { + filter.setMinQuality(df::item_quality::Ordinary); + filter.setMaxQuality(df::item_quality::Artifact); + } if (itemPassesScreen(out, item) && matchesFilters(item, jitem, heat, filter, special)) { if (item_ids) item_ids->emplace_back(item->id); @@ -732,7 +737,25 @@ static int getAvailableItems(lua_State *L) { "entering getAvailableItems building_type=%d subtype=%d custom=%d index=%d\n", type, subtype, custom, index); vector item_ids; - scanAvailableItems(*out, type, subtype, custom, index, true, &item_ids); + scanAvailableItems(*out, type, subtype, custom, index, true, false, NULL, &item_ids); + Lua::PushVector(L, item_ids); + return 1; +} + +static int getAvailableItemsByHeat(lua_State *L) { + color_ostream *out = Lua::GetOutput(L); + if (!out) + out = &Core::getInstance().getConsole(); + df::building_type type = (df::building_type)luaL_checkint(L, 1); + int16_t subtype = luaL_checkint(L, 2); + int32_t custom = luaL_checkint(L, 3); + int index = luaL_checkint(L, 4); + HeatSafety heat = (HeatSafety)luaL_checkint(L, 5); + DEBUG(status,*out).print( + "entering getAvailableItemsByHeat building_type=%d subtype=%d custom=%d index=%d\n", + type, subtype, custom, index); + vector item_ids; + scanAvailableItems(*out, type, subtype, custom, index, true, true, &heat, &item_ids); Lua::PushVector(L, item_ids); return 1; } @@ -755,7 +778,7 @@ static int countAvailableItems(color_ostream &out, df::building_type type, int16 DEBUG(status,out).print( "entering countAvailableItems building_type=%d subtype=%d custom=%d index=%d\n", type, subtype, custom, index); - int count = scanAvailableItems(out, type, subtype, custom, index, false); + int count = scanAvailableItems(out, type, subtype, custom, index, false, false); if (count) return count; @@ -968,7 +991,7 @@ static int getMaterialFilter(lua_State *L) { return 0; const auto &mat_filter = filters[index].getMaterials(); map counts; - scanAvailableItems(*out, type, subtype, custom, index, false, NULL, &counts); + scanAvailableItems(*out, type, subtype, custom, index, false, false, NULL, NULL, &counts); HeatSafety heat = get_heat_safety_filter(key); const df::job_item *jitem = get_job_items(*out, key)[index]; // name -> {count=int, enabled=bool, category=string, heat=string} @@ -1232,6 +1255,7 @@ DFHACK_PLUGIN_LUA_FUNCTIONS { DFHACK_PLUGIN_LUA_COMMANDS { DFHACK_LUA_COMMAND(getGlobalSettings), DFHACK_LUA_COMMAND(getAvailableItems), + DFHACK_LUA_COMMAND(getAvailableItemsByHeat), DFHACK_LUA_COMMAND(setMaterialMaskFilter), DFHACK_LUA_COMMAND(getMaterialMaskFilter), DFHACK_LUA_COMMAND(setMaterialFilter), diff --git a/plugins/lua/buildingplan/itemselection.lua b/plugins/lua/buildingplan/itemselection.lua index 4b8ee73d8..bc836bc33 100644 --- a/plugins/lua/buildingplan/itemselection.lua +++ b/plugins/lua/buildingplan/itemselection.lua @@ -21,6 +21,29 @@ function get_automaterial_selection(building_type) return tracker.list[#tracker.list] end +local function get_artifact_name(item) + local gref = dfhack.items.getGeneralRef(item, df.general_ref_type.IS_ARTIFACT) + if not gref then return end + local artifact = df.artifact_record.find(gref.artifact_id) + if not artifact then return end + return dfhack.TranslateName(artifact.name) +end + +function get_item_description(item_id, item, safety_label) + item = item or df.item.find(item_id) + if not item then + return ('No %s safe mechanisms available'):format(safety_label:lower()) + end + local desc = item.flags.artifact and get_artifact_name(item) or + dfhack.items.getDescription(item, 0, true) + local wear_level = item:getWear() + if wear_level == 1 then desc = ('x%sx'):format(desc) + elseif wear_level == 2 then desc = ('X%sX'):format(desc) + elseif wear_level == 3 then desc = ('XX%sXX'):format(desc) + end + return desc +end + local function sort_by_type(a, b) local ad, bd = a.data, b.data return ad.item_type < bd.item_type or @@ -57,7 +80,7 @@ ItemSelection.ATTRS{ frame_title='Choose items', frame={w=56, h=24, l=4, t=7}, resizable=true, - index=DEFAULT_NIL, + get_available_items_fn=DEFAULT_NIL, desc=DEFAULT_NIL, quantity=DEFAULT_NIL, autoselect=DEFAULT_NIL, @@ -99,9 +122,9 @@ function ItemSelection:init() text_pen=BUILD_TEXT_PEN, text_hpen=BUILD_TEXT_HPEN, text={ - ' Use filter ', NEWLINE, - ' for remaining ', NEWLINE, - ' items ', + ' ', NEWLINE, + ' Autoselect ', NEWLINE, + ' ', }, on_click=self:callback('submit'), visible=function() return self.num_selected < self.quantity end, @@ -238,13 +261,12 @@ local function make_search_key(str) end function ItemSelection:get_choices(sort_fn) - local item_ids = require('plugins.buildingplan').getAvailableItems(uibs.building_type, - uibs.building_subtype, uibs.custom_type, self.index-1) + local item_ids = self.get_available_items_fn() local buckets = {} for _,item_id in ipairs(item_ids) do local item = df.item.find(item_id) if not item then goto continue end - local desc = dfhack.items.getDescription(item, 0, true) + local desc = get_item_description(item_id, item) if buckets[desc] then local bucket = buckets[desc] table.insert(bucket.data.item_ids, item_id) @@ -396,7 +418,7 @@ ItemSelectionScreen.ATTRS { pass_pause=false, pass_mouse_clicks=false, defocusable=false, - index=DEFAULT_NIL, + get_available_items_fn=DEFAULT_NIL, desc=DEFAULT_NIL, quantity=DEFAULT_NIL, autoselect=DEFAULT_NIL, @@ -407,7 +429,7 @@ ItemSelectionScreen.ATTRS { function ItemSelectionScreen:init() self:addviews{ ItemSelection{ - index=self.index, + get_available_items_fn=self.get_available_items_fn, desc=self.desc, quantity=self.quantity, autoselect=self.autoselect, diff --git a/plugins/lua/buildingplan/mechanisms.lua b/plugins/lua/buildingplan/mechanisms.lua index b3475be2b..0993953cd 100644 --- a/plugins/lua/buildingplan/mechanisms.lua +++ b/plugins/lua/buildingplan/mechanisms.lua @@ -1,8 +1,11 @@ local _ENV = mkmodule('plugins.buildingplan.mechanisms') +local itemselection = require('plugins.buildingplan.itemselection') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') +local view_sheets = df.global.game.main_interface.view_sheets + -------------------------------- -- MechanismOverlay -- @@ -17,53 +20,148 @@ MechanismOverlay.ATTRS{ function MechanismOverlay:init() self:addviews{ + widgets.Label{ + frame={t=4, l=2}, + text='Mechanism safety:' + }, widgets.CycleHotkeyLabel{ - view_id='safety1', - frame={t=4, l=4, w=40}, + view_id='safety_lever', + frame={t=4, l=21, w=15}, key='CUSTOM_G', - label='Lever mechanism safety:', + label='Lever:', options={ {label='Any', value=0}, {label='Magma', value=2, pen=COLOR_RED}, {label='Fire', value=1, pen=COLOR_LIGHTRED}, }, initial_option=0, + on_change=self:callback('choose_mechanism', 'lever', true), }, widgets.CycleHotkeyLabel{ - view_id='safety2', - frame={t=5, l=4, w=40}, + view_id='safety_target', + frame={t=4, l=38, w=16}, key='CUSTOM_SHIFT_G', - label='Target mechanism safety:', + label='Target:', options={ {label='Any', value=0}, {label='Magma', value=2, pen=COLOR_RED}, {label='Fire', value=1, pen=COLOR_LIGHTRED}, }, initial_option=0, + on_change=self:callback('choose_mechanism', 'target', true), }, widgets.HotkeyLabel{ - frame={t=6, l=9, w=48, h=3}, + frame={t=7, l=8, w=49, h=2}, key='CUSTOM_M', - label='Choose', + label=function() + return itemselection.get_item_description(view_sheets.linking_lever_mech_lever_id, + nil, + self.subviews.safety_lever:getOptionLabel()) + end, auto_height=false, - on_activate=function() end, + enabled=function() return view_sheets.linking_lever_mech_lever_id ~= -1 end, + on_activate=self:callback('choose_mechanism', 'lever', false), }, widgets.HotkeyLabel{ - frame={t=9, l=9, w=48, h=3}, + frame={t=10, l=8, w=49, h=2}, key='CUSTOM_SHIFT_M', - label='Choose', + label=function() + return itemselection.get_item_description(view_sheets.linking_lever_mech_target_id, + nil, + self.subviews.safety_target:getOptionLabel()) + end, auto_height=false, - on_activate=function() end, + enabled=function() return view_sheets.linking_lever_mech_target_id ~= -1 end, + on_activate=self:callback('choose_mechanism', 'target', false), }, } end +local item_selection_dlg +local function reset_dlg() + if item_selection_dlg then + if item_selection_dlg:isActive() then + item_selection_dlg:dismiss() + end + item_selection_dlg = nil + end +end + +local function get_available_items(safety, other_mechanism) + local item_ids = require('plugins.buildingplan').getAvailableItemsByHeat( + df.building_type.Trap, df.trap_type.Lever, -1, 0, safety) + for idx,item_id in ipairs(item_ids) do + if item_id == other_mechanism then + table.remove(item_ids, idx) + break + end + end + return item_ids +end + +function MechanismOverlay:save_id(which, item_id) + local saved_id = ('saved_%s_id'):format(which) + local ui_id = ('linking_lever_mech_%s_id'):format(which) + view_sheets[ui_id] = item_id + self[saved_id] = item_id +end + +function MechanismOverlay:choose_mechanism(which, autoselect) + local widget_id = 'safety_' .. which + local safety = self.subviews[widget_id]:getOptionValue() + local ui_other_id = ('linking_lever_mech_%s_id'):format(which == 'lever' and 'target' or 'lever') + local available_item_ids = get_available_items(safety, view_sheets[ui_other_id]) + + if autoselect then + self:save_id(which, available_item_ids[1] or -1) + return + end + + -- to integrate with ItemSelection's last used sorting + df.global.buildreq.building_type = df.building_type.Trap + + local desc = self.subviews[widget_id]:getOptionLabel() + if desc ~= 'Any' then + desc = desc .. ' safe' + end + desc = desc .. ' mechanism' + + item_selection_dlg = item_selection_dlg or itemselection.ItemSelectionScreen{ + get_available_items_fn=function() return available_item_ids end, + desc=desc, + quantity=1, + autoselect=false, + on_cancel=reset_dlg, + on_submit=function(chosen_ids) + self:save_id(which, chosen_ids[1] or available_item_ids[1] -1) + reset_dlg() + end, + }:show() +end + function MechanismOverlay:onInput(keys) - if keys._MOUSE_L and self:getMousePos() then - MechanismOverlay.super.onInput(self, keys) - -- don't let clicks bleed through the panel + if MechanismOverlay.super.onInput(self, keys) then return true end + if keys._MOUSE_L then + if self:getMousePos() then + -- don't let clicks bleed through the panel + return true + end + -- don't allow the lever to be linked if mechanisms are not set + return view_sheets.linking_lever_mech_lever_id == -1 or + view_sheets.linking_lever_mech_target_id == -1 + end +end + +function MechanismOverlay:onRenderFrame(dc, rect) + MechanismOverlay.super.onRenderFrame(self, dc, rect) + if self.saved_lever_id ~= view_sheets.linking_lever_mech_lever_id then + self:choose_mechanism('lever', true) + end + if self.saved_target_id ~= view_sheets.linking_lever_mech_target_id then + self:choose_mechanism('target', true) + end end return _ENV diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index 688d3bf74..2f150710f 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -809,8 +809,12 @@ function PlannerOverlay:onInput(keys) for idx = num_filters,1,-1 do chosen_items[idx] = {} local filter = filters[idx] + local get_available_items_fn = function() + return require('plugins.buildingplan').getAvailableItems( + uibs.building_type, uibs.building_subtype, uibs.custom_type, idx-1) + end local selection_screen = itemselection.ItemSelectionScreen{ - index=idx, + get_available_items_fn=get_available_items_fn, desc=require('plugins.buildingplan').get_desc(filter), quantity=get_quantity(filter, is_hollow, bounds), autoselect=autoselect, From 7873ff8b5aa91723277b860d41342f6fb5784b8c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Nov 2023 16:41:58 -0700 Subject: [PATCH 832/851] docs and branding --- docs/plugins/buildingplan.rst | 7 +++ plugins/lua/buildingplan/mechanisms.lua | 63 +++++++++++++------------ 2 files changed, 41 insertions(+), 29 deletions(-) diff --git a/docs/plugins/buildingplan.rst b/docs/plugins/buildingplan.rst index db04a97f7..b1e77a80d 100644 --- a/docs/plugins/buildingplan.rst +++ b/docs/plugins/buildingplan.rst @@ -190,3 +190,10 @@ bump the items for this building to the front of their respective queues. Note that each item type and filter configuration has its own queue, so even if an item is in queue position 1, there may be other queues that snag the needed item first. + +Lever linking +------------- + +When linking levers, `buildingplan` extends the vanilla panel by offering +control over which mechanisms are chosen for installation at the lever and at +the target. Heat safety filters are provided for convenience. diff --git a/plugins/lua/buildingplan/mechanisms.lua b/plugins/lua/buildingplan/mechanisms.lua index 0993953cd..4b6e42885 100644 --- a/plugins/lua/buildingplan/mechanisms.lua +++ b/plugins/lua/buildingplan/mechanisms.lua @@ -20,35 +20,40 @@ MechanismOverlay.ATTRS{ function MechanismOverlay:init() self:addviews{ - widgets.Label{ - frame={t=4, l=2}, - text='Mechanism safety:' - }, - widgets.CycleHotkeyLabel{ - view_id='safety_lever', - frame={t=4, l=21, w=15}, - key='CUSTOM_G', - label='Lever:', - options={ - {label='Any', value=0}, - {label='Magma', value=2, pen=COLOR_RED}, - {label='Fire', value=1, pen=COLOR_LIGHTRED}, - }, - initial_option=0, - on_change=self:callback('choose_mechanism', 'lever', true), - }, - widgets.CycleHotkeyLabel{ - view_id='safety_target', - frame={t=4, l=38, w=16}, - key='CUSTOM_SHIFT_G', - label='Target:', - options={ - {label='Any', value=0}, - {label='Magma', value=2, pen=COLOR_RED}, - {label='Fire', value=1, pen=COLOR_LIGHTRED}, - }, - initial_option=0, - on_change=self:callback('choose_mechanism', 'target', true), + widgets.BannerPanel{ + frame={t=4, l=1, r=1, h=1}, + subviews={ + widgets.Label{ + frame={t=0, l=1}, + text='Mechanism safety:' + }, + widgets.CycleHotkeyLabel{ + view_id='safety_lever', + frame={t=0, l=20, w=15}, + key='CUSTOM_G', + label='Lever:', + options={ + {label='Any', value=0}, + {label='Magma', value=2, pen=COLOR_RED}, + {label='Fire', value=1, pen=COLOR_LIGHTRED}, + }, + initial_option=0, + on_change=self:callback('choose_mechanism', 'lever', true), + }, + widgets.CycleHotkeyLabel{ + view_id='safety_target', + frame={t=0, l=38, w=16}, + key='CUSTOM_SHIFT_G', + label='Target:', + options={ + {label='Any', value=0}, + {label='Magma', value=2, pen=COLOR_RED}, + {label='Fire', value=1, pen=COLOR_LIGHTRED}, + }, + initial_option=0, + on_change=self:callback('choose_mechanism', 'target', true), + }, + } }, widgets.HotkeyLabel{ frame={t=7, l=8, w=49, h=2}, From f93bb60b3b0fecce58e432a534f7d45f5d829aff Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 3 Nov 2023 17:41:32 -0700 Subject: [PATCH 833/851] move the safety line down by one --- plugins/lua/buildingplan/mechanisms.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/buildingplan/mechanisms.lua b/plugins/lua/buildingplan/mechanisms.lua index 4b6e42885..163255ca3 100644 --- a/plugins/lua/buildingplan/mechanisms.lua +++ b/plugins/lua/buildingplan/mechanisms.lua @@ -21,7 +21,7 @@ MechanismOverlay.ATTRS{ function MechanismOverlay:init() self:addviews{ widgets.BannerPanel{ - frame={t=4, l=1, r=1, h=1}, + frame={t=5, l=1, r=1, h=1}, subviews={ widgets.Label{ frame={t=0, l=1}, From e196ceb8f9ddb27bfb995931137b810d7b78c630 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 4 Nov 2023 18:59:20 -0700 Subject: [PATCH 834/851] support search for work animal assignment --- docs/changelog.txt | 1 + plugins/lua/sort/info.lua | 47 +++++++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 7a13ba6f4..a6533ef82 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -66,6 +66,7 @@ Template for new versions: ## Misc Improvements - `buildingplan`: display how many items are available on the planner panel - `sort`: allow searching by profession on the squad assignment page +- `sort`: add search for work animal assignment screen; allow filtering by miltary/civilian - `dreamfort`: Inside+ and Clearcutting burrows now automatically created and managed ## Documentation diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index a48b1d986..f9233bf6c 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -109,11 +109,6 @@ local function get_race_name(raw_id) return raw.name[1] end -local function get_trainer_search_key(unit) - if not unit then return end - return ('%s %s'):format(dfhack.TranslateName(unit.name), dfhack.units.getProfessionName(unit)) -end - -- get name in both dwarvish and English local function get_artifact_search_key(artifact) return ('%s %s'):format(dfhack.TranslateName(artifact.name), dfhack.TranslateName(artifact.name, true)) @@ -166,7 +161,7 @@ InfoOverlay = defclass(InfoOverlay, sortoverlay.SortOverlay) InfoOverlay.ATTRS{ default_pos={x=64, y=8}, viewscreens='dwarfmode/Info', - frame={w=40, h=4}, + frame={w=40, h=5}, } function InfoOverlay:init() @@ -185,6 +180,25 @@ function InfoOverlay:init() }, }, }, + widgets.BannerPanel{ + view_id='filter_panel', + frame={l=0, t=1, r=0, h=1}, + visible=function() return self:get_key() == 'PET_WA' end, + subviews={ + widgets.CycleHotkeyLabel{ + view_id='subset', + frame={l=1, t=0}, + key='CUSTOM_SHIFT_F', + label='Show:', + options={ + {label='All', value='all', pen=COLOR_GREEN}, + {label='Military', value='military', pen=COLOR_YELLOW}, + {label='Civilians', value='civilian', pen=COLOR_CYAN}, + }, + on_change=function() self:do_search(self.subviews.search.text, true) end, + }, + }, + }, } local CRI_UNIT_VECS = { @@ -209,7 +223,12 @@ function InfoOverlay:init() self:register_handler('PET_OT', creatures.atk_index, curry(sortoverlay.single_vector_search, {get_search_key_fn=get_race_name})) self:register_handler('PET_AT', creatures.trainer, - curry(sortoverlay.single_vector_search, {get_search_key_fn=get_trainer_search_key})) + curry(sortoverlay.single_vector_search, {get_search_key_fn=sortoverlay.get_unit_search_key})) + self:register_handler('PET_WA', creatures.work_animal_recipient, + curry(sortoverlay.single_vector_search, { + get_search_key_fn=sortoverlay.get_unit_search_key, + matches_filters_fn=self:callback('matches_filters'), + })) self:register_handler('WORK_DETAILS', work_details.assignable_unit, work_details_search) for idx,name in ipairs(df.artifacts_mode_type) do @@ -227,6 +246,8 @@ function InfoOverlay:get_key() return 'PET_OT' elseif creatures.adding_trainer then return 'PET_AT' + elseif creatures.assign_work_animal then + return 'PET_WA' end end return df.unit_list_mode_type[creatures.current_mode] @@ -275,6 +296,8 @@ function InfoOverlay:updateFrames() local frame = self.subviews.panel.frame if frame.l == l and frame.t == t then return ret end frame.l, frame.t = l, t + local frame2 = self.subviews.filter_panel.frame + frame2.l, frame2.t = l, t + 1 return true end @@ -296,6 +319,16 @@ function InfoOverlay:onInput(keys) return InfoOverlay.super.onInput(self, keys) end +function InfoOverlay:matches_filters(unit) + local subset = self.subviews.subset:getOptionValue() + if subset == 'all' then + return true + elseif unit.military.squad_id == -1 then + return subset == 'civilian' + end + return subset == 'military' +end + -- ---------------------- -- CandidatesOverlay -- From 749ccc518253f93d86bd325cfbbf57901a8eda9e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 4 Nov 2023 19:06:03 -0700 Subject: [PATCH 835/851] filter out non-denominational temples if one is established --- docs/changelog.txt | 1 + plugins/lua/sort/locationselector.lua | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 7a13ba6f4..2a03e6a60 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -62,6 +62,7 @@ Template for new versions: ## Fixes - `stockpiles`: hide configure and help buttons when the overlay panel is minimized - `caravan`: price of vermin swarms correctly adjusted down. a stack of 10000 bees is worth 10, not 10000 +- `sort`: when filtering out already-established temples in the location assignment screen, also filter out the "No specific deity" option if a non-denominational temple has already been established ## Misc Improvements - `buildingplan`: display how many items are available on the planner panel diff --git a/plugins/lua/sort/locationselector.lua b/plugins/lua/sort/locationselector.lua index f88095203..bdacc1630 100644 --- a/plugins/lua/sort/locationselector.lua +++ b/plugins/lua/sort/locationselector.lua @@ -131,7 +131,6 @@ function LocationSelectorOverlay:get_cache() end function LocationSelectorOverlay:matches_temple_filter(id, flag) - if id == -1 then return true end local hide_established = self.subviews.hide_established:getOptionValue() return not hide_established or not safe_index(self:get_cache(), 'temple', flag, id) end From f5d0c5b29124be522458e7bcefff6ad6535968bf Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 4 Nov 2023 19:10:19 -0700 Subject: [PATCH 836/851] unregister event listeners on disable --- plugins/burrow.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/burrow.cpp b/plugins/burrow.cpp index 743035fbb..8e4bfef2e 100644 --- a/plugins/burrow.cpp +++ b/plugins/burrow.cpp @@ -66,6 +66,8 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { init_diggers(out); EventManager::registerListener(EventManager::EventType::JOB_STARTED, EventManager::EventHandler(jobStartedHandler, 0), plugin_self); EventManager::registerListener(EventManager::EventType::JOB_COMPLETED, EventManager::EventHandler(jobCompletedHandler, 0), plugin_self); + } else { + EventManager::unregisterAll(plugin_self); } } else { From 1c5deaff380f67297640e182ed2127b6e7152cf3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 4 Nov 2023 23:57:10 -0700 Subject: [PATCH 837/851] improve interface for single-tile stairs --- docs/changelog.txt | 1 + plugins/lua/buildingplan/planneroverlay.lua | 37 +++++++++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 990b8daba..57e1ed9e1 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -66,6 +66,7 @@ Template for new versions: ## Misc Improvements - `buildingplan`: display how many items are available on the planner panel +- `buildingplan`: clarify interface when building single-tile staircases - `sort`: allow searching by profession on the squad assignment page - `sort`: add search for work animal assignment screen; allow filtering by miltary/civilian - `dreamfort`: Inside+ and Clearcutting burrows now automatically created and managed diff --git a/plugins/lua/buildingplan/planneroverlay.lua b/plugins/lua/buildingplan/planneroverlay.lua index 2f150710f..06872ea09 100644 --- a/plugins/lua/buildingplan/planneroverlay.lua +++ b/plugins/lua/buildingplan/planneroverlay.lua @@ -171,6 +171,18 @@ local function is_stairs() and uibs.building_subtype == df.construction_type.UpDownStair end +local function is_single_level_stairs() + if not is_stairs() then return false end + local _, _, dimz = get_cur_area_dims() + return dimz == 1 +end + +local function is_multi_level_stairs() + if not is_stairs() then return false end + local _, _, dimz = get_cur_area_dims() + return dimz > 1 +end + local direction_panel_frame = {t=4, h=13, w=46, r=28} local direction_panel_types = utils.invert{ @@ -435,10 +447,10 @@ function PlannerOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='stairs_top_subtype', - frame={b=5, l=23, w=30}, + frame={b=7, l=1, w=30}, key='CUSTOM_R', - label='Top Stair Type: ', - visible=is_stairs, + label='Top stair type: ', + visible=is_multi_level_stairs, options={ {label='Auto', value='auto'}, {label='UpDown', value=df.construction_type.UpDownStair}, @@ -447,16 +459,28 @@ function PlannerOverlay:init() }, widgets.CycleHotkeyLabel { view_id='stairs_bottom_subtype', - frame={b=4, l=23, w=30}, + frame={b=6, l=1, w=30}, key='CUSTOM_B', label='Bottom Stair Type:', - visible=is_stairs, + visible=is_multi_level_stairs, options={ {label='Auto', value='auto'}, {label='UpDown', value=df.construction_type.UpDownStair}, {label='Up', value=df.construction_type.UpStair}, }, }, + widgets.CycleHotkeyLabel{ + view_id='stairs_only_subtype', + frame={b=7, l=1, w=30}, + key='CUSTOM_R', + label='Single level stair:', + visible=is_single_level_stairs, + options={ + {label='Up', value=df.construction_type.UpStair}, + {label='UpDown', value=df.construction_type.UpDownStair}, + {label='Down', value=df.construction_type.DownStair}, + }, + }, widgets.CycleHotkeyLabel { -- TODO: this thing also needs a slider view_id='weapons', frame={b=4, l=1, w=28}, @@ -910,7 +934,8 @@ end function PlannerOverlay:get_stairs_subtype(pos, bounds) local subtype = uibs.building_subtype if pos.z == bounds.z1 then - local opt = self.subviews.stairs_bottom_subtype:getOptionValue() + local opt = bounds.z1 == bounds.z2 and self.subviews.stairs_only_subtype:getOptionValue() or + self.subviews.stairs_bottom_subtype:getOptionValue() if opt == 'auto' then local tt = dfhack.maps.getTileType(pos) local shape = df.tiletype.attrs[tt].shape From 4686dcec42b85c3eb07fd891366596617c4bf73f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 5 Nov 2023 01:26:14 -0700 Subject: [PATCH 838/851] filter units by squad or burrow on work animal assignment page --- docs/changelog.txt | 2 +- docs/plugins/sort.rst | 3 +- plugins/lua/sort/info.lua | 98 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 57e1ed9e1..c7069e272 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -68,7 +68,7 @@ Template for new versions: - `buildingplan`: display how many items are available on the planner panel - `buildingplan`: clarify interface when building single-tile staircases - `sort`: allow searching by profession on the squad assignment page -- `sort`: add search for work animal assignment screen; allow filtering by miltary/civilian +- `sort`: add search for work animal assignment screen; allow filtering by miltary/squad/civilian/burrow - `dreamfort`: Inside+ and Clearcutting burrows now automatically created and managed ## Documentation diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 4833cbf83..95033d949 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -102,7 +102,8 @@ The Info overlay adds search support to many of the fort-wide "Info" panels name (with either English or native language last names), profession, or special status (like "necromancer"). If there is text in the second column, you can search for that text as well. This is often a job name or a status, like -"caged". +"caged". The work animal assignment page can also filter by squad or burrow +membership. Interrogation overlay --------------------- diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index f9233bf6c..9110ec825 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -161,9 +161,35 @@ InfoOverlay = defclass(InfoOverlay, sortoverlay.SortOverlay) InfoOverlay.ATTRS{ default_pos={x=64, y=8}, viewscreens='dwarfmode/Info', - frame={w=40, h=5}, + frame={w=40, h=6}, } +local function get_squad_options() + local options = {{label='Any', value='all', pen=COLOR_GREEN}} + local fort = df.historical_entity.find(df.global.plotinfo.group_id) + if not fort then return options end + for _, squad_id in ipairs(fort.squads) do + table.insert(options, { + label=dfhack.military.getSquadName(squad_id), + value=squad_id, + pen=COLOR_YELLOW, + }) + end + return options +end + +local function get_burrow_options() + local options = {{label='Any', value='all', pen=COLOR_GREEN}} + for _, burrow in ipairs(df.global.plotinfo.burrows.list) do + table.insert(options, { + label=#burrow.name > 0 and burrow.name or ('Burrow %d'):format(burrow.id + 1), + value=burrow.id, + pen=COLOR_YELLOW, + }) + end + return options +end + function InfoOverlay:init() self:addviews{ widgets.BannerPanel{ @@ -181,7 +207,7 @@ function InfoOverlay:init() }, }, widgets.BannerPanel{ - view_id='filter_panel', + view_id='subset_panel', frame={l=0, t=1, r=0, h=1}, visible=function() return self:get_key() == 'PET_WA' end, subviews={ @@ -194,7 +220,55 @@ function InfoOverlay:init() {label='All', value='all', pen=COLOR_GREEN}, {label='Military', value='military', pen=COLOR_YELLOW}, {label='Civilians', value='civilian', pen=COLOR_CYAN}, + {label='Burrowed', value='burrow', pen=COLOR_MAGENTA}, + }, + on_change=function(value) + local squad = self.subviews.squad + local burrow = self.subviews.burrow + squad.visible = false + burrow.visible = false + if value == 'military' then + squad.options = get_squad_options() + squad:setOption('all') + squad.visible = true + elseif value == 'burrow' then + burrow.options = get_burrow_options() + burrow:setOption('all') + burrow.visible = true + end + self:do_search(self.subviews.search.text, true) + end, + }, + }, + }, + widgets.BannerPanel{ + view_id='subfilter_panel', + frame={l=0, t=2, r=0, h=1}, + visible=function() + local subset = self.subviews.subset:getOptionValue() + return self:get_key() == 'PET_WA' and (subset == 'military' or subset == 'burrow') + end, + subviews={ + widgets.CycleHotkeyLabel{ + view_id='squad', + frame={l=1, t=0}, + key='CUSTOM_SHIFT_S', + label='Squad:', + options={ + {label='Any', value='all', pen=COLOR_GREEN}, }, + visible=false, + on_change=function() self:do_search(self.subviews.search.text, true) end, + }, + widgets.CycleHotkeyLabel{ + view_id='burrow', + frame={l=1, t=0}, + key='CUSTOM_SHIFT_B', + label='Burrow:', + options={ + {label='Any', value='all', pen=COLOR_GREEN}, + }, + visible=false, on_change=function() self:do_search(self.subviews.search.text, true) end, }, }, @@ -296,8 +370,10 @@ function InfoOverlay:updateFrames() local frame = self.subviews.panel.frame if frame.l == l and frame.t == t then return ret end frame.l, frame.t = l, t - local frame2 = self.subviews.filter_panel.frame + local frame2 = self.subviews.subset_panel.frame frame2.l, frame2.t = l, t + 1 + local frame3 = self.subviews.subfilter_panel.frame + frame3.l, frame3.t = l, t + 2 return true end @@ -323,10 +399,20 @@ function InfoOverlay:matches_filters(unit) local subset = self.subviews.subset:getOptionValue() if subset == 'all' then return true - elseif unit.military.squad_id == -1 then - return subset == 'civilian' + elseif subset == 'civilian' then + return unit.military.squad_id == -1 + elseif subset == 'military' then + local squad_id = unit.military.squad_id + if squad_id == -1 then return false end + local target_id = self.subviews.squad:getOptionValue() + if target_id == 'all' then return true end + return target_id == squad_id + elseif subset == 'burrow' then + local target_id = self.subviews.burrow:getOptionValue() + if target_id == 'all' then return true end + return utils.binsearch(unit.burrows, target_id) end - return subset == 'military' + return true end -- ---------------------- From 49d4a40761e01670e3633a84ec91f8e3dc4ce969 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 5 Nov 2023 01:27:40 -0700 Subject: [PATCH 839/851] return untranslated name as the readable name --- docs/changelog.txt | 1 + library/modules/Units.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 57e1ed9e1..6dee690ca 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -76,6 +76,7 @@ Template for new versions: ## API - ``Gui::revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target - ``Maps::getWalkableGroup``: get the walkability group of a tile +- ``Units::getReadableName``: now returns the *untranslated* name ## Lua - ``dfhack.gui.revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index a9d361706..ff36481b7 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -1282,7 +1282,7 @@ string Units::getReadableName(df::unit* unit) { race_name = "hunter " + race_name; if (isWar(unit)) race_name = "war " + race_name; - string name = Translation::TranslateName(getVisibleName(unit)); + string name = Translation::TranslateName(getVisibleName(unit), false); if (name.empty()) { name = race_name; } else { From b5962feae923ee1c3649c532de7e91450ef03667 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 5 Nov 2023 00:06:47 -0700 Subject: [PATCH 840/851] normalize effectiveness and potential rating scales --- docs/changelog.txt | 1 + plugins/lua/sort.lua | 20 +++++++++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index c7069e272..b2cd693a5 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -69,6 +69,7 @@ Template for new versions: - `buildingplan`: clarify interface when building single-tile staircases - `sort`: allow searching by profession on the squad assignment page - `sort`: add search for work animal assignment screen; allow filtering by miltary/squad/civilian/burrow +- `sort`: on the squad assignment screen, make effectiveness and potential ratings use the same scale so effectiveness is always less than or equal to potential for a unit and so you can tell when units are approaching their maximum potential - `dreamfort`: Inside+ and Clearcutting burrows now automatically created and managed ## Documentation diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 604120f97..bc2991891 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -431,14 +431,19 @@ local function get_melee_combat_potential(unit) local spatial_sense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value local kinesthetic_sense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value + -- assume highest skill ratings + local skill_rating = df.skill_rating.Legendary5 + local melee_combat_rating = df.skill_rating.Legendary5 + -- melee combat potential rating - local rating = strength * 264 + endurance * 84 + body_size_base * 77 + kinesthetic_sense * 74 - + agility * 33 + willpower * 31 + spatial_sense * 27 + toughness * 25 + local rating = skill_rating * 27000 + melee_combat_rating * 9000 + + strength * 180 + body_size_base * 100 + kinesthetic_sense * 50 + endurance * 50 + + agility * 30 + toughness * 20 + willpower * 20 + spatial_sense * 20 return rating end local function get_melee_combat_potential_rating(unit) - return get_rating(get_melee_combat_potential(unit), 300000, 2600000, 81, 64, 46, 29) + return get_rating(get_melee_combat_potential(unit), 350000, 2750000, 64, 52, 40, 28) end local function sort_by_melee_combat_potential_desc(unit_id_1, unit_id_2) @@ -480,13 +485,18 @@ local function get_ranged_combat_potential(unit) local spatial_sense = unit.status.current_soul.mental_attrs.SPATIAL_SENSE.max_value local kinesthetic_sense = unit.status.current_soul.mental_attrs.KINESTHETIC_SENSE.max_value + -- assume highest skill ratings + local skill_rating = df.skill_rating.Legendary5 + local ranged_combat = df.skill_rating.Legendary5 + -- ranged combat potential formula - local rating = agility * 5 + kinesthetic_sense * 2 + spatial_sense * 5 + focus * 2 + local rating = skill_rating * 24000 + ranged_combat * 8000 + + agility * 15 + spatial_sense * 15 + kinesthetic_sense * 6 + focus * 6 return rating end local function get_ranged_combat_potential_rating(unit) - return get_rating(get_ranged_combat_potential(unit), 0, 70000, 73, 57, 41, 25) + return get_rating(get_ranged_combat_potential(unit), 0, 800000, 72, 52, 31, 11) end local function sort_by_ranged_combat_potential_desc(unit_id_1, unit_id_2) From 539caf3dbaf58f7aec0ad7440f9dfe18204b1054 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 5 Nov 2023 01:18:21 -0800 Subject: [PATCH 841/851] handle inactive burrows when assigning/clearing units --- docs/changelog.txt | 1 + library/modules/Burrows.cpp | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 4059aa577..522291a92 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -77,6 +77,7 @@ Template for new versions: - ``Gui::revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target - ``Maps::getWalkableGroup``: get the walkability group of a tile - ``Units::getReadableName``: now returns the *untranslated* name +- ``Burrows::setAssignedUnit``: now properly handles inactive burrows ## Lua - ``dfhack.gui.revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target diff --git a/library/modules/Burrows.cpp b/library/modules/Burrows.cpp index 9e63c0dbc..afd6ac9e3 100644 --- a/library/modules/Burrows.cpp +++ b/library/modules/Burrows.cpp @@ -78,8 +78,10 @@ void Burrows::clearUnits(df::burrow *burrow) { auto unit = df::unit::find(burrow->units[i]); - if (unit) + if (unit) { erase_from_vector(unit->burrows, burrow->id); + erase_from_vector(unit->inactive_burrows, burrow->id); + } } burrow->units.clear(); @@ -90,7 +92,8 @@ bool Burrows::isAssignedUnit(df::burrow *burrow, df::unit *unit) CHECK_NULL_POINTER(unit); CHECK_NULL_POINTER(burrow); - return binsearch_index(unit->burrows, burrow->id) >= 0; + return binsearch_index(unit->burrows, burrow->id) >= 0 || + binsearch_index(unit->inactive_burrows, burrow->id) >= 0; } void Burrows::setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable) @@ -100,14 +103,15 @@ void Burrows::setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable) CHECK_NULL_POINTER(unit); CHECK_NULL_POINTER(burrow); - if (enable) - { - insert_into_vector(unit->burrows, burrow->id); + if (enable) { + if (burrow->limit_workshops & 2) // inactive flag + insert_into_vector(unit->inactive_burrows, burrow->id); + else + insert_into_vector(unit->burrows, burrow->id); insert_into_vector(burrow->units, unit->id); - } - else - { + } else { erase_from_vector(unit->burrows, burrow->id); + erase_from_vector(unit->inactive_burrows, burrow->id); erase_from_vector(burrow->units, unit->id); } } From 42298b4d2ec2ee862ebfdf42b0c2ca538a91109d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 5 Nov 2023 03:09:30 -0800 Subject: [PATCH 842/851] show how many work animals a unit has when assigning --- docs/changelog.txt | 1 + library/modules/Gui.cpp | 2 ++ plugins/lua/sort.lua | 1 + plugins/lua/sort/info.lua | 68 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 522291a92..23b5720d1 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -69,6 +69,7 @@ Template for new versions: - `buildingplan`: clarify interface when building single-tile staircases - `sort`: allow searching by profession on the squad assignment page - `sort`: add search for work animal assignment screen; allow filtering by miltary/squad/civilian/burrow +- `sort`: new overlay on the animal assignment screen that shows how many work animals each visible unit already has assigned to them - `dreamfort`: Inside+ and Clearcutting burrows now automatically created and managed ## Documentation diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index a6a28239d..4fba833d9 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -252,6 +252,8 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode) newFocusString += "/ActivityDetails"; else if (game->main_interface.info.creatures.adding_trainer) newFocusString += "/AddingTrainer"; + else if (game->main_interface.info.creatures.assign_work_animal) + newFocusString += "/AssignWorkAnimal"; else newFocusString += '/' + enum_item_key(game->main_interface.info.creatures.current_mode); break; diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 604120f97..f5c2dde84 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1279,6 +1279,7 @@ OVERLAY_WIDGETS = { squad_assignment=SquadAssignmentOverlay, squad_annotation=SquadAnnotationOverlay, info=require('plugins.sort.info').InfoOverlay, + workanimals=require('plugins.sort.info').WorkAnimalOverlay, candidates=require('plugins.sort.info').CandidatesOverlay, interrogation=require('plugins.sort.info').InterrogationOverlay, location_selector=require('plugins.sort.locationselector').LocationSelectorOverlay, diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index 9110ec825..a4b026cac 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -1,6 +1,7 @@ local _ENV = mkmodule('plugins.sort.info') local gui = require('gui') +local overlay = require('plugins.overlay') local sortoverlay = require('plugins.sort.sortoverlay') local widgets = require('gui.widgets') local utils = require('utils') @@ -469,6 +470,73 @@ function CandidatesOverlay:onRenderBody(dc) end end +-- ---------------------- +-- WorkAnimalOverlay +-- + +WorkAnimalOverlay = defclass(WorkAnimalOverlay, overlay.OverlayWidget) +WorkAnimalOverlay.ATTRS{ + default_pos={x=-33, y=12}, + viewscreens='dwarfmode/Info/CREATURES/AssignWorkAnimal', + default_enabled=true, + frame={w=29, h=1}, +} + +function WorkAnimalOverlay:init() + self:addviews{ + widgets.Label{ + view_id='annotations', + frame={t=0, l=0}, + text='', + } + } +end + +local function get_work_animal_counts() + local counts = {} + for _,unit in ipairs(df.global.world.units.active) do + if not dfhack.units.isOwnCiv(unit) or + (not dfhack.units.isWar(unit) and not dfhack.units.isHunter(unit)) + then + goto continue + end + local owner_id = unit.relationship_ids.Pet + if owner_id == -1 then goto continue end + counts[owner_id] = (counts[owner_id] or 0) + 1 + ::continue:: + end + return counts +end + +function WorkAnimalOverlay:onRenderFrame(dc, rect) + local _, sh = dfhack.screen.getWindowSize() + local _, t = get_panel_offsets() + local list_height = sh - (17 + t) + local num_elems = list_height // 3 + local max_elem = math.min(#creatures.work_animal_recipient-1, + creatures.scroll_position_work_animal+num_elems-1) + + local annotations = {} + local counts = get_work_animal_counts() + for idx=creatures.scroll_position_work_animal,max_elem do + table.insert(annotations, NEWLINE) + table.insert(annotations, NEWLINE) + local animal_count = counts[creatures.work_animal_recipient[idx].id] + if animal_count and animal_count > 0 then + table.insert(annotations, {text='[', pen=COLOR_RED}) + table.insert(annotations, ('Assigned work animals: %d'):format(animal_count)) + table.insert(annotations, {text=']', pen=COLOR_RED}) + end + table.insert(annotations, NEWLINE) + end + + self.subviews.annotations.frame.t = t + self.subviews.annotations:setText(annotations) + self.frame.h = list_height + t + + WorkAnimalOverlay.super.onRenderFrame(self, dc, rect) +end + -- ---------------------- -- InterrogationOverlay -- From 2ce55efed708f14a4f4e333e52316892946017fc Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 5 Nov 2023 03:20:36 -0800 Subject: [PATCH 843/851] add filter for unburrowed units --- plugins/lua/sort/info.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index a4b026cac..8d4a0a802 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -180,7 +180,10 @@ local function get_squad_options() end local function get_burrow_options() - local options = {{label='Any', value='all', pen=COLOR_GREEN}} + local options = { + {label='Any', value='all', pen=COLOR_GREEN}, + {label='Unburrowed', value='none', pen=COLOR_LIGHTRED}, + } for _, burrow in ipairs(df.global.plotinfo.burrows.list) do table.insert(options, { label=#burrow.name > 0 and burrow.name or ('Burrow %d'):format(burrow.id + 1), @@ -410,8 +413,9 @@ function InfoOverlay:matches_filters(unit) return target_id == squad_id elseif subset == 'burrow' then local target_id = self.subviews.burrow:getOptionValue() - if target_id == 'all' then return true end - return utils.binsearch(unit.burrows, target_id) + if target_id == 'all' then return #unit.burrows + #unit.inactive_burrows > 0 end + if target_id == 'none' then return #unit.burrows + #unit.inactive_burrows == 0 end + return utils.binsearch(unit.burrows, target_id) or utils.binsearch(unit.inactive_burrows, target_id) end return true end From 4081ddcf208bc94391d7cd00f64f59022e0024ac Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 5 Nov 2023 03:22:51 -0800 Subject: [PATCH 844/851] update docs --- docs/plugins/sort.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index 95033d949..eb3e20663 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -105,6 +105,13 @@ can search for that text as well. This is often a job name or a status, like "caged". The work animal assignment page can also filter by squad or burrow membership. +Work animals overlay +-------------------- + +In addition to the search and filter widgets provided by the Info tabs overlay, +the work animal assignment screen has an additional overlay that annotates each +visible unit with the number of work animals that unit already has. + Interrogation overlay --------------------- From cabcd01d4a7002a7321d18e393ce5a2d777b3627 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 6 Nov 2023 07:13:46 +0000 Subject: [PATCH 845/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 2382a3343..3683a1b39 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 2382a334367b7a46a1ddeefc0e43a63491d6062c +Subproject commit 3683a1b39bca1c6eff7b92058d2518960c36d83d From 4572ec3d098289cd3329b7cb96fbe5d0788052d6 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 6 Nov 2023 06:01:15 -0800 Subject: [PATCH 846/851] allow getMousePos to return out of bounds coordinates --- docs/changelog.txt | 2 ++ docs/dev/Lua API.rst | 6 ++++-- library/LuaApi.cpp | 5 +++-- library/include/modules/Gui.h | 2 +- library/modules/Gui.cpp | 4 ++-- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1df3e567f..e1b55f382 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -80,10 +80,12 @@ Template for new versions: - ``Maps::getWalkableGroup``: get the walkability group of a tile - ``Units::getReadableName``: now returns the *untranslated* name - ``Burrows::setAssignedUnit``: now properly handles inactive burrows +- ``Gui::getMousePos``: now takes an optional ``allow_out_of_bounds`` parameter so coordinates can be returned for mouse positions outside of the game map (i.e. in the blank space around the map) ## Lua - ``dfhack.gui.revealInDwarfmodeMap``: gained ``highlight`` parameter to control setting the tile highlight on the zoom target - ``dfhack.maps.getWalkableGroup``: get the walkability group of a tile +- ``dfhack.gui.getMousePos``: support new optional ``allow_out_of_bounds`` parameter - ``gui.FRAME_THIN``: a panel frame suitable for floating tooltips ## Removed diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index abab94829..fa7094b40 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1140,10 +1140,12 @@ Announcements If you want a guaranteed announcement without parsing, use ``dfhack.gui.showAutoAnnouncement`` instead. -* ``dfhack.gui.getMousePos()`` +* ``dfhack.gui.getMousePos([allow_out_of_bounds])`` Returns the map coordinates of the map tile the mouse is over as a table of - ``{x, y, z}``. If the cursor is not over the map, returns ``nil``. + ``{x, y, z}``. If the cursor is not over a valid tile, returns ``nil``. To + allow the function to return coordinates outside of the map, set + ``allow_out_of_bounds`` to ``true``. Other ~~~~~ diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 1fd4b5ecf..a8e901a6d 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1505,8 +1505,9 @@ static int gui_getDwarfmodeViewDims(lua_State *state) static int gui_getMousePos(lua_State *L) { - auto pos = Gui::getMousePos(); - if (pos.isValid()) + bool allow_out_of_bounds = lua_toboolean(L, 1); + df::coord pos = Gui::getMousePos(allow_out_of_bounds); + if ((allow_out_of_bounds && pos.z >= 0) || pos.isValid()) Lua::Push(L, pos); else lua_pushnil(L); diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h index 03ca4a2c1..7f21b78fc 100644 --- a/library/include/modules/Gui.h +++ b/library/include/modules/Gui.h @@ -150,7 +150,7 @@ namespace DFHack */ DFHACK_EXPORT df::coord getViewportPos(); DFHACK_EXPORT df::coord getCursorPos(); - DFHACK_EXPORT df::coord getMousePos(); + DFHACK_EXPORT df::coord getMousePos(bool allow_out_of_bounds = false); static const int AREA_MAP_WIDTH = 23; static const int MENU_WIDTH = 30; diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 4fba833d9..475ac5728 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -2257,7 +2257,7 @@ bool Gui::setDesignationCoords (const int32_t x, const int32_t y, const int32_t } // returns the map coordinates that the mouse cursor is over -df::coord Gui::getMousePos() +df::coord Gui::getMousePos(bool allow_out_of_bounds) { df::coord pos; if (gps && gps->precise_mouse_x > -1) { @@ -2271,7 +2271,7 @@ df::coord Gui::getMousePos() pos.y += gps->mouse_y; } } - if (!Maps::isValidTilePos(pos.x, pos.y, pos.z)) + if (!allow_out_of_bounds && !Maps::isValidTilePos(pos.x, pos.y, pos.z)) return df::coord(); return pos; } From 8361ef69810bce48b3c85b6bd2f9be1f19c4307d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 6 Nov 2023 08:52:48 -0800 Subject: [PATCH 847/851] military and burrow membership filters for burrow assignment --- docs/changelog.txt | 1 + plugins/lua/sort.lua | 1 + plugins/lua/sort/info.lua | 49 +++---- plugins/lua/sort/sortoverlay.lua | 4 +- plugins/lua/sort/unitselector.lua | 216 +++++++++++++++++++++++++++--- 5 files changed, 229 insertions(+), 42 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 1df3e567f..0a07c69d0 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -58,6 +58,7 @@ Template for new versions: - `prospect`: can now give you an estimate of resources from the embark screen. hover the mouse over a potential embark area and run `prospect`. - `burrow`: integrated 3d box fill and 2d/3d flood fill extensions for burrow painting mode - `buildingplan`: allow specific mechanisms to be selected when linking levers +- `sort`: military and burrow membership filters for the burrow assignment screen ## Fixes - `stockpiles`: hide configure and help buttons when the overlay panel is minimized diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 6b9c963bd..f06f86f0d 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -1295,6 +1295,7 @@ OVERLAY_WIDGETS = { location_selector=require('plugins.sort.locationselector').LocationSelectorOverlay, unit_selector=require('plugins.sort.unitselector').UnitSelectorOverlay, worker_assignment=require('plugins.sort.unitselector').WorkerAssignmentOverlay, + burrow_assignment=require('plugins.sort.unitselector').BurrowAssignmentOverlay, slab=require('plugins.sort.slab').SlabOverlay, world=require('plugins.sort.world').WorldOverlay, } diff --git a/plugins/lua/sort/info.lua b/plugins/lua/sort/info.lua index 8d4a0a802..7f9b49b7b 100644 --- a/plugins/lua/sort/info.lua +++ b/plugins/lua/sort/info.lua @@ -165,7 +165,7 @@ InfoOverlay.ATTRS{ frame={w=40, h=6}, } -local function get_squad_options() +function get_squad_options() local options = {{label='Any', value='all', pen=COLOR_GREEN}} local fort = df.historical_entity.find(df.global.plotinfo.group_id) if not fort then return options end @@ -179,7 +179,7 @@ local function get_squad_options() return options end -local function get_burrow_options() +function get_burrow_options() local options = { {label='Any', value='all', pen=COLOR_GREEN}, {label='Unburrowed', value='none', pen=COLOR_LIGHTRED}, @@ -194,6 +194,25 @@ local function get_burrow_options() return options end +function matches_squad_burrow_filters(unit, subset, target_squad_id, target_burrow_id) + if subset == 'all' then + return true + elseif subset == 'civilian' then + return unit.military.squad_id == -1 + elseif subset == 'military' then + local squad_id = unit.military.squad_id + if squad_id == -1 then return false end + if target_squad_id == 'all' then return true end + return target_squad_id == squad_id + elseif subset == 'burrow' then + if target_burrow_id == 'all' then return #unit.burrows + #unit.inactive_burrows > 0 end + if target_burrow_id == 'none' then return #unit.burrows + #unit.inactive_burrows == 0 end + return utils.binsearch(unit.burrows, target_burrow_id) or + utils.binsearch(unit.inactive_burrows, target_burrow_id) + end + return true +end + function InfoOverlay:init() self:addviews{ widgets.BannerPanel{ @@ -217,7 +236,7 @@ function InfoOverlay:init() subviews={ widgets.CycleHotkeyLabel{ view_id='subset', - frame={l=1, t=0}, + frame={l=1, t=0, r=1}, key='CUSTOM_SHIFT_F', label='Show:', options={ @@ -255,7 +274,7 @@ function InfoOverlay:init() subviews={ widgets.CycleHotkeyLabel{ view_id='squad', - frame={l=1, t=0}, + frame={l=1, t=0, r=1}, key='CUSTOM_SHIFT_S', label='Squad:', options={ @@ -266,7 +285,7 @@ function InfoOverlay:init() }, widgets.CycleHotkeyLabel{ view_id='burrow', - frame={l=1, t=0}, + frame={l=1, t=0, r=1}, key='CUSTOM_SHIFT_B', label='Burrow:', options={ @@ -400,24 +419,8 @@ function InfoOverlay:onInput(keys) end function InfoOverlay:matches_filters(unit) - local subset = self.subviews.subset:getOptionValue() - if subset == 'all' then - return true - elseif subset == 'civilian' then - return unit.military.squad_id == -1 - elseif subset == 'military' then - local squad_id = unit.military.squad_id - if squad_id == -1 then return false end - local target_id = self.subviews.squad:getOptionValue() - if target_id == 'all' then return true end - return target_id == squad_id - elseif subset == 'burrow' then - local target_id = self.subviews.burrow:getOptionValue() - if target_id == 'all' then return #unit.burrows + #unit.inactive_burrows > 0 end - if target_id == 'none' then return #unit.burrows + #unit.inactive_burrows == 0 end - return utils.binsearch(unit.burrows, target_id) or utils.binsearch(unit.inactive_burrows, target_id) - end - return true + return matches_squad_burrow_filters(unit, self.subviews.subset:getOptionValue(), + self.subviews.squad:getOptionValue(), self.subviews.burrow:getOptionValue()) end -- ---------------------- diff --git a/plugins/lua/sort/sortoverlay.lua b/plugins/lua/sort/sortoverlay.lua index 3d80bb70c..82d7d8fca 100644 --- a/plugins/lua/sort/sortoverlay.lua +++ b/plugins/lua/sort/sortoverlay.lua @@ -5,9 +5,9 @@ local utils = require('utils') function get_unit_search_key(unit) return ('%s %s %s'):format( - dfhack.units.getReadableName(unit), -- last name is in english + dfhack.units.getReadableName(unit), dfhack.units.getProfessionName(unit), - dfhack.TranslateName(unit.name, false, true)) -- get untranslated last name + dfhack.TranslateName(unit.name, true, true)) -- get English last name end local function copy_to_lua_table(vec) diff --git a/plugins/lua/sort/unitselector.lua b/plugins/lua/sort/unitselector.lua index 806d3ec77..377ef0551 100644 --- a/plugins/lua/sort/unitselector.lua +++ b/plugins/lua/sort/unitselector.lua @@ -1,6 +1,9 @@ local _ENV = mkmodule('plugins.sort.unitselector') +local info = require('plugins.sort.info') +local gui = require('gui') local sortoverlay = require('plugins.sort.sortoverlay') +local utils = require('utils') local widgets = require('gui.widgets') local unit_selector = df.global.game.main_interface.unit_selector @@ -9,12 +12,25 @@ local unit_selector = df.global.game.main_interface.unit_selector -- UnitSelectorOverlay -- +local WIDGET_WIDTH = 31 + UnitSelectorOverlay = defclass(UnitSelectorOverlay, sortoverlay.SortOverlay) UnitSelectorOverlay.ATTRS{ default_pos={x=62, y=6}, viewscreens='dwarfmode/UnitSelector', frame={w=31, h=1}, - handled_screens=DEFAULT_NIL, + -- pen, pit, chain, and cage assignment are handled by dedicated screens + -- squad fill position screen has a specialized overlay + -- we *could* add search functionality to vanilla screens for pit and cage, + -- but then we'd have to handle the itemid vector + handled_screens={ + ZONE_BEDROOM_ASSIGNMENT='already', + ZONE_OFFICE_ASSIGNMENT='already', + ZONE_DINING_HALL_ASSIGNMENT='already', + ZONE_TOMB_ASSIGNMENT='already', + OCCUPATION_ASSIGNMENT='selected', + SQUAD_KILL_ORDER='selected', + }, } local function get_unit_id_search_key(unit_id) @@ -26,7 +42,7 @@ end function UnitSelectorOverlay:init() self:addviews{ widgets.BannerPanel{ - frame={l=0, t=0, r=0, h=1}, + frame={l=0, t=0, w=WIDGET_WIDTH, h=1}, visible=self:callback('get_key'), subviews={ widgets.EditField{ @@ -40,20 +56,10 @@ function UnitSelectorOverlay:init() }, } - -- pen, pit, chain, and cage assignment are handled by dedicated screens - -- squad fill position screen has a specialized overlay - -- we *could* add search functionality to vanilla screens for pit and cage, - -- but then we'd have to handle the itemid vector - self.handled_screens = self.handled_screens or { - ZONE_BEDROOM_ASSIGNMENT='already', - ZONE_OFFICE_ASSIGNMENT='already', - ZONE_DINING_HALL_ASSIGNMENT='already', - ZONE_TOMB_ASSIGNMENT='already', - OCCUPATION_ASSIGNMENT='selected', - BURROW_ASSIGNMENT='selected', - SQUAD_KILL_ORDER='selected', - } + self:register_handlers() +end +function UnitSelectorOverlay:register_handlers() for name,flags_vec in pairs(self.handled_screens) do self:register_handler(name, unit_selector.unid, curry(sortoverlay.flags_vector_search, {get_search_key_fn=get_unit_id_search_key}, @@ -77,13 +83,15 @@ function UnitSelectorOverlay:onRenderBody(dc) end function UnitSelectorOverlay:onInput(keys) + if UnitSelectorOverlay.super.onInput(self, keys) then + return true + end if keys._MOUSE_L then self.refresh_search = true end - return UnitSelectorOverlay.super.onInput(self, keys) end --- ---------------------- +-- ----------------------- -- WorkerAssignmentOverlay -- @@ -95,4 +103,178 @@ WorkerAssignmentOverlay.ATTRS{ handled_screens={WORKER_ASSIGNMENT='selected'}, } +-- ----------------------- +-- BurrowAssignmentOverlay +-- + +local DEFAULT_OVERLAY_WIDTH = 58 + +BurrowAssignmentOverlay = defclass(BurrowAssignmentOverlay, UnitSelectorOverlay) +BurrowAssignmentOverlay.ATTRS{ + viewscreens='dwarfmode/UnitSelector', + frame={w=DEFAULT_OVERLAY_WIDTH, h=5}, + handled_screens={BURROW_ASSIGNMENT='selected'}, +} + +local function get_screen_width() + local sw = dfhack.screen.getWindowSize() + return sw +end + +local function toggle_all() + if #unit_selector.unid == 0 then return end + local burrow = df.burrow.find(unit_selector.burrow_id) + if not burrow then return end + local target_state = unit_selector.selected[0] == 0 + local target_val = target_state and 1 or 0 + for i,unit_id in ipairs(unit_selector.unid) do + local unit = df.unit.find(unit_id) + if unit then + dfhack.burrows.setAssignedUnit(burrow, unit, target_state) + unit_selector.selected[i] = target_val + end + end +end + +function BurrowAssignmentOverlay:init() + self:addviews{ + widgets.Panel{ + view_id='top_mask', + frame={l=WIDGET_WIDTH, r=0, t=0, h=1}, + frame_background=gui.CLEAR_PEN, + visible=function() return get_screen_width() >= 144 end, + }, + widgets.Panel{ + view_id='wide_mask', + frame={r=0, t=1, h=2, w=DEFAULT_OVERLAY_WIDTH}, + frame_background=gui.CLEAR_PEN, + visible=function() return get_screen_width() >= 144 end, + }, + widgets.Panel{ + view_id='narrow_mask', + frame={l=0, t=1, h=2, w=24}, + frame_background=gui.CLEAR_PEN, + visible=function() return get_screen_width() < 144 end, + }, + widgets.BannerPanel{ + view_id='subset_panel', + frame={l=0, t=1, w=WIDGET_WIDTH, h=1}, + subviews={ + widgets.CycleHotkeyLabel{ + view_id='subset', + frame={l=1, t=0, r=1}, + key='CUSTOM_SHIFT_F', + label='Show:', + options={ + {label='All', value='all', pen=COLOR_GREEN}, + {label='Military', value='military', pen=COLOR_YELLOW}, + {label='Civilians', value='civilian', pen=COLOR_CYAN}, + {label='Burrowed', value='burrow', pen=COLOR_MAGENTA}, + }, + on_change=function(value) + local squad = self.subviews.squad + local burrow = self.subviews.burrow + squad.visible = false + burrow.visible = false + if value == 'military' then + squad.options = info.get_squad_options() + squad:setOption('all') + squad.visible = true + elseif value == 'burrow' then + burrow.options = info.get_burrow_options() + burrow:setOption('all') + burrow.visible = true + end + self:do_search(self.subviews.search.text, true) + end, + }, + }, + }, + widgets.BannerPanel{ + view_id='subfilter_panel', + frame={l=0, t=2, w=WIDGET_WIDTH, h=1}, + visible=function() + local subset = self.subviews.subset:getOptionValue() + return subset == 'military' or subset == 'burrow' + end, + subviews={ + widgets.CycleHotkeyLabel{ + view_id='squad', + frame={l=1, t=0, r=1}, + key='CUSTOM_SHIFT_S', + label='Squad:', + options={ + {label='Any', value='all', pen=COLOR_GREEN}, + }, + visible=false, + on_change=function() self:do_search(self.subviews.search.text, true) end, + }, + widgets.CycleHotkeyLabel{ + view_id='burrow', + frame={l=1, t=0, r=1}, + key='CUSTOM_SHIFT_B', + label='Burrow:', + options={ + {label='Any', value='all', pen=COLOR_GREEN}, + }, + visible=false, + on_change=function() self:do_search(self.subviews.search.text, true) end, + }, + }, + }, + widgets.BannerPanel{ + frame={r=0, t=4, w=25, h=1}, + subviews={ + widgets.HotkeyLabel{ + frame={l=1, t=0, r=1}, + label='Select all/none', + key='CUSTOM_CTRL_A', + on_activate=toggle_all, + }, + }, + }, + } +end + +function BurrowAssignmentOverlay:register_handlers() + for name,flags_vec in pairs(self.handled_screens) do + self:register_handler(name, unit_selector.unid, + curry(sortoverlay.flags_vector_search, { + get_search_key_fn=get_unit_id_search_key, + matches_filters_fn=self:callback('matches_filters'), + }, + unit_selector[flags_vec])) + end +end + +function BurrowAssignmentOverlay:matches_filters(unit_id) + local unit = df.unit.find(unit_id) + if not unit then return false end + return info.matches_squad_burrow_filters(unit, self.subviews.subset:getOptionValue(), + self.subviews.squad:getOptionValue(), self.subviews.burrow:getOptionValue()) +end + +local function clicked_on_mask(self, keys) + if not keys._MOUSE_L then return false end + for _,mask in ipairs{'top_mask', 'wide_mask', 'narrow_mask'} do + if utils.getval(self.subviews[mask].visible) then + if self.subviews[mask]:getMousePos() then + return true + end + end + end + return false +end + +function BurrowAssignmentOverlay:onInput(keys) + return BurrowAssignmentOverlay.super.onInput(self, keys) or + clicked_on_mask(self, keys) +end + +function BurrowAssignmentOverlay:onRenderFrame(dc, rect) + local sw = get_screen_width() + self.frame.w = math.min(DEFAULT_OVERLAY_WIDTH, sw - 94) + BurrowAssignmentOverlay.super.onRenderFrame(self, dc, rect) +end + return _ENV From 5f49132ba30b3221a8a7f06d208f638309db778d Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 6 Nov 2023 16:56:55 +0000 Subject: [PATCH 848/851] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 3683a1b39..a09044a7c 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 3683a1b39bca1c6eff7b92058d2518960c36d83d +Subproject commit a09044a7c0f2fff53eaee6fec3a839394f48e55c From 649dfcca3f391719c6f2e341682ff536be6135b9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 19:28:06 +0000 Subject: [PATCH 849/851] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.4.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0) - [github.com/python-jsonschema/check-jsonschema: 0.27.0 → 0.27.1](https://github.com/python-jsonschema/check-jsonschema/compare/0.27.0...0.27.1) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 00228be82..45d51dc30 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,7 +4,7 @@ ci: repos: # shared across repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-added-large-files - id: check-case-conflict @@ -20,7 +20,7 @@ repos: args: ['--fix=lf'] - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.27.0 + rev: 0.27.1 hooks: - id: check-github-workflows - repo: https://github.com/Lucas-C/pre-commit-hooks From 2760fd75315afda58e4a5fbed4613bb6a316cd36 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Mon, 6 Nov 2023 22:50:58 +0000 Subject: [PATCH 850/851] 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 a23ec834b..6375044bc 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit a23ec834bbbd2a9d47defd0fa1add717c837632a +Subproject commit 6375044bc504cf5bf4579659755966bb30704b7f diff --git a/scripts b/scripts index a09044a7c..0ab280651 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit a09044a7c0f2fff53eaee6fec3a839394f48e55c +Subproject commit 0ab280651ead18b8678ea081f4ab1b0edc044847 From b22e57fe1f5b076bc4ac9cdd4b8b04d9cbe4005d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 6 Nov 2023 16:19:52 -0800 Subject: [PATCH 851/851] allow 3d box select to start or end out of bounds --- plugins/lua/burrow.lua | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/plugins/lua/burrow.lua b/plugins/lua/burrow.lua index 5248beb31..42257dc50 100644 --- a/plugins/lua/burrow.lua +++ b/plugins/lua/burrow.lua @@ -13,7 +13,7 @@ local if_burrow = df.global.game.main_interface.burrow local function is_choosing_area(pos) return if_burrow.doing_rectangle and - selection_rect.start_x >= 0 and + selection_rect.start_z >= 0 and (pos or dfhack.gui.getMousePos()) end @@ -23,10 +23,17 @@ local function reset_selection_rect() selection_rect.start_z = -30000 end +local function clamp(pos) + return xyz2pos( + math.max(0, math.min(df.global.world.map.x_count-1, pos.x)), + math.max(0, math.min(df.global.world.map.y_count-1, pos.y)), + math.max(0, math.min(df.global.world.map.z_count-1, pos.z))) +end + local function get_bounds(pos1, pos2) - pos1 = pos1 or dfhack.gui.getMousePos() - pos2 = pos2 or xyz2pos(selection_rect.start_x, selection_rect.start_y, selection_rect.start_z) - local bounds = { + pos1 = clamp(pos1 or dfhack.gui.getMousePos(true)) + pos2 = clamp(pos2 or xyz2pos(selection_rect.start_x, selection_rect.start_y, selection_rect.start_z)) + return { x1=math.min(pos1.x, pos2.x), x2=math.max(pos1.x, pos2.x), y1=math.min(pos1.y, pos2.y), @@ -34,18 +41,6 @@ local function get_bounds(pos1, pos2) z1=math.min(pos1.z, pos2.z), z2=math.max(pos1.z, pos2.z), } - - -- clamp to map edges - bounds = { - x1=math.max(0, bounds.x1), - x2=math.min(df.global.world.map.x_count-1, bounds.x2), - y1=math.max(0, bounds.y1), - y2=math.min(df.global.world.map.y_count-1, bounds.y2), - z1=math.max(0, bounds.z1), - z2=math.min(df.global.world.map.z_count-1, bounds.z2), - } - - return bounds end local function get_cur_area_dims() @@ -114,7 +109,7 @@ function BurrowDesignationOverlay:onInput(keys) -- have been initialized. instead, allow clicks to go through so that vanilla -- behavior is triggered before we modify the burrow further elseif keys._MOUSE_L then - local pos = dfhack.gui.getMousePos() + local pos = dfhack.gui.getMousePos(true) if pos then local now_ms = dfhack.getTickCount() if not same_xyz(pos, self.saved_pos) then