From 2deeda11d23a1844fc65cd195028045e4591baae Mon Sep 17 00:00:00 2001 From: Dan Amlund Date: Sun, 28 Jan 2018 13:04:52 +0100 Subject: [PATCH 1/9] add many new cases for Gui::getSelectedUnit: report list, combat log list, military screen, unit health, unit custumize, assigning to cage, viewing cage, pitting, penning, burrows, look at corpse, look at corpse piece, look at named spatter --- library/modules/Gui.cpp | 121 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 4 deletions(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index d6eedcef7..380a76dee 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -49,16 +49,21 @@ using namespace DFHack; #include "df/announcement_flags.h" #include "df/assign_trade_status.h" +#include "df/building_cagest.h" #include "df/building_civzonest.h" #include "df/building_furnacest.h" #include "df/building_trapst.h" +#include "df/building_type.h" #include "df/building_workshopst.h" #include "df/d_init.h" #include "df/game_mode.h" #include "df/general_ref.h" #include "df/global_objects.h" #include "df/graphic.h" +#include "df/historical_figure.h" #include "df/interfacest.h" +#include "df/item_corpsepiecest.h" +#include "df/item_corpsest.h" #include "df/job.h" #include "df/layer_object_listst.h" #include "df/occupation.h" @@ -74,8 +79,10 @@ using namespace DFHack; #include "df/ui_unit_view_mode.h" #include "df/unit.h" #include "df/unit_inventory_item.h" +#include "df/viewscreen_announcelistst.h" #include "df/viewscreen_assign_display_itemst.h" #include "df/viewscreen_buildinglistst.h" +#include "df/viewscreen_customize_unitst.h" #include "df/viewscreen_dungeon_monsterstatusst.h" #include "df/viewscreen_dungeonmodest.h" #include "df/viewscreen_dwarfmodest.h" @@ -89,6 +96,7 @@ using namespace DFHack; #include "df/viewscreen_layer_noblelistst.h" #include "df/viewscreen_layer_overall_healthst.h" #include "df/viewscreen_layer_stockpilest.h" +#include "df/viewscreen_layer_unit_healthst.h" #include "df/viewscreen_layer_unit_relationshipst.h" #include "df/viewscreen_locationsst.h" #include "df/viewscreen_petst.h" @@ -97,6 +105,7 @@ using namespace DFHack; #include "df/viewscreen_tradegoodsst.h" #include "df/viewscreen_unitlistst.h" #include "df/viewscreen_unitst.h" +#include "df/viewscreen_reportlistst.h" #include "df/viewscreen_workquota_conditionst.h" #include "df/viewscreen_workshop_profilest.h" #include "df/world.h" @@ -818,6 +827,9 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) using df::global::ui_look_cursor; using df::global::ui_look_list; using df::global::ui_selected_unit; + using df::global::ui_building_in_assign; + using df::global::ui_building_assign_units; + using df::global::ui_building_item_cursor; if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitst, top)) { @@ -934,12 +946,63 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) return NULL; } + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_reportlistst, top)) + return vector_get(screen->units, screen->cursor); + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_announcelistst, top)) + { + auto *report = vector_get(screen->reports, screen->sel_idx); + for (df::unit *unit : world->units.all) + { + if (unit == screen->unit) + continue; + for (int32_t report_id : unit->reports.log[screen->report_type]) + { + if (report_id == report->id) + return unit; + } + } + } + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_militaryst, top)) + { + if (screen->page == df::viewscreen_layer_militaryst::T_page::Positions) { + auto positions = getLayerList(screen, 1); + if (positions->enabled && positions->active) + return vector_get(screen->positions.assigned, positions->cursor); + + auto candidates = getLayerList(screen, 2); + if (candidates->enabled && candidates->active) + return vector_get(screen->positions.candidates, candidates->cursor); + } + if (screen->page == df::viewscreen_layer_militaryst::T_page::Equip) { + auto positions = getLayerList(screen, 1); + if (positions->enabled && positions->active) + return vector_get(screen->equip.units, positions->cursor); + } + } + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_unit_healthst, top)) + return screen->unit; + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_customize_unitst, top)) + return screen->unit; + if (auto dfscreen = dfhack_viewscreen::try_cast(top)) return dfscreen->getSelectedUnit(); if (!Gui::dwarfmode_hotkey(top)) return NULL; + // general assigning units in building, i.e. (q)uery cage -> (a)ssign + if (ui_building_in_assign && *ui_building_in_assign + && ui_building_assign_units && ui_building_item_cursor + && ui->main.mode != Zones) // dont show for (i) zone + return vector_get(*ui_building_assign_units, *ui_building_item_cursor); + + if (ui->follow_unit != -1) + return df::unit::find(ui->follow_unit); + switch (ui->main.mode) { case ViewUnits: { @@ -948,16 +1011,66 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) return vector_get(world->units.active, *ui_selected_unit); } + case ZonesPitInfo: // (i) zone -> (P)it + case ZonesPenInfo: // (i) zone -> pe(N) + { + if (!ui_building_assign_units || !ui_building_item_cursor) + return NULL; + + return vector_get(*ui_building_assign_units, *ui_building_item_cursor); + } + case Burrows: + { + if (ui->burrows.in_add_units_mode) + return vector_get(ui->burrows.list_units, ui->burrows.unit_cursor_pos); + + return NULL; + } + case QueryBuilding: + { + df::building *building = getAnyBuilding(top); + if (building->getType() == df::building_type::Cage) + { + auto *cage = static_cast(building); + if (*ui_building_item_cursor < cage->assigned_units.size()) + return df::unit::find(cage->assigned_units[*ui_building_item_cursor]); + } + return NULL; + } case LookAround: { if (!ui_look_list || !ui_look_cursor) return NULL; auto item = vector_get(ui_look_list->items, *ui_look_cursor); - if (item && item->type == df::ui_look_list::T_items::Unit) - return item->unit; - else - return NULL; + if (item) { + if (item->type == df::ui_look_list::T_items::Unit) + return item->unit; + else if (item->type == df::ui_look_list::T_items::Item) + { + if (item->item->getType() == df::item_type::CORPSE) + { + // loo(k) at corpse + auto *corpse = static_cast(item->item); + return df::unit::find(corpse->unit_id); + } + else if (item->item->getType() == df::item_type::CORPSEPIECE) + { + // loo(k) at corpse piece + auto *corpsepiece = static_cast(item->item); + return df::unit::find(corpsepiece->unit_id); + } + } + else if (item->type == df::ui_look_list::T_items::Spatter) + { + // loo(k) at blood/ichor/.. spatter with a name + MaterialInfo mat; + if (mat.decode(item->spatter_mat_type, item->spatter_mat_index)) + return df::unit::find(mat.figure->unit_id); + } + } + + return NULL; } default: return NULL; From 325e0b0e33b0a6b9ca830c9d43777d0f5564d26f Mon Sep 17 00:00:00 2001 From: lethosor Date: Wed, 31 Jan 2018 09:57:11 -0500 Subject: [PATCH 2/9] binpatch.lua: check for empty patches --- library/lua/binpatch.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/library/lua/binpatch.lua b/library/lua/binpatch.lua index d8e95b29f..0cae97e5b 100644 --- a/library/lua/binpatch.lua +++ b/library/lua/binpatch.lua @@ -17,6 +17,7 @@ local function load_patch(name) local old_bytes = {} local new_bytes = {} + local has_bytes = false for line in file:lines() do if string.match(line, '^%x+:') then @@ -34,10 +35,14 @@ local function load_patch(name) old_bytes[offset] = oldv new_bytes[offset] = newv + has_bytes = true end end file:close() + if not has_bytes then + return nil, 'no patch bytes found' + end return { name = name, old_bytes = old_bytes, new_bytes = new_bytes } end From 537e94d75a818b7ac704c297be41d364fee81b74 Mon Sep 17 00:00:00 2001 From: Dan Amlund Date: Sun, 28 Jan 2018 13:37:27 +0100 Subject: [PATCH 3/9] fix segfault when splatter did not have historical figure --- library/modules/Gui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 380a76dee..e0dd46a32 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -1065,7 +1065,7 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) { // loo(k) at blood/ichor/.. spatter with a name MaterialInfo mat; - if (mat.decode(item->spatter_mat_type, item->spatter_mat_index)) + if (mat.decode(item->spatter_mat_type, item->spatter_mat_index) && mat.figure) return df::unit::find(mat.figure->unit_id); } } From 38491b4be871a75692f557116d7143dc2d49712a Mon Sep 17 00:00:00 2001 From: Dan Amlund Date: Wed, 31 Jan 2018 20:01:49 +0100 Subject: [PATCH 4/9] add checks to avoid potential segfaults. use more dfhack idiomatic code --- library/modules/Gui.cpp | 79 ++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index e0dd46a32..e3cebd45e 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -951,16 +951,27 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) if (VIRTUAL_CAST_VAR(screen, df::viewscreen_announcelistst, top)) { - auto *report = vector_get(screen->reports, screen->sel_idx); - for (df::unit *unit : world->units.all) - { - if (unit == screen->unit) - continue; - for (int32_t report_id : unit->reports.log[screen->report_type]) + if (screen->unit) { + // in (r)eports -> enter + auto *report = vector_get(screen->reports, screen->sel_idx); + if (report) { - if (report_id == report->id) - return unit; + for (df::unit *unit : world->units.all) + { + if (unit && screen->report_type >= 0 && screen->report_type < 3 + && unit != screen->unit) // find 'other' unit related to this report + { + for (int32_t report_id : unit->reports.log[screen->report_type]) + { + if (report_id == report->id) + return unit; + } + } + } } + } else { + // in (a)nnouncements + return NULL; // cannot determine unit from reports } } @@ -968,16 +979,16 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) { if (screen->page == df::viewscreen_layer_militaryst::T_page::Positions) { auto positions = getLayerList(screen, 1); - if (positions->enabled && positions->active) + if (positions && positions->enabled && positions->active) return vector_get(screen->positions.assigned, positions->cursor); auto candidates = getLayerList(screen, 2); - if (candidates->enabled && candidates->active) + if (candidates && candidates->enabled && candidates->active) return vector_get(screen->positions.candidates, candidates->cursor); } if (screen->page == df::viewscreen_layer_militaryst::T_page::Equip) { auto positions = getLayerList(screen, 1); - if (positions->enabled && positions->active) + if (positions && positions->enabled && positions->active) return vector_get(screen->equip.units, positions->cursor); } } @@ -994,10 +1005,13 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) if (!Gui::dwarfmode_hotkey(top)) return NULL; + if (!ui) + return NULL; + // general assigning units in building, i.e. (q)uery cage -> (a)ssign if (ui_building_in_assign && *ui_building_in_assign - && ui_building_assign_units && ui_building_item_cursor - && ui->main.mode != Zones) // dont show for (i) zone + && ui_building_assign_units && ui_building_item_cursor + && ui->main.mode != Zones) // dont show for (i) zone return vector_get(*ui_building_assign_units, *ui_building_item_cursor); if (ui->follow_unit != -1) @@ -1006,7 +1020,7 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) switch (ui->main.mode) { case ViewUnits: { - if (!ui_selected_unit) + if (!ui_selected_unit || !ui_selected_unit) return NULL; return vector_get(world->units.active, *ui_selected_unit); @@ -1014,10 +1028,10 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) case ZonesPitInfo: // (i) zone -> (P)it case ZonesPenInfo: // (i) zone -> pe(N) { - if (!ui_building_assign_units || !ui_building_item_cursor) - return NULL; + if (ui_building_assign_units || ui_building_item_cursor) + return vector_get(*ui_building_assign_units, *ui_building_item_cursor); - return vector_get(*ui_building_assign_units, *ui_building_item_cursor); + return NULL; } case Burrows: { @@ -1028,12 +1042,13 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) } case QueryBuilding: { - df::building *building = getAnyBuilding(top); - if (building->getType() == df::building_type::Cage) + if (df::building *building = getAnyBuilding(top)) { - auto *cage = static_cast(building); - if (*ui_building_item_cursor < cage->assigned_units.size()) - return df::unit::find(cage->assigned_units[*ui_building_item_cursor]); + if (VIRTUAL_CAST_VAR(cage, df::building_cagest, building)) + { + if (ui_building_item_cursor) + return df::unit::find(vector_get(cage->assigned_units, *ui_building_item_cursor)); + } } return NULL; } @@ -1042,24 +1057,16 @@ df::unit *Gui::getAnyUnit(df::viewscreen *top) if (!ui_look_list || !ui_look_cursor) return NULL; - auto item = vector_get(ui_look_list->items, *ui_look_cursor); - if (item) { + if (auto item = vector_get(ui_look_list->items, *ui_look_cursor)) + { if (item->type == df::ui_look_list::T_items::Unit) return item->unit; else if (item->type == df::ui_look_list::T_items::Item) { - if (item->item->getType() == df::item_type::CORPSE) - { - // loo(k) at corpse - auto *corpse = static_cast(item->item); - return df::unit::find(corpse->unit_id); - } - else if (item->item->getType() == df::item_type::CORPSEPIECE) - { - // loo(k) at corpse piece - auto *corpsepiece = static_cast(item->item); - return df::unit::find(corpsepiece->unit_id); - } + if (VIRTUAL_CAST_VAR(corpse, df::item_corpsest, item->item)) + return df::unit::find(corpse->unit_id); // loo(k) at corpse + else if (VIRTUAL_CAST_VAR(corpsepiece, df::item_corpsepiecest, item->item)) + return df::unit::find(corpsepiece->unit_id); // loo(k) at corpse piece } else if (item->type == df::ui_look_list::T_items::Spatter) { From 636448f431a1298dfb00822a12812de929bc0c7e Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 03:28:32 -0500 Subject: [PATCH 5/9] Update changelog --- NEWS.rst | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index a14bafa9f..917af3fe7 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -44,26 +44,50 @@ New Scripts - `devel/check-other-ids`: Checks the validity of "other" vectors in the ``world`` global - `gui/cp437-table`: An in-game CP437 table +- `view-unit-reports`: opens the reports screen with combat reports for the selected unit Fixes ----- - Fixed issues with the console output color affecting the prompt on Windows - `createitem`: stopped items from teleporting away in some forts - `devel/inject-raws`: now recognizes spaces in reaction names +- `dig`: added support for designation priorities - fixes issues with + designations from ``digv`` and related commands having extremely high priority +- `dwarfmonitor`: + + - fixed display of creatures and poetic/music/dance forms on ``prefs`` screen + - added "view unit" option + - now exposes the selected unit to other tools + - `gui/gm-unit`: can now edit mining skill - `gui/quickcmd`: stopped error from adding too many commands +- `quicksave`: fixed an issue where the "Saving..." indicator often wouldn't appear Misc Improvements ----------------- - The console now provides suggestions for built-in commands +- `binpatch`: now reports errors for empty patch files - `devel/export-dt-ini`: avoid hardcoding flags - `exportlegends`: - reordered some tags to match DF's order - added progress indicators for exporting long lists +- `force`: now provides useful help +- `full-heal`: + + - can now select corpses to resurrect + - now resets body part temperatures upon resurrection to prevent creatures + from freezing/melting again + - now resets units' vanish countdown to reverse effects of `exterminate` + - `gui/gm-editor`: added enum names to enum edit dialogs -- `gui/gm-unit`: made skill search case-insensitive +- `gui/gm-unit`: + + - made skill search case-insensitive + - added a profession editor + - misc. layout improvements + - `gui/liquids`: added more keybindings: 0-7 to change liquid level, P/B to cycle backwards - `gui/pathable`: added tile types to sidebar - `gui/rename`: added "clear" and "special characters" options @@ -76,7 +100,22 @@ Misc Improvements Removed ------- -- `warn-stuck-trees`: the corresponding DF bug was fixed in 0.44.01 +- `warn-stuck-trees`: :bug:`9252` fixed in DF 0.44.01 +- `tweak`: ``kitchen-keys``: :bug:`614` fixed in DF 0.44.04 + +Internals +--------- +- ``Gui::getAnyUnit()`` supports many more screens/menus +- New globals available: + + - ``version`` + - ``min_load_version`` + - ``movie_version`` + - ``basic_seed`` + - ``title`` + - ``title_spaced`` + - ``ui_building_resize_radius`` + - ``soul_next_id`` Lua --- From 426839aac290ef0a8a78648ee5ba48519c1e8f87 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 17:58:59 -0500 Subject: [PATCH 6/9] Update scripts, xml, NEWS for dfhack/scripts#37 --- NEWS.rst | 10 ++++++++++ library/xml | 2 +- scripts | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 917af3fe7..f704508bd 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -41,9 +41,16 @@ DFHack future New Scripts ----------- +- `break-dance`: Breaks up a stuck dance activity +- `cannibalism`: Allows consumption of sapient corpses - `devel/check-other-ids`: Checks the validity of "other" vectors in the ``world`` global +- `fillneeds`: Use with a unit selected to make them focused and unstressed +- `firestarter`: Lights things on fire: items, locations, entire inventories even! +- `flashstep`: Teleports adventurer to cursor +- `ghostly`: Turns an adventurer into a ghost or back - `gui/cp437-table`: An in-game CP437 table +- `questport`: Sends your adventurer to the location of your quest log cursor - `view-unit-reports`: opens the reports screen with combat reports for the selected unit Fixes @@ -61,6 +68,7 @@ Fixes - `gui/gm-unit`: can now edit mining skill - `gui/quickcmd`: stopped error from adding too many commands +- `names`: fixed many errors - `quicksave`: fixed an issue where the "Saving..." indicator often wouldn't appear Misc Improvements @@ -91,11 +99,13 @@ Misc Improvements - `gui/liquids`: added more keybindings: 0-7 to change liquid level, P/B to cycle backwards - `gui/pathable`: added tile types to sidebar - `gui/rename`: added "clear" and "special characters" options +- `launch`: can now ride creatures - `modtools/skill-change`: - now updates skill levels appropriately - only prints output if ``-loud`` is passed +- `names`: can now edit names of units - `remotefortressreader`: includes item stack sizes and some performance improvements Removed diff --git a/library/xml b/library/xml index ef5b1c8f0..718788141 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ef5b1c8f037a6240acdd3957fb7b6b9de529c5e2 +Subproject commit 7187881412f8ee7518527641e0df52a3ed4a52e3 diff --git a/scripts b/scripts index b330e696e..8d079a591 160000 --- a/scripts +++ b/scripts @@ -1 +1 @@ -Subproject commit b330e696e6cb6a607d8cc77679bbe0fa5e51598c +Subproject commit 8d079a59122d9ba72ce9c0f7687402a343d09bc7 From e88ba60ba5884261a85073b0413c24a2141e892d Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 18:08:15 -0500 Subject: [PATCH 7/9] Document "dig" priority arguments --- docs/Plugins.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/Plugins.rst b/docs/Plugins.rst index 04f5df321..c896b5fd0 100644 --- a/docs/Plugins.rst +++ b/docs/Plugins.rst @@ -1930,6 +1930,13 @@ Basic commands: :dfhack-keybind:`digv` +.. note:: + + All commands implemented by the `dig` plugin (listed by ``ls dig``) support + specifying the designation priority with ``-p#``, ``-p #``, or ``p=#``, + where ``#`` is a number from 1 to 7. If a priority is not specified, the + priority selected in-game is used as the default. + .. _digexp: digexp From bdba95f90c1e99e98dee6bcd37031ca2631a53d7 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 18:10:16 -0500 Subject: [PATCH 8/9] memview: check for tags from sizecheck --- plugins/devel/memview.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/plugins/devel/memview.cpp b/plugins/devel/memview.cpp index b93319a07..d84a3b578 100644 --- a/plugins/devel/memview.cpp +++ b/plugins/devel/memview.cpp @@ -53,7 +53,14 @@ size_t convert(const std::string& p,bool ishex=false) conv>>ret; return ret; } -bool isAddr(uintptr_t *trg,vector & ranges) +bool isAddr(void *trg, vector &ranges) +{ + for (auto &r : ranges) + if (r.isInRange(trg)) + return true; + return false; +} +bool isAddrAt(uintptr_t *trg, vector &ranges) { if(trg[0]%4==0) for(size_t i=0;i & parameters) is_enabled = true; memdata.state=STATE_ON; } - if(parameters.size()>1) + if (vector_get(parameters, 1, string("a")).substr(0, 1) == "a") + memdata.len = detect_size(memdata.addr); + else if (parameters.size()>1) memdata.len=convert(parameters[1]); else memdata.len=20*16; From d71e252b5038f584f38d92c453b6e8ff71cac311 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sat, 3 Feb 2018 22:17:28 -0500 Subject: [PATCH 9/9] Bump to r1 --- CMakeLists.txt | 4 ++-- NEWS.rst | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e92fc967..c7eb1f234 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,8 +141,8 @@ endif() # set up versioning. set(DF_VERSION "0.44.05") -set(DFHACK_RELEASE "alpha1") -set(DFHACK_PRERELEASE TRUE) +set(DFHACK_RELEASE "r1") +set(DFHACK_PRERELEASE FALSE) set(DFHACK_VERSION "${DF_VERSION}-${DFHACK_RELEASE}") diff --git a/NEWS.rst b/NEWS.rst index f704508bd..ce8635675 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -36,8 +36,8 @@ Changelog .. contents:: :depth: 2 -DFHack future -============= +DFHack 0.44.05-r1 +================= New Scripts -----------