Merge remote-tracking branch 'upstream/develop' into 5008-beta1

develop
Kelly Kinkade 2023-04-18 23:05:06 -05:00
commit f477b82ea9
38 changed files with 394 additions and 122 deletions

@ -14,7 +14,7 @@ on:
release_channel: release_channel:
description: Release channel description: Release channel
type: string type: string
required: true required: false
default: beta default: beta
jobs: jobs:
@ -38,7 +38,9 @@ jobs:
ccache-win64-cross-msvc ccache-win64-cross-msvc
- name: Cross-compile win64 artifacts - name: Cross-compile win64 artifacts
env: env:
CMAKE_EXTRA_ARGS: '-DBUILD_STONESENSE: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: | run: |
cd build cd build
bash -x build-win64-from-linux.sh bash -x build-win64-from-linux.sh

3
.gitignore vendored

@ -80,3 +80,6 @@ tags
# external plugins # external plugins
/plugins/CMakeLists.custom.txt /plugins/CMakeLists.custom.txt
# steam api
depends/steam

@ -191,8 +191,8 @@ if(NOT EXISTS ${dfhack_SOURCE_DIR}/library/xml/codegen.pl
endif() endif()
# set up versioning. # set up versioning.
set(DF_VERSION "50.08") set(DF_VERSION "50.07")
set(DFHACK_RELEASE "rc1") set(DFHACK_RELEASE "r2rc1")
set(DFHACK_PRERELEASE TRUE) set(DFHACK_PRERELEASE TRUE)
set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}")
@ -312,6 +312,7 @@ if(WIN32)
${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll ${SDLREAL_DOWNLOAD_DIR}/SDLreal.dll
"5a09604daca6b2b5ce049d79af935d6a") "5a09604daca6b2b5ce049d79af935d6a")
endif() endif()
endif() endif()
if(APPLE) if(APPLE)

@ -41,6 +41,8 @@ fi
if ! docker run --rm -i -v "$srcdir":/src -v "$srcdir/build/win64-cross/":/src/build \ if ! docker run --rm -i -v "$srcdir":/src -v "$srcdir/build/win64-cross/":/src/build \
-e BUILDER_UID=$builder_uid \ -e BUILDER_UID=$builder_uid \
-e CCACHE_DIR=/src/build/ccache \ -e CCACHE_DIR=/src/build/ccache \
-e steam_username \
-e steam_password \
--name dfhack-win \ --name dfhack-win \
ghcr.io/dfhack/build-env:msvc \ ghcr.io/dfhack/build-env:msvc \
bash -c "cd /src/build && dfhack-configure windows 64 Release -DCMAKE_INSTALL_PREFIX=/src/build/output cmake .. -DBUILD_DOCS=1 $CMAKE_EXTRA_ARGS && dfhack-make -j$jobs install" \ bash -c "cd /src/build && dfhack-configure windows 64 Release -DCMAKE_INSTALL_PREFIX=/src/build/output cmake .. -DBUILD_DOCS=1 $CMAKE_EXTRA_ARGS && dfhack-make -j$jobs install" \

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

@ -49,6 +49,9 @@ keybinding add Ctrl-H@dwarfmode autodump-destroy-here
# apply blueprints to the map # apply blueprints to the map
keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort
# toggle keyboard cursor
keybinding add Alt-K@dwarfmode toggle-kbd-cursor
# show information collected by dwarfmonitor # show information collected by dwarfmonitor
#keybinding add Alt-M@dwarfmode/Default "dwarfmonitor prefs" #keybinding add Alt-M@dwarfmode/Default "dwarfmonitor prefs"
#keybinding add Ctrl-F@dwarfmode/Default "dwarfmonitor stats" #keybinding add Ctrl-F@dwarfmode/Default "dwarfmonitor stats"

@ -144,3 +144,4 @@ enable \
alias add autounsuspend suspendmanager alias add autounsuspend suspendmanager
alias add gui/dig gui/design alias add gui/dig gui/design
alias add toggle-kbd-cursor lua "local flags4 = df.global.d_init.flags4 if flags4.KEYBOARD_CURSOR then flags4.KEYBOARD_CURSOR = false else local guidm = require('gui.dwarfmode') guidm.setCursorPos(guidm.Viewport.get():getCenter()) flags4.KEYBOARD_CURSOR = true end"

@ -1 +1 @@
Subproject commit 6ed8aa46462ea01a1122fc49422840a2facc9757 Subproject commit d5e17c6012e7eefb0cbe3e130a56c24bd11f0094

@ -1,5 +1,5 @@
project(lua CXX) project(lua CXX)
cmake_minimum_required(VERSION 2.8) cmake_minimum_required(VERSION 3.21)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLUA_USE_APICHECK") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DLUA_USE_APICHECK")

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

@ -162,7 +162,7 @@ You can run them all from the launcher.
First, let's import some useful manager orders to keep your fort stocked with First, let's import some useful manager orders to keep your fort stocked with
basic necessities. Run ``orders import library/basic``. If you go to your basic necessities. Run ``orders import library/basic``. If you go to your
mangager orders screen, you can see all the orders that have been created for you. manager orders screen, you can see all the orders that have been created for you.
Note that you could have imported the orders directly from this screen as well, 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. using the DFHack `overlay` widget at the bottom of the manager orders panel.

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

@ -12,6 +12,7 @@ Name Github Other
8Z 8Z 8Z 8Z
Abel abstern Abel abstern
acwatkins acwatkins acwatkins acwatkins
Alex Blamey Cubittus
Alexander Collins gearsix Alexander Collins gearsix
Alexander Gavrilov angavrilov ag Alexander Gavrilov angavrilov ag
Amber Brown hawkowl Amber Brown hawkowl
@ -133,6 +134,7 @@ Milo Christiansen milochristiansen
MithrilTuxedo MithrilTuxedo MithrilTuxedo MithrilTuxedo
mizipzor mizipzor mizipzor mizipzor
moversti moversti moversti moversti
mrrho mrrho
Murad Beybalaev Erquint Murad Beybalaev Erquint
Myk Taylor myk002 Myk Taylor myk002
napagokc napagokc napagokc napagokc
@ -158,6 +160,7 @@ Petr Mrázek peterix
Pfhreak Pfhreak Pfhreak Pfhreak
Pierre Lulé plule Pierre Lulé plule
Pierre-David Bélanger pierredavidbelanger Pierre-David Bélanger pierredavidbelanger
PopnROFL PopnROFL
potato potato
ppaawwll ppaawwll 🐇🐇🐇🐇 ppaawwll ppaawwll 🐇🐇🐇🐇
Priit Laes plaes Priit Laes plaes
@ -201,6 +204,7 @@ SeerSkye SeerSkye
seishuuu seishuuu seishuuu seishuuu
Seth Woodworth sethwoodworth Seth Woodworth sethwoodworth
Shim Panze Shim-Panze Shim Panze Shim-Panze
Silver silverflyone
simon simon
Simon Jackson sizeak Simon Jackson sizeak
Simon Lees simotek Simon Lees simotek
@ -235,6 +239,7 @@ ViTuRaS ViTuRaS
Vjek vjek Vjek vjek
Warmist warmist Warmist warmist
Wes Malone wesQ3 Wes Malone wesQ3
Will H TSM-EVO
Will Rogers wjrogers Will Rogers wjrogers
WoosterUK WoosterUK WoosterUK WoosterUK
XianMaeve XianMaeve XianMaeve XianMaeve

@ -38,6 +38,10 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
## Fixes ## Fixes
## Misc Improvements ## Misc Improvements
- `buildingplan`: minimized planner panel stays minimized until you change it again
- ``toggle-kbd-cursor``: add hotkey for toggling the keyboard cursor (Alt-K)
- `gui/control-panel`: add preference option for hiding the terminal console on startup
- `gui/control-panel`: add preference option for hiding "armok" tools in command lists
## Documentation ## Documentation

@ -1,5 +1,5 @@
project(dfapi) project(dfapi)
cmake_minimum_required(VERSION 2.8.12) cmake_minimum_required(VERSION 3.21)
# prevent CMake warnings about INTERFACE_LINK_LIBRARIES vs LINK_INTERFACE_LIBRARIES # prevent CMake warnings about INTERFACE_LINK_LIBRARIES vs LINK_INTERFACE_LIBRARIES
cmake_policy(SET CMP0022 NEW) cmake_policy(SET CMP0022 NEW)

@ -1314,6 +1314,15 @@ static void run_dfhack_init(color_ostream &out, Core *core)
// load user overrides // load user overrides
std::vector<std::string> prefixes(1, "dfhack"); std::vector<std::string> prefixes(1, "dfhack");
loadScriptFiles(core, out, prefixes, CONFIG_PATH + "init"); loadScriptFiles(core, out, prefixes, CONFIG_PATH + "init");
// if the option is set, hide the terminal
auto L = Lua::Core::State;
Lua::StackUnwinder top(L);
Lua::CallLuaModuleFunction(out, L, "dfhack", "getHideConsoleOnStartup", 0, 1,
Lua::DEFAULT_LUA_LAMBDA, [&](lua_State* L) {
if (lua_toboolean(L, -1))
core->getConsole().hide();
}, false);
} }
// Load dfhack.init in a dedicated thread (non-interactive console mode) // Load dfhack.init in a dedicated thread (non-interactive console mode)
@ -2083,7 +2092,8 @@ void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event eve
if (!df::global::world) if (!df::global::world)
return; return;
std::string rawFolder = "save/" + (df::global::world->cur_savegame.save_dir) + "/init";
std::string rawFolder = !isWorldLoaded() ? "" : "save/" + World::ReadWorldFolder() + "/init";
auto i = table.find(event); auto i = table.find(event);
if ( i != table.end() ) { if ( i != table.end() ) {

@ -51,6 +51,18 @@ if dfhack.is_core_context then
SC_UNPAUSED = 8 SC_UNPAUSED = 8
end end
-- User-changeable options
dfhack.HIDE_CONSOLE_ON_STARTUP = true
function dfhack.getHideConsoleOnStartup()
return dfhack.HIDE_CONSOLE_ON_STARTUP
end
dfhack.HIDE_ARMOK_TOOLS = false
function dfhack.getHideArmokTools()
return dfhack.HIDE_ARMOK_TOOLS
end
-- Error handling -- Error handling
safecall = dfhack.safecall safecall = dfhack.safecall

@ -745,6 +745,7 @@ end
local NO_LOGIC_SCREENS = { local NO_LOGIC_SCREENS = {
'viewscreen_loadgamest', 'viewscreen_loadgamest',
'viewscreen_adopt_regionst',
'viewscreen_export_regionst', 'viewscreen_export_regionst',
'viewscreen_choose_game_typest', 'viewscreen_choose_game_typest',
'viewscreen_worldst', 'viewscreen_worldst',

@ -788,7 +788,11 @@ function ls(filter_str, skip_tags, show_dev_commands, exclude_strs)
table.insert(excludes, {str=argparse.stringList(exclude_strs)}) table.insert(excludes, {str=argparse.stringList(exclude_strs)})
end end
if not show_dev_commands then if not show_dev_commands then
table.insert(excludes, {tag='dev'}) local dev_tags = {'dev', 'unavailable'}
if dfhack.getHideArmokTools() then
table.insert(dev_tags, 'armok')
end
table.insert(excludes, {tag=dev_tags})
end end
list_entries(skip_tags, include, excludes) list_entries(skip_tags, include, excludes)
end end
@ -813,7 +817,16 @@ function tags(tag)
local skip_tags = true local skip_tags = true
local include = {entry_type={ENTRY_TYPES.COMMAND}, tag=tag} local include = {entry_type={ENTRY_TYPES.COMMAND}, tag=tag}
list_entries(skip_tags, include)
local excludes = {tag={}}
if tag ~= 'unavailable' then
table.insert(excludes.tag, 'unavailable')
end
if tag ~= 'armok' and dfhack.getHideArmokTools() then
table.insert(excludes.tag, 'armok')
end
list_entries(skip_tags, include, excludes)
end end
return _ENV return _ENV

@ -439,6 +439,7 @@ bool MaterialInfo::matches(const df::dfhack_material_category &cat) const
return true; return true;
if (cat.bits.milk && linear_index(material->reaction_product.id, std::string("CHEESE_MAT")) >= 0) if (cat.bits.milk && linear_index(material->reaction_product.id, std::string("CHEESE_MAT")) >= 0)
return true; return true;
TEST(gem, IS_GEM);
return false; return false;
} }

@ -1,7 +1,29 @@
project(package_windows) project(package_windows)
if(WIN32) if(WIN32)
add_executable(launchdf WIN32 launchdf.c) if (BUILD_DFLAUNCH)
install(TARGETS launchdf if ((DEFINED ENV{steam_username}) AND (DEFINED ENV{steam_password}))
DESTINATION ${DFHACK_DATA_DESTINATION}) # download Steam SDK
set (STEAMAPI_DIR ${dfhack_SOURCE_DIR}/depends/steam)
file(DOWNLOAD "https://partner.steamgames.com/downloads/steamworks_sdk_156.zip"
${STEAMAPI_DIR}/steamworks_sdk_156.zip
EXPECTED_HASH MD5=af5a579990dbe5ae4c1b0689260d001b
USERPWD $ENV{steam_username}:$ENV{steam_password}
)
file(ARCHIVE_EXTRACT
INPUT ${STEAMAPI_DIR}/steamworks_sdk_156.zip
DESTINATION ${STEAMAPI_DIR})
set(STEAMAPI_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.lib")
set(STEAMAPI_SOURCE_DIR "${STEAMAPI_DIR}/sdk/public/steam")
set(STEAMAPI_SHARED_LIBRARY "${STEAMAPI_DIR}/sdk/redistributable_bin/win64/steam_api64.dll")
else()
message(SEND_ERROR "Need to set steam_username and steam_password in environment to download Steamworks SDK")
endif()
include_directories(${STEAMAPI_SOURCE_DIR})
link_libraries(${STEAMAPI_LIBRARY})
add_executable(launchdf WIN32 launchdf.cpp)
install(TARGETS launchdf DESTINATION ${DFHACK_DATA_DESTINATION})
install(FILES ${STEAMAPI_SHARED_LIBRARY} DESTINATION ${DFHACK_DATA_DESTINATION})
endif()
endif() endif()

@ -1,72 +0,0 @@
#include <process.h>
#include <windows.h>
static BOOL is_running_on_wine() {
static const char *(CDECL *pwine_get_version)(void);
HMODULE hntdll = GetModuleHandle("ntdll.dll");
if(!hntdll)
return FALSE;
pwine_get_version = (void *)GetProcAddress(hntdll, "wine_get_version");
return !!pwine_get_version;
}
static LPCWSTR launch_via_steam_posix() {
const char* argv[] = { "/bin/sh", "-c", "\"steam -applaunch 975370\"", NULL };
// does not return on success
_execv(argv[0], argv);
return L"Could not launch Dwarf Fortress";
}
static LPCWSTR launch_via_steam_windows() {
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
WCHAR steamPath[1024];
DWORD datasize = 1024;
LONG retCode = RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam",
L"SteamExe", RRF_RT_REG_SZ, NULL, &steamPath, &datasize);
if (retCode != ERROR_SUCCESS)
return L"Could not find Steam client executable";
WCHAR commandLine[1024] = L"steam.exe -applaunch 975370";
if (CreateProcessW(steamPath, commandLine,
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0)
return L"Could not launch Dwarf Fortress";
return NULL;
}
// this method doesn't properly attribute Steam playtime metrics to DF,
// but that's better than not having DF start at all.
static BOOL launch_direct() {
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
return CreateProcessW(L"Dwarf Fortress.exe",
NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
}
int WINAPI wWinMain(HINSTANCE hi, HINSTANCE hpi, PWSTR cmd, int ns) {
LPCWSTR err = is_running_on_wine() ? launch_via_steam_posix() : launch_via_steam_windows();
if (err && !launch_direct()) {
MessageBoxW(NULL, err, NULL, 0);
exit(1);
}
exit(0);
}

@ -0,0 +1,223 @@
#include <process.h>
#include <windows.h>
#include <TlHelp32.h>
#include "steam_api.h"
#include <string>
const uint32 DFHACK_STEAM_APPID = 2346660;
const uint32 DF_STEAM_APPID = 975370;
static BOOL is_running_on_wine() {
typedef const char* (CDECL wine_get_version)(void);
static wine_get_version* pwine_get_version;
HMODULE hntdll = GetModuleHandle("ntdll.dll");
if(!hntdll)
return FALSE;
pwine_get_version = (wine_get_version*) GetProcAddress(hntdll, "wine_get_version");
return !!pwine_get_version;
}
static LPCWSTR launch_via_steam_posix() {
const char* argv[] = { "/bin/sh", "-c", "\"steam -applaunch 975370\"", NULL };
// does not return on success
_execv(argv[0], argv);
return L"Could not launch Dwarf Fortress";
}
static LPCWSTR launch_via_steam_windows() {
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
WCHAR steamPath[1024] = L"";
DWORD datasize = 1024;
LONG retCode = RegGetValueW(HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam",
L"SteamExe", RRF_RT_REG_SZ, NULL, &steamPath, &datasize);
if (retCode != ERROR_SUCCESS)
return L"Could not find Steam client executable";
WCHAR commandLine[1024] = L"steam.exe -applaunch 975370";
BOOL res = CreateProcessW(steamPath, commandLine,
NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if (res)
{
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return NULL;
}
else
{
return L"Could not launch Dwarf Fortress";
}
}
static LPCWSTR launch_direct() {
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
BOOL res = CreateProcessW(L"Dwarf Fortress.exe",
NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if (res)
{
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return NULL;
}
return L"Could not launch via non-steam fallback method";
}
DWORD findDwarfFortressProcess()
{
PROCESSENTRY32W entry;
entry.dwSize = sizeof(PROCESSENTRY32W);
const auto snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
if (!Process32FirstW(snapshot, &entry))
{
CloseHandle(snapshot);
return -1;
}
do {
std::wstring executableName(entry.szExeFile);
if (executableName == L"Dwarf Fortress.exe")
{
CloseHandle(snapshot);
return entry.th32ProcessID;
}
} while (Process32NextW(snapshot, &entry));
CloseHandle(snapshot);
return -1;
}
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) {
// initialize steam context
if (SteamAPI_RestartAppIfNecessary(DFHACK_STEAM_APPID))
{
exit(0);
}
if (!SteamAPI_Init())
{
// could not initialize steam context, attempt fallback launch
LPCWSTR err = launch_direct();
if (err != NULL)
{
MessageBoxW(NULL, err, NULL, 0);
exit(1);
}
exit(0);
}
bool wine = is_running_on_wine();
if (wine)
{
// attempt launch via steam client
LPCWSTR err = launch_via_steam_posix();
if (err != NULL)
// steam client launch failed, attempt fallback launch
err = launch_direct();
if (err != NULL)
{
MessageBoxW(NULL, err, NULL, 0);
exit(1);
}
exit(0);
}
// steam detected and not running in wine
bool df_installed = SteamApps()->BIsAppInstalled(DF_STEAM_APPID);
if (!df_installed)
{
// Steam DF is not installed. Assume DF is installed in same directory as DFHack and do a fallback launch
LPCWSTR err = launch_direct();
if (err != NULL)
{
MessageBoxW(NULL, err, NULL, 0);
exit(1);
}
exit(0);
}
// obtain DF app path
char buf[2048] = "";
int b1 = SteamApps()->GetAppInstallDir(DFHACK_STEAM_APPID, (char*)&buf, 2048);
std::string dfhack_install_folder = (b1 != -1) ? std::string(buf) : "";
int b2 = SteamApps()->GetAppInstallDir(DF_STEAM_APPID, (char*)&buf, 2048);
std::string df_install_folder = (b2 != -1) ? std::string(buf) : "";
if (df_install_folder != dfhack_install_folder)
{
// DF and DFHack are not installed in the same library
MessageBoxW(NULL, L"DFHack and Dwarf Fortress must be installed in the same Steam library.\nAborting.", NULL, 0);
exit(1);
}
DWORD df_pid = findDwarfFortressProcess();
if (df_pid == -1)
{
LPCWSTR err = launch_via_steam_windows();
if (err != NULL)
{
MessageBoxW(NULL, err, NULL, 0);
exit(1);
}
int counter = 0;
do {
if (counter++ > 60)
{
MessageBoxW(NULL, L"Dwarf Fortress took too long to launch, aborting", NULL, 0);
exit(1);
}
Sleep(1000);
df_pid = findDwarfFortressProcess();
} while (df_pid == -1);
}
HANDLE hDF = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, df_pid);
// in the future open an IPC connection so that we can proxy SteamAPI calls for the DFSteam module
// this will eventuallyh need to become a loop with a WaitForMultipleObjects call
WaitForSingleObject(hDF, INFINITE);
CloseHandle(hDF);
exit(0);
}

@ -6,11 +6,6 @@ if(UNIX)
endif() endif()
endif() endif()
include_directories("${dfhack_SOURCE_DIR}/library/include")
include_directories("${dfhack_SOURCE_DIR}/library/proto")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/proto")
include_directories("${dfhack_SOURCE_DIR}/library/depends/xgetopt")
macro(car var) macro(car var)
set(${var} ${ARGV1}) set(${var} ${ARGV1})
endmacro() endmacro()
@ -123,6 +118,11 @@ macro(dfhack_plugin)
add_library(${PLUGIN_NAME} MODULE ${PLUGIN_SOURCES}) add_library(${PLUGIN_NAME} MODULE ${PLUGIN_SOURCES})
ide_folder(${PLUGIN_NAME} "Plugins") 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) if(NUM_PROTO)
add_dependencies(${PLUGIN_NAME} generate_proto_${PLUGIN_NAME}) add_dependencies(${PLUGIN_NAME} generate_proto_${PLUGIN_NAME})
target_link_libraries(${PLUGIN_NAME} dfhack protobuf-lite dfhack-version ${PLUGIN_LINK_LIBRARIES}) target_link_libraries(${PLUGIN_NAME} dfhack protobuf-lite dfhack-version ${PLUGIN_LINK_LIBRARIES})

@ -150,6 +150,7 @@ static const df::dfhack_material_category stone_cat(df::dfhack_material_category
static const df::dfhack_material_category wood_cat(df::dfhack_material_category::mask_wood); static const df::dfhack_material_category wood_cat(df::dfhack_material_category::mask_wood);
static const df::dfhack_material_category metal_cat(df::dfhack_material_category::mask_metal); static const df::dfhack_material_category metal_cat(df::dfhack_material_category::mask_metal);
static const df::dfhack_material_category glass_cat(df::dfhack_material_category::mask_glass); static const df::dfhack_material_category glass_cat(df::dfhack_material_category::mask_glass);
static const df::dfhack_material_category gem_cat(df::dfhack_material_category::mask_gem);
static const df::dfhack_material_category clay_cat(df::dfhack_material_category::mask_clay); static const df::dfhack_material_category clay_cat(df::dfhack_material_category::mask_clay);
static const df::dfhack_material_category cloth_cat(df::dfhack_material_category::mask_cloth); static const df::dfhack_material_category cloth_cat(df::dfhack_material_category::mask_cloth);
static const df::dfhack_material_category silk_cat(df::dfhack_material_category::mask_silk); static const df::dfhack_material_category silk_cat(df::dfhack_material_category::mask_silk);
@ -169,6 +170,9 @@ static void cache_matched(int16_t type, int32_t index) {
} else if (mi.matches(glass_cat)) { } else if (mi.matches(glass_cat)) {
DEBUG(status).print("cached glass material: %s (%d, %d)\n", mi.toString().c_str(), type, index); DEBUG(status).print("cached glass material: %s (%d, %d)\n", mi.toString().c_str(), type, index);
mat_cache.emplace(mi.toString(), std::make_pair(mi, "glass")); mat_cache.emplace(mi.toString(), std::make_pair(mi, "glass"));
} else if (mi.matches(gem_cat)) {
DEBUG(status).print("cached gem material: %s (%d, %d)\n", mi.toString().c_str(), type, index);
mat_cache.emplace(mi.toString(), std::make_pair(mi, "gem"));
} else if (mi.matches(clay_cat)) { } else if (mi.matches(clay_cat)) {
DEBUG(status).print("cached clay material: %s (%d, %d)\n", mi.toString().c_str(), type, index); DEBUG(status).print("cached clay material: %s (%d, %d)\n", mi.toString().c_str(), type, index);
mat_cache.emplace(mi.toString(), std::make_pair(mi, "clay")); mat_cache.emplace(mi.toString(), std::make_pair(mi, "clay"));
@ -800,6 +804,8 @@ static int setMaterialMaskFilter(lua_State *L) {
mask |= metal_cat.whole; mask |= metal_cat.whole;
else if (cat == "glass") else if (cat == "glass")
mask |= glass_cat.whole; mask |= glass_cat.whole;
else if (cat == "gem")
mask |= gem_cat.whole;
else if (cat == "clay") else if (cat == "clay")
mask |= clay_cat.whole; mask |= clay_cat.whole;
else if (cat == "cloth") else if (cat == "cloth")
@ -850,6 +856,7 @@ static int getMaterialMaskFilter(lua_State *L) {
ret.emplace("wood", !bits || bits & wood_cat.whole); ret.emplace("wood", !bits || bits & wood_cat.whole);
ret.emplace("metal", !bits || bits & metal_cat.whole); ret.emplace("metal", !bits || bits & metal_cat.whole);
ret.emplace("glass", !bits || bits & glass_cat.whole); ret.emplace("glass", !bits || bits & glass_cat.whole);
ret.emplace("gem", !bits || bits & gem_cat.whole);
ret.emplace("clay", !bits || bits & clay_cat.whole); ret.emplace("clay", !bits || bits & clay_cat.whole);
ret.emplace("cloth", !bits || bits & cloth_cat.whole); ret.emplace("cloth", !bits || bits & cloth_cat.whole);
ret.emplace("silk", !bits || bits & silk_cat.whole); ret.emplace("silk", !bits || bits & silk_cat.whole);
@ -897,6 +904,8 @@ static int setMaterialFilter(lua_State *L) {
mask.whole |= metal_cat.whole; mask.whole |= metal_cat.whole;
else if (mat.matches(glass_cat)) else if (mat.matches(glass_cat))
mask.whole |= glass_cat.whole; mask.whole |= glass_cat.whole;
else if (mat.matches(gem_cat))
mask.whole |= gem_cat.whole;
else if (mat.matches(clay_cat)) else if (mat.matches(clay_cat))
mask.whole |= clay_cat.whole; mask.whole |= clay_cat.whole;
else if (mat.matches(cloth_cat)) else if (mat.matches(cloth_cat))

@ -49,7 +49,22 @@ static int cleanupHotkeys(lua_State *) {
return 0; return 0;
} }
static void add_binding_if_valid(const string &sym, const string &cmdline, df::viewscreen *screen, bool filtermenu) { static bool should_hide_armok(color_ostream &out, const string &cmdline) {
bool should_hide = false;
auto L = Lua::Core::State;
Lua::StackUnwinder top(L);
Lua::CallLuaModuleFunction(out, L, "plugins.hotkeys", "should_hide_armok", 1, 1,
[&](lua_State *L){
Lua::Push(L, cmdline);
}, [&](lua_State *L){
should_hide = lua_toboolean(L, -1);
});
return should_hide;
}
static void add_binding_if_valid(color_ostream &out, const string &sym, const string &cmdline, df::viewscreen *screen, bool filtermenu) {
if (!can_invoke(cmdline, screen)) if (!can_invoke(cmdline, screen))
return; return;
@ -59,6 +74,11 @@ static void add_binding_if_valid(const string &sym, const string &cmdline, df::v
return; return;
} }
if (should_hide_armok(out, cmdline)) {
DEBUG(log).print("filtering out armok keybinding\n");
return;
}
current_bindings[sym] = cmdline; current_bindings[sym] = cmdline;
sorted_keys.push_back(sym); sorted_keys.push_back(sym);
string keyspec = sym + "@" + MENU_SCREEN_FOCUS_STRING; string keyspec = sym + "@" + MENU_SCREEN_FOCUS_STRING;
@ -67,7 +87,7 @@ static void add_binding_if_valid(const string &sym, const string &cmdline, df::v
Core::getInstance().AddKeyBinding(keyspec, binding); Core::getInstance().AddKeyBinding(keyspec, binding);
} }
static void find_active_keybindings(df::viewscreen *screen, bool filtermenu) { static void find_active_keybindings(color_ostream &out, df::viewscreen *screen, bool filtermenu) {
DEBUG(log).print("scanning for active keybindings\n"); DEBUG(log).print("scanning for active keybindings\n");
if (valid) if (valid)
cleanupHotkeys(NULL); cleanupHotkeys(NULL);
@ -103,7 +123,7 @@ static void find_active_keybindings(df::viewscreen *screen, bool filtermenu) {
string::size_type colon_pos = invoke_cmd->find(":"); string::size_type colon_pos = invoke_cmd->find(":");
// colons at location 0 are for commands like ":lua" // colons at location 0 are for commands like ":lua"
if (colon_pos == string::npos || colon_pos == 0) { if (colon_pos == string::npos || colon_pos == 0) {
add_binding_if_valid(sym, *invoke_cmd, screen, filtermenu); add_binding_if_valid(out, sym, *invoke_cmd, screen, filtermenu);
} }
else { else {
vector<string> tokens; vector<string> tokens;
@ -111,7 +131,7 @@ static void find_active_keybindings(df::viewscreen *screen, bool filtermenu) {
string focus = tokens[0].substr(1); string focus = tokens[0].substr(1);
if(Gui::matchFocusString(focus)) { if(Gui::matchFocusString(focus)) {
auto cmdline = trim(tokens[1]); auto cmdline = trim(tokens[1]);
add_binding_if_valid(sym, cmdline, screen, filtermenu); add_binding_if_valid(out, sym, cmdline, screen, filtermenu);
} }
} }
} }
@ -124,7 +144,10 @@ static void find_active_keybindings(df::viewscreen *screen, bool filtermenu) {
} }
static int getHotkeys(lua_State *L) { static int getHotkeys(lua_State *L) {
find_active_keybindings(Gui::getCurViewscreen(true), true); color_ostream *out = Lua::GetOutput(L);
if (!out)
out = &Core::getInstance().getConsole();
find_active_keybindings(*out, Gui::getCurViewscreen(true), true);
Lua::PushVector(L, sorted_keys); Lua::PushVector(L, sorted_keys);
Lua::Push(L, current_bindings); Lua::Push(L, current_bindings);
return 2; return 2;
@ -140,7 +163,7 @@ static void list(color_ostream &out) {
DEBUG(log).print("listing active hotkeys\n"); DEBUG(log).print("listing active hotkeys\n");
bool was_valid = valid; bool was_valid = valid;
if (!valid) if (!valid)
find_active_keybindings(Gui::getCurViewscreen(true), false); find_active_keybindings(out, Gui::getCurViewscreen(true), false);
out.print("Valid keybindings for the current focus:\n %s\n", out.print("Valid keybindings for the current focus:\n %s\n",
join_strings("\n", Gui::getCurFocus(true)).c_str()); join_strings("\n", Gui::getCurFocus(true)).c_str());
@ -176,6 +199,8 @@ static command_result hotkeys_cmd(color_ostream &out, vector <string> & paramete
return Core::getInstance().runCommand(out, INVOKE_MENU_COMMAND ); return Core::getInstance().runCommand(out, INVOKE_MENU_COMMAND );
} }
CoreSuspender guard;
if (parameters[0] == "list") { if (parameters[0] == "list") {
list(out); list(out);
return CR_OK; return CR_OK;
@ -185,8 +210,6 @@ static command_result hotkeys_cmd(color_ostream &out, vector <string> & paramete
if (parameters.size() != 2 || parameters[0] != "invoke") if (parameters.size() != 2 || parameters[0] != "invoke")
return CR_WRONG_USAGE; return CR_WRONG_USAGE;
CoreSuspender guard;
int index = string_to_int(parameters[1], -1); int index = string_to_int(parameters[1], -1);
if (index < 0) if (index < 0)
return CR_WRONG_USAGE; return CR_WRONG_USAGE;

@ -111,6 +111,8 @@ function get_desc(filter)
desc = 'Ballista part' desc = 'Ballista part'
elseif desc == 'Catapultpart' then elseif desc == 'Catapultpart' then
desc = 'Catapult part' desc = 'Catapult part'
elseif desc == 'Smallgem' then
desc = 'Small, cut gem'
end end
return desc return desc

@ -452,6 +452,7 @@ function QualityAndMaterialsPage:refresh()
make_cat_choice('Wood', 'wood', 'CUSTOM_SHIFT_O', cats), make_cat_choice('Wood', 'wood', 'CUSTOM_SHIFT_O', cats),
make_cat_choice('Metal', 'metal', 'CUSTOM_SHIFT_M', cats), make_cat_choice('Metal', 'metal', 'CUSTOM_SHIFT_M', cats),
make_cat_choice('Glass', 'glass', 'CUSTOM_SHIFT_G', cats), make_cat_choice('Glass', 'glass', 'CUSTOM_SHIFT_G', cats),
make_cat_choice('Gem', 'gem', 'CUSTOM_SHIFT_E', cats),
make_cat_choice('Clay', 'clay', 'CUSTOM_SHIFT_C', cats), make_cat_choice('Clay', 'clay', 'CUSTOM_SHIFT_C', cats),
make_cat_choice('Cloth', 'cloth', 'CUSTOM_SHIFT_L', cats), make_cat_choice('Cloth', 'cloth', 'CUSTOM_SHIFT_L', cats),
make_cat_choice('Silk', 'silk', 'CUSTOM_SHIFT_K', cats), make_cat_choice('Silk', 'silk', 'CUSTOM_SHIFT_K', cats),

@ -729,7 +729,6 @@ function PlannerOverlay:onInput(keys)
return true return true
end end
self.selected = 1 self.selected = 1
self.minimized = false
self.subviews.hollow:setOption(false) self.subviews.hollow:setOption(false)
self:reset() self:reset()
reset_counts_flag = true reset_counts_flag = true

@ -5,6 +5,19 @@ local helpdb = require('helpdb')
local overlay = require('plugins.overlay') local overlay = require('plugins.overlay')
local widgets = require('gui.widgets') local widgets = require('gui.widgets')
local function get_command(cmdline)
local first_word = cmdline:trim():split(' +')[1]
if first_word:startswith(':') then first_word = first_word:sub(2) end
return first_word
end
function should_hide_armok(cmdline)
local command = get_command(cmdline)
return dfhack.getHideArmokTools() and
helpdb.is_entry(command) and
helpdb.get_entry_tags(command).armok
end
-- ----------------- -- -- ----------------- --
-- HotspotMenuWidget -- -- HotspotMenuWidget --
-- ----------------- -- -- ----------------- --
@ -232,10 +245,9 @@ end
function Menu:onSelect(_, choice) function Menu:onSelect(_, choice)
if not choice or #self.subviews == 0 then return end if not choice or #self.subviews == 0 then return end
local first_word = choice.command:trim():split(' +')[1] local command = get_command(choice.command)
if first_word:startswith(':') then first_word = first_word:sub(2) end self.subviews.help.text_to_wrap = helpdb.is_entry(command) and
self.subviews.help.text_to_wrap = helpdb.is_entry(first_word) and helpdb.get_entry_short_help(command) or 'Command not found'
helpdb.get_entry_short_help(first_word) or 'Command not found'
self.subviews.help_panel:updateLayout() self.subviews.help_panel:updateLayout()
end end

@ -24,23 +24,9 @@ set(PROJECT_PROTO
ui_sidebar_mode ui_sidebar_mode
) )
set(PLUGIN_PROTOS)
foreach(pbuf ${PROJECT_PROTO})
list(APPEND PLUGIN_PROTOS ${CMAKE_CURRENT_SOURCE_DIR}/../proto/${pbuf}.proto)
endforeach()
string(REPLACE ".proto" ".pb.cc" PLUGIN_PROTO_SRCS "${PLUGIN_PROTOS}")
string(REPLACE ".proto" ".pb.h" PLUGIN_PROTO_HDRS "${PLUGIN_PROTOS}")
set_source_files_properties(${PLUGIN_PROTO_SRCS} ${PLUGIN_PROTO_HDRS} PROPERTIES GENERATED TRUE)
set_source_files_properties( ${PROJECT_HDRS} ${PLUGIN_PROTO_HDRS} PROPERTIES HEADER_FILE_ONLY TRUE)
# mash them together (headers are marked as headers and nothing will try to compile them)
list(APPEND PROJECT_SRCS ${PROJECT_HDRS} ${PLUGIN_PROTOS} ${PLUGIN_PROTO_SRCS} ${PLUGIN_PROTO_HDRS})
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
set(PROJECT_LIBS ${PROJECT_LIBS} SDL) set(PROJECT_LIBS ${PROJECT_LIBS} SDL)
endif() endif()
# this makes sure all the stuff is put in proper places and linked to dfhack # this makes sure all the stuff is put in proper places and linked to dfhack
dfhack_plugin(RemoteFortressReader ${PROJECT_SRCS} LINK_LIBRARIES protobuf-lite ${PROJECT_LIBS} COMPILE_FLAGS_MSVC "/FI\"Export.h\"" COMPILE_FLAGS_GCC "-include Export.h -Wno-misleading-indentation" ) dfhack_plugin(RemoteFortressReader ${PROJECT_SRCS} LINK_LIBRARIES ${PROJECT_LIBS} PROTOBUFS ${PROJECT_PROTO})

@ -0,0 +1,3 @@
*.pb.cc
*.pb.cc.rule
*.pb.h

@ -1 +1 @@
Subproject commit ec1a69788fd6329008672523b622fd8b390fea73 Subproject commit 6fba9905a71f626ecc640fd3de988e147d16cb4e