From ac06508d92ec9bc7f52ceb819894d46c3107f42b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 12 Jan 2023 14:42:40 -0800 Subject: [PATCH 01/80] add some more icon textures we can use contributed by TaxiService on the DFHack Discord server --- data/art/icons.png | Bin 0 -> 2026 bytes library/include/modules/Textures.h | 8 +++++++- library/modules/Textures.cpp | 7 +++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 data/art/icons.png diff --git a/data/art/icons.png b/data/art/icons.png new file mode 100644 index 0000000000000000000000000000000000000000..141d9f79f4004fc1417346adbcfae25aee34df50 GIT binary patch literal 2026 zcmbVNdsI?+9w&3R&2-$v)UqWcn`5m47X-YdF$!25(+rt3bw?2{LJF7QDwNesQ$BOY znlhSfa_W@nnmUe|qmDDaQkycf(iRPE8y|@nz3ipvUNYPLqceNX-gAHV_xgT5-}kxM z;b9vc>{i%eFc=5kCJrB+z0l$ICmZy;Xv9m0PRkK)6cPbT5RFg;VFJZ)0)*$ug^3U! z5{h^2ybAeaFbgFzK@<`dx|u10R73;=jKoe22S=ybpvPay*o5*dBzK7cQiMrTqO z_;(Kh)us|ln0!v~J6-55fFMN>C6h$bXf#9(l?ba6NdO3fRt^fq2bJ(q?@}N_t&c*z zdY*v;sYNQ85|P0Qyp>Uy0H+`U1k}>xjo!sP%!5D3r$slIfO=1U3mqjBdsK7^(Cv4cPgn~V+`0B|`V znZssNC^Rme1_BHQdmhVEs1cz;1kLM}p?c@ALBYR^WwKR}5P?+!7*3wAfN&{{z-lS1 z#Iqylc&|vALJVuvYpv;-^OggtWT}uiSOv@RZ{y39eLz2h_P_j|!;1f(n2}IpNY>)` zuVR@$LMza^d|&$L=6&-(3bbQXXln>vb14{%?Ft?zP@wHQc6^I8mbfse&DBVQZRPdn#uTZ7V#kUEU>aIIu*miBS{6Q^Rr6_?nY zCKk~MowtHJ?en{B*O3xbxn@HkX z;`zE9Gb2BIYT=YJ zpN{;Xi%i+mS%2Ympo!ddvcY@Fl}(K1R@<7tR6SqSRT#OaV#waSXR71*dhBZlS!!zU zEVumP#aHgCy?YH6%S=ZW2=ilD`>H0#V@^F&)QnHf>Ovk8P42}=d+yB8eA`zH^%*;!k{=%Q(FtNSb23PPM&-^NLzXn+!>QlvoEcl z5A44nTX#@vc@Qx=_zK&yCGKP?IU*@2+cWIK?9b1@G^du#ihZr?+A0p_M$Gi+sqGtP z-gJ~ygLh)ewpC3Sjm8eof@4F~M~91!*(@`8@*XZMfr_a9mfZ0#N^abj^3GGsfCJZX zVcv~wQk>?|4pchIhxgib8~8_tQ2By-EU%FUQl#~_XTCC=elfhu}vAf z4cFC_{rZz7-=v>y*EYV&8Whztp&oa)%BzddeA2cv_oL$Y+p(vggl7cyg@_ja!|o8x z!*>Z*k3BL3{s=pZeE8IvQ#Wz0m>V87x5v)adQ5Q3ekE^hc71tRd@lM~Lb<)|P|?e? zdtDZ;tUBk{-g>#TzWu7DyV_+mSnJg$aco?G>&DiVetJEsa?*Y>_rhPBKRQGhI&^hm z$p-HgOT+*CXiaj{cVEX&x!lRxc(~Li1KDxj=fp-}hh6@at&2A=%Nc`z{oDdGr*n!g zHEko>3oMQ~+sCtHrYU^izE(4J2yA}zvG;APMX#=jAHQclChjx1$DQ*0eCkZ1;I4Dk zBX^^rZTr*0AM1J`Ag8u#vtOq<&oy%7)wORw+ddm=@qP5|EymRT-4oBdv!`e6$QV1* WSykTcj~`qAzC3Oir#vYB%YOsl(pV1w literal 0 HcmV?d00001 diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index e088ce477..e3e5a8ec0 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -31,9 +31,15 @@ void cleanup(); DFHACK_EXPORT long getDfhackLogoTexposStart(); /** - * Get the texpos for the UI pin tiles. Each are 2x2 grids. + * 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(); + } } diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index 3ae8658c8..78ed53d97 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -21,6 +21,7 @@ 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; // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set @@ -117,6 +118,8 @@ void Textures::init(color_ostream &out) { &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); DEBUG(textures,out).print("loaded %ld textures\n", g_num_dfhack_textures); @@ -160,3 +163,7 @@ long Textures::getGreenPinTexposStart() { long Textures::getRedPinTexposStart() { return g_red_pin_texpos_start; } + +long Textures::getIconsTexposStart() { + return g_icons_texpos_start; +} From 478b5ada3975703a7866c9c24cfe806bf644b5e8 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 12 Jan 2023 22:17:39 -0800 Subject: [PATCH 02/80] expose icons texpos to Lua --- library/LuaApi.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 90815708d..9f3d590dd 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1692,6 +1692,7 @@ static const LuaWrapper::FunctionReg dfhack_textures_module[] = { WRAPM(Textures, getDfhackLogoTexposStart), WRAPM(Textures, getGreenPinTexposStart), WRAPM(Textures, getRedPinTexposStart), + WRAPM(Textures, getIconsTexposStart), { NULL, NULL } }; From 508777897be527c1e7c64afe47b62bfcfc14503f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 12 Jan 2023 22:30:47 -0800 Subject: [PATCH 03/80] allow tile list icons to be rendered properly --- library/lua/gui/widgets.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 5414fefaa..79372b153 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1694,7 +1694,7 @@ function List:onRenderBody(dc) local function paint_icon(icon, obj) if type(icon) ~= 'string' then - dc:char(nil,icon) + dc:tile(nil,icon) else if current then dc:string(icon, obj.icon_pen or self.icon_pen or cur_pen) From 3af91e15729e59f5eb457fb19ac3dba360e42053 Mon Sep 17 00:00:00 2001 From: 20k Date: Fri, 13 Jan 2023 11:48:07 +0000 Subject: [PATCH 04/80] update fortress reader for structures change --- plugins/remotefortressreader/building_reader.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/remotefortressreader/building_reader.cpp b/plugins/remotefortressreader/building_reader.cpp index e1f29e358..7cc715147 100644 --- a/plugins/remotefortressreader/building_reader.cpp +++ b/plugins/remotefortressreader/building_reader.cpp @@ -619,13 +619,13 @@ void CopyBuilding(int buildingIndex, RemoteFortressReader::BuildingInstance * re continue; if (zone->type != df::civzone_type::ArcheryRange) continue; - if(zone->dir_x < 0) + if(zone->zone_settings.archery.dir_x < 0) remote_build->set_direction(EAST); - else if(zone->dir_x > 0) + else if(zone->zone_settings.archery.dir_x > 0) remote_build->set_direction(WEST); - else if (zone->dir_y < 0) + else if (zone->zone_settings.archery.dir_y < 0) remote_build->set_direction(SOUTH); - else if (zone->dir_y > 0) + else if (zone->zone_settings.archery.dir_y > 0) remote_build->set_direction(NORTH); break; } From cc0ff6a93dd3635425e6c4604868eb739c5a8348 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Jan 2023 12:16:49 -0800 Subject: [PATCH 05/80] raise trigger lock screens (if possible) so they don't get stuck under new viewscreens and become lost (and therefore overlay will be forever locked) --- plugins/lua/overlay.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index 4fc375d72..42116735a 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -43,7 +43,12 @@ end local function triggered_screen_has_lock() if not trigger_lock_holder_screen then return false end - if trigger_lock_holder_screen:isActive() then return true end + if trigger_lock_holder_screen:isActive() then + if trigger_lock_holder_screen.raise then + trigger_lock_holder_screen:raise() + end + return true + end return register_trigger_lock_screen(nil, nil) end @@ -429,9 +434,8 @@ local function _update_viewscreen_widgets(vs_name, vs, now_ms) return now_ms end --- not subject to trigger lock since these widgets are already filtered by --- viewscreen function update_viewscreen_widgets(vs_name, vs) + if triggered_screen_has_lock() then return end local now_ms = _update_viewscreen_widgets(vs_name, vs, nil) _update_viewscreen_widgets('all', vs, now_ms) end From 6c6c4e159f9b86329459214c4da2fc08d3b70cec Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Jan 2023 12:17:51 -0800 Subject: [PATCH 06/80] add reminder why we can't clear mouse_lbut --- library/lua/gui.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 8a2a406aa..a0412a3a8 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -725,6 +725,7 @@ function ZScreen:onInput(keys) if ZScreen.super.onInput(self, keys) then -- ensure underlying DF screens don't also react to handled clicks 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 end if keys._MOUSE_R_DOWN then From 807f3f6327d9930078b1336869933fbc40677baa Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Jan 2023 12:18:18 -0800 Subject: [PATCH 07/80] update behavior of hotspot menu - disappears on click outside its borders - disappears on r-click - mouse over the help panel counts as "over the menu" (so the menu doesn't close if the player moves the mouse to the help text) - menu panels appear next to the logo hotspot instead of over it, allowing players to avoid clicking on the wrong item if they intend to click on the logo --- plugins/lua/hotkeys.lua | 101 +++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 42 deletions(-) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 53885d8fa..2fb32a692 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -32,12 +32,7 @@ function HotspotMenuWidget:overlay_onupdate() end function HotspotMenuWidget:overlay_trigger() - local hotkeys, bindings = getHotkeys() - return MenuScreen{ - hotspot_frame=self.frame, - hotkeys=hotkeys, - bindings=bindings, - mouseover=self.mouseover}:show() + return MenuScreen{hotspot_frame=self.frame}:show() end local dscreen = dfhack.screen @@ -71,21 +66,17 @@ end -- register the menu hotspot with the overlay OVERLAY_WIDGETS = {menu=HotspotMenuWidget} --- ---------- -- --- MenuScreen -- --- ---------- -- +-- ---- -- +-- Menu -- +-- ---- -- local ARROW = string.char(26) local MAX_LIST_WIDTH = 45 local MAX_LIST_HEIGHT = 15 -MenuScreen = defclass(MenuScreen, gui.Screen) -MenuScreen.ATTRS{ - focus_path='hotkeys/menu', +Menu = defclass(MenuScreen, widgets.Panel) +Menu.ATTRS{ hotspot_frame=DEFAULT_NIL, - hotkeys=DEFAULT_NIL, - bindings=DEFAULT_NIL, - mouseover=false, } -- get a map from the binding string to a list of hotkey strings that all @@ -142,10 +133,11 @@ local function get_choices(hotkeys, bindings, is_inverted) return choices, max_width end -function MenuScreen:init() +function Menu:init() + local hotkeys, bindings = getHotkeys() + local is_inverted = not not self.hotspot_frame.b - local choices,list_width = get_choices(self.hotkeys, self.bindings, - is_inverted) + local choices,list_width = get_choices(hotkeys, bindings, is_inverted) local list_frame = copyall(self.hotspot_frame) list_frame.w = list_width + 2 @@ -156,9 +148,9 @@ function MenuScreen:init() list_frame.b = math.max(0, list_frame.b - 1) end if list_frame.l then - list_frame.l = math.max(0, list_frame.l - 1) + list_frame.l = math.max(0, list_frame.l + 5) else - list_frame.r = math.max(0, list_frame.r - 1) + 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} @@ -207,11 +199,7 @@ function MenuScreen:init() end end -function MenuScreen:onDismiss() - cleanupHotkeys() -end - -function MenuScreen:onSelect(_, choice) +function Menu:onSelect(_, choice) if not choice or #self.subviews == 0 then return end local first_word = choice.command:trim():split(' +')[1] if first_word:startswith(':') then first_word = first_word:sub(2) end @@ -220,22 +208,21 @@ function MenuScreen:onSelect(_, choice) self.subviews.help_panel:updateLayout() end -function MenuScreen:onSubmit(_, choice) +function Menu:onSubmit(_, choice) if not choice then return end - dfhack.screen.hideGuard(self, dfhack.run_command, choice.command) - self:dismiss() + dfhack.screen.hideGuard(self.parent_view, dfhack.run_command, choice.command) + self.parent_view:dismiss() end -function MenuScreen:onSubmit2(_, choice) +function Menu:onSubmit2(_, choice) if not choice then return end - self:dismiss() + self.parent_view:dismiss() dfhack.run_script('gui/launcher', choice.command) end -function MenuScreen:onInput(keys) - if keys.LEAVESCREEN then - self:dismiss() - return true +function Menu:onInput(keys) + if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then + return false elseif keys.STANDARDSCROLL_RIGHT then self:onSubmit2(self.subviews.list:getSelected()) return true @@ -246,19 +233,28 @@ function MenuScreen:onInput(keys) self:onSubmit2(list:getSelected()) return true end + if not self:getMouseFramePos() then + self.parent_view:dismiss() + return true + end end - return self:inputToSubviews(keys) + self:inputToSubviews(keys) + return true -- we're modal end -function MenuScreen:onRenderFrame(dc, rect) +function Menu:onRenderFrame(dc, rect) if self.initialize then self.initialize() self.initialize = nil end - self:renderParent() end -function MenuScreen:onRenderBody(dc) +function Menu:getMouseFramePos() + return self.subviews.list_panel:getMouseFramePos() or + self.subviews.help_panel:getMouseFramePos() +end + +function Menu:onRenderBody(dc) local panel = self.subviews.list_panel local list = self.subviews.list local idx = list:getIdxUnderMouse() @@ -267,14 +263,35 @@ function MenuScreen:onRenderBody(dc) -- selection, don't override the selection until the mouse moves to -- another item list:setSelected(idx) - self.mouseover = true self.last_mouse_idx = idx - elseif not panel:getMousePos(gui.ViewRect{rect=panel.frame_rect}) - and self.mouseover then + 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:dismiss() + self.parent_view:dismiss() end end +-- ---------- -- +-- MenuScreen -- +-- ---------- -- + +MenuScreen = defclass(MenuScreen, gui.ZScreen) +MenuScreen.ATTRS { + focus_path='hotkeys/menu', + hotspot_frame=DEFAULT_NIL, +} + +function MenuScreen:init() + self:addviews{ + Menu{hotspot_frame=self.hotspot_frame}, + } +end + +function MenuScreen:onDismiss() + cleanupHotkeys() +end + return _ENV From 8f434bf9a697a81b5b0635023248903fdda0f9b3 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Jan 2023 12:36:16 -0800 Subject: [PATCH 08/80] add blueprint back to the build (dig and build phases only) --- docs/plugins/blueprint.rst | 9 ++++++++- plugins/CMakeLists.txt | 2 +- plugins/blueprint.cpp | 11 +++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/plugins/blueprint.rst b/docs/plugins/blueprint.rst index aa2d0fa03..3b63719cb 100644 --- a/docs/plugins/blueprint.rst +++ b/docs/plugins/blueprint.rst @@ -3,7 +3,7 @@ blueprint .. dfhack-tool:: :summary: Record a live game map in a quickfort blueprint. - :tags: untested fort design buildings map stockpiles + :tags: fort design buildings map stockpiles With ``blueprint``, you can export the structure of a portion of your fortress in a blueprint file that you (or anyone else) can later play back with @@ -15,6 +15,13 @@ selected interactively with the ``gui/blueprint`` command or, if the GUI is not used, starts at the active cursor location and extends right and down for the requested width and height. +.. admonition:: Note + + blueprint is still in the process of being updated for the new version of + DF. Stockpiles (the "place" phase), zones (the "zone" phase), building + (the "query" phase), and game configuration (the "config" phase) are not + yet supported. + Usage ----- diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 727df63c5..1166caae7 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -86,7 +86,7 @@ dfhack_plugin(autofarm autofarm.cpp) #dfhack_plugin(automelt automelt.cpp) #dfhack_plugin(autonestbox autonestbox.cpp LINK_LIBRARIES lua) #dfhack_plugin(autotrade autotrade.cpp) -#dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua) +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) diff --git a/plugins/blueprint.cpp b/plugins/blueprint.cpp index 509b1e6bc..3d34f592e 100644 --- a/plugins/blueprint.cpp +++ b/plugins/blueprint.cpp @@ -850,6 +850,7 @@ static const char * get_tile_build(const df::coord &pos, return add_expansion_syntax(ctx, keys); } +/* TODO: understand how this changes for v50 static const char * get_place_keys(const tile_context &ctx) { df::building_stockpilest* sp = virtual_cast(ctx.b); @@ -1086,6 +1087,7 @@ static const char * get_tile_rooms(const df::coord &, const tile_context &ctx) { str << "r{+ " << (max_dim - 3) << "}&"; return cache(str); } +*/ static bool create_output_dir(color_ostream &out, const blueprint_options &opts) { @@ -1326,6 +1328,7 @@ static bool do_transform(color_ostream &out, get_tile_construct, ensure_building); add_processor(processors, opts, "build", "build", opts.build, get_tile_build, ensure_building); +/* TODO: understand how this changes for v50 add_processor(processors, opts, "place", "place", opts.place, get_tile_place, ensure_building); add_processor(processors, opts, "zone", "zone", opts.zone, get_tile_zone); @@ -1333,6 +1336,14 @@ static bool do_transform(color_ostream &out, get_tile_query, ensure_building); add_processor(processors, opts, "query", "rooms", opts.rooms, get_tile_rooms, ensure_building); +*/ if (opts.place) + out.printerr("'place' blueprints are not yet supported for the current version of DF\n"); + if (opts.zone) + out.printerr("'zone' blueprints are not yet supported for the current version of DF\n"); + if (opts.query) + out.printerr("'query' blueprints are not yet supported for the current version of DF\n"); + if (opts.rooms) + out.printerr("'rooms' blueprints are not yet supported for the current version of DF\n"); if (processors.empty()) { out.printerr("no phases requested! nothing to do!\n"); From 40aa7539536a205f4fc583ad59da5af6fbcac461 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Jan 2023 12:43:49 -0800 Subject: [PATCH 09/80] fix docs typo --- docs/plugins/blueprint.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/blueprint.rst b/docs/plugins/blueprint.rst index 3b63719cb..b10921d30 100644 --- a/docs/plugins/blueprint.rst +++ b/docs/plugins/blueprint.rst @@ -19,8 +19,8 @@ requested width and height. blueprint is still in the process of being updated for the new version of DF. Stockpiles (the "place" phase), zones (the "zone" phase), building - (the "query" phase), and game configuration (the "config" phase) are not - yet supported. + configuration (the "query" phase), and game configuration (the "config" + phase) are not yet supported. Usage ----- From 4f88d27e08e54ed5be41c95bc083b43eea94d338 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Jan 2023 17:05:08 -0800 Subject: [PATCH 10/80] cancel EditField editing on r-click --- library/lua/gui/widgets.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 9293e737c..ff1c0cedc 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -708,7 +708,7 @@ function EditField:onInput(keys) end end - if self.key and keys.LEAVESCREEN then + 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 From e450af74aab8bf3dbadd55c33221f583c3d2bdbd Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Jan 2023 17:05:23 -0800 Subject: [PATCH 11/80] pull the useful bits out of MenuOverlay --- library/lua/gui/dwarfmode.lua | 140 +++++++++------------------------- 1 file changed, 35 insertions(+), 105 deletions(-) diff --git a/library/lua/gui/dwarfmode.lua b/library/lua/gui/dwarfmode.lua index bb381be24..675a7228e 100644 --- a/library/lua/gui/dwarfmode.lua +++ b/library/lua/gui/dwarfmode.lua @@ -286,6 +286,19 @@ function get_hotkey_target(key) end end +function getMapKey(keys) + for code in pairs(keys) do + if MOVEMENT_KEYS[code] or HOTKEY_KEYS[code] + or code == '_MOUSE_M_DOWN' or code == '_MOUSE_M' + or code == 'ZOOM_OUT' or code == 'ZOOM_IN' then + if not HOTKEY_KEYS[code] or get_hotkey_target(code) then + return true + end + return code + end + end +end + function Viewport:scrollByKey(key) local dx, dy, dz = get_movement_delta(key, 10, 20) if dx then @@ -339,13 +352,9 @@ function DwarfOverlay:selectBuilding(building,cursor,viewport,gap) end function DwarfOverlay:propagateMoveKeys(keys) - for code,_ in pairs(keys) do - if MOVEMENT_KEYS[code] or HOTKEY_KEYS[code] then - if not HOTKEY_KEYS[code] or get_hotkey_target(code) then - self:sendInputToParent(code) - end - return code - end + local map_key = getMapKey(keys) + if map_key then + self:sendInputToParent(map_key) end end @@ -414,124 +423,45 @@ function DwarfOverlay:onAboutToShow(parent) end end -MenuOverlay = defclass(MenuOverlay, DwarfOverlay) - -MenuOverlay.ATTRS { - frame_inset = 0, - frame_background = gui.CLEAR_PEN, - - -- if sidebar_mode is set, we will enter the specified sidebar mode on show - -- and restore the previous sidebar mode on dismiss. otherwise it is up to - -- the caller to ensure we are in a sidebar mode where the menu is visible. - sidebar_mode = DEFAULT_NIL, -} - -function MenuOverlay:init() - if not dfhack.isMapLoaded() then - -- sidebar menus are only valid when a fort map is loaded - error('A fortress map must be loaded.') - end - - if self.sidebar_mode then - self.saved_sidebar_mode = df.global.plotinfo.main.mode - -- what mode should we restore when this window is dismissed? ideally, we'd - -- restore the mode that the user has set, but we should fall back to - -- restoring the default mode if either of the following conditions are - -- true: - -- 1) enterSidebarMode doesn't support getting back into the current mode - -- 2) a dfhack viewscreen is currently visible. in this case, we can't trust - -- that the current sidebar mode was set by the user. it could just be a - -- MenuOverlay subclass that is currently being shown that has set the - -- sidebar mode for its own purposes. - if not SIDEBAR_MODE_KEYS[self.saved_sidebar_mode] - or dfhack.gui.getCurFocus(true):find('^dfhack/') then - self.saved_sidebar_mode = df.ui_sidebar_mode.Default - end - - enterSidebarMode(self.sidebar_mode) - end -end - -function MenuOverlay:computeFrame(parent_rect) - return self.df_layout.menu, gui.inset_frame(self.df_layout.menu, self.frame_inset) -end - -function MenuOverlay:onAboutToShow(parent) - self:updateLayout() - if not self.df_layout.menu then - error("The menu panel of dwarfmode is not visible") - end -end - -function MenuOverlay:onDismiss() - if self.saved_sidebar_mode then - enterSidebarMode(self.saved_sidebar_mode) - end -end - -function MenuOverlay:render(dc) - self:renderParent() - - local menu = self.df_layout.menu - if menu then - -- Paint signature on the frame. - dscreen.paintString( - {fg=COLOR_BLACK,bg=COLOR_DARKGREY}, - menu.x1+1, menu.y2+1, "DFHack" - ) - - if self.frame_background then - dc:fill(menu, self.frame_background) - end - - MenuOverlay.super.render(self, dc) - end -end - -- Framework for managing rendering over the map area. This function is intended --- to be called from a subclass's onRenderBody() function. +-- to be called from a window's onRenderFrame() function. -- --- get_overlay_char_fn takes a coordinate position and an is_cursor boolean and --- returns the char to render at that position and, optionally, the foreground --- and background colors to use to draw the char. If nothing should be rendered --- at that position, the function should return nil. If no foreground color is --- specified, it defaults to COLOR_GREEN. If no background color is specified, --- it defaults to COLOR_BLACK. +-- get_overlay_pen_fn takes a coordinate position and an is_cursor boolean and +-- returns the pen (and optional char and tile) to render at that position. If +-- nothing should be rendered at that position, the function should return nil. -- -- bounds_rect has elements {x1, x2, y1, y2} in global map coordinates (not -- screen coordinates). The rect is intersected with the visible map viewport to -- get the range over which get_overlay_char_fn is called. If bounds_rect is not -- specified, the entire viewport is scanned. -- --- example call from a subclass: --- function MyMenuOverlaySubclass:onRenderBody() --- local function get_overlay_char(pos) --- return safe_index(self.overlay_chars, pos.z, pos.y, pos.x), COLOR_RED +-- example call: +-- function MyMapOverlay:onRenderFrame(dc, rect) +-- local function get_overlay_pen(pos) +-- if safe_index(self.overlay_map, pos.z, pos.y, pos.x) then +-- return COLOR_GREEN, 'X', dfhack.screen.findGraphicsTile('CURSORS', 4, 3) +-- end -- end --- self:renderMapOverlay(get_overlay_char, self.overlay_bounds) +-- guidm.renderMapOverlay(get_overlay_pen, self.overlay_bounds) -- end -function MenuOverlay:renderMapOverlay(get_overlay_char_fn, bounds_rect) - local vp = self:getViewport() +function renderMapOverlay(get_overlay_pen_fn, bounds_rect) + local vp = Viewport.get() local rect = gui.ViewRect{rect=vp, clip_view=bounds_rect and gui.ViewRect{rect=bounds_rect} or nil} - -- nothing to do if the viewport is completely separate from the bounds_rect + -- nothing to do if the viewport is completely disjoint from the bounds_rect if rect:isDefunct() then return end - local dc = gui.Painter.new(self.df_layout.map) local z = df.global.window_z local cursor = getCursorPos() for y=rect.clip_y1,rect.clip_y2 do for x=rect.clip_x1,rect.clip_x2 do local pos = xyz2pos(x, y, z) - local overlay_char, fg_color, bg_color = get_overlay_char_fn( - pos, same_xy(cursor, pos)) - if not overlay_char then goto continue end - local stile = vp:tileToScreen(pos) - dc:map(true):seek(stile.x, stile.y): - pen(fg_color or COLOR_GREEN, bg_color or COLOR_BLACK): - char(overlay_char):map(false) - ::continue:: + local overlay_pen, char, tile = get_overlay_pen_fn(pos, same_xy(cursor, pos)) + if overlay_pen then + local stile = vp:tileToScreen(pos) + dscreen.paintTile(overlay_pen, stile.x, stile.y, char, tile, true) + end end end end From b77e896041fca4d557e333cd73c05dc36c9d0449 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 13 Jan 2023 17:08:25 -0800 Subject: [PATCH 12/80] update EditField docs --- docs/dev/Lua API.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 33b48c0a7..b3f1f52db 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4468,9 +4468,10 @@ calling ``setFocus(true)`` on the field object. If an activation ``key`` is specified, the ``EditField`` will manage its own focus. It will start in the unfocused state, and pressing the activation key will acquire keyboard focus. Pressing the Enter key will release keyboard focus -and then call the ``on_submit`` callback. Pressing the Escape key will also -release keyboard focus, but first it will restore the text that was displayed -before the ``EditField`` gained focus and then call the ``on_change`` callback. +and then call the ``on_submit`` callback. Pressing the Escape key (or r-clicking +with the mouse) will also release keyboard focus, but first it will restore the +text that was displayed before the ``EditField`` gained focus and then call the +``on_change`` callback. The ``EditField`` cursor can be moved to where you want to insert/remove text. You can click where you want the cursor to move or you can use any of the From 3459d61dc4c83c7b3f0ebfab21dccf1063e3063e Mon Sep 17 00:00:00 2001 From: Amber Brown Date: Sat, 14 Jan 2023 13:16:07 +1100 Subject: [PATCH 13/80] Use vswhere to find MSBUILD --- build/win64/build-debug.bat | 7 +++---- build/win64/build-release.bat | 6 ++---- build/win64/generate-MSVC-all.bat | 4 +--- build/win64/generate-MSVC-gui.bat | 6 ++---- build/win64/generate-MSVC-minimal.bat | 4 +--- build/win64/generate-MSVC-release.bat | 4 +--- build/win64/generate-MSVC-testing.bat | 4 +--- build/win64/install-debug.bat | 6 ++---- build/win64/install-release.bat | 6 ++---- build/win64/msvc_include.bat | 9 +++++++++ build/win64/package-debug.bat | 7 ++----- build/win64/package-release.bat | 7 ++----- 12 files changed, 28 insertions(+), 42 deletions(-) create mode 100644 build/win64/msvc_include.bat diff --git a/build/win64/build-debug.bat b/build/win64/build-debug.bat index a04cb9984..fdcdce6b8 100644 --- a/build/win64/build-debug.bat +++ b/build/win64/build-debug.bat @@ -1,4 +1,3 @@ -call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 -cd VC2022 -msbuild /m /p:Platform=x64 /p:Configuration=RelWithDebInfo ALL_BUILD.vcxproj -cd .. +call msvc_include.bat +%msbuild% /m /p:Platform=x64 /p:Configuration=RelWithDebInfo VC2022/ALL_BUILD.vcxproj + diff --git a/build/win64/build-release.bat b/build/win64/build-release.bat index 8068e5074..39174794a 100644 --- a/build/win64/build-release.bat +++ b/build/win64/build-release.bat @@ -1,5 +1,3 @@ -call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64 -cd VC2022 -msbuild /m /p:Platform=x64 /p:Configuration=Release ALL_BUILD.vcxproj -cd .. +call msvc_include.bat +%msbuild% /m /p:Platform=x64 /p:Configuration=Release VC2022/ALL_BUILD.vcxproj pause diff --git a/build/win64/generate-MSVC-all.bat b/build/win64/generate-MSVC-all.bat index ea8db34c0..f43a03596 100644 --- a/build/win64/generate-MSVC-all.bat +++ b/build/win64/generate-MSVC-all.bat @@ -1,6 +1,4 @@ IF EXIST DF_PATH.txt SET /P _DF_PATH= Date: Sat, 14 Jan 2023 14:07:14 +1100 Subject: [PATCH 14/80] let cmake deal with VS2022 instead :) --- build/win64/build-debug.bat | 4 +--- build/win64/build-release.bat | 4 +--- build/win64/install-debug.bat | 3 +-- build/win64/install-release.bat | 3 +-- build/win64/msvc_include.bat | 9 --------- build/win64/package-debug.bat | 3 +-- build/win64/package-release.bat | 3 +-- 7 files changed, 6 insertions(+), 23 deletions(-) delete mode 100644 build/win64/msvc_include.bat diff --git a/build/win64/build-debug.bat b/build/win64/build-debug.bat index fdcdce6b8..2db9df402 100644 --- a/build/win64/build-debug.bat +++ b/build/win64/build-debug.bat @@ -1,3 +1 @@ -call msvc_include.bat -%msbuild% /m /p:Platform=x64 /p:Configuration=RelWithDebInfo VC2022/ALL_BUILD.vcxproj - +cmake --build VC2022 -t ALL_BUILD -- /m /p:Platform=x64 /p:Configuration=RelWithDebInfo diff --git a/build/win64/build-release.bat b/build/win64/build-release.bat index 39174794a..f719d64bc 100644 --- a/build/win64/build-release.bat +++ b/build/win64/build-release.bat @@ -1,3 +1 @@ -call msvc_include.bat -%msbuild% /m /p:Platform=x64 /p:Configuration=Release VC2022/ALL_BUILD.vcxproj -pause +cmake --build VC2022 -t ALL_BUILD -- /m /p:Platform=x64 /p:Configuration=Release diff --git a/build/win64/install-debug.bat b/build/win64/install-debug.bat index 2fc03eca1..b6c22b0e3 100644 --- a/build/win64/install-debug.bat +++ b/build/win64/install-debug.bat @@ -1,2 +1 @@ -call msvc_include.bat -%msbuild% /m /p:Platform=x64 /p:Configuration=RelWithDebInfo VC2022/INSTALL.vcxproj +cmake --build VC2022 -t INSTALL -- /m /p:Platform=x64 /p:Configuration=RelWithDebInfo diff --git a/build/win64/install-release.bat b/build/win64/install-release.bat index 3194812b8..61aabf771 100644 --- a/build/win64/install-release.bat +++ b/build/win64/install-release.bat @@ -1,2 +1 @@ -call msvc_include.bat -%msbuild% /m /p:Platform=x64 /p:Configuration=Release VC2022/INSTALL.vcxproj +cmake --build VC2022 -t INSTALL -- /m /p:Platform=x64 /p:Configuration=Release diff --git a/build/win64/msvc_include.bat b/build/win64/msvc_include.bat deleted file mode 100644 index 0dbcc90cc..000000000 --- a/build/win64/msvc_include.bat +++ /dev/null @@ -1,9 +0,0 @@ -@ECHO OFF -setlocal enabledelayedexpansion - -FOR /F "usebackq tokens=*" %%F IN (`"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" -requires Microsoft.Component.MSBuild -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -version [17.0^,] -products * -find MSBuild\**\Bin\MSBuild.exe`) DO ( - endlocal & set "MSBUILD="%%F"" - goto :EOF -) -echo "Cannot find a Visual Studio 2022/Build Tools installation" -exit 1 \ No newline at end of file diff --git a/build/win64/package-debug.bat b/build/win64/package-debug.bat index 72ca65a0a..afaec234a 100644 --- a/build/win64/package-debug.bat +++ b/build/win64/package-debug.bat @@ -1,3 +1,2 @@ -call msvc_include.bat -%msbuild% /m /p:Platform=x64 /p:Configuration=RelWithDebInfo VC2022/PACKAGE.vcxproj +cmake --build VC2022 -t PACKAGE -- /m /p:Platform=x64 /p:Configuration=RelWithDebInfo exit %ERRORLEVEL% diff --git a/build/win64/package-release.bat b/build/win64/package-release.bat index e796d6481..75b35bcd5 100644 --- a/build/win64/package-release.bat +++ b/build/win64/package-release.bat @@ -1,2 +1 @@ -call msvc_include.bat -%msbuild% /m /p:Platform=x64 /p:Configuration=Release VC2022/PACKAGE.vcxproj +cmake --build VC2022 -t PACKAGE -- /m /p:Platform=x64 /p:Configuration=Release From 5f60791b399319bf4ec82a53e34145c946f45629 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 14 Jan 2023 07:13:34 +0000 Subject: [PATCH 15/80] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index a8c5ac9e9..e1ef58a34 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit a8c5ac9e94e26f0901917efac213ebedc7e0c276 +Subproject commit e1ef58a343b01b91766deb17d5945b6274797eae From f19ae16c9d64f2678bef68af5719eededbc2e279 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Jan 2023 01:00:38 -0800 Subject: [PATCH 16/80] give more control over the resizing dimensions of ResizingPanels --- docs/dev/Lua API.rst | 7 +++++++ library/lua/gui/widgets.lua | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 33b48c0a7..728551ff6 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -4416,6 +4416,13 @@ Subclass of Panel; automatically adjusts its own frame height and width to the minimum required to show its subviews. Pairs nicely with a parent Panel that has ``autoarrange_subviews`` enabled. +It has the following attributes: + +:auto_height: Sets self.frame.h from the positions and height of its subviews + (default is ``true``). +:auto_width: Sets self.frame.w from the positions and width of its subviews + (default is ``false``). + Pages class ----------- diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 9293e737c..1488eda90 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -530,6 +530,11 @@ Window.ATTRS { ResizingPanel = defclass(ResizingPanel, Panel) +ResizingPanel.ATTRS{ + auto_height = true, + auto_width = false, +} + -- adjust our frame dimensions according to positions and sizes of our subviews function ResizingPanel:postUpdateLayout(frame_body) local w, h = 0, 0 @@ -550,6 +555,8 @@ function ResizingPanel:postUpdateLayout(frame_body) end if not self.frame then self.frame = {} end local oldw, oldh = self.frame.w, self.frame.h + if not self.auto_height then h = oldh end + if not self.auto_width then w = oldw end self.frame.w, self.frame.h = w, h if not self._updateLayoutGuard and (oldw ~= w or oldh ~= h) then self._updateLayoutGuard = true -- protect against infinite loops From 69e5730f77dde00c693d92ae5c114112e6a0a26e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Jan 2023 01:07:18 -0800 Subject: [PATCH 17/80] document dfhack.job.removeJob() --- docs/dev/Lua API.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 33b48c0a7..49e275578 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1144,6 +1144,10 @@ Job module Prints info about the job item. +* ``dfhack.job.removeJob(job)`` + + Cancels a job, cleans up all references to it, and removes it from the world. + * ``dfhack.job.getGeneralRef(job, type)`` Searches for a general_ref with the given type. From 7c53d848cdcf50cb96f3f697c2d3fc0a30012d0f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Jan 2023 01:21:58 -0800 Subject: [PATCH 18/80] sync tags from spreadsheet --- docs/plugins/fastdwarf.rst | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/fastdwarf.rst b/docs/plugins/fastdwarf.rst index 217c098ef..fb0524c3b 100644 --- a/docs/plugins/fastdwarf.rst +++ b/docs/plugins/fastdwarf.rst @@ -3,7 +3,7 @@ fastdwarf .. dfhack-tool:: :summary: Dwarves teleport and/or finish jobs instantly. - :tags: untested fort armok units + :tags: fort armok units Usage ----- diff --git a/scripts b/scripts index e1ef58a34..8064f7160 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit e1ef58a343b01b91766deb17d5945b6274797eae +Subproject commit 8064f71601664fb841f830850ce390092e685276 From f82acec9d4c6af09d869535505588a4072180792 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sat, 14 Jan 2023 09:26:48 +0000 Subject: [PATCH 19/80] 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 18446d51e..ab0593b40 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 18446d51e4133a06271fd2672f5b816b8c56e937 +Subproject commit ab0593b40a1a41c19432ec6bd88fc9ecf60b5fb6 From dbc26f0d37863e60dea4d3e3f96029a230909856 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Thu, 12 Jan 2023 17:14:43 -0800 Subject: [PATCH 20/80] enable next batch of plugins to test --- plugins/CMakeLists.txt | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 1166caae7..a09f453db 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -84,7 +84,7 @@ dfhack_plugin(autofarm autofarm.cpp) #add_subdirectory(autolabor) #dfhack_plugin(automaterial automaterial.cpp LINK_LIBRARIES lua) #dfhack_plugin(automelt automelt.cpp) -#dfhack_plugin(autonestbox autonestbox.cpp LINK_LIBRARIES lua) +dfhack_plugin(autonestbox autonestbox.cpp LINK_LIBRARIES lua) #dfhack_plugin(autotrade autotrade.cpp) dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua) #dfhack_plugin(burrows burrows.cpp LINK_LIBRARIES lua) @@ -94,12 +94,12 @@ dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua) 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(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(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) @@ -113,7 +113,7 @@ dfhack_plugin(dig-now dig-now.cpp LINK_LIBRARIES lua) #dfhack_plugin(embark-tools embark-tools.cpp) dfhack_plugin(eventful eventful.cpp LINK_LIBRARIES lua) dfhack_plugin(fastdwarf fastdwarf.cpp) -#dfhack_plugin(filltraffic filltraffic.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) @@ -122,7 +122,7 @@ dfhack_plugin(fastdwarf fastdwarf.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(infiniteSky infiniteSky.cpp) #dfhack_plugin(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) #dfhack_plugin(jobutils jobutils.cpp) #dfhack_plugin(lair lair.cpp) @@ -130,10 +130,10 @@ dfhack_plugin(liquids liquids.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(luasocket luasocket.cpp LINK_LIBRARIES clsocket lua dfhack-tinythread) #dfhack_plugin(manipulator manipulator.cpp) #dfhack_plugin(map-render map-render.cpp LINK_LIBRARIES lua) -#dfhack_plugin(misery misery.cpp) +dfhack_plugin(misery misery.cpp) #dfhack_plugin(mode mode.cpp) #dfhack_plugin(mousequery mousequery.cpp) -#dfhack_plugin(nestboxes nestboxes.cpp) +dfhack_plugin(nestboxes nestboxes.cpp) dfhack_plugin(orders orders.cpp LINK_LIBRARIES jsoncpp_static) dfhack_plugin(overlay overlay.cpp LINK_LIBRARIES lua) dfhack_plugin(pathable pathable.cpp LINK_LIBRARIES lua) @@ -149,7 +149,7 @@ add_subdirectory(remotefortressreader) dfhack_plugin(reveal reveal.cpp LINK_LIBRARIES lua) #dfhack_plugin(search search.cpp) dfhack_plugin(seedwatch seedwatch.cpp) -#dfhack_plugin(showmood showmood.cpp) +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) @@ -158,7 +158,7 @@ dfhack_plugin(seedwatch seedwatch.cpp) #add_subdirectory(stockpiles) #dfhack_plugin(stocks stocks.cpp) #dfhack_plugin(strangemood strangemood.cpp) -#dfhack_plugin(tailor tailor.cpp) +dfhack_plugin(tailor tailor.cpp) dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(title-folder title-folder.cpp) #dfhack_plugin(title-version title-version.cpp) @@ -166,7 +166,7 @@ dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(tubefill tubefill.cpp) #add_subdirectory(tweak) #dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua) -#dfhack_plugin(workNow workNow.cpp) +dfhack_plugin(workNow workNow.cpp) dfhack_plugin(xlsxreader xlsxreader.cpp LINK_LIBRARIES lua xlsxio_read_STATIC zip expat) #dfhack_plugin(zone zone.cpp) From 9606f7bf4fdacdeeb56de37417c3f4e020379153 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Jan 2023 09:50:17 -0800 Subject: [PATCH 21/80] remove ones that don't work, mark as tested those that do --- docs/plugins/RemoteFortressReader.rst | 2 +- docs/plugins/cleaners.rst | 2 +- docs/plugins/cursecheck.rst | 2 +- docs/plugins/filltraffic.rst | 2 +- docs/plugins/misery.rst | 2 +- docs/plugins/nestboxes.rst | 2 +- plugins/CMakeLists.txt | 8 ++++---- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/plugins/RemoteFortressReader.rst b/docs/plugins/RemoteFortressReader.rst index 9b45452bc..c70adc608 100644 --- a/docs/plugins/RemoteFortressReader.rst +++ b/docs/plugins/RemoteFortressReader.rst @@ -3,7 +3,7 @@ RemoteFortressReader .. dfhack-tool:: :summary: Backend for Armok Vision. - :tags: untested dev graphics + :tags: dev graphics :no-command: .. dfhack-command:: RemoteFortressReader_version diff --git a/docs/plugins/cleaners.rst b/docs/plugins/cleaners.rst index dd484f5df..14a25d62f 100644 --- a/docs/plugins/cleaners.rst +++ b/docs/plugins/cleaners.rst @@ -6,7 +6,7 @@ cleaners .. dfhack-tool:: :summary: Provides commands for cleaning spatter from the map. - :tags: untested adventure fort armok fps items map units + :tags: adventure fort armok fps items map units :no-command: .. dfhack-command:: clean diff --git a/docs/plugins/cursecheck.rst b/docs/plugins/cursecheck.rst index fd97ee252..94012919b 100644 --- a/docs/plugins/cursecheck.rst +++ b/docs/plugins/cursecheck.rst @@ -3,7 +3,7 @@ cursecheck .. dfhack-tool:: :summary: Check for cursed creatures. - :tags: untested fort armok inspection units + :tags: fort armok inspection units This command checks a single map tile (or the whole map/world) for cursed creatures (ghosts, vampires, necromancers, werebeasts, zombies, etc.). diff --git a/docs/plugins/filltraffic.rst b/docs/plugins/filltraffic.rst index f92549dee..beb57dccd 100644 --- a/docs/plugins/filltraffic.rst +++ b/docs/plugins/filltraffic.rst @@ -6,7 +6,7 @@ filltraffic .. dfhack-tool:: :summary: Set traffic designations using flood-fill starting at the cursor. - :tags: untested fort design productivity map + :tags: fort design productivity map .. dfhack-command:: alltraffic :summary: Set traffic designations for every single tile of the map. diff --git a/docs/plugins/misery.rst b/docs/plugins/misery.rst index 38c2b23b4..f2c4d1952 100644 --- a/docs/plugins/misery.rst +++ b/docs/plugins/misery.rst @@ -3,7 +3,7 @@ misery .. dfhack-tool:: :summary: Increase the intensity of negative dwarven thoughts. - :tags: untested fort armok auto units + :tags: fort armok auto units When enabled, negative thoughts that your dwarves have will multiply by the specified factor. diff --git a/docs/plugins/nestboxes.rst b/docs/plugins/nestboxes.rst index 91d83aa1a..3c07cc30c 100644 --- a/docs/plugins/nestboxes.rst +++ b/docs/plugins/nestboxes.rst @@ -3,7 +3,7 @@ nestboxes .. dfhack-tool:: :summary: Protect fertile eggs incubating in a nestbox. - :tags: untested fort auto animals + :tags: fort auto animals :no-command: This plugin will automatically scan for and forbid fertile eggs incubating in a diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index a09f453db..661fa2624 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -84,7 +84,7 @@ dfhack_plugin(autofarm autofarm.cpp) #add_subdirectory(autolabor) #dfhack_plugin(automaterial automaterial.cpp LINK_LIBRARIES lua) #dfhack_plugin(automelt automelt.cpp) -dfhack_plugin(autonestbox autonestbox.cpp LINK_LIBRARIES lua) +#dfhack_plugin(autonestbox autonestbox.cpp LINK_LIBRARIES lua) #dfhack_plugin(autotrade autotrade.cpp) dfhack_plugin(blueprint blueprint.cpp LINK_LIBRARIES lua) #dfhack_plugin(burrows burrows.cpp LINK_LIBRARIES lua) @@ -122,7 +122,7 @@ dfhack_plugin(filltraffic filltraffic.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(infiniteSky infiniteSky.cpp) #dfhack_plugin(isoworldremote isoworldremote.cpp PROTOBUFS isoworldremote) #dfhack_plugin(jobutils jobutils.cpp) #dfhack_plugin(lair lair.cpp) @@ -158,7 +158,7 @@ dfhack_plugin(showmood showmood.cpp) #add_subdirectory(stockpiles) #dfhack_plugin(stocks stocks.cpp) #dfhack_plugin(strangemood strangemood.cpp) -dfhack_plugin(tailor tailor.cpp) +#dfhack_plugin(tailor tailor.cpp) dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(title-folder title-folder.cpp) #dfhack_plugin(title-version title-version.cpp) @@ -166,7 +166,7 @@ dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(tubefill tubefill.cpp) #add_subdirectory(tweak) #dfhack_plugin(workflow workflow.cpp LINK_LIBRARIES lua) -dfhack_plugin(workNow workNow.cpp) +#dfhack_plugin(workNow workNow.cpp) dfhack_plugin(xlsxreader xlsxreader.cpp LINK_LIBRARIES lua xlsxio_read_STATIC zip expat) #dfhack_plugin(zone zone.cpp) From e7696b1f0362e2422127caaefe047bee20c7f059 Mon Sep 17 00:00:00 2001 From: Kelvie Wong Date: Fri, 13 Jan 2023 21:02:33 -0800 Subject: [PATCH 22/80] Allow symlinked dfhack-run This is useful for symlinking this script somewhere on your $PATH, and having it work without having to find the correct directory. --- package/linux/dfhack-run | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package/linux/dfhack-run b/package/linux/dfhack-run index 55001cfcb..b5e6ccfe2 100755 --- a/package/linux/dfhack-run +++ b/package/linux/dfhack-run @@ -1,6 +1,6 @@ #!/bin/sh -DF_DIR=$(dirname "$0") +DF_DIR=$(dirname "$(readlink -f "$0")") cd "${DF_DIR}" export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"./hack/libs":"./hack" From 1eb5dd9a4f428cc851272b683146254de5872b27 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Jan 2023 18:30:44 -0800 Subject: [PATCH 23/80] fix incorrect function name for setting targets --- plugins/lua/autochop.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/autochop.lua b/plugins/lua/autochop.lua index e6f8e7008..6b8c9f943 100644 --- a/plugins/lua/autochop.lua +++ b/plugins/lua/autochop.lua @@ -63,7 +63,7 @@ function parse_commandline(...) elseif command == 'undesignate' then autochop_undesignate() elseif command == 'target' then - setTarget(args[2], args[3]) + setTargets(args[2], args[3]) elseif command == 'chop' then do_set_burrow_config('chop', true, args[2]) elseif command == 'nochop' then From cd114603f4fcb02db56d83fac5cf18a4f01b2140 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 14 Jan 2023 21:34:25 -0500 Subject: [PATCH 24/80] pre-commit: fix path to Authors.rst --- .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 6b23e9cdd..669a08db9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,6 +39,6 @@ repos: name: Check Authors.rst language: python entry: python3 ci/authors-rst.py - files: docs/Authors\.rst + files: docs/about/Authors\.rst pass_filenames: false exclude: '^(depends/|data/.*\.json$|.*\.diff$)' From b0d6f6a3c39c8868c27a26f92d87be8f81ae4ab8 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 14 Jan 2023 21:48:50 -0500 Subject: [PATCH 25/80] Update Authors.rst Missing authors since 0.47.05-r5 --- docs/about/Authors.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/about/Authors.rst b/docs/about/Authors.rst index 280594674..b0031607a 100644 --- a/docs/about/Authors.rst +++ b/docs/about/Authors.rst @@ -13,6 +13,7 @@ Name Github Other Abel abstern acwatkins acwatkins Alexander Gavrilov angavrilov ag +Amber Brown hawkowl Amostubal Amostubal Andrea Cattaneo acattaneo88 AndreasPK AndreasPK @@ -46,10 +47,12 @@ David Corbett dscorbett David Seguin dseguin David Timm dtimm Deon +dikbut Tjudge1 DoctorVanGogh DoctorVanGogh Donald Ruegsegger hashaash doomchild doomchild DwarvenM DwarvenM +EarthPulseAcademy EarthPulseAcademy ElMendukol ElMendukol enjia2000 Eric Wald eswald @@ -66,8 +69,10 @@ Guilherme Abraham GuilhermeAbraham Harlan Playford playfordh Hayati Ayguen hayguen Herwig Hochleitner bendlas +Hevlikn Hevlikn Ian S kremlin- IndigoFenix +James 20k James Gilles kazimuth James Logsdon jlogsdon Jared Adams @@ -80,14 +85,18 @@ Joel Meador janxious John Beisley huin John Shade gsvslto Jonas Ask +Jonathan Clark AridTag Josh Cooper cppcooper coope +jowario jowario kane-t kane-t Kelly Kinkade ab9rf +Kib Arekatír arekatir KlonZK KlonZK Kris Parker kaypy Kristjan Moore kristjanmoore Kromtec Kromtec Kurik Amudnil +Kévin Boissonneault KABoissonneault Lethosor lethosor LordGolias LordGolias Mark Nielson pseudodragon @@ -111,6 +120,7 @@ Milo Christiansen milochristiansen MithrilTuxedo MithrilTuxedo mizipzor mizipzor moversti moversti +Murad Beybalaev Erquint Myk Taylor myk002 napagokc napagokc Neil Little nmlittle @@ -119,7 +129,10 @@ Nicolas Ayala nicolasayala Nik Nyby nikolas Nikolay Amiantov abbradar nocico nocico +NotRexButCaesar NotRexButCaesar +Nuno Fernandes UnknowableCoder Omniclasm +oorzkws oorzkws OwnageIsMagic OwnageIsMagic palenerd dlmarquis PassionateAngler PassionateAngler @@ -133,6 +146,7 @@ Pierre-David Bélanger pierredavidbelanger potato Priit Laes plaes Putnam Putnam3145 +quarque2 quarque2 Quietust quietust _Q Rafał Karczmarczyk CarabusX Raidau Raidau @@ -145,6 +159,7 @@ reverb Rich Rauenzahn rrauenza Rinin Rinin rndmvar rndmvar +Rob Bailey actionninja Robert Heinrich rh73 Robert Janetzko robertjanetzko Rocco Moretti roccomoretti @@ -165,8 +180,10 @@ scamtank scamtank Sebastian Wolfertz Enkrod seishuuu seishuuu Seth Woodworth sethwoodworth +Shim Panze Shim-Panze simon Simon Jackson sizeak +Simon Lees simotek stolencatkarma Stoyan Gaydarov sgayda2 Su Moth-Tolias @@ -198,6 +215,7 @@ Vjek vjek Warmist warmist Wes Malone wesQ3 Will Rogers wjrogers +WoosterUK WoosterUK ZechyW ZechyW Zhentar Zhentar zilpin zilpin From 6a107ba68b4388ec7093ac204f1138d391843078 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 14 Jan 2023 21:48:50 -0500 Subject: [PATCH 26/80] Update links to compilation docs from remaining pages Ref #2517 --- docs/Installing.rst | 4 ++-- index.rst | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Installing.rst b/docs/Installing.rst index 05db198b8..bc58a39b7 100644 --- a/docs/Installing.rst +++ b/docs/Installing.rst @@ -50,7 +50,7 @@ The GCC 4.8 build is built on Ubuntu 14.04 and targets an older glibc, so it should work on older distributions. In the event that none of the provided binaries work on your distribution, -you may need to `compile DFHack from source `. +you may need to `compile DFHack from source `. macOS ----- @@ -86,7 +86,7 @@ restrictions apply (e.g. a file named ``Windows64`` is for 64-bit Windows DF). or by clicking "Download ZIP" on the repo homepage. This will give you an incomplete copy of the DFHack source code, which will not work as-is. (If you want to compile DFHack instead of using a pre-built release, see - `compile` for instructions.) + `building-dfhack-index` for instructions.) Installing DFHack ================= diff --git a/index.rst b/index.rst index af0f76052..cf808a59e 100644 --- a/index.rst +++ b/index.rst @@ -17,7 +17,7 @@ Quick Links * `Installation guide ` * `Getting help ` * :source:`Source code <>` - (**important:** read `compile` before attempting to build from source.) + (**important:** read `building-dfhack-index` before attempting to build from source.) User Manual =========== From 698c467f6ad059f0a18a9cf4cafcd21bdf81d398 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Jan 2023 23:56:30 -0800 Subject: [PATCH 27/80] add quickstart help --- docs/Quickstart.rst | 167 ++++++++++++++++++++++++++++++++++++++++++++ index.rst | 2 + 2 files changed, 169 insertions(+) create mode 100644 docs/Quickstart.rst diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst new file mode 100644 index 000000000..c61658f35 --- /dev/null +++ b/docs/Quickstart.rst @@ -0,0 +1,167 @@ +.. _quickstart: + +Quickstart guide +================ + +Welcome to DFHack! This guide will help get you oriented with the DFHack system +and teach you how to find and use the tools productively. If you're reading this +in `dfhack-quickstart-guide`, hit the right arrow key or click on the hotkey +hint in the lower right corner of the window to go to the next page. + +What is DFHack? +--------------- + +DFHack is a framework for Dwarf Fortress that provides a unified, cross-platform +environment that enables mods and tools to significantly extend the game. The +default DFHack distribution contains a variety of tools, including bugfixes, +interface improvements, automation agents, design blueprints, modding tools, and +more. Third-party tools (e.g. mods downloaded from Steam Workshop or the forums) +can also seamlessly integrate with the DFHack framework and extend the game far +beyond what can be done by just modding the raws. + +DFHack's mission is to provide tools and interfaces for players and modders to: +- expand the bounds of what is possible in Dwarf Fortress +- reduce the impact of game bugs +- give the player more agency and control over the game +- provide alternatives to toilsome or frustrating aspects of gameplay +- overall, make the game more fun + +What can I do with DFHack tools? +-------------------------------- + +DFHack has been around for a long time -- almost as long as Dwarf Fortress +itself. Many of the game's rough edges have been smoothed with DFHack tools. +Here are some common tasks people use DFHack tools to accomplish: + +- Automatically chop trees when log stocks are low +- Record fortress layouts in blueprint files and later play them back in + different forts +- Import and export lists of manager orders +- Clean contaminants from map squares that dwarves can't reach +- Automatically butcher excess livestock so you don't become overrun with + animals +- Promote time-sensitive job types (e.g. food hauling) so they are done + expediently +- Quickly scan the map for visible ores of specific types so you can focus + your mining + +Some tools are one-shot commands. For example, you can run `unforbid all ` +to claim all 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 preventing your chefs from cooking seeds that you need for planting. +Enableable tools that affect a fort save their state with the fort and will +remember that they are enabled the next time you load your save. + +Other 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). These overlays +can be configured with the `gui/overlay` tool. + +How can I figure out which commands to run? +------------------------------------------- + +There are several ways to scan DFHack tools and find the one 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` tool. + +When you hover the mouse over the logo (or hit the :kbd:`Ctrl`:kbd:`Shift`:kbd:`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 global hotkey you can hit to invoke the command without +even opening the hover list. + +You can run any DFHack tool from `gui/launcher`, which is always listed first in +the hover list. You can also bring up the launcher by tapping the backtick key +(\`) or hitting :kbd:`Ctrl`:kbd:`Shift`:kbd:`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 :kbd:`Alt`:kbd:`S` (or by clicking on the "history search" hotkey hint). + +Once you have typed (or autocompleted, or searched for) a command name, other +commands related to the one you have selected will appear in the autocomplete list. +Scanning through the related tools 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. + +How do DFHack in-game windows work? +----------------------------------- + +Many DFHack tools have graphical interfaces that appear in-game. You can tell +which windows belong to DFHack tools because they will have the word "DFHack" +printed across their bottom frame. DFHack provides a custom windowing system +that gives the player a lot of control over where the windows appear and whether +they capture keyboard and mouse input. + +The DFHack windowing system allows you to use DFHack tools without interrupting +the game. That is, if the game is unpaused, it will continue to run while a +DFHack window is open. You can also interact with the map, scrolling it with the +keyboard or mouse and selecting units, buildings, and items. Some tools will +force-pause the game if it make sense to. + +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 be reasonably resized). DFHack windows +close with :kbd:`Esc` or a right mouse click, but if you want to keep a DFHack +tool open while you interact with the game, you can hit :kbd:`Alt`:kbd:`L` or +click the pin in the upper right corner of the DFHack window so that it turns +green. The DFHack window will then ignore :kbd:`Esc` button presses and right +clicks that would otherwise close the window. Note that you can still right +click *on* the DFHack tool window to close it, even when it is pinned. + +You can have multiple DFHack tool windows on the screen at the same time. The +one that is receiving keyboard input has a highlighted title bar and will appear +over other windows if dragged over them. Clicking on a DFHack window that is not +currently active will bring it to the foreground and make it the active window. + +Where do I go next? +------------------- + +To recap: + +You can get to popular, relevant tools for the current context by hovering +the mouse over DFHack logo or by hitting :kbd:`Ctrl`:kbd:`Shift`:kbd:`C`. + +You can get to the launcher and its integrated autocomplete, history search, +and help text by hitting backtick (\`) or :kbd:`Ctrl`:kbd:`Shift`:kbd:`D`, +or, of course, by running it from the logo hover list. + +You can list and start tools that run in the background with the `enable` +command. + +You can configure screen overlays with the `gui/overlay` tool. + +With those four tools, 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 from the launcher. + +First, let's import some useful manager orders to keep your fort stocked with +basic necessities. Run ``orders import library/basic``. If you go to your +mangager orders screen, you can see all the orders that have been created for you. + +Next, try setting up `autochop` by running the GUI configuration `gui/autochop`. +You can enable it from the GUI, so you don't need to run `enable autochop ` +directly. You can set a target number of logs, and let autochop will manage +your logging industry for you. You can control where your woodsdwarves go to +cut down trees by setting up burrows and configuring autochop to only cut in +those burrows. + +Finally, let's set up a water supply for your fort with `gui/quickfort`. Launching +`gui/quickfort` will give you a list of blueprints you can load. Type in ``aquifer_tap`` +to filter for just those blueprints. Select the ``aquifer_tap -n /help`` blueprint +to see the instructions for how to build an aquifer tap. Then, go back and load the +``aquifer_tap -n /dig`` blueprint, find some space in a light aquifer layer, and +apply the blueprint there. It was that easy! + +There are many more tools to explore. Have fun! diff --git a/index.rst b/index.rst index af0f76052..2792e2d9a 100644 --- a/index.rst +++ b/index.rst @@ -15,6 +15,7 @@ Quick Links * `Downloads `_ * `Installation guide ` +* `quickstart` * `Getting help ` * :source:`Source code <>` (**important:** read `compile` before attempting to build from source.) @@ -26,6 +27,7 @@ User Manual :maxdepth: 2 /docs/Introduction + /docs/Quickstart /docs/Installing /docs/Core /docs/Tools From 121ab059c8628f9988681b841f3e0b77dc506b18 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Jan 2023 23:58:18 -0800 Subject: [PATCH 28/80] update changelog --- docs/changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 08aa39951..64ae81399 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: ## Documentation - `overlay-dev-guide`: added troubleshooting tips and common development workflows - added DFHack architecture diagrams to the dev intro +- added DFHack Quickstart guide ## API - ``Gui::getDwarfmodeDims``: now only returns map viewport dimensions; menu dimensions are obsolete From ab52d7a4ca19e5c08fbb0329082620b38a66b43e Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sat, 14 Jan 2023 23:59:01 -0800 Subject: [PATCH 29/80] remove extra whitespace --- docs/Quickstart.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst index c61658f35..ac7309d9a 100644 --- a/docs/Quickstart.rst +++ b/docs/Quickstart.rst @@ -19,7 +19,7 @@ more. Third-party tools (e.g. mods downloaded from Steam Workshop or the forums) can also seamlessly integrate with the DFHack framework and extend the game far beyond what can be done by just modding the raws. -DFHack's mission is to provide tools and interfaces for players and modders to: +DFHack's mission is to provide tools and interfaces for players and modders to: - expand the bounds of what is possible in Dwarf Fortress - reduce the impact of game bugs - give the player more agency and control over the game From 22e0f4325c18702ea6ea0431ea81b26c7901f6eb Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 00:49:11 -0800 Subject: [PATCH 30/80] wording --- docs/Quickstart.rst | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst index ac7309d9a..0e7f82c55 100644 --- a/docs/Quickstart.rst +++ b/docs/Quickstart.rst @@ -34,8 +34,7 @@ itself. Many of the game's rough edges have been smoothed with DFHack tools. Here are some common tasks people use DFHack tools to accomplish: - Automatically chop trees when log stocks are low -- Record fortress layouts in blueprint files and later play them back in - different forts +- Record blueprint files that allow copy and paste of fort designs - Import and export lists of manager orders - Clean contaminants from map squares that dwarves can't reach - Automatically butcher excess livestock so you don't become overrun with @@ -54,12 +53,12 @@ seeds and preventing your chefs from cooking seeds that you need for planting. Enableable tools that affect a fort save their state with the fort and will remember that they are enabled the next time you load your save. -Other 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). These overlays -can be configured with the `gui/overlay` tool. +And still other 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). +These overlays can be configured with the `gui/overlay` tool. How can I figure out which commands to run? ------------------------------------------- From d14a3b2c8312ed42f74a85c6c4b4b52c9c0b9d19 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 00:49:30 -0800 Subject: [PATCH 31/80] ensure the untested warning doesn't bork on bad scripts --- library/lua/dfhack.lua | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 26794eedf..df6302b82 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -698,11 +698,14 @@ local valid_script_flags = { local warned_scripts = {} function dfhack.run_script(name,...) - if not warned_scripts[name] and require('helpdb').get_entry_tags(name).untested then - warned_scripts[name] = true - dfhack.printerr(('UNTESTED WARNING: the "%s" script has not been validated to work well with this version of DF.'):format(name)) - dfhack.printerr('It may not work as expected, or it may corrupt your game.') - qerror('Please run the command again to ignore this warning and proceed.') + if not warned_scripts[name] then + local helpdb = require('helpdb') + if helpdb.is_entry(name) and helpdb.get_entry_tags(name).untested then + warned_scripts[name] = true + dfhack.printerr(('UNTESTED WARNING: the "%s" script has not been validated to work well with this version of DF.'):format(name)) + dfhack.printerr('It may not work as expected, or it may corrupt your game.') + qerror('Please run the command again to ignore this warning and proceed.') + end end return dfhack.run_script_with_env(nil, name, nil, ...) From de8815c85c2fc72dcacd03aa9efc944cf0a7783d Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 10:39:06 -0800 Subject: [PATCH 32/80] apply suggestions from the good people on discord --- docs/Quickstart.rst | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst index 0e7f82c55..ed2707c45 100644 --- a/docs/Quickstart.rst +++ b/docs/Quickstart.rst @@ -107,17 +107,22 @@ The DFHack windowing system allows you to use DFHack tools without interrupting the game. That is, if the game is unpaused, it will continue to run while a DFHack window is open. You can also interact with the map, scrolling it with the keyboard or mouse and selecting units, buildings, and items. Some tools will -force-pause the game if it make sense to. +force-pause the game if it makes sense to, like `gui/quickfort`, since you cannot +interact with the map normally while placing a blueprint. 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 be reasonably resized). DFHack windows -close with :kbd:`Esc` or a right mouse click, but if you want to keep a DFHack -tool open while you interact with the game, you can hit :kbd:`Alt`:kbd:`L` or -click the pin in the upper right corner of the DFHack window so that it turns -green. The DFHack window will then ignore :kbd:`Esc` button presses and right -clicks that would otherwise close the window. Note that you can still right -click *on* the DFHack tool window to close it, even when it is pinned. +(if the tool window has components that can be reasonably resized). + +DFHack windows close with a right mouse click or keyboard :kbd:`Esc`, but if you +want to keep a DFHack tool open while you interact with the game, you can click the +pin in the upper right corner of the DFHack window or hit :kbd:`Alt`:kbd:`L` so +that the pin turns green. The DFHack window will then ignore right clicks and +:kbd:`Esc` key presses that would otherwise close the window. This is especially +useful for the configuration tool windows for the automation tools. For example, +you can pin the `gui/autochop` window and let it sit there monitoring your +logging industry as you play, using it as a live status window. Note that you can +still right click *on* the DFHack tool window to close it, even when it is pinned. You can have multiple DFHack tool windows on the screen at the same time. The one that is receiving keyboard input has a highlighted title bar and will appear From caf533c3c3e3e7aec6b0de8580441a0be150e7d5 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Sun, 15 Jan 2023 21:38:11 +0000 Subject: [PATCH 33/80] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 8064f7160..a370b2ff6 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 8064f71601664fb841f830850ce390092e685276 +Subproject commit a370b2ff60988e832af5955ae4288d4118a9a26e From b855170c64a3f4595297ed9f9bd14438afb7e6d2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 13:42:26 -0800 Subject: [PATCH 34/80] fix typos in quickstart guide --- docs/Quickstart.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst index ed2707c45..f9e929b14 100644 --- a/docs/Quickstart.rst +++ b/docs/Quickstart.rst @@ -20,6 +20,7 @@ can also seamlessly integrate with the DFHack framework and extend the game far beyond what can be done by just modding the raws. DFHack's mission is to provide tools and interfaces for players and modders to: + - expand the bounds of what is possible in Dwarf Fortress - reduce the impact of game bugs - give the player more agency and control over the game @@ -49,7 +50,7 @@ to claim all 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 preventing your chefs from cooking seeds that you need for planting. +seeds and prevent your chefs from cooking seeds that you need for planting. Enableable tools that affect a fort save their state with the fort and will remember that they are enabled the next time you load your save. @@ -135,7 +136,7 @@ Where do I go next? To recap: You can get to popular, relevant tools for the current context by hovering -the mouse over DFHack logo or by hitting :kbd:`Ctrl`:kbd:`Shift`:kbd:`C`. +the mouse over the DFHack logo or by hitting :kbd:`Ctrl`:kbd:`Shift`:kbd:`C`. You can get to the launcher and its integrated autocomplete, history search, and help text by hitting backtick (\`) or :kbd:`Ctrl`:kbd:`Shift`:kbd:`D`, @@ -156,7 +157,7 @@ mangager orders screen, you can see all the orders that have been created for yo Next, try setting up `autochop` by running the GUI configuration `gui/autochop`. You can enable it from the GUI, so you don't need to run `enable autochop ` -directly. You can set a target number of logs, and let autochop will manage +directly. You can set a target number of logs, and autochop will manage your logging industry for you. You can control where your woodsdwarves go to cut down trees by setting up burrows and configuring autochop to only cut in those burrows. From 20f865eba0a5f9748aa191b083495291897e0c07 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 15:59:09 -0800 Subject: [PATCH 35/80] don't reset scroll pos when window is resized or moved --- docs/changelog.txt | 1 + library/lua/gui/widgets.lua | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/docs/changelog.txt b/docs/changelog.txt index 64ae81399..0deac83e8 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 +- ``widgets.WrappedLabel``: no longer resets scroll position when window is moved or resized ## Misc Improvements - Scrollable widgets now react to mouse wheel events when the mouse is over the widget diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index e3cdfc808..73de5ad4d 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -1366,6 +1366,10 @@ function WrappedLabel:getWrappedText(width) return text_to_wrap:wrap(width - self.indent) end +function WrappedLabel:preUpdateLayout() + self.saved_start_line_num = self.start_line_num +end + -- we can't set the text in init() since we may not yet have a frame that we -- can get wrapping bounds from. function WrappedLabel:postComputeFrame() @@ -1378,6 +1382,7 @@ function WrappedLabel:postComputeFrame() table.insert(text, NEWLINE) end self:setText(text) + self:scroll(self.saved_start_line_num - 1) end ------------------ From 65ceb565f89327fb2bac3dffd751eb4e3d76d735 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 16:30:55 -0800 Subject: [PATCH 36/80] rename dfhack-quickstart-guide -> quickstart-guide --- docs/Quickstart.rst | 4 ++-- scripts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst index f9e929b14..31aadfd3f 100644 --- a/docs/Quickstart.rst +++ b/docs/Quickstart.rst @@ -5,8 +5,8 @@ Quickstart guide Welcome to DFHack! This guide will help get you oriented with the DFHack system and teach you how to find and use the tools productively. If you're reading this -in `dfhack-quickstart-guide`, hit the right arrow key or click on the hotkey -hint in the lower right corner of the window to go to the next page. +in `quickstart-guide`, hit the right arrow key or click on the hotkey hint in +the lower right corner of the window to go to the next page. What is DFHack? --------------- diff --git a/scripts b/scripts index a370b2ff6..11d5ac853 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit a370b2ff60988e832af5955ae4288d4118a9a26e +Subproject commit 11d5ac853dbf708e994323e4e1b78a2298c977fe From 86ddf43230d2d9d249422c161fa12f998b1b1f21 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 20:17:23 -0800 Subject: [PATCH 37/80] add hotkey for launching the quickstart guide from the hover menu --- plugins/lua/hotkeys.lua | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index 2fb32a692..2ec38fff6 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -140,12 +140,18 @@ function Menu:init() local choices,list_width = get_choices(hotkeys, bindings, is_inverted) local list_frame = copyall(self.hotspot_frame) + local list_widget_frame = {h=math.min(#choices, MAX_LIST_HEIGHT)} + local quickstart_frame = {} list_frame.w = list_width + 2 - list_frame.h = math.min(#choices, MAX_LIST_HEIGHT) + 2 + list_frame.h = list_widget_frame.h + 4 if list_frame.t then list_frame.t = math.max(0, list_frame.t - 1) + list_widget_frame.t = 0 + quickstart_frame.b = 0 else list_frame.b = math.max(0, list_frame.b - 1) + list_widget_frame.b = 0 + quickstart_frame.t = 0 end if list_frame.l then list_frame.l = math.max(0, list_frame.l + 5) @@ -161,21 +167,30 @@ function Menu:init() end self:addviews{ - widgets.ResizingPanel{ + widgets.Panel{ view_id='list_panel', - autoarrange_subviews=true, frame=list_frame, frame_style=gui.GREY_LINE_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'}) + end, + }, }, }, widgets.ResizingPanel{ @@ -247,6 +262,7 @@ function Menu:onRenderFrame(dc, rect) self.initialize() self.initialize = nil end + Menu.super.onRenderFrame(dc, rect) end function Menu:getMouseFramePos() From fb5675ef1bbe34a13f5e77f5d2d092366ac9336c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 20:41:48 -0800 Subject: [PATCH 38/80] keep windows on the screen when the DF window is resized --- library/lua/gui/widgets.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 73de5ad4d..f56eff096 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -456,6 +456,20 @@ end function Panel:computeFrame(parent_rect) local sw, sh = parent_rect.width, parent_rect.height + if self.frame then + if self.frame.t and self.frame.h and self.frame.t + self.frame.h > sh then + self.frame.t = math.max(0, sh - self.frame.h) + end + if self.frame.b and self.frame.h and self.frame.b + self.frame.h > sh then + self.frame.b = math.max(0, sh - self.frame.h) + end + if self.frame.l and self.frame.w and self.frame.l + self.frame.w > sw then + self.frame.l = math.max(0, sw - self.frame.w) + end + if self.frame.r and self.frame.w and self.frame.r + self.frame.w > sw then + self.frame.r = math.max(0, sw - self.frame.w) + end + end return gui.compute_frame_body(sw, sh, self.frame, self.frame_inset, self.frame_style and 1 or 0) end From e7a30a9af8a8c8e47ef76789644ad906dd82735f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 22:23:29 -0800 Subject: [PATCH 39/80] sync tested spreadsheet to docs --- docs/plugins/cleanconst.rst | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/cleanconst.rst b/docs/plugins/cleanconst.rst index 420635fe2..12b1db0e5 100644 --- a/docs/plugins/cleanconst.rst +++ b/docs/plugins/cleanconst.rst @@ -3,7 +3,7 @@ cleanconst .. dfhack-tool:: :summary: Cleans up construction materials. - :tags: untested fort fps buildings + :tags: fort fps buildings This tool alters all constructions on the map so that they spawn their building component when they are disassembled, allowing their actual build items to be diff --git a/scripts b/scripts index 11d5ac853..59a10f9e0 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 11d5ac853dbf708e994323e4e1b78a2298c977fe +Subproject commit 59a10f9e072e54da2b8fee7dac6e0ada639eb67b From 50cc6d965dd4ede112432ff3a202204ce6716a66 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 23:13:58 -0800 Subject: [PATCH 40/80] update to new save directory structure --- ci/download-df.sh | 6 +++--- docs/Core.rst | 14 ++++++-------- docs/guides/modding-guide.rst | 3 +-- library/Core.cpp | 8 +++----- library/lua/dfhack.lua | 2 +- plugins/autogems.cpp | 2 +- plugins/rendermax/renderer_light.cpp | 4 ++-- plugins/tweak/tweaks/title-start-rename.h | 2 +- 8 files changed, 18 insertions(+), 23 deletions(-) diff --git a/ci/download-df.sh b/ci/download-df.sh index bb1e91759..8d94d54dd 100755 --- a/ci/download-df.sh +++ b/ci/download-df.sh @@ -23,7 +23,7 @@ if ! test -f "$df_tardest"; then fi done <}/raw/scripts` (only if a save is loaded) -#. :file:`raw/scripts` +#. :file:`save/{world}/scripts` (only if a save is loaded) #. :file:`hack/scripts` For example, if ``teleport`` is run, these folders are searched in order for -``teleport.lua`` or ``teleport.rb``, and the first matching file is run. +``teleport.lua``, and the first matching file is run. Script paths can be added by modifying :file:`dfhack-config/script-paths.txt`. Each line should start with one of these characters: diff --git a/docs/guides/modding-guide.rst b/docs/guides/modding-guide.rst index 9fe62bf6a..ab52e0288 100644 --- a/docs/guides/modding-guide.rst +++ b/docs/guides/modding-guide.rst @@ -61,8 +61,7 @@ be: 1. ``own-scripts/`` 2. ``dfhack-config/scripts/`` -3. ``data/save/*/raw/scripts/`` -4. ``raw/scripts/`` +3. ``save/*/scripts/`` 5. ``hack/scripts/`` The structure of the game diff --git a/library/Core.cpp b/library/Core.cpp index 78257a262..e2c983116 100644 --- a/library/Core.cpp +++ b/library/Core.cpp @@ -472,9 +472,8 @@ void Core::getScriptPaths(std::vector *dest) if (df::global::world && isWorldLoaded()) { string save = World::ReadWorldFolder(); if (save.size()) - dest->push_back(df_path + "/data/save/" + save + "/raw/scripts"); + dest->push_back(df_path + "/save/" + save + "/scripts"); } - dest->push_back(df_path + "/raw/scripts"); dest->push_back(df_path + "/hack/scripts"); for (auto it = script_paths[1].begin(); it != script_paths[1].end(); ++it) dest->push_back(*it); @@ -2053,7 +2052,7 @@ void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event eve if (!df::global::world) return; - std::string rawFolder = "data/save/" + (df::global::world->cur_savegame.save_dir) + "/raw/"; + std::string rawFolder = "save/" + (df::global::world->cur_savegame.save_dir) + "/init"; auto i = table.find(event); if ( i != table.end() ) { @@ -2064,7 +2063,6 @@ void Core::handleLoadAndUnloadScripts(color_ostream& out, state_change_event eve loadScriptFiles(this, out, set, CONFIG_PATH + "init"); loadScriptFiles(this, out, set, rawFolder); - loadScriptFiles(this, out, set, rawFolder + "objects/"); } for (auto it = state_change_scripts.begin(); it != state_change_scripts.end(); ++it) @@ -2125,7 +2123,7 @@ void Core::onStateChange(color_ostream &out, state_change_event event) case SC_MAP_UNLOADED: if (world && world->cur_savegame.save_dir.size()) { - std::string save_dir = "data/save/" + world->cur_savegame.save_dir; + std::string save_dir = "save/" + world->cur_savegame.save_dir; std::string evtlogpath = save_dir + "/events-dfhack.log"; std::ofstream evtlog; evtlog.open(evtlogpath, std::ios_base::app); // append diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index df6302b82..a4d233a9e 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -871,7 +871,7 @@ end function dfhack.getSavePath() if dfhack.isWorldLoaded() then - return dfhack.getDFPath() .. '/data/save/' .. df.global.world.cur_savegame.save_dir + return dfhack.getDFPath() .. '/save/' .. df.global.world.cur_savegame.save_dir end end diff --git a/plugins/autogems.cpp b/plugins/autogems.cpp index 8cf419aba..87eaafd16 100644 --- a/plugins/autogems.cpp +++ b/plugins/autogems.cpp @@ -299,7 +299,7 @@ IMPLEMENT_VMETHOD_INTERPOSE(autogem_hook, feed); IMPLEMENT_VMETHOD_INTERPOSE(autogem_hook, render); bool read_config(color_ostream &out) { - std::string path = "data/save/" + World::ReadWorldFolder() + "/autogems.json"; + std::string path = "save/" + World::ReadWorldFolder() + "/autogems.json"; if (!Filesystem::isfile(path)) { // no need to require the config file to exist return true; diff --git a/plugins/rendermax/renderer_light.cpp b/plugins/rendermax/renderer_light.cpp index 428de3a25..d806d0c3e 100644 --- a/plugins/rendermax/renderer_light.cpp +++ b/plugins/rendermax/renderer_light.cpp @@ -1171,11 +1171,11 @@ void lightingEngineViewscreen::loadSettings() std::string rawFolder; if(df::global::world->cur_savegame.save_dir!="") { - rawFolder= "data/save/" + (df::global::world->cur_savegame.save_dir) + "/raw/"; + rawFolder= "save/" + (df::global::world->cur_savegame.save_dir) + "/"; } else { - rawFolder= "raw/"; + rawFolder= "dfhack-config/"; } const std::string settingsfile=rawFolder+"rendermax.lua"; diff --git a/plugins/tweak/tweaks/title-start-rename.h b/plugins/tweak/tweaks/title-start-rename.h index baa1552ab..289979be4 100644 --- a/plugins/tweak/tweaks/title-start-rename.h +++ b/plugins/tweak/tweaks/title-start-rename.h @@ -17,7 +17,7 @@ struct title_start_rename_hook : df::viewscreen_titlest { inline std::string full_save_dir(const std::string ®ion_name) { - return std::string("data/save/") + region_name; + return std::string("save/") + region_name; } bool do_rename() From 762cd46d14be7738464c430ec4919092882654e4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 23:28:01 -0800 Subject: [PATCH 41/80] look for init.d directories in the root instead of raw/ --- docs/Core.rst | 6 +++--- docs/dev/Lua API.rst | 4 ++-- docs/guides/modding-guide.rst | 14 +++++++------- library/lua/dfhack.lua | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/Core.rst b/docs/Core.rst index 28e20a827..86e357b27 100644 --- a/docs/Core.rst +++ b/docs/Core.rst @@ -216,10 +216,10 @@ after a modded save is unloaded. .. _other_init_files: -raw/init.d/\*.lua -................. +init.d/\*.lua +............. -Any lua script named ``raw/init.d/*.lua``, in the save or main DF directory, +Any lua script named ``init.d/*.lua``, in the save or main DF directory, will be run when any world or that save is loaded. diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 39bd57046..813406013 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5883,9 +5883,9 @@ all script modules. Save init script ================ -If a save directory contains a file called ``raw/init.lua``, it is +If a save directory contains a file called ``init.lua``, it is automatically loaded and executed every time the save is loaded. -The same applies to any files called ``raw/init.d/*.lua``. Every +The same applies to any files called ``init.d/*.lua``. Every such script can define the following functions to be called by dfhack: * ``function onStateChange(op) ... end`` diff --git a/docs/guides/modding-guide.rst b/docs/guides/modding-guide.rst index ab52e0288..224448cf1 100644 --- a/docs/guides/modding-guide.rst +++ b/docs/guides/modding-guide.rst @@ -358,7 +358,7 @@ names for the mod folders within it. In the example below, we'll use a mod ID of ``example-mod`` mod will be developed in the ``/path/to/mymods/example-mod/`` directory and has a basic structure that looks like this:: - raw/init.d/example-mod.lua + init.d/example-mod.lua raw/objects/... raw/scripts/example-mod.lua raw/scripts/example-mod/... @@ -366,13 +366,13 @@ directory and has a basic structure that looks like this:: Let's go through that line by line. -* A short (one-line) script in ``raw/init.d/`` to initialise your +* A short (one-line) script in ``init.d/`` to initialise your mod when a save is loaded. * Modifications to the game raws (potentially with custom raw tokens) go in ``raw/objects/``. -* A control script in ``raw/scripts/`` that handles enabling and disabling your +* A control script in ``scripts/`` that handles enabling and disabling your mod. -* A subfolder for your mod under ``raw/scripts/`` will contain all the internal +* A subfolder for your mod under ``scripts/`` will contain all the internal scripts and/or modules used by your mod. It is a good idea to use a version control system to organize changes to your @@ -384,10 +384,10 @@ Unless you want to install your ``raw/`` folder into your DF game folder every time you make a change to your scripts, you should add your development scripts directory to your script paths in ``dfhack-config/script-paths.txt``:: - +/path/to/mymods/example-mod/raw/scripts/ + +/path/to/mymods/example-mod/scripts/ Ok, you're all set up! Now, let's take a look at an example -``raw/scripts/example-mod.lua`` file:: +``scripts/example-mod.lua`` file:: -- main setup and teardown for example-mod -- this next line indicates that the script supports the "enable" @@ -474,7 +474,7 @@ Ok, you're all set up! Now, let's take a look at an example You can call ``enable example-mod`` and ``disable example-mod`` yourself while developing, but for end users you can start your mod automatically from -``raw/init.d/example-mod.lua``:: +``init.d/example-mod.lua``:: dfhack.run_command('enable example-mod') diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index a4d233a9e..e2cb7069b 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -905,14 +905,14 @@ if dfhack.is_core_context then local path = dfhack.getSavePath() if path and op == SC_WORLD_LOADED then - loadInitFile(path, path..'/raw/init.lua') + loadInitFile(path, path..'/init.lua') - local dirlist = dfhack.internal.getDir(path..'/raw/init.d/') + local dirlist = dfhack.internal.getDir(path..'/init.d/') if dirlist then table.sort(dirlist) for i,name in ipairs(dirlist) do if string.match(name,'%.lua$') then - loadInitFile(path, path..'/raw/init.d/'..name) + loadInitFile(path, path..'/init.d/'..name) end end end From a56d62e1dc86e281fe2e99e9910bb25c43d7182b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Sun, 15 Jan 2023 23:28:14 -0800 Subject: [PATCH 42/80] update changelog --- docs/changelog.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 0deac83e8..06c3975ca 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -42,6 +42,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Scrollable widgets now react to mouse wheel events when the mouse is over the widget - the ``dfhack-config/scripts/`` folder is now searched for scripts by default - `hotkeys`: overlay hotspot widget now shows the DFHack logo in graphics mode and "DFHack" in text mode +- `script-paths`: removed "raw" directories from default script paths. now the default locations to search for scripts are ``dfhack-config/scripts``, ``save/*/scripts``, and ``hack/scripts`` +- ``init.d``: directories have moved from the ``raw`` subfolder (which no longer exists) to the root of the main DF folder or a savegame folder ## Documentation - `overlay-dev-guide`: added troubleshooting tips and common development workflows @@ -69,8 +71,6 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - ``gui.CLEAR_PEN``: now clears the background and foreground and writes to the background (before it would always write to the foreground) - ``gui.KEEP_LOWER_PEN``: a general use pen that writes associated tiles to the foreground while keeping the existing background -## Internals - ## Removed - ``fix-job-postings`` from the `workflow` plugin is now obsolete since affected savegames can no longer be loaded - Ruby is no longer a supported DFHack scripting language From 6b039aac9d22954fed007c5d008d92f8ebab186b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Jan 2023 00:15:17 -0800 Subject: [PATCH 43/80] update Quickstart guide --- docs/Quickstart.rst | 124 +++++++++++++++++++++++++------------------- 1 file changed, 72 insertions(+), 52 deletions(-) diff --git a/docs/Quickstart.rst b/docs/Quickstart.rst index 31aadfd3f..f6f8920c2 100644 --- a/docs/Quickstart.rst +++ b/docs/Quickstart.rst @@ -13,11 +13,11 @@ What is DFHack? DFHack is a framework for Dwarf Fortress that provides a unified, cross-platform environment that enables mods and tools to significantly extend the game. The -default DFHack distribution contains a variety of tools, including bugfixes, -interface improvements, automation agents, design blueprints, modding tools, and -more. Third-party tools (e.g. mods downloaded from Steam Workshop or the forums) -can also seamlessly integrate with the DFHack framework and extend the game far -beyond what can be done by just modding the raws. +default DFHack distribution contains a wide variety of tools, including bugfixes, +interface improvements, automation agents, design blueprints, modding building +blocks, and more. Third-party tools (e.g. mods downloaded from Steam Workshop or +the forums) can also seamlessly integrate with the DFHack framework and extend +the game far beyond what can be done by just modding the raws. DFHack's mission is to provide tools and interfaces for players and modders to: @@ -25,7 +25,7 @@ DFHack's mission is to provide tools and interfaces for players and modders to: - reduce the impact of game bugs - give the player more agency and control over the game - provide alternatives to toilsome or frustrating aspects of gameplay -- overall, make the game more fun +- **make the game more fun** What can I do with DFHack tools? -------------------------------- @@ -43,7 +43,7 @@ Here are some common tasks people use DFHack tools to accomplish: - Promote time-sensitive job types (e.g. food hauling) so they are done expediently - Quickly scan the map for visible ores of specific types so you can focus - your mining + your mining efforts Some tools are one-shot commands. For example, you can run `unforbid all ` to claim all items on the map after a messy siege. @@ -51,15 +51,15 @@ to claim all 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. -Enableable tools that affect a fort save their state with the fort and will -remember that they are enabled the next time you load your save. +Tools that are enabled in the context of a fort will save their state with that +fort, and the will remember that they are enabled the next time you load your save. -And still other tools add information to the screen or provide new integrated +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). -These overlays can be configured with the `gui/overlay` tool. +These overlays can be enabled and configured with the `gui/overlay` interface. How can I figure out which commands to run? ------------------------------------------- @@ -70,26 +70,25 @@ 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` tool. -When you hover the mouse over the logo (or hit the :kbd:`Ctrl`:kbd:`Shift`:kbd:`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 global hotkey you can hit to invoke the command without -even opening the hover list. +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 global hotkey you can hit to invoke the command without even +opening the hover list. You can run any DFHack tool from `gui/launcher`, which is always listed first in the hover list. You can also bring up the launcher by tapping the backtick key -(\`) or hitting :kbd:`Ctrl`:kbd:`Shift`:kbd:`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 :kbd:`Alt`:kbd:`S` (or by clicking on the "history search" hotkey hint). - -Once you have typed (or autocompleted, or searched for) a command name, other -commands related to the one you have selected will appear in the autocomplete list. -Scanning through the related tools 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. +(\`) 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 autocomplete list. +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 @@ -100,7 +99,7 @@ How do DFHack in-game windows work? Many DFHack tools have graphical interfaces that appear in-game. You can tell which windows belong to DFHack tools because they will have the word "DFHack" -printed across their bottom frame. DFHack provides a custom windowing system +printed across their bottom frame edge. DFHack provides a custom windowing system that gives the player a lot of control over where the windows appear and whether they capture keyboard and mouse input. @@ -108,26 +107,28 @@ The DFHack windowing system allows you to use DFHack tools without interrupting the game. That is, if the game is unpaused, it will continue to run while a DFHack window is open. You can also interact with the map, scrolling it with the keyboard or mouse and selecting units, buildings, and items. Some tools will +capture all keyboard input, such as tools with editable text fields, and some will force-pause the game if it makes sense to, like `gui/quickfort`, since you cannot -interact with the map normally while placing a blueprint. +interact with the map normally while trying to apply a blueprint. 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 be reasonably resized). +(if the tool window has components that can reasonably be resized). -DFHack windows close with a right mouse click or keyboard :kbd:`Esc`, but if you +DFHack windows close with a right mouse click or keyboard Esc, but if you want to keep a DFHack tool open while you interact with the game, you can click the -pin in the upper right corner of the DFHack window or hit :kbd:`Alt`:kbd:`L` so +pin in the upper right corner of the DFHack window or hit Alt-L so that the pin turns green. The DFHack window will then ignore right clicks and -:kbd:`Esc` key presses that would otherwise close the window. This is especially +Esc key presses that would otherwise close the window. This is especially useful for the configuration tool windows for the automation tools. For example, -you can pin the `gui/autochop` window and let it sit there monitoring your -logging industry as you play, using it as a live status window. Note that you can -still right click *on* the DFHack tool window to close it, even when it is pinned. +you can pin the `gui/autochop` window, set it to minimal mode, and let it sit +there monitoring your logging industry as you play, using it as a live status +window. Note that you can still right click *on* the DFHack tool window to close +it, even when it is pinned. You can have multiple DFHack tool windows on the screen at the same time. The one that is receiving keyboard input has a highlighted title bar and will appear -over other windows if dragged over them. Clicking on a DFHack window that is not +over other windows if dragged across them. Clicking on a DFHack window that is not currently active will bring it to the foreground and make it the active window. Where do I go next? @@ -136,11 +137,11 @@ 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 :kbd:`Ctrl`:kbd:`Shift`:kbd:`C`. +the mouse over the DFHack logo or by hitting Ctrl-Shift-C. You can get to the launcher and its integrated autocomplete, history search, -and help text by hitting backtick (\`) or :kbd:`Ctrl`:kbd:`Shift`:kbd:`D`, -or, of course, by running it from the logo hover list. +and help text by hitting backtick (\`) or Ctrl-Shift-D, or, of course, by +running it from the logo hover list. You can list and start tools that run in the background with the `enable` command. @@ -149,7 +150,7 @@ You can configure screen overlays with the `gui/overlay` tool. With those four tools, 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 from the launcher. +You can run them all from the launcher. First, let's import some useful manager orders to keep your fort stocked with basic necessities. Run ``orders import library/basic``. If you go to your @@ -160,13 +161,32 @@ You can enable it from the GUI, so you don't need to run `enable autochop Date: Mon, 16 Jan 2023 00:15:36 -0800 Subject: [PATCH 44/80] update scripts head --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index 59a10f9e0..28f8aef51 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 59a10f9e072e54da2b8fee7dac6e0ada639eb67b +Subproject commit 28f8aef51277ebaa8923f381482ec161870609af From 00cee1c6002107637c5fc31c68a3da6408c6e4c5 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Jan 2023 11:03:51 -0800 Subject: [PATCH 45/80] fix numbered list --- docs/guides/modding-guide.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/modding-guide.rst b/docs/guides/modding-guide.rst index 224448cf1..73d9407d6 100644 --- a/docs/guides/modding-guide.rst +++ b/docs/guides/modding-guide.rst @@ -62,7 +62,7 @@ be: 1. ``own-scripts/`` 2. ``dfhack-config/scripts/`` 3. ``save/*/scripts/`` -5. ``hack/scripts/`` +4. ``hack/scripts/`` The structure of the game ------------------------- From 9c36c3978fe870c8fe1a8097bd126a91bb5d7f7c Mon Sep 17 00:00:00 2001 From: lethosor Date: Mon, 16 Jan 2023 16:06:00 -0500 Subject: [PATCH 46/80] Update xml, scripts --- library/xml | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/xml b/library/xml index ab0593b40..06906687f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ab0593b40a1a41c19432ec6bd88fc9ecf60b5fb6 +Subproject commit 06906687f89733032e5cc813bdc9acfdd2405f31 diff --git a/scripts b/scripts index 28f8aef51..64013d4b6 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 28f8aef51277ebaa8923f381482ec161870609af +Subproject commit 64013d4b65ee60f36191a7d442fc2c8ef1fc388d From e98271ddc389b54cd3514466116dfcd8acef2237 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Jan 2023 13:53:16 -0800 Subject: [PATCH 47/80] document that enableable scripts must also be modules --- docs/dev/Lua API.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 813406013..ab7d6434e 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -5812,9 +5812,13 @@ Enabling and disabling scripts ============================== Scripts can choose to recognize the built-in ``enable`` and ``disable`` commands -by including the following line anywhere in their file:: +by including the following line near the top of their file:: - --@ enable = true + --@enable = true + --@module = true + +Note that enableable scripts must also be `modules ` so their +``isEnabled()`` functions can be called from outside the script. When the ``enable`` and ``disable`` commands are invoked, the ``dfhack_flags`` table passed to the script will have the following fields set: @@ -5829,7 +5833,8 @@ command. Example usage:: - --@ enable = true + --@enable = true + --@module = true enabled = enabled or false function isEnabled() From 3958d376843f858c9056bed1a295a2508f49c271 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Jan 2023 16:56:31 -0800 Subject: [PATCH 48/80] update changelog and submodules for 50.05-alpha1 --- CMakeLists.txt | 2 +- docs/changelog.txt | 14 ++++++++++++++ library/xml | 2 +- scripts | 2 +- 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dcb5b42ff..49bb29f04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,7 +196,7 @@ endif() # set up versioning. set(DF_VERSION "50.05") -set(DFHACK_RELEASE "alpha0") +set(DFHACK_RELEASE "alpha1") set(DFHACK_PRERELEASE TRUE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/docs/changelog.txt b/docs/changelog.txt index 06c3975ca..a5d4ab434 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -35,6 +35,20 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins +## Fixes + +## Misc Improvements + +## Documentation + +## API + +## Lua + +## Removed + +# 50.05-alpha1 + ## Fixes - ``widgets.WrappedLabel``: no longer resets scroll position when window is moved or resized diff --git a/library/xml b/library/xml index 06906687f..9cd1b4ea9 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 06906687f89733032e5cc813bdc9acfdd2405f31 +Subproject commit 9cd1b4ea9ab99919a64f2dfaa0c776ab007ec2d4 diff --git a/scripts b/scripts index 64013d4b6..d3bc3b4d3 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 64013d4b65ee60f36191a7d442fc2c8ef1fc388d +Subproject commit d3bc3b4d379d3511a1aae51da7ccd6f553198195 From bb3f640afa36661dfd08b1b2996196df82e88f00 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Jan 2023 17:43:00 -0800 Subject: [PATCH 49/80] silence check for usefulness. it's useful. i get it --- plugins/autochop.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/autochop.cpp b/plugins/autochop.cpp index 0c20c0cb4..34a8979ff 100644 --- a/plugins/autochop.cpp +++ b/plugins/autochop.cpp @@ -522,10 +522,8 @@ static void scan_logs(int32_t *usable_logs, const vector &citizens, if (item->getType() != item_type::WOOD) continue; - if (!is_valid_item(item)) { - INFO(status).print("autochop is_valid_item actually caught something useful!! Please tell the DFHack team.\n"); + if (!is_valid_item(item)) continue; - } if (!is_accessible_item(item->pos, citizens)) { if (inaccessible_logs) From d6b69ca8fc7357c25c09f87a29a9ac427869ecbf Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Jan 2023 01:08:02 -0800 Subject: [PATCH 50/80] move useful functions from uicommon to MiscUtils --- library/include/MiscUtils.h | 31 ++++++++++++++++++++++++++----- plugins/uicommon.h | 18 ------------------ 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index d089640ef..124987535 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -23,17 +23,20 @@ distribution. */ #pragma once + #include "Export.h" + #include -#include -#include #include #include -#include -#include -#include #include +#include +#include +#include #include +#include +#include +#include #if defined(_MSC_VER) #define DFHACK_FUNCTION_SIG __FUNCSIG__ @@ -338,6 +341,24 @@ inline typename T::mapped_type map_find( return (it == map.end()) ? defval : it->second; } +template +static void for_each_(std::vector &v, Fn func) +{ + std::for_each(v.begin(), v.end(), func); +} + +template +static void for_each_(std::map &v, Fn func) +{ + std::for_each(v.begin(), v.end(), func); +} + +template +static void transform_(const std::vector &src, std::vector &dst, Fn func) +{ + std::transform(src.begin(), src.end(), std::back_inserter(dst), func); +} + DFHACK_EXPORT bool prefix_matches(const std::string &prefix, const std::string &key, std::string *tail = NULL); template diff --git a/plugins/uicommon.h b/plugins/uicommon.h index 03914b461..6179324d4 100644 --- a/plugins/uicommon.h +++ b/plugins/uicommon.h @@ -65,24 +65,6 @@ struct coord32_t } }; -template -static void for_each_(vector &v, Fn func) -{ - for_each(v.begin(), v.end(), func); -} - -template -static void for_each_(map &v, Fn func) -{ - for_each(v.begin(), v.end(), func); -} - -template -static void transform_(const vector &src, vector &dst, Fn func) -{ - transform(src.begin(), src.end(), back_inserter(dst), func); -} - typedef int8_t UIColor; static inline void OutputString(UIColor color, int &x, int &y, const std::string &text, From a96ddcec80d6bfae7a1256eca5bab81e2c1b3881 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Mon, 16 Jan 2023 23:49:11 -0800 Subject: [PATCH 51/80] add buildingplan skeleton --- plugins/CMakeLists.txt | 2 +- plugins/buildingplan.cpp | 166 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 plugins/buildingplan.cpp diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 661fa2624..e38c27125 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -89,7 +89,7 @@ dfhack_plugin(autofarm autofarm.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(buildingplan buildingplan.cpp LINK_LIBRARIES lua) #dfhack_plugin(changeitem changeitem.cpp) dfhack_plugin(changelayer changelayer.cpp) dfhack_plugin(changevein changevein.cpp) diff --git a/plugins/buildingplan.cpp b/plugins/buildingplan.cpp new file mode 100644 index 000000000..1688d7d55 --- /dev/null +++ b/plugins/buildingplan.cpp @@ -0,0 +1,166 @@ +#include "Core.h" +#include "Debug.h" +#include "PluginManager.h" + +#include "modules/Persistence.h" +#include "modules/World.h" + +#include "df/world.h" + +#include +#include + +using std::string; +using std::vector; + +using namespace DFHack; + +DFHACK_PLUGIN("buildingplan"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + +REQUIRE_GLOBAL(world); + +// logging levels can be dynamically controlled with the `debugfilter` command. +namespace DFHack { + // for configuration-related logging + DBG_DECLARE(buildingplan, status, DebugCategory::LINFO); + // for logging during the periodic scan + DBG_DECLARE(buildingplan, cycle, DebugCategory::LINFO); +} + +static const string CONFIG_KEY = string(plugin_name) + "/config"; +static PersistentDataItem config; +enum ConfigValues { + CONFIG_IS_ENABLED = 0, + CONFIG_BLOCKS = 1, + CONFIG_BOULDERS = 2, + CONFIG_LOGS = 3, + CONFIG_BARS = 4, +}; +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 = 600; // twice per game day +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); + + // provide a configuration interface for the plugin + commands.push_back(PluginCommand( + plugin_name, + "Plan building placement before you have materials.", + 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); + } 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) { + 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); + set_config_bool(CONFIG_BLOCKS, true); + set_config_bool(CONFIG_BOULDERS, true); + set_config_bool(CONFIG_LOGS, true); + set_config_bool(CONFIG_BARS, false); + } + + // 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) { + if (is_enabled && world->frame_counter - cycle_timestamp >= CYCLE_TICKS) + do_cycle(out); + return CR_OK; +} + +static command_result do_command(color_ostream &out, vector ¶meters) { + // be sure to suspend the core if any DF state is read or modified + CoreSuspender suspend; + + if (!Core::getInstance().isWorldLoaded()) { + out.printerr("Cannot run %s without a loaded world.\n", plugin_name); + return CR_FAILURE; + } + + // TODO: configuration logic + // simple commandline parsing can be done in C++, but there are lua libraries + // that can easily handle more complex commandlines. see the blueprint plugin + // for an example. + + return CR_OK; +} + +///////////////////////////////////////////////////// +// cycle logic +// + +static void do_cycle(color_ostream &out) { + // mark that we have recently run + cycle_timestamp = world->frame_counter; + + DEBUG(cycle,out).print("running %s cycle\n", plugin_name); + + // TODO: logic that runs every get_config_val(CONFIG_CYCLE_TICKS) ticks +} From bc42f7c73c7ef04ad376724563ed1e4fbb5ddd89 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 17 Jan 2023 04:05:17 -0800 Subject: [PATCH 52/80] get buildingplan minimally functional for quickfort --- plugins/buildingplan.cpp | 588 +++++++++++++++++++++++++++++++++-- plugins/lua/buildingplan.lua | 29 +- 2 files changed, 587 insertions(+), 30 deletions(-) diff --git a/plugins/buildingplan.cpp b/plugins/buildingplan.cpp index 1688d7d55..7080be4d5 100644 --- a/plugins/buildingplan.cpp +++ b/plugins/buildingplan.cpp @@ -1,16 +1,30 @@ #include "Core.h" #include "Debug.h" +#include "LuaTools.h" #include "PluginManager.h" +#include "modules/Items.h" +#include "modules/Job.h" +#include "modules/Materials.h" #include "modules/Persistence.h" #include "modules/World.h" +#include "df/building.h" +#include "df/building_design.h" +#include "df/item.h" +#include "df/job_item.h" #include "df/world.h" +#include #include #include +#include +using std::map; +using std::pair; +using std::queue; using std::string; +using std::unordered_map; using std::vector; using namespace DFHack; @@ -29,7 +43,8 @@ namespace DFHack { } static const string CONFIG_KEY = string(plugin_name) + "/config"; -static PersistentDataItem config; +static const string BLD_CONFIG_KEY = string(plugin_name) + "/building"; + enum ConfigValues { CONFIG_IS_ENABLED = 0, CONFIG_BLOCKS = 1, @@ -37,20 +52,76 @@ enum ConfigValues { CONFIG_LOGS = 3, CONFIG_BARS = 4, }; -static int get_config_val(int index) { - if (!config.isValid()) + +enum BuildingConfigValues { + BLD_CONFIG_ID = 0, +}; + +static int get_config_val(PersistentDataItem &c, int index) { + if (!c.isValid()) return -1; - return config.ival(index); + return c.ival(index); +} +static bool get_config_bool(PersistentDataItem &c, int index) { + return get_config_val(c, index) == 1; } -static bool get_config_bool(int index) { - return get_config_val(index) == 1; +static void set_config_val(PersistentDataItem &c, int index, int value) { + if (c.isValid()) + c.ival(index) = value; } -static void set_config_val(int index, int value) { - if (config.isValid()) - config.ival(index) = value; +static void set_config_bool(PersistentDataItem &c, int index, bool value) { + set_config_val(c, index, value ? 1 : 0); } -static void set_config_bool(int index, bool value) { - set_config_val(index, value ? 1 : 0); + +class PlannedBuilding { +public: + const df::building::key_field_type id; + + PlannedBuilding(color_ostream &out, df::building *building) : id(building->id) { + DEBUG(status,out).print("creating persistent data for building %d\n", id); + config = DFHack::World::AddPersistentData(BLD_CONFIG_KEY); + set_config_val(config, BLD_CONFIG_ID, id); + } + + PlannedBuilding(DFHack::PersistentDataItem &config) + : config(config), id(get_config_val(config, BLD_CONFIG_ID)) { } + + void remove(color_ostream &out); + + // Ensure the building still exists and is in a valid state. It can disappear + // for lots of reasons, such as running the game with the buildingplan plugin + // disabled, manually removing the building, modifying it via the API, etc. + df::building * getBuildingIfValidOrRemoveIfNot(color_ostream &out) { + auto bld = df::building::find(id); + bool valid = bld && bld->getBuildStage() == 0; + if (!valid) { + remove(out); + return NULL; + } + return bld; + } + +private: + DFHack::PersistentDataItem config; +}; + +static PersistentDataItem config; +// building id -> PlannedBuilding +unordered_map planned_buildings; +// vector id -> filter bucket -> queue of (building id, job_item index) +map>>> tasks; + +// note that this just removes the PlannedBuilding. the tasks will get dropped +// as we discover them in the tasks queues and they fail to be found in planned_buildings. +// this "lazy" task cleaning algorithm works because there is no way to +// re-register a building once it has been removed -- if it has been booted out of +// planned_buildings, then it has either been built or desroyed. therefore there is +// no chance of duplicate tasks getting added to the tasks queues. +void PlannedBuilding::remove(color_ostream &out) { + DEBUG(status,out).print("removing persistent data for building %d\n", id); + DFHack::World::DeletePersistentData(config); + if (planned_buildings.count(id) > 0) + planned_buildings.erase(id); } static const int32_t CYCLE_TICKS = 600; // twice per game day @@ -58,6 +129,7 @@ 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); +static bool registerPlannedBuilding(color_ostream &out, PlannedBuilding & pb); DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { DEBUG(status,out).print("initializing %s\n", plugin_name); @@ -81,7 +153,7 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) { 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); + set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); } else { DEBUG(status,out).print("%s from the API, but already %s; no action\n", is_enabled ? "enabled" : "disabled", @@ -102,19 +174,28 @@ DFhackCExport command_result plugin_load_data (color_ostream &out) { 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); - set_config_bool(CONFIG_BLOCKS, true); - set_config_bool(CONFIG_BOULDERS, true); - set_config_bool(CONFIG_LOGS, true); - set_config_bool(CONFIG_BARS, false); + set_config_bool(config, CONFIG_IS_ENABLED, is_enabled); + set_config_bool(config, CONFIG_BLOCKS, true); + set_config_bool(config, CONFIG_BOULDERS, true); + set_config_bool(config, CONFIG_LOGS, true); + set_config_bool(config, CONFIG_BARS, false); } // 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); + is_enabled = get_config_bool(config, CONFIG_IS_ENABLED); DEBUG(status,out).print("loading persisted enabled state: %s\n", is_enabled ? "true" : "false"); + + vector building_configs; + World::GetPersistentData(&building_configs, BLD_CONFIG_KEY); + planned_buildings.clear(); + tasks.clear(); + const size_t num_building_configs = building_configs.size(); + for (size_t idx = 0; idx < num_building_configs; ++idx) + registerPlannedBuilding(out, PlannedBuilding(building_configs[idx])); + return CR_OK; } @@ -124,19 +205,43 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan DEBUG(status,out).print("world unloaded; disabling %s\n", plugin_name); is_enabled = false; + planned_buildings.clear(); + tasks.clear(); } } return CR_OK; } +static bool cycle_requested = false; + DFhackCExport command_result plugin_onupdate(color_ostream &out) { - if (is_enabled && world->frame_counter - cycle_timestamp >= CYCLE_TICKS) + if (is_enabled && + (cycle_requested || world->frame_counter - cycle_timestamp >= CYCLE_TICKS)) do_cycle(out); return CR_OK; } +static bool call_buildingplan_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 buildingplan lua function: '%s'\n", 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.buildingplan", fn_name, + nargs, nres, + std::forward(args_lambda), + std::forward(res_lambda)); +} + static command_result do_command(color_ostream &out, vector ¶meters) { - // be sure to suspend the core if any DF state is read or modified CoreSuspender suspend; if (!Core::getInstance().isWorldLoaded()) { @@ -144,23 +249,452 @@ static command_result do_command(color_ostream &out, vector ¶meters) return CR_FAILURE; } - // TODO: configuration logic - // simple commandline parsing can be done in C++, but there are lua libraries - // that can easily handle more complex commandlines. see the blueprint plugin - // for an example. + bool show_help = false; + if (!call_buildingplan_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 CR_OK; + return show_help ? CR_WRONG_USAGE : CR_OK; } ///////////////////////////////////////////////////// // cycle logic // +struct BadFlags { + uint32_t whole; + + BadFlags() { + df::item_flags flags; + #define F(x) flags.bits.x = true; + F(dump); F(forbid); F(garbage_collect); + F(hostile); F(on_fire); F(rotten); F(trader); + F(in_building); F(construction); F(in_job); + F(owned); F(in_chest); F(removed); F(encased); + F(spider_web); + #undef F + whole = flags.whole; + } +}; + +static bool itemPassesScreen(df::item * item) { + static const BadFlags bad_flags; + return !(item->flags.whole & bad_flags.whole) + && !item->isAssignedToStockpile(); +} + +static bool matchesFilters(df::item * item, df::job_item * job_item) { + // check the properties that are not checked by Job::isSuitableItem() + if (job_item->item_type > -1 && job_item->item_type != item->getType()) + return false; + + if (job_item->item_subtype > -1 && + job_item->item_subtype != item->getSubtype()) + return false; + + if (job_item->flags2.bits.building_material && !item->isBuildMat()) + return false; + + if (job_item->metal_ore > -1 && !item->isMetalOre(job_item->metal_ore)) + return false; + + if (job_item->has_tool_use > df::tool_uses::NONE + && !item->hasToolUse(job_item->has_tool_use)) + return false; + + return DFHack::Job::isSuitableItem( + job_item, item->getType(), item->getSubtype()) + && DFHack::Job::isSuitableMaterial( + job_item, item->getMaterial(), item->getMaterialIndex(), + item->getType()); +} + +static bool isJobReady(color_ostream &out, df::job * job) { + int needed_items = 0; + for (auto job_item : job->job_items) { needed_items += job_item->quantity; } + if (needed_items) { + DEBUG(cycle,out).print("building needs %d more item(s)\n", needed_items); + return false; + } + return true; +} + +static bool job_item_idx_lt(df::job_item_ref *a, df::job_item_ref *b) { + // we want the items in the opposite order of the filters + return a->job_item_idx > b->job_item_idx; +} + +// this function does not remove the job_items since their quantity fields are +// now all at 0, so there is no risk of having extra items attached. we don't +// remove them to keep the "finalize with buildingplan active" path as similar +// as possible to the "finalize with buildingplan disabled" path. +static void finalizeBuilding(color_ostream &out, df::building * bld) { + DEBUG(cycle,out).print("finalizing building %d\n", bld->id); + auto job = bld->jobs[0]; + + // sort the items so they get added to the structure in the correct order + std::sort(job->items.begin(), job->items.end(), job_item_idx_lt); + + // derive the material properties of the building and job from the first + // applicable item. if any boulders are involved, it makes the whole + // structure "rough". + bool rough = false; + for (auto attached_item : job->items) { + df::item *item = attached_item->item; + rough = rough || item->getType() == df::item_type::BOULDER; + if (bld->mat_type == -1) { + bld->mat_type = item->getMaterial(); + job->mat_type = bld->mat_type; + } + if (bld->mat_index == -1) { + bld->mat_index = item->getMaterialIndex(); + job->mat_index = bld->mat_index; + } + } + + if (bld->needsDesign()) { + auto act = (df::building_actual *)bld; + if (!act->design) + act->design = new df::building_design(); + act->design->flags.bits.rough = rough; + } + + // we're good to go! + job->flags.bits.suspend = false; + Job::checkBuildingsNow(); +} + +static df::building * popInvalidTasks(color_ostream &out, queue> & task_queue) { + while (!task_queue.empty()) { + auto & task = task_queue.front(); + auto id = task.first; + if (planned_buildings.count(id) > 0) { + auto bld = planned_buildings.at(id).getBuildingIfValidOrRemoveIfNot(out); + if (bld && bld->jobs[0]->job_items[task.second]->quantity) + return bld; + } + DEBUG(cycle,out).print("discarding invalid task: bld=%d, job_item_idx=%d\n", id, task.second); + task_queue.pop(); + } + return NULL; +} + +static void doVector(color_ostream &out, df::job_item_vector_id vector_id, + map>> & buckets) { + auto other_id = ENUM_ATTR(job_item_vector_id, other, vector_id); + auto item_vector = df::global::world->items.other[other_id]; + DEBUG(cycle,out).print("matching %zu item(s) in vector %s against %zu filter bucket(s)\n", + item_vector.size(), + ENUM_KEY_STR(job_item_vector_id, vector_id).c_str(), + buckets.size()); + for (auto item_it = item_vector.rbegin(); + item_it != item_vector.rend(); + ++item_it) { + auto item = *item_it; + if (!itemPassesScreen(item)) + continue; + for (auto bucket_it = buckets.begin(); bucket_it != buckets.end(); ) { + auto & task_queue = bucket_it->second; + auto bld = popInvalidTasks(out, task_queue); + if (!bld) { + DEBUG(cycle,out).print("removing empty bucket: %s/%s; %zu bucket(s) left\n", + ENUM_KEY_STR(job_item_vector_id, vector_id).c_str(), + bucket_it->first.c_str(), + buckets.size() - 1); + bucket_it = buckets.erase(bucket_it); + continue; + } + auto & task = task_queue.front(); + auto id = task.first; + auto job = bld->jobs[0]; + auto filter_idx = task.second; + if (matchesFilters(item, job->job_items[filter_idx]) + && DFHack::Job::attachJobItem(job, item, + df::job_item_ref::Hauled, filter_idx)) + { + MaterialInfo material; + material.decode(item); + ItemTypeInfo item_type; + item_type.decode(item); + DEBUG(cycle,out).print("attached %s %s to filter %d for %s(%d): %s/%s\n", + material.toString().c_str(), + item_type.toString().c_str(), + filter_idx, + ENUM_KEY_STR(building_type, bld->getType()).c_str(), + id, + ENUM_KEY_STR(job_item_vector_id, vector_id).c_str(), + bucket_it->first.c_str()); + // keep quantity aligned with the actual number of remaining + // items so if buildingplan is turned off, the building will + // be completed with the correct number of items. + --job->job_items[filter_idx]->quantity; + task_queue.pop(); + if (isJobReady(out, job)) { + finalizeBuilding(out, bld); + planned_buildings.at(id).remove(out); + } + if (task_queue.empty()) { + DEBUG(cycle,out).print( + "removing empty item bucket: %s/%s; %zu left\n", + ENUM_KEY_STR(job_item_vector_id, vector_id).c_str(), + bucket_it->first.c_str(), + buckets.size() - 1); + buckets.erase(bucket_it); + } + // we found a home for this item; no need to look further + break; + } + ++bucket_it; + } + if (buckets.empty()) + break; + } +} + +struct VectorsToScanLast { + std::vector vectors; + VectorsToScanLast() { + // order is important here. we want to match boulders before wood and + // everything before bars. blocks are not listed here since we'll have + // already scanned them when we did the first pass through the buckets. + vectors.push_back(df::job_item_vector_id::BOULDER); + vectors.push_back(df::job_item_vector_id::WOOD); + vectors.push_back(df::job_item_vector_id::BAR); + } +}; + static void do_cycle(color_ostream &out) { + static const VectorsToScanLast vectors_to_scan_last; + // mark that we have recently run cycle_timestamp = world->frame_counter; + cycle_requested = false; + + DEBUG(cycle,out).print("running %s cycle for %zu registered buildings\n", + plugin_name, planned_buildings.size()); + + for (auto it = tasks.begin(); it != tasks.end(); ) { + auto vector_id = it->first; + // we could make this a set, but it's only three elements + if (std::find(vectors_to_scan_last.vectors.begin(), + vectors_to_scan_last.vectors.end(), + vector_id) != vectors_to_scan_last.vectors.end()) { + ++it; + continue; + } + + auto & buckets = it->second; + doVector(out, vector_id, buckets); + if (buckets.empty()) { + DEBUG(cycle,out).print("removing empty vector: %s; %zu vector(s) left\n", + ENUM_KEY_STR(job_item_vector_id, vector_id).c_str(), + tasks.size() - 1); + it = tasks.erase(it); + } + else + ++it; + } + for (auto vector_id : vectors_to_scan_last.vectors) { + if (tasks.count(vector_id) == 0) + continue; + auto & buckets = tasks[vector_id]; + doVector(out, vector_id, buckets); + if (buckets.empty()) { + DEBUG(cycle,out).print("removing empty vector: %s; %zu vector(s) left\n", + ENUM_KEY_STR(job_item_vector_id, vector_id).c_str(), + tasks.size() - 1); + tasks.erase(vector_id); + } + } + DEBUG(cycle,out).print("cycle done; %zu registered building(s) left\n", + planned_buildings.size()); +} + +///////////////////////////////////////////////////// +// Lua API +// core will already be suspended when coming in through here +// - DEBUG(cycle,out).print("running %s cycle\n", plugin_name); +static string getBucket(const df::job_item & ji) { + std::ostringstream ser; - // TODO: logic that runs every get_config_val(CONFIG_CYCLE_TICKS) ticks + // pull out and serialize only known relevant fields. if we miss a few, then + // the filter bucket will be slighly less specific than it could be, but + // that's probably ok. we'll just end up bucketing slightly different items + // together. this is only a problem if the different filter at the front of + // the queue doesn't match any available items and blocks filters behind it + // that could be matched. + ser << ji.item_type << ':' << ji.item_subtype << ':' << ji.mat_type << ':' + << ji.mat_index << ':' << ji.flags1.whole << ':' << ji.flags2.whole + << ':' << ji.flags3.whole << ':' << ji.flags4 << ':' << ji.flags5 << ':' + << ji.metal_ore << ':' << ji.has_tool_use; + + return ser.str(); } + +// get a list of item vectors that we should search for matches +static vector getVectorIds(color_ostream &out, df::job_item *job_item) +{ + std::vector ret; + + // if the filter already has the vector_id set to something specific, use it + if (job_item->vector_id > df::job_item_vector_id::IN_PLAY) + { + DEBUG(status,out).print("using vector_id from job_item: %s\n", + ENUM_KEY_STR(job_item_vector_id, job_item->vector_id).c_str()); + ret.push_back(job_item->vector_id); + return ret; + } + + // if the filer is for building material, refer to our global settings for + // which vectors to search + if (job_item->flags2.bits.building_material) + { + if (get_config_bool(config, CONFIG_BLOCKS)) + ret.push_back(df::job_item_vector_id::BLOCKS); + if (get_config_bool(config, CONFIG_BOULDERS)) + ret.push_back(df::job_item_vector_id::BOULDER); + if (get_config_bool(config, CONFIG_LOGS)) + ret.push_back(df::job_item_vector_id::WOOD); + if (get_config_bool(config, CONFIG_BARS)) + ret.push_back(df::job_item_vector_id::BAR); + } + + // fall back to IN_PLAY if no other vector was appropriate + if (ret.empty()) + ret.push_back(df::job_item_vector_id::IN_PLAY); + return ret; +} +static bool registerPlannedBuilding(color_ostream &out, PlannedBuilding & pb) { + df::building * bld = pb.getBuildingIfValidOrRemoveIfNot(out); + if (!bld) + return false; + + if (bld->jobs.size() != 1) { + DEBUG(status,out).print("unexpected number of jobs: want 1, got %zu\n", bld->jobs.size()); + return false; + } + auto job_items = bld->jobs[0]->job_items; + int num_job_items = job_items.size(); + if (num_job_items < 1) { + DEBUG(status,out).print("unexpected number of job items: want >0, got %d\n", num_job_items); + return false; + } + int32_t id = bld->id; + for (int job_item_idx = 0; job_item_idx < num_job_items; ++job_item_idx) { + auto job_item = job_items[job_item_idx]; + auto bucket = getBucket(*job_item); + auto vector_ids = getVectorIds(out, job_item); + + // if there are multiple vector_ids, schedule duplicate tasks. after + // the correct number of items are matched, the extras will get popped + // as invalid + for (auto vector_id : vector_ids) { + for (int item_num = 0; item_num < job_item->quantity; ++item_num) { + tasks[vector_id][bucket].push(std::make_pair(id, job_item_idx)); + DEBUG(status,out).print("added task: %s/%s/%d,%d; " + "%zu vector(s), %zu filter bucket(s), %zu task(s) in bucket", + ENUM_KEY_STR(job_item_vector_id, vector_id).c_str(), + bucket.c_str(), id, job_item_idx, tasks.size(), + tasks[vector_id].size(), tasks[vector_id][bucket].size()); + } + } + } + + // suspend jobs + for (auto job : bld->jobs) + job->flags.bits.suspend = true; + + // add the planned buildings to our register + planned_buildings.emplace(bld->id, pb); + + return true; +} + +static void printStatus(color_ostream &out) { + DEBUG(status,out).print("entering buildingplan_printStatus\n"); + out.print("buildingplan is %s\n\n", is_enabled ? "enabled" : "disabled"); + out.print(" finding materials for %zd buildings\n", planned_buildings.size()); + out.print("Current settings:\n"); + out.print(" use blocks: %s\n", get_config_bool(config, CONFIG_BLOCKS) ? "yes" : "no"); + out.print(" use boulders: %s\n", get_config_bool(config, CONFIG_BOULDERS) ? "yes" : "no"); + out.print(" use logs: %s\n", get_config_bool(config, CONFIG_LOGS) ? "yes" : "no"); + out.print(" use bars: %s\n", get_config_bool(config, CONFIG_BARS) ? "yes" : "no"); + out.print("\n"); +} + +static bool setSetting(color_ostream &out, string name, bool value) { + DEBUG(status,out).print("entering setSetting (%s -> %s)\n", name, value ? "true" : "false"); + if (name == "blocks") + set_config_bool(config, CONFIG_BLOCKS, value); + else if (name == "boulders") + set_config_bool(config, CONFIG_BOULDERS, value); + else if (name == "logs") + set_config_bool(config, CONFIG_LOGS, value); + else if (name == "bars") + set_config_bool(config, CONFIG_BARS, value); + else { + out.printerr("unrecognized setting: '%s'\n", name.c_str()); + return false; + } + return true; +} + +static bool isPlannableBuilding(color_ostream &out, df::building_type type, int16_t subtype, int32_t custom) { + DEBUG(status,out).print("entering isPlannableBuilding\n"); + int num_filters = 0; + if (!call_buildingplan_lua(&out, "get_num_filters", 3, 1, + [&](lua_State *L) { + Lua::Push(L, type); + Lua::Push(L, subtype); + Lua::Push(L, custom); + }, + [&](lua_State *L) { + num_filters = lua_tonumber(L, -1); + })) { + return false; + } + return num_filters >= 1; +} + +static bool isPlannedBuilding(color_ostream &out, df::building *bld) { + TRACE(status,out).print("entering isPlannedBuilding\n"); + return bld && planned_buildings.count(bld->id) > 0; +} + +static bool addPlannedBuilding(color_ostream &out, df::building *bld) { + DEBUG(status,out).print("entering addPlannedBuilding\n"); + if (!bld || planned_buildings.count(bld->id) + || !isPlannableBuilding(out, bld->getType(), bld->getSubtype(), + bld->getCustomType())) + return false; + return registerPlannedBuilding(out, PlannedBuilding(out, bld)); +} + +static void doCycle(color_ostream &out) { + DEBUG(status,out).print("entering doCycle\n"); + do_cycle(out); +} + +static void scheduleCycle(color_ostream &out) { + DEBUG(status,out).print("entering scheduleCycle\n"); + cycle_requested = true; +} + +DFHACK_PLUGIN_LUA_FUNCTIONS { + DFHACK_LUA_FUNCTION(printStatus), + DFHACK_LUA_FUNCTION(setSetting), + DFHACK_LUA_FUNCTION(isPlannableBuilding), + DFHACK_LUA_FUNCTION(isPlannedBuilding), + DFHACK_LUA_FUNCTION(addPlannedBuilding), + DFHACK_LUA_FUNCTION(doCycle), + DFHACK_LUA_FUNCTION(scheduleCycle), + DFHACK_LUA_END +}; diff --git a/plugins/lua/buildingplan.lua b/plugins/lua/buildingplan.lua index a01a1d0b1..9b953dd7c 100644 --- a/plugins/lua/buildingplan.lua +++ b/plugins/lua/buildingplan.lua @@ -14,11 +14,31 @@ local _ENV = mkmodule('plugins.buildingplan') --]] -local dialogs = require('gui.dialogs') -local guidm = require('gui.dwarfmode') +local argparse = require('argparse') require('dfhack.buildings') --- does not need the core suspended +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(...) + local args, opts = {...}, {} + local positionals = process_args(opts, args) + + if opts.help then + return false + end + + return true +end + function get_num_filters(btype, subtype, custom) local filters = dfhack.buildings.getFiltersByType( {}, btype, subtype, custom) @@ -26,6 +46,9 @@ function get_num_filters(btype, subtype, custom) return 0 end +local dialogs = require('gui.dialogs') +local guidm = require('gui.dwarfmode') + local function to_title_case(str) str = str:gsub('(%a)([%w_]*)', function (first, rest) return first:upper()..rest:lower() end) From 27ba25cdbbf6c084c016465e85414e72f3a9c415 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Tue, 17 Jan 2023 09:34:56 -0600 Subject: [PATCH 53/80] remove compatibility with msvc express because it's not 2017 anymore --- CMakeLists.txt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 49bb29f04..37f44a727 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,14 +132,8 @@ endif() find_package(Perl REQUIRED) # set up folder structures for IDE solutions -# MSVC Express won't load solutions that use this. It also doesn't include MFC supported -# Check for MFC! -find_package(MFC QUIET) -if(MFC_FOUND OR (NOT MSVC)) - option(CMAKE_USE_FOLDERS "Enable folder grouping of projects in IDEs." ON) -else() - option(CMAKE_USE_FOLDERS "Enable folder grouping of projects in IDEs." OFF) -endif() +# checking for msvc express is meaningless now, all available editions of msvc support folder groupings +option(CMAKE_USE_FOLDERS "Enable folder grouping of projects in IDEs." ON) if(CMAKE_USE_FOLDERS) set_property(GLOBAL PROPERTY USE_FOLDERS ON) From acd2256900baba0e214982ba5db96364b21102c2 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 17 Jan 2023 21:26:33 -0800 Subject: [PATCH 54/80] restore orders library functionality --- docs/changelog.txt | 1 + docs/plugins/orders.rst | 2 +- plugins/orders.cpp | 21 ++++++++------------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index a5d4ab434..542c2b54f 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 +- `orders`: allow the orders library to be listed and imported properly (if you previously copied the orders library into your ``dfhack-config/orders`` directory to work around this bug, you can remove those files now) ## Misc Improvements diff --git a/docs/plugins/orders.rst b/docs/plugins/orders.rst index bc15fd175..8beb246e4 100644 --- a/docs/plugins/orders.rst +++ b/docs/plugins/orders.rst @@ -23,7 +23,7 @@ Usage one-time orders first, then yearly, seasonally, monthly, and finally, daily. You can keep your orders automatically sorted by adding the following command to -your ``onMapLoad.init`` file:: +your ``dfhack-config/init/onMapLoad.init`` file:: repeat -name orders-sort -time 1 -timeUnits days -command [ orders sort ] diff --git a/plugins/orders.cpp b/plugins/orders.cpp index 6118b3997..e3c57d0f1 100644 --- a/plugins/orders.cpp +++ b/plugins/orders.cpp @@ -41,7 +41,7 @@ DFHACK_PLUGIN("orders"); REQUIRE_GLOBAL(world); static const std::string ORDERS_DIR = "dfhack-config/orders"; -static const std::string ORDERS_LIBRARY_DIR = "dfhack-config/orders/library"; +static const std::string ORDERS_LIBRARY_DIR = "hack/data/orders"; static command_result orders_command(color_ostream & out, std::vector & parameters); @@ -86,6 +86,11 @@ static command_result orders_command(color_ostream & out, std::vector files; - if (0 < Filesystem::listdir_recursive(ORDERS_DIR, files, 0, false)) - { - out << COLOR_LIGHTRED << "Unable to list files in directory: " << ORDERS_DIR << std::endl; - return CR_FAILURE; - } + Filesystem::listdir_recursive(ORDERS_DIR, files, 0, false); - if (files.empty()) - { - out << COLOR_YELLOW << "No exported orders yet. Create manager orders and export them with 'orders export ', or copy pre-made orders .json files into " << ORDERS_DIR << "." << std::endl << std::endl; - } - - for (auto it : files) - { + for (auto it : files) { if (it.second) continue; // skip directories std::string name = it.first; From 7d8066f3c7c54c62d75dccf7c21da6b91fef350b Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 17 Jan 2023 21:55:27 -0800 Subject: [PATCH 55/80] allow buildingplan to be "always on" --- data/init/dfhack.tools.init | 3 +++ plugins/buildingplan.cpp | 45 +++++++++++++------------------------ 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/data/init/dfhack.tools.init b/data/init/dfhack.tools.init index 741298109..fdad95be6 100644 --- a/data/init/dfhack.tools.init +++ b/data/init/dfhack.tools.init @@ -81,6 +81,9 @@ # Allow DFHack tools to overlay functionality and information on the DF screen enable overlay +# Allow buildings to be placed now and built later when materials are available +enable buildingplan + # Dwarf Manipulator (simple in-game Dwarf Therapist replacement) #enable manipulator diff --git a/plugins/buildingplan.cpp b/plugins/buildingplan.cpp index 7080be4d5..09313c21a 100644 --- a/plugins/buildingplan.cpp +++ b/plugins/buildingplan.cpp @@ -46,7 +46,6 @@ static const string CONFIG_KEY = string(plugin_name) + "/config"; static const string BLD_CONFIG_KEY = string(plugin_name) + "/building"; enum ConfigValues { - CONFIG_IS_ENABLED = 0, CONFIG_BLOCKS = 1, CONFIG_BOULDERS = 2, CONFIG_LOGS = 3, @@ -79,12 +78,12 @@ public: PlannedBuilding(color_ostream &out, df::building *building) : id(building->id) { DEBUG(status,out).print("creating persistent data for building %d\n", id); - config = DFHack::World::AddPersistentData(BLD_CONFIG_KEY); - set_config_val(config, BLD_CONFIG_ID, id); + bld_config = DFHack::World::AddPersistentData(BLD_CONFIG_KEY); + set_config_val(bld_config, BLD_CONFIG_ID, id); } - PlannedBuilding(DFHack::PersistentDataItem &config) - : config(config), id(get_config_val(config, BLD_CONFIG_ID)) { } + PlannedBuilding(DFHack::PersistentDataItem &bld_config) + : bld_config(bld_config), id(get_config_val(bld_config, BLD_CONFIG_ID)) { } void remove(color_ostream &out); @@ -102,7 +101,7 @@ public: } private: - DFHack::PersistentDataItem config; + DFHack::PersistentDataItem bld_config; }; static PersistentDataItem config; @@ -144,16 +143,10 @@ DFhackCExport command_result plugin_init(color_ostream &out, std::vector building_configs; - World::GetPersistentData(&building_configs, BLD_CONFIG_KEY); + DEBUG(status,out).print("loading persisted state\n"); planned_buildings.clear(); tasks.clear(); + vector building_configs; + World::GetPersistentData(&building_configs, BLD_CONFIG_KEY); const size_t num_building_configs = building_configs.size(); for (size_t idx = 0; idx < num_building_configs; ++idx) registerPlannedBuilding(out, PlannedBuilding(building_configs[idx])); @@ -201,13 +187,9 @@ DFhackCExport command_result plugin_load_data (color_ostream &out) { 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; - planned_buildings.clear(); - tasks.clear(); - } + DEBUG(status,out).print("world unloaded; clearing state for %s\n", plugin_name); + planned_buildings.clear(); + tasks.clear(); } return CR_OK; } @@ -215,6 +197,9 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan static bool cycle_requested = false; DFhackCExport command_result plugin_onupdate(color_ostream &out) { + if (!Core::getInstance().isWorldLoaded()) + return CR_OK; + if (is_enabled && (cycle_requested || world->frame_counter - cycle_timestamp >= CYCLE_TICKS)) do_cycle(out); @@ -245,7 +230,7 @@ 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); + out.printerr("Cannot configure %s without a loaded world.\n", plugin_name); return CR_FAILURE; } From 3dd418a46ccbd633a42482690760cfa489ab0eb8 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 18 Jan 2023 07:14:53 +0000 Subject: [PATCH 56/80] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index d3bc3b4d3..f50bd8cb4 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit d3bc3b4d379d3511a1aae51da7ccd6f553198195 +Subproject commit f50bd8cb4cb9aa8fc4b57c4bb1cd95bd5f8c3582 From ba8e3c187b311f126b602bc033168a685bca330a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Tue, 17 Jan 2023 23:56:54 -0800 Subject: [PATCH 57/80] add reference to removed script ref: DFHack/scripts#531 --- docs/about/Removed.rst | 6 ++++++ scripts | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index 0fef8cbe9..d8bc204b8 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -124,6 +124,12 @@ 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. +.. _masspit: + +masspit +======= +Replaced with a GUI version: `gui/masspit`. + .. _resume: resume diff --git a/scripts b/scripts index f50bd8cb4..36c564406 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit f50bd8cb4cb9aa8fc4b57c4bb1cd95bd5f8c3582 +Subproject commit 36c564406babb7734caeb691928083dd850eed8a From 653e09c322c895f0e3dc7c6d324ac2d5e046ad88 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 18 Jan 2023 00:08:21 -0800 Subject: [PATCH 58/80] make gcc happy --- plugins/buildingplan.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/plugins/buildingplan.cpp b/plugins/buildingplan.cpp index 09313c21a..1407e5c46 100644 --- a/plugins/buildingplan.cpp +++ b/plugins/buildingplan.cpp @@ -83,7 +83,7 @@ public: } PlannedBuilding(DFHack::PersistentDataItem &bld_config) - : bld_config(bld_config), id(get_config_val(bld_config, BLD_CONFIG_ID)) { } + : id(get_config_val(bld_config, BLD_CONFIG_ID)), bld_config(bld_config) { } void remove(color_ostream &out); @@ -179,8 +179,10 @@ DFhackCExport command_result plugin_load_data (color_ostream &out) { vector building_configs; World::GetPersistentData(&building_configs, BLD_CONFIG_KEY); const size_t num_building_configs = building_configs.size(); - for (size_t idx = 0; idx < num_building_configs; ++idx) - registerPlannedBuilding(out, PlannedBuilding(building_configs[idx])); + for (size_t idx = 0; idx < num_building_configs; ++idx) { + PlannedBuilding pb(building_configs[idx]); + registerPlannedBuilding(out, pb); + } return CR_OK; } @@ -616,7 +618,7 @@ static void printStatus(color_ostream &out) { } static bool setSetting(color_ostream &out, string name, bool value) { - DEBUG(status,out).print("entering setSetting (%s -> %s)\n", name, value ? "true" : "false"); + DEBUG(status,out).print("entering setSetting (%s -> %s)\n", name.c_str(), value ? "true" : "false"); if (name == "blocks") set_config_bool(config, CONFIG_BLOCKS, value); else if (name == "boulders") @@ -660,7 +662,8 @@ static bool addPlannedBuilding(color_ostream &out, df::building *bld) { || !isPlannableBuilding(out, bld->getType(), bld->getSubtype(), bld->getCustomType())) return false; - return registerPlannedBuilding(out, PlannedBuilding(out, bld)); + PlannedBuilding pb(out, bld); + return registerPlannedBuilding(out, pb); } static void doCycle(color_ostream &out) { From b598b38891455cc7ef1b9a6b4578a81da08e8c22 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Wed, 18 Jan 2023 14:40:31 -0600 Subject: [PATCH 59/80] tailor: reenable and improve logging reenable plugin remove `using std;` switch to standard logger and add some debug and trace level log messages --- plugins/CMakeLists.txt | 2 +- plugins/tailor.cpp | 91 ++++++++++++++++++++++++++---------------- 2 files changed, 57 insertions(+), 36 deletions(-) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 661fa2624..71a4fef82 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -158,7 +158,7 @@ dfhack_plugin(showmood showmood.cpp) #add_subdirectory(stockpiles) #dfhack_plugin(stocks stocks.cpp) #dfhack_plugin(strangemood strangemood.cpp) -#dfhack_plugin(tailor tailor.cpp) +dfhack_plugin(tailor tailor.cpp) dfhack_plugin(tiletypes tiletypes.cpp Brushes.h LINK_LIBRARIES lua) #dfhack_plugin(title-folder title-folder.cpp) #dfhack_plugin(title-version title-version.cpp) diff --git a/plugins/tailor.cpp b/plugins/tailor.cpp index 0a8a82f5b..2b1d0c63c 100644 --- a/plugins/tailor.cpp +++ b/plugins/tailor.cpp @@ -6,6 +6,7 @@ #include "Core.h" #include "DataDefs.h" +#include "Debug.h" #include "PluginManager.h" #include "df/creature_raw.h" @@ -29,18 +30,23 @@ #include "modules/World.h" using namespace DFHack; -using namespace std; using df::global::world; using df::global::plotinfo; DFHACK_PLUGIN("tailor"); + #define AUTOENABLE false DFHACK_PLUGIN_IS_ENABLED(enabled); REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(plotinfo); +namespace DFHack { + DBG_DECLARE(tailor, cycle, DebugCategory::LINFO); + DBG_DECLARE(tailor, config, DebugCategory::LINFO); +} + class Tailor { // ARMOR, SHOES, HELM, GLOVES, PANTS @@ -48,7 +54,7 @@ class Tailor { private: - const map jobTypeMap = { + const std::map jobTypeMap = { { df::job_type::MakeArmor, df::item_type::ARMOR }, { df::job_type::MakePants, df::item_type::PANTS }, { df::job_type::MakeHelm, df::item_type::HELM }, @@ -56,7 +62,7 @@ private: { df::job_type::MakeShoes, df::item_type::SHOES } }; - const map itemTypeMap = { + const std::map itemTypeMap = { { df::item_type::ARMOR, df::job_type::MakeArmor }, { df::item_type::PANTS, df::job_type::MakePants }, { df::item_type::HELM, df::job_type::MakeHelm }, @@ -107,13 +113,13 @@ private: std::list all_materials = { M_SILK, M_CLOTH, M_YARN, M_LEATHER }; - map, int> available; // key is item type & size - map, int> needed; // same - map, int> queued; // same + std::map, int> available; // key is item type & size + std::map, int> needed; // same + std::map, int> queued; // same - map sizes; // this maps body size to races + std::map sizes; // this maps body size to races - map, int> orders; // key is item type, item subtype, size + std::map, int> orders; // key is item type, item subtype, size std::map supply; @@ -147,7 +153,7 @@ private: df::item_type t = i->getType(); int size = world->raws.creatures.all[i->getMakerRace()]->adultsize; - available[make_pair(t, size)] += 1; + available[std::make_pair(t, size)] += 1; } } @@ -180,7 +186,7 @@ private: supply[M_LEATHER] += i->getStackSize(); } - out->print("tailor: available silk %d yarn %d cloth %d leather %d\n", supply[M_SILK], supply[M_YARN], supply[M_CLOTH], supply[M_LEATHER]); + DEBUG(cycle).print("tailor: available silk %d yarn %d cloth %d leather %d\n", supply[M_SILK], supply[M_YARN], supply[M_CLOTH], supply[M_LEATHER]); } void scan_replacements() @@ -193,10 +199,10 @@ private: Units::isBaby(u)) continue; // skip units we don't control - set wearing; + std::set wearing; wearing.clear(); - deque worn; + std::deque worn; worn.clear(); for (auto inv : u->inventory) @@ -212,10 +218,16 @@ private: int size = world->raws.creatures.all[u->race]->adultsize; sizes[size] = u->race; - for (auto ty : set{ df::item_type::ARMOR, df::item_type::PANTS, df::item_type::SHOES }) + for (auto ty : std::set{ df::item_type::ARMOR, df::item_type::PANTS, df::item_type::SHOES }) { if (wearing.count(ty) == 0) - needed[make_pair(ty, size)] += 1; + { + TRACE(cycle).print("tailor: one %s of size %d needed to cover %s\n", + ENUM_KEY_STR(item_type, ty).c_str(), + size, + Translation::TranslateName(&u->name, false).c_str()); + needed[std::make_pair(ty, size)] += 1; + } } for (auto w : worn) @@ -227,13 +239,13 @@ private: std::string description; w->getItemDescription(&description, 0); - if (available[make_pair(ty, size)] > 0) + if (available[std::make_pair(ty, size)] > 0) { if (w->flags.bits.owned) { bool confiscated = Items::setOwner(w, NULL); - out->print( + INFO(cycle).print( "tailor: %s %s from %s.\n", (confiscated ? "confiscated" : "could not confiscate"), description.c_str(), @@ -242,18 +254,22 @@ private: } if (wearing.count(ty) == 0) - available[make_pair(ty, size)] -= 1; + { + DEBUG(cycle).print("tailor: allocating a %s to %s\n", + ENUM_KEY_STR(item_type, ty).c_str(), + Translation::TranslateName(&u->name, false).c_str()); + available[std::make_pair(ty, size)] -= 1; + } if (w->getWear() > 1) w->flags.bits.dump = true; } else { - // out->print("%s worn by %s needs replacement\n", - // description.c_str(), - // Translation::TranslateName(&u->name, false).c_str() - // ); - orders[make_tuple(o, w->getSubtype(), size)] += 1; + DEBUG(cycle).print ("%s worn by %s needs replacement, but none available\n", + description.c_str(), + Translation::TranslateName(&u->name, false).c_str()); + orders[std::make_tuple(o, w->getSubtype(), size)] += 1; } } } @@ -270,7 +286,7 @@ private: int count = a.second; int sub = 0; - vector v; + std::vector v; switch (ty) { case df::item_type::ARMOR: v = entity->resources.armor_type; break; @@ -299,7 +315,8 @@ private: } const df::job_type j = itemTypeMap.at(ty); - orders[make_tuple(j, sub, size)] += count; + orders[std::make_tuple(j, sub, size)] += count; + DEBUG(cycle).print("tailor: %s times %d of size %d ordered\n", ENUM_KEY_STR(job_type, j).c_str(), count, size); } } @@ -318,7 +335,11 @@ private: int size = world->raws.creatures.all[race]->adultsize; - orders[make_tuple(o->job_type, sub, size)] -= o->amount_left; + orders[std::make_tuple(o->job_type, sub, size)] -= o->amount_left; + TRACE(cycle).print("tailor: existing order for %d %s of size %d detected\n", + o->amount_left, + ENUM_KEY_STR(job_type, o->job_type).c_str(), + size); } } @@ -333,14 +354,14 @@ private: int sub; int size; - tie(ty, sub, size) = o.first; + std::tie(ty, sub, size) = o.first; int count = o.second; if (count > 0) { - vector v; + std::vector v; BitArray* fl; - string name_s, name_p; + std::string name_s, name_p; switch (ty) { @@ -382,7 +403,7 @@ private: if (!can_make) { - out->print("tailor: civilization cannot make %s, skipped\n", name_p.c_str()); + INFO(cycle).print("tailor: civilization cannot make %s, skipped\n", name_p.c_str()); continue; } @@ -416,7 +437,7 @@ private: world->manager_orders.push_back(order); - out->print("tailor: added order #%d for %d %s %s, sized for %s\n", + INFO(cycle).print("tailor: added order #%d for %d %s %s, sized for %s\n", order->id, c, bitfield_to_string(order->material_category).c_str(), @@ -464,9 +485,9 @@ public: } public: - command_result set_materials(color_ostream& out, vector& parameters) + command_result set_materials(color_ostream& out, std::vector& parameters) { - list newmat; + std::list newmat; newmat.clear(); for (auto m = parameters.begin() + 1; m != parameters.end(); m++) @@ -475,7 +496,7 @@ public: auto mm = std::find_if(all_materials.begin(), all_materials.end(), nameMatch); if (mm == all_materials.end()) { - out.print("tailor: material %s not recognized\n", m->c_str()); + WARN(config,out).print("tailor: material %s not recognized\n", m->c_str()); return CR_WRONG_USAGE; } else { @@ -484,7 +505,7 @@ public: } material_order = newmat; - out.print("tailor: material list set to %s\n", get_material_list().c_str()); + INFO(config,out).print("tailor: material list set to %s\n", get_material_list().c_str()); return CR_OK; } @@ -549,7 +570,7 @@ DFhackCExport command_result plugin_onupdate(color_ostream& out) return CR_OK; } -static command_result tailor_cmd(color_ostream& out, vector & parameters) { +static command_result tailor_cmd(color_ostream& out, std::vector & parameters) { bool desired = enabled; if (parameters.size() == 1 && (parameters[0] == "enable" || parameters[0] == "on" || parameters[0] == "1")) { From 1a283eaf47167f98c3398ba0c461c4e47721053d Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Wed, 18 Jan 2023 16:24:01 -0600 Subject: [PATCH 60/80] autofarm: fix repetition in status output because C++ std::map is not the same as a ruby table --- docs/changelog.txt | 1 + plugins/autofarm.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/changelog.txt b/docs/changelog.txt index 542c2b54f..c119e0c89 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 +- `autofarm`: don't duplicate status line entries for crops with no current supply - `orders`: allow the orders library to be listed and imported properly (if you previously copied the orders library into your ``dfhack-config/orders`` directory to work around this bug, you can remove those files now) ## Misc Improvements diff --git a/plugins/autofarm.cpp b/plugins/autofarm.cpp index 238627c3a..f7acde17f 100644 --- a/plugins/autofarm.cpp +++ b/plugins/autofarm.cpp @@ -332,6 +332,7 @@ public: void status(color_ostream& out) { out << "Autofarm is " << (enabled ? "Active." : "Stopped.") << '\n'; + for (auto& lc : lastCounts) { auto plant = world->raws.plants.all[lc.first]; @@ -340,7 +341,7 @@ public: for (auto& th : thresholds) { - if (lastCounts[th.first] > 0) + if (lastCounts.find(th.first) != lastCounts.end()) continue; auto plant = world->raws.plants.all[th.first]; out << plant->id << " limit " << getThreshold(th.first) << " current 0" << '\n'; From a813bcb76929cba6fbc17fddbcbc8a88d335cde4 Mon Sep 17 00:00:00 2001 From: Kelly Kinkade Date: Wed, 18 Jan 2023 16:54:30 -0600 Subject: [PATCH 61/80] use slightly more succinct idiom --- plugins/autofarm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/autofarm.cpp b/plugins/autofarm.cpp index f7acde17f..566c49355 100644 --- a/plugins/autofarm.cpp +++ b/plugins/autofarm.cpp @@ -341,7 +341,7 @@ public: for (auto& th : thresholds) { - if (lastCounts.find(th.first) != lastCounts.end()) + if (lastCounts.count(th.first) > 0) continue; auto plant = world->raws.plants.all[th.first]; out << plant->id << " limit " << getThreshold(th.first) << " current 0" << '\n'; From 2cf0d0769c0b2bfa90f6b60dfffab9f3f5845b34 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 18 Jan 2023 15:44:47 -0800 Subject: [PATCH 62/80] fix reference to renamed var --- plugins/lua/overlay.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/lua/overlay.lua b/plugins/lua/overlay.lua index 42116735a..cf599fd08 100644 --- a/plugins/lua/overlay.lua +++ b/plugins/lua/overlay.lua @@ -348,7 +348,7 @@ end local function do_trigger(args, quiet) if triggered_screen_has_lock() then dfhack.printerr(('cannot trigger widget; widget "%s" is already active') - :format(active_triggered_widget)) + :format(trigger_lock_holder_description)) return end do_by_names_or_numbers(args[1], function(name, db_entry) From 452d44d9858003fae4dc2d4401346c326c9fb65b Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Wed, 18 Jan 2023 23:55:29 +0000 Subject: [PATCH 63/80] 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 9cd1b4ea9..dc8875f93 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 9cd1b4ea9ab99919a64f2dfaa0c776ab007ec2d4 +Subproject commit dc8875f93437b18ec46c7721afa31e6857c1ae74 diff --git a/scripts b/scripts index 36c564406..7482da71a 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 36c564406babb7734caeb691928083dd850eed8a +Subproject commit 7482da71ac3d869dda44854f4649b1be8318f69b From 5b1b0ca867b564a775c94eb50d6bfa781af2cb8f Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 18 Jan 2023 16:05:07 -0800 Subject: [PATCH 64/80] sync spreadsheet to docs --- docs/plugins/tailor.rst | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/tailor.rst b/docs/plugins/tailor.rst index d578fd308..af7d253b2 100644 --- a/docs/plugins/tailor.rst +++ b/docs/plugins/tailor.rst @@ -3,7 +3,7 @@ tailor .. dfhack-tool:: :summary: Automatically keep your dwarves in fresh clothing. - :tags: untested fort auto workorders + :tags: fort auto workorders Whenever the bookkeeper updates stockpile records, this plugin will scan the fort. If there are fresh cloths available, dwarves who are wearing tattered diff --git a/scripts b/scripts index 7482da71a..5df7b41a0 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 7482da71ac3d869dda44854f4649b1be8318f69b +Subproject commit 5df7b41a05137ce9245eaaaaf85571a10214c005 From 086ca5bcff3e6a301aa1dad454a98cb56162fe6c Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 18 Jan 2023 16:15:49 -0800 Subject: [PATCH 65/80] tombstone create-items --- docs/about/Removed.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index d8bc204b8..6b812bd64 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -16,6 +16,12 @@ command-prompt ============== Replaced by `gui/launcher --minimal `. +.. _create-items: + +create-items +============ +Replaced by `gui/create-item --multi`. + .. _deteriorateclothes: deteriorateclothes From d52aff8ff39a0e7db9cdede585891bc0fb988063 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Thu, 19 Jan 2023 07:14:40 +0000 Subject: [PATCH 66/80] 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 dc8875f93..bb4e4e053 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit dc8875f93437b18ec46c7721afa31e6857c1ae74 +Subproject commit bb4e4e05380404356321ba83f0160c31bf2ec647 diff --git a/scripts b/scripts index 5df7b41a0..ecab2af83 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 5df7b41a05137ce9245eaaaaf85571a10214c005 +Subproject commit ecab2af833a4a3f5bb85226a739e64bc8f48f2ef From d5610ab85968f79b4d4261cf0c7e77e12fe81451 Mon Sep 17 00:00:00 2001 From: 20k Date: Thu, 19 Jan 2023 03:26:00 +0000 Subject: [PATCH 67/80] zone <-> building interop --- library/modules/Buildings.cpp | 268 +++++++++++++++++++++++++--------- 1 file changed, 203 insertions(+), 65 deletions(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 2e7143533..600be91d7 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -102,7 +102,6 @@ struct CoordHash { }; static unordered_map locationToBuilding; -static unordered_map, CoordHash> locationToCivzones; static df::building_extents_type *getExtentTile(df::building_extents &extent, df::coord2d tile) { @@ -115,18 +114,36 @@ static df::building_extents_type *getExtentTile(df::building_extents &extent, df return &extent.extents[dx + dy*extent.width]; } +void add_building_to_all_zones(df::building* bld); + +static void buildings_fixzones() +{ + auto& vec = world->buildings.other[buildings_other_id::IN_PLAY]; + + bool changed = false; + + for (size_t i = 0; i < vec.size(); i++) + { + df::building* bld = vec[i]; + + add_building_to_all_zones(bld); + } +} + /* * A monitor to work around this bug, in its application to buildings: * * http://www.bay12games.com/dwarves/mantisbt/view.php?id=1416 */ bool buildings_do_onupdate = false; +static bool buildings_do_fixzones = false; void buildings_onStateChange(color_ostream &out, state_change_event event) { switch (event) { case SC_MAP_LOADED: buildings_do_onupdate = true; + buildings_do_fixzones = true; break; case SC_MAP_UNLOADED: buildings_do_onupdate = false; @@ -138,6 +155,12 @@ void buildings_onStateChange(color_ostream &out, state_change_event event) void buildings_onUpdate(color_ostream &out) { + if (buildings_do_fixzones) + { + buildings_fixzones(); + buildings_do_fixzones = false; + } + buildings_do_onupdate = false; df::job_list_link *link = world->jobs.list.next; @@ -167,6 +190,163 @@ void buildings_onUpdate(color_ostream &out) } } +static void building_into_zone_unidir(df::building* bld, df::building_civzonest* zone) +{ + for (size_t bid = 0; bid < zone->contained_buildings.size(); bid++) + { + if (zone->contained_buildings[bid] == bld) + return; + } + + zone->contained_buildings.push_back(bld); + + std::sort(zone->contained_buildings.begin(), zone->contained_buildings.end(), [](df::building* b1, df::building* b2) + { + return b1->id < b2->id; + }); +} + +static void zone_into_building_unidir(df::building* bld, df::building_civzonest* zone) +{ + for (size_t bid = 0; bid < bld->relations.size(); bid++) + { + if (bld->relations[bid] == zone) + return; + } + + bld->relations.push_back(zone); + + std::sort(bld->relations.begin(), bld->relations.end(), [](df::building* b1, df::building* b2) + { + return b1->id < b2->id; + }); +} + +static void add_building_to_zone(df::building* bld, df::building_civzonest* zone) +{ + if (!bld->canBeRoom()) + return; + + building_into_zone_unidir(bld, zone); + zone_into_building_unidir(bld, zone); +} + +static bool is_suitable_building_for_zoning(df::building* bld) +{ + return bld->canBeRoom(); +} + +static void add_building_to_all_zones(df::building* bld) +{ + if (!is_suitable_building_for_zoning(bld)) + return; + + df::coord coord(bld->centerx, bld->centery, bld->z); + + std::vector cv; + Buildings::findCivzonesAt(&cv, coord); + + for (size_t i=0; i < cv.size(); i++) + { + add_building_to_zone(bld, cv[i]); + } +} + +static void add_zone_to_all_buildings(df::building* zone_as_building) +{ + if (zone_as_building->getType() != building_type::Civzone) + return; + + auto zone = strict_virtual_cast(zone_as_building); + + if (zone == nullptr) + return; + + auto& vec = world->buildings.other[buildings_other_id::IN_PLAY]; + + for (size_t i = 0; i < vec.size(); i++) + { + auto against = vec[i]; + + if (zone->z != against->z) + continue; + + if (!is_suitable_building_for_zoning(against)) + continue; + + int32_t cx = against->centerx; + int32_t cy = against->centery; + + df::coord2d coord(cx, cy); + + //can a zone without extents exist? + if (zone->room.extents && zone->isExtentShaped()) + { + auto etile = getExtentTile(zone->room, coord); + if (!etile || !*etile) + continue; + + add_building_to_zone(against, zone); + } + } +} + +static void remove_building_from_zone(df::building* bld, df::building_civzonest* zone) +{ + for (int bid = 0; bid < (int)zone->contained_buildings.size(); bid++) + { + if (zone->contained_buildings[bid] == bld) + { + zone->contained_buildings.erase(zone->contained_buildings.begin() + bid); + bid--; + } + } + + for (int bid = 0; bid < (int)bld->relations.size(); bid++) + { + if (bld->relations[bid] == zone) + { + bld->relations.erase(bld->relations.begin() + bid); + bid--; + } + } +} + +static void remove_building_from_all_zones(df::building* bld) +{ + df::coord coord(bld->centerx, bld->centery, bld->z); + + std::vector cv; + Buildings::findCivzonesAt(&cv, coord); + + for (size_t i=0; i < cv.size(); i++) + { + remove_building_from_zone(bld, cv[i]); + } +} + +static void remove_zone_from_all_buildings(df::building* zone_as_building) +{ + if (zone_as_building->getType() != building_type::Civzone) + return; + + auto zone = strict_virtual_cast(zone_as_building); + + if (zone == nullptr) + return; + + auto& vec = world->buildings.other[buildings_other_id::IN_PLAY]; + + //this is a paranoid check and slower than it could be. Zones contain a list of children + //good for fixing potentially bad game states when deleting a zone + for (size_t i = 0; i < vec.size(); i++) + { + df::building* bld = vec[i]; + + remove_building_from_zone(bld, zone); + } +} + uint32_t Buildings::getNumBuildings() { return world->buildings.all.size(); @@ -325,78 +505,30 @@ static void cacheBuilding(df::building *building, bool is_civzone) { for (int32_t y = p1.y; y <= p2.y; y++) { df::coord pt(x, y, building->z); if (Buildings::containsTile(building, pt, is_civzone)) { - if (is_civzone) - locationToCivzones[pt].push_back(id); - else + if (!is_civzone) locationToBuilding[pt] = id; } } } } -static int32_t nextCivzone = 0; -static void cacheNewCivzones() { - if (!world || !building_next_id) - return; - - int32_t nextBuildingId = *building_next_id; - for (int32_t id = nextCivzone; id < nextBuildingId; ++id) { - auto &vec = world->buildings.other[buildings_other_id::ANY_ZONE]; - int32_t idx = df::building::binsearch_index(vec, id); - if (idx > -1) - cacheBuilding(vec[idx], true); - } - nextCivzone = nextBuildingId; -} - bool Buildings::findCivzonesAt(std::vector *pvec, df::coord pos) { pvec->clear(); - // Tiles have an occupancy->bits.building flag to quickly determine if it is - // covered by a buildling, but there is no such flag for civzones. - // Therefore, we need to make sure that our cache is authoratative. - // Otherwise, we would have to fall back to linearly scanning the list of - // all civzones on a cache miss. - // - // Since we guarantee our cache contains *at least* all tiles that are - // currently covered by civzones, we can conclude that if a tile is not in - // the cache, there is no civzone there. Civzones *can* be dynamically - // shrunk, so we still need to verify that civzones that once covered this - // tile continue to cover this tile. - cacheNewCivzones(); - - auto civzones_it = locationToCivzones.find(pos); - if (civzones_it == locationToCivzones.end()) - return false; - - set ids_to_remove; - auto &civzones = civzones_it->second; - for (int32_t id : civzones) { - int32_t idx = df::building::binsearch_index( - world->buildings.other[buildings_other_id::ANY_ZONE], id); - df::building_civzonest *civzone = NULL; - if (idx > -1) - civzone = world->buildings.other.ANY_ZONE[idx]; - if (!civzone || civzone->z != pos.z || - !containsTile(civzone, pos, true)) { - ids_to_remove.insert(id); + for (df::building_civzonest* zone : world->buildings.other.ACTIVITY_ZONE) + { + if (pos.z != zone->z) continue; - } - pvec->push_back(civzone); - } - // civzone no longer occupies this tile; update the cache - if (!ids_to_remove.empty()) { - for (auto it = civzones.begin(); it != civzones.end(); ) { - if (ids_to_remove.count(*it)) { - it = civzones.erase(it); + if (zone->room.extents && zone->isExtentShaped()) + { + auto etile = getExtentTile(zone->room, pos); + if (!etile || !*etile) continue; - } - ++it; + + pvec->push_back(zone); } - if (civzones.empty()) - locationToCivzones.erase(pos); } return !pvec->empty(); @@ -1053,7 +1185,6 @@ static int getMaxStockpileId() return max_id; } -/* TODO: understand how this changes for v50 static int getMaxCivzoneId() { auto &vec = world->buildings.other[buildings_other_id::ANY_ZONE]; @@ -1068,7 +1199,6 @@ static int getMaxCivzoneId() return max_id; } -*/ bool Buildings::constructAbstract(df::building *bld) { @@ -1087,12 +1217,14 @@ bool Buildings::constructAbstract(df::building *bld) stock->stockpile_number = getMaxStockpileId() + 1; break; -/* TODO: understand how this changes for v50 case building_type::Civzone: if (auto zone = strict_virtual_cast(bld)) + { zone->zone_num = getMaxCivzoneId() + 1; + + add_zone_to_all_buildings(zone); + } break; -*/ default: break; @@ -1186,6 +1318,8 @@ bool Buildings::constructWithItems(df::building *bld, std::vector ite bld->mat_index = items[i]->getMaterialIndex(); } + add_building_to_all_zones(bld); + createDesign(bld, rough); return true; } @@ -1232,6 +1366,8 @@ bool Buildings::constructWithFilters(df::building *bld, std::vectoruncategorize(); + + remove_building_from_all_zones(bld); + remove_zone_from_all_buildings(bld); + delete bld; if (world->selected_building == bld) @@ -1314,8 +1454,6 @@ void Buildings::clearBuildings(color_ostream& out) { corner1.clear(); corner2.clear(); locationToBuilding.clear(); - locationToCivzones.clear(); - nextCivzone = 0; } void Buildings::updateBuildings(color_ostream&, void* ptr) From c05b7526b1fe9af7dd913a9c5b241f437de4e802 Mon Sep 17 00:00:00 2001 From: cjhammel Date: Thu, 19 Jan 2023 15:12:24 -0500 Subject: [PATCH 68/80] Update Units.cpp fixes renamed value --- library/modules/Units.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 6d5ec7fde..787160f76 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -1426,7 +1426,7 @@ int Units::computeMovementSpeed(df::unit *unit) if (isBaby(unit)) speed += 3000; - if (unit->flags3.bits.unk15) + if (unit->flags3.bits.diving) speed /= 20; if (unit->counters2.exhaustion >= 2000) From 5982644383dd427444bfd87f73ae2e7e7b081818 Mon Sep 17 00:00:00 2001 From: cjhammel Date: Thu, 19 Jan 2023 15:32:52 -0500 Subject: [PATCH 69/80] Update Removed.rst fixed formatting for create-items --- docs/about/Removed.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index 6b812bd64..5da3c2442 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -20,7 +20,7 @@ Replaced by `gui/launcher --minimal `. create-items ============ -Replaced by `gui/create-item --multi`. +Replaced by ``gui/create-item --multi``. .. _deteriorateclothes: From 8b7c8d83b599ef4ba437ef098a3fcf96b646b2fc Mon Sep 17 00:00:00 2001 From: 20k Date: Thu, 19 Jan 2023 17:49:24 +0000 Subject: [PATCH 70/80] remove save fixup Add notifyCivzoneModified --- docs/dev/Lua API.rst | 5 +++++ library/LuaApi.cpp | 1 + library/include/modules/Buildings.h | 5 +++++ library/modules/Buildings.cpp | 34 +++++++++-------------------- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index ab7d6434e..ebd82ce19 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -1998,6 +1998,11 @@ Low-level building creation functions: Destroys the building, or queues a deconstruction job. Returns *true* if the building was destroyed and deallocated immediately. +* ``dfhack.buildings.notifyCivzoneModified(building)`` + + Rebuilds the civzone <-> overlapping building association mapping. + Call after changing extents or modifying size in some fashion + * ``dfhack.buildings.markedForRemoval(building)`` Returns *true* if the building is marked for removal (with :kbd:`x`), *false* diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 9f3d590dd..84612f790 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -2239,6 +2239,7 @@ static const LuaWrapper::FunctionReg dfhack_buildings_module[] = { WRAPM(Buildings, constructWithItems), WRAPM(Buildings, constructWithFilters), WRAPM(Buildings, deconstruct), + WRAPM(Buildings, notifyCivzoneModified), WRAPM(Buildings, markedForRemoval), WRAPM(Buildings, getRoomDescription), WRAPM(Buildings, isActivityZone), diff --git a/library/include/modules/Buildings.h b/library/include/modules/Buildings.h index aa539c02a..f4e8f37be 100644 --- a/library/include/modules/Buildings.h +++ b/library/include/modules/Buildings.h @@ -202,6 +202,11 @@ DFHACK_EXPORT bool deconstruct(df::building *bld); */ DFHACK_EXPORT bool markedForRemoval(df::building *bld); +/** + * Rebuilds a civzones building associations after it has been modified +*/ +DFHACK_EXPORT void notifyCivzoneModified(df::building* bld); + void updateBuildings(color_ostream& out, void* ptr); void clearBuildings(color_ostream& out); diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 600be91d7..6e7190f9c 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -114,36 +114,18 @@ static df::building_extents_type *getExtentTile(df::building_extents &extent, df return &extent.extents[dx + dy*extent.width]; } -void add_building_to_all_zones(df::building* bld); - -static void buildings_fixzones() -{ - auto& vec = world->buildings.other[buildings_other_id::IN_PLAY]; - - bool changed = false; - - for (size_t i = 0; i < vec.size(); i++) - { - df::building* bld = vec[i]; - - add_building_to_all_zones(bld); - } -} - /* * A monitor to work around this bug, in its application to buildings: * * http://www.bay12games.com/dwarves/mantisbt/view.php?id=1416 */ bool buildings_do_onupdate = false; -static bool buildings_do_fixzones = false; void buildings_onStateChange(color_ostream &out, state_change_event event) { switch (event) { case SC_MAP_LOADED: buildings_do_onupdate = true; - buildings_do_fixzones = true; break; case SC_MAP_UNLOADED: buildings_do_onupdate = false; @@ -155,12 +137,6 @@ void buildings_onStateChange(color_ostream &out, state_change_event event) void buildings_onUpdate(color_ostream &out) { - if (buildings_do_fixzones) - { - buildings_fixzones(); - buildings_do_fixzones = false; - } - buildings_do_onupdate = false; df::job_list_link *link = world->jobs.list.next; @@ -1450,6 +1426,16 @@ bool Buildings::markedForRemoval(df::building *bld) return false; } +void Buildings::notifyCivzoneModified(df::building* bld) +{ + if (bld->getType() != building_type::Civzone) + return; + + //remove zone here needs to be the slow method + remove_zone_from_all_buildings(bld); + add_zone_to_all_buildings(bld); +} + void Buildings::clearBuildings(color_ostream& out) { corner1.clear(); corner2.clear(); From 4d9c411358e7619f51dafe2edb7a05d64cd49c11 Mon Sep 17 00:00:00 2001 From: 20k Date: Thu, 19 Jan 2023 22:17:54 +0000 Subject: [PATCH 71/80] fix flag --- library/modules/Buildings.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/modules/Buildings.cpp b/library/modules/Buildings.cpp index 6e7190f9c..653f8bccf 100644 --- a/library/modules/Buildings.cpp +++ b/library/modules/Buildings.cpp @@ -198,20 +198,20 @@ static void zone_into_building_unidir(df::building* bld, df::building_civzonest* }); } +static bool is_suitable_building_for_zoning(df::building* bld) +{ + return bld->canMakeRoom(); +} + static void add_building_to_zone(df::building* bld, df::building_civzonest* zone) { - if (!bld->canBeRoom()) + if (!is_suitable_building_for_zoning(bld)) return; building_into_zone_unidir(bld, zone); zone_into_building_unidir(bld, zone); } -static bool is_suitable_building_for_zoning(df::building* bld) -{ - return bld->canBeRoom(); -} - static void add_building_to_all_zones(df::building* bld) { if (!is_suitable_building_for_zoning(bld)) From 7b906cbf6fa6489a9f35e292de7cfc4946db9713 Mon Sep 17 00:00:00 2001 From: Myk Date: Thu, 19 Jan 2023 16:53:24 -0800 Subject: [PATCH 72/80] Update docs/about/Removed.rst Co-authored-by: Alan --- docs/about/Removed.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index 5da3c2442..ad36ed8a8 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -20,7 +20,7 @@ Replaced by `gui/launcher --minimal `. create-items ============ -Replaced by ``gui/create-item --multi``. +Replaced by `gui/create-item --multi `. .. _deteriorateclothes: From 298736d911e2074b94ab71ccfe500cc48238769b Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 20 Jan 2023 07:14:41 +0000 Subject: [PATCH 73/80] Auto-update submodules scripts: master --- scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts b/scripts index ecab2af83..d6e975748 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit ecab2af833a4a3f5bb85226a739e64bc8f48f2ef +Subproject commit d6e975748c4e4a468fe54ebcc82f7eeec3e1f662 From 4183bace4dfebfec0e9b46097586cc1a16a4267a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 18 Jan 2023 13:38:23 -0800 Subject: [PATCH 74/80] update autodump, only commands, add hotkeys --- data/init/dfhack.keybindings.init | 17 +++++------ docs/plugins/autodump.rst | 40 ++++++++------------------ library/modules/Gui.cpp | 7 ++--- plugins/CMakeLists.txt | 2 +- plugins/autodump.cpp | 47 +++++++++++++++++-------------- 5 files changed, 51 insertions(+), 62 deletions(-) diff --git a/data/init/dfhack.keybindings.init b/data/init/dfhack.keybindings.init index c4323ecbc..7ef615984 100644 --- a/data/init/dfhack.keybindings.init +++ b/data/init/dfhack.keybindings.init @@ -27,8 +27,8 @@ keybinding add Ctrl-Shift-K gui/cp437-table # dwarfmode bindings # ###################### -# quicksave, only in main dwarfmode screen and menu page -#keybinding add Ctrl-Alt-S@dwarfmode/Default quicksave +# quicksave +keybinding add Ctrl-Alt-S@dwarfmode quicksave # toggle the display of water level as 1-7 tiles #keybinding add Ctrl-W@dwarfmode|dungeonmode twaterlvl @@ -40,14 +40,15 @@ keybinding add Ctrl-Shift-K gui/cp437-table # clean the selected tile of blood etc #keybinding add Ctrl-C spotclean -# destroy the selected item -#keybinding add Ctrl-K@dwarfmode autodump-destroy-item +# teleport all unforbidden items marked for dumping to the tile under the keyboard cursor +keybinding add Ctrl-Alt-D autodump -# destroy items designated for dump in the selected tile -#keybinding add Ctrl-Shift-K@dwarfmode autodump-destroy-here +# destroy the selected unit or items that are marked for dump under +keybinding add Ctrl-Alt-K autodump-destroy-here +#keybinding add Ctrl-Alt-K@dwarfmode "exterminate this" -# apply blueprints to the map (Alt-F for compatibility with LNP Quickfort) -#keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort +# apply blueprints to the map +keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort #keybinding add Alt-F@dwarfmode gui/quickfort # show information collected by dwarfmonitor diff --git a/docs/plugins/autodump.rst b/docs/plugins/autodump.rst index ec83b6082..facf70ca9 100644 --- a/docs/plugins/autodump.rst +++ b/docs/plugins/autodump.rst @@ -2,48 +2,32 @@ autodump ======== .. dfhack-tool:: - :summary: Automatically set items in a stockpile to be dumped. - :tags: untested fort armok fps productivity items stockpiles - :no-command: - -.. dfhack-command:: autodump - :summary: Teleports items marked for dumping to the cursor position. + :summary: Instantly gather or destroy items marked for dumping. + :tags: fort armok fps items .. dfhack-command:: autodump-destroy-here - :summary: Destroy items marked for dumping under the cursor. - -.. dfhack-command:: autodump-destroy-item - :summary: Destroys the selected item. + :summary: Destroy items marked for dumping under the keyboard cursor. -When `enabled `, this plugin adds an option to the :kbd:`q` menu for -stockpiles. When the ``autodump`` option is selected for the stockpile, any -items placed in the stockpile will automatically be designated to be dumped. +This tool can instantly move all unforbidden items marked for dumping to the +tile under the keyboard cursor. After moving the items, the dump flag is unset +and the forbid flag is set, just as if it had been dumped normally. Be aware +that dwarves that are en route to pick up the item for dumping may still come +and move the item to your dump zone. -When invoked as a command, it can instantly move all unforbidden items marked -for dumping to the tile under the cursor. After moving the items, the dump flag -is unset and the forbid flag is set, just as if it had been dumped normally. Be -aware that dwarves that are en route to pick up the item for dumping may still -come and move the item to your dump zone. - -The cursor must be placed on a floor tile so the items can be dumped there. +The keyboard cursor must be placed on a floor tile so the items can be dumped +there. Usage ----- :: - enable autodump autodump [] autodump-destroy-here - autodump-destroy-item ``autodump-destroy-here`` is an alias for ``autodump destroy-here`` and is intended for use as a keybinding. -``autodump-destroy-item`` destroys only the selected item. The item may be -selected in the :kbd:`k` list or in the container item list. If called again -before the game is resumed, cancels destruction of the item. - Options ------- @@ -67,5 +51,5 @@ Examples Teleports items marked for dumping to the cursor position. ``autodump destroy`` Destroys all unforbidden items marked for dumping -``autodump-destroy-item`` - Destroys the selected item. +``autodump-destroy-here`` + Destroys items on the selected tile that are marked for dumping. diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 0fb455fc9..35631dfc6 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -46,6 +46,7 @@ using namespace DFHack; #include "modules/Screen.h" #include "modules/Maps.h" #include "modules/Units.h" +#include "modules/World.h" #include "DataDefs.h" @@ -625,10 +626,8 @@ bool Gui::anywhere_hotkey(df::viewscreen *) { return true; } -bool Gui::dwarfmode_hotkey(df::viewscreen *top) -{ - // Require the main dwarf mode screen - return !!strict_virtual_cast(top); +bool Gui::dwarfmode_hotkey(df::viewscreen *top) { + return World::isFortressMode(); } bool Gui::unitjobs_hotkey(df::viewscreen *top) diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 200cb3e2f..04bfceab1 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -78,7 +78,7 @@ set_source_files_properties( Brushes.h PROPERTIES HEADER_FILE_ONLY TRUE ) dfhack_plugin(autobutcher autobutcher.cpp LINK_LIBRARIES lua) dfhack_plugin(autochop autochop.cpp LINK_LIBRARIES lua) #dfhack_plugin(autoclothing autoclothing.cpp) -#dfhack_plugin(autodump autodump.cpp) +dfhack_plugin(autodump autodump.cpp) dfhack_plugin(autofarm autofarm.cpp) #dfhack_plugin(autogems autogems.cpp LINK_LIBRARIES jsoncpp_static) #add_subdirectory(autolabor) diff --git a/plugins/autodump.cpp b/plugins/autodump.cpp index fb215c26b..c21f5c31b 100644 --- a/plugins/autodump.cpp +++ b/plugins/autodump.cpp @@ -1,33 +1,34 @@ // Quick Dumper : Moves items marked as "dump" to cursor // FIXME: local item cache in map blocks needs to be fixed after teleporting items -#include -#include -#include -#include -#include -#include -#include -#include -using namespace std; #include "Core.h" #include "Console.h" +#include "DataDefs.h" #include "Export.h" #include "PluginManager.h" + #include "modules/Maps.h" #include "modules/Gui.h" #include "modules/Items.h" #include "modules/Materials.h" #include "modules/MapCache.h" -#include "DataDefs.h" #include "df/item.h" #include "df/world.h" #include "df/general_ref.h" #include "df/viewscreen_dwarfmodest.h" #include "df/building_stockpilest.h" -#include "uicommon.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; using namespace DFHack; using namespace df::enums; @@ -40,6 +41,7 @@ DFHACK_PLUGIN("autodump"); REQUIRE_GLOBAL(gps); REQUIRE_GLOBAL(world); +/* TODO: merge with stockpiles plugin // Stockpile interface START static const string PERSISTENCE_KEY = "autodump/stockpiles"; @@ -267,6 +269,7 @@ DFhackCExport command_result plugin_enable(color_ostream &out, bool enable) } // Stockpile interface END +*/ command_result df_autodump(color_ostream &out, vector & parameters); command_result df_autodump_destroy_here(color_ostream &out, vector & parameters); @@ -276,18 +279,21 @@ DFhackCExport command_result plugin_init ( color_ostream &out, vector & parame MapCache MC; int dumped_total = 0; - int cx, cy, cz; DFCoord pos_cursor; if(!destroy || here) { - if (!Gui::getCursorCoords(cx,cy,cz)) - { - out.printerr("Cursor position not found. Please enable the cursor.\n"); + pos_cursor = Gui::getMousePos(); + if (!pos_cursor.isValid()) { + out.printerr("Mouse cursor must be over a suitable map tile.\n"); return CR_FAILURE; } - pos_cursor = DFCoord(cx,cy,cz); } if (!destroy) { @@ -441,13 +445,14 @@ command_result df_autodump(color_ostream &out, vector & parameters) command_result df_autodump_destroy_here(color_ostream &out, vector & parameters) { - // HOTKEY COMMAND; CORE ALREADY SUSPENDED if (!parameters.empty()) return CR_WRONG_USAGE; vector args; args.push_back("destroy-here"); + CoreSuspender suspend; + return autodump_main(out, args); } From eae2cec22f2911b6a08b166cee8a2ff9b482039a Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 18 Jan 2023 13:57:42 -0800 Subject: [PATCH 75/80] use keyboard cursor and adapt to a "bad" cursor not being equal to -30000 anymore --- library/include/df/custom/coord.methods.inc | 2 +- library/include/df/custom/coord2d.methods.inc | 2 +- library/lua/dfhack.lua | 4 ++-- library/modules/Gui.cpp | 6 +++--- plugins/autodump.cpp | 10 +++++----- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/library/include/df/custom/coord.methods.inc b/library/include/df/custom/coord.methods.inc index 6814be3c2..aa6eda484 100644 --- a/library/include/df/custom/coord.methods.inc +++ b/library/include/df/custom/coord.methods.inc @@ -3,7 +3,7 @@ coord(uint16_t _x, uint16_t _y, uint16_t _z) : x(_x), y(_y), z(_z) {} operator coord2d() const { return coord2d(x,y); } -bool isValid() const { return x != -30000; } +bool isValid() const { return x >= 0; } void clear() { x = y = z = -30000; } bool operator==(const coord &other) const diff --git a/library/include/df/custom/coord2d.methods.inc b/library/include/df/custom/coord2d.methods.inc index 202192bb8..512149ce3 100644 --- a/library/include/df/custom/coord2d.methods.inc +++ b/library/include/df/custom/coord2d.methods.inc @@ -1,6 +1,6 @@ coord2d(uint16_t _x, uint16_t _y) : x(_x), y(_y) {} -bool isValid() const { return x != -30000; } +bool isValid() const { return x >= 0; } void clear() { x = y = -30000; } bool operator==(const coord2d &other) const diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index e2cb7069b..b931b2ff4 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -321,7 +321,7 @@ end function pos2xyz(pos) if pos then local x = pos.x - if x and x ~= -30000 then + if x and x >= 0 then return x, pos.y, pos.z end end @@ -346,7 +346,7 @@ end function pos2xy(pos) if pos then local x = pos.x - if x and x ~= -30000 then + if x and x >= 0 then return x, pos.y end end diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 35631dfc6..c661cf254 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -649,7 +649,7 @@ bool Gui::item_details_hotkey(df::viewscreen *top) static bool has_cursor() { - return df::global::cursor && df::global::cursor->x != -30000; + return Gui::getCursorPos().isValid(); } bool Gui::cursor_hotkey(df::viewscreen *top) @@ -1720,7 +1720,7 @@ bool Gui::autoDFAnnouncement(df::report_init r, string message) // Check if the announcement will actually be announced if (*gamemode == game_mode::ADVENTURE) { - if (r.pos.x != -30000 && + if (r.pos.x >= 0 && r.type != announcement_type::CREATURE_SOUND && r.type != announcement_type::REGULAR_CONVERSATION && r.type != announcement_type::CONFLICT_CONVERSATION && @@ -2151,7 +2151,7 @@ bool Gui::getDesignationCoords (int32_t &x, int32_t &y, int32_t &z) x = selection_rect->start_x; y = selection_rect->start_y; z = selection_rect->start_z; - return (x == -30000) ? false : true; + return (x >= 0) ? false : true; } bool Gui::setDesignationCoords (const int32_t x, const int32_t y, const int32_t z) diff --git a/plugins/autodump.cpp b/plugins/autodump.cpp index c21f5c31b..aed6fa0ea 100644 --- a/plugins/autodump.cpp +++ b/plugins/autodump.cpp @@ -281,12 +281,12 @@ DFhackCExport command_result plugin_init ( color_ostream &out, vector & parame MapCache MC; int dumped_total = 0; - DFCoord pos_cursor; + df::coord pos_cursor; if(!destroy || here) { - pos_cursor = Gui::getMousePos(); + pos_cursor = Gui::getCursorPos(); if (!pos_cursor.isValid()) { - out.printerr("Mouse cursor must be over a suitable map tile.\n"); + out.printerr("Keyboard cursor must be over a suitable map tile.\n"); return CR_FAILURE; } } From a1a4125fd970e2a13fc49155e67f3a94857872e4 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Wed, 18 Jan 2023 15:44:25 -0800 Subject: [PATCH 76/80] properly react to lack of a mouse cursor --- library/lua/gui.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 9f1db9d7c..530848f61 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -481,7 +481,7 @@ end function View:getMousePos(view_rect) local rect = view_rect or self.frame_body local x,y = dscreen.getMousePos() - if rect and rect:inClipGlobalXY(x,y) then + if rect and x and rect:inClipGlobalXY(x,y) then return rect:localXY(x,y) end end From 226a0ff1646d7a9d5af789ccd0daac2795577786 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 20 Jan 2023 09:39:37 -0800 Subject: [PATCH 77/80] revert autodump hotkeys. we need to discuss how keybindings work more --- data/init/dfhack.keybindings.init | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/data/init/dfhack.keybindings.init b/data/init/dfhack.keybindings.init index 7ef615984..ea38f35ba 100644 --- a/data/init/dfhack.keybindings.init +++ b/data/init/dfhack.keybindings.init @@ -40,14 +40,13 @@ keybinding add Ctrl-Alt-S@dwarfmode quicksave # clean the selected tile of blood etc #keybinding add Ctrl-C spotclean -# teleport all unforbidden items marked for dumping to the tile under the keyboard cursor -keybinding add Ctrl-Alt-D autodump +# destroy the selected item +#keybinding add Ctrl-K@dwarfmode autodump-destroy-item -# destroy the selected unit or items that are marked for dump under -keybinding add Ctrl-Alt-K autodump-destroy-here -#keybinding add Ctrl-Alt-K@dwarfmode "exterminate this" +# destroy items designated for dump in the selected tile +#keybinding add Ctrl-Shift-K@dwarfmode autodump-destroy-here -# apply blueprints to the map +# apply blueprints to the map (Alt-F for compatibility with LNP Quickfort) keybinding add Ctrl-Shift-Q@dwarfmode gui/quickfort #keybinding add Alt-F@dwarfmode gui/quickfort From b7f90d543e6dfa1698d1646b3d9897990471c495 Mon Sep 17 00:00:00 2001 From: DFHack-Urist via GitHub Actions <63161697+DFHack-Urist@users.noreply.github.com> Date: Fri, 20 Jan 2023 19:47:11 +0000 Subject: [PATCH 78/80] 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 bb4e4e053..5d43fd9fd 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit bb4e4e05380404356321ba83f0160c31bf2ec647 +Subproject commit 5d43fd9fd91007cf674bfde44b2c5a0ac70170db diff --git a/scripts b/scripts index d6e975748..76beb51ec 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit d6e975748c4e4a468fe54ebcc82f7eeec3e1f662 +Subproject commit 76beb51ecb8897e5c2679a87b34e88f443d44f9a From 25c3bf4a2445162fd6f495b6ffcd3c2e893664d9 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 20 Jan 2023 11:57:13 -0800 Subject: [PATCH 79/80] adjust to name change --- library/modules/Units.cpp | 2 +- scripts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 787160f76..a6e6daa46 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -1936,7 +1936,7 @@ int Units::getStressCategory(df::unit *unit) if (!unit->status.current_soul) return int(stress_cutoffs.size()) / 2; - return getStressCategoryRaw(unit->status.current_soul->personality.stress_level); + return getStressCategoryRaw(unit->status.current_soul->personality.stress); } int Units::getStressCategoryRaw(int32_t stress_level) diff --git a/scripts b/scripts index 76beb51ec..5bdfd379b 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit 76beb51ecb8897e5c2679a87b34e88f443d44f9a +Subproject commit 5bdfd379b2d13f56bab455f94af56ec0ce3e0cb1 From e138ac1da5f7d6f7289d58d18f39996e8baf4749 Mon Sep 17 00:00:00 2001 From: Myk Taylor Date: Fri, 20 Jan 2023 12:23:02 -0800 Subject: [PATCH 80/80] update stonesense --- plugins/stonesense | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/stonesense b/plugins/stonesense index 6376bbc63..a045369db 160000 --- a/plugins/stonesense +++ b/plugins/stonesense @@ -1 +1 @@ -Subproject commit 6376bbc630feaf8b4f68623cdd2c28c87ac11af4 +Subproject commit a045369db6728979e709625908df3f4f36e868ca