From a31542862aa0a3f8a64db9dcf4d7351394c2dfe9 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 14 Jan 2012 19:31:43 +0400 Subject: [PATCH] Add utility functions to retrieve the selected job/unit/item. Units can be selected via 'u', 'j', 'v' and 'k'; full-screen unit details view not supported. Items can be selected via 't', 'k', 'v'->inventory. Also, when viewing a container item full-screen, the selected contained item or unit is returned; never the container itself. The api is used in rename to allow setting nicknames for arbitrary units, including animals and enemies. --- Memory.xml | 19 +++- library/include/DataDefs.h | 8 +- library/include/modules/Gui.h | 15 +++ library/modules/Gui.cpp | 208 ++++++++++++++++++++++++++++++++++ library/xml | 2 +- plugins/cleaners.cpp | 2 + plugins/rename.cpp | 74 +++++++++--- 7 files changed, 310 insertions(+), 18 deletions(-) diff --git a/Memory.xml b/Memory.xml index 62f20f9ab..811bef3e9 100644 --- a/Memory.xml +++ b/Memory.xml @@ -1095,6 +1095,11 @@
+
+
+
+
+
@@ -2348,6 +2353,12 @@
+ +
+
+
+
+
cmake @@ -3230,11 +3241,17 @@
- +
+ +
+
+
+
+
diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index 4acf19c35..e998dc386 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -249,10 +249,16 @@ namespace df { SIMPLE_GLOBAL(job_next_id,int) \ SIMPLE_GLOBAL(ui_look_cursor,int) \ SIMPLE_GLOBAL(ui_workshop_job_cursor,int) \ + SIMPLE_GLOBAL(ui_building_item_cursor,int) \ SIMPLE_GLOBAL(ui_workshop_in_add,bool) \ + SIMPLE_GLOBAL(ui_selected_unit,int) \ + SIMPLE_GLOBAL(cur_year,int) \ + SIMPLE_GLOBAL(cur_year_tick,int) \ GLOBAL(ui_sidebar_menus,ui_sidebar_menus) \ GLOBAL(ui_build_selector,ui_build_selector) \ - GLOBAL(ui_look_list,ui_look_list) + GLOBAL(ui_look_list,ui_look_list) \ + GLOBAL(ui_unit_view_mode, ui_unit_view_mode) + #define SIMPLE_GLOBAL(name,tname) \ namespace global { extern DFHACK_EXPORT tname *name; } diff --git a/library/include/modules/Gui.h b/library/include/modules/Gui.h index 7e07cbd4d..ce087d490 100644 --- a/library/include/modules/Gui.h +++ b/library/include/modules/Gui.h @@ -35,6 +35,8 @@ distribution. namespace df { struct viewscreen; struct job; + struct unit; + struct item; }; /** @@ -46,11 +48,24 @@ namespace DFHack { class Core; + DFHACK_EXPORT bool item_details_hotkey(Core *, df::viewscreen *top); + DFHACK_EXPORT bool unitjobs_hotkey(Core *, df::viewscreen *top); + DFHACK_EXPORT bool workshop_job_hotkey(Core *c, df::viewscreen *top); DFHACK_EXPORT bool build_selector_hotkey(Core *c, df::viewscreen *top); + DFHACK_EXPORT bool view_unit_hotkey(Core *c, df::viewscreen *top); + DFHACK_EXPORT bool unit_inventory_hotkey(Core *c, df::viewscreen *top); + + DFHACK_EXPORT bool any_job_hotkey(Core *c, df::viewscreen *top); + DFHACK_EXPORT bool any_unit_hotkey(Core *c, df::viewscreen *top); + DFHACK_EXPORT bool any_item_hotkey(Core *c, df::viewscreen *top); DFHACK_EXPORT df::job *getSelectedWorkshopJob(Core *c, bool quiet = false); + DFHACK_EXPORT df::job *getSelectedJob(Core *c, bool quiet = false); + DFHACK_EXPORT df::unit *getSelectedUnit(Core *c, bool quiet = false); + DFHACK_EXPORT df::item *getSelectedItem(Core *c, bool quiet = false); + class DFContextShared; /** * A GUI screen diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 04f23ccba..86b73f556 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -38,17 +38,25 @@ using namespace std; #include "ModuleFactory.h" #include "Core.h" #include "PluginManager.h" +#include "MiscUtils.h" using namespace DFHack; #include "DataDefs.h" #include "df/world.h" #include "df/cursor.h" #include "df/viewscreen_dwarfmodest.h" +#include "df/viewscreen_unitjobsst.h" +#include "df/viewscreen_itemst.h" #include "df/ui.h" +#include "df/ui_unit_view_mode.h" +#include "df/ui_sidebar_menus.h" +#include "df/ui_look_list.h" #include "df/job.h" #include "df/ui_build_selector.h" #include "df/building_workshopst.h" #include "df/building_furnacest.h" +#include "df/general_ref.h" +#include "df/unit_inventory_item.h" using namespace df::enums; @@ -69,6 +77,18 @@ bool DFHack::dwarfmode_hotkey(Core *, df::viewscreen *top) return !!strict_virtual_cast(top); } +bool DFHack::unitjobs_hotkey(Core *, df::viewscreen *top) +{ + // Require the main dwarf mode screen + return !!strict_virtual_cast(top); +} + +bool DFHack::item_details_hotkey(Core *, df::viewscreen *top) +{ + // Require the main dwarf mode screen + return !!strict_virtual_cast(top); +} + bool DFHack::cursor_hotkey(Core *c, df::viewscreen *top) { if (!dwarfmode_hotkey(c, top)) @@ -147,6 +167,34 @@ bool DFHack::build_selector_hotkey(Core *c, df::viewscreen *top) } } +bool DFHack::view_unit_hotkey(Core *c, df::viewscreen *top) +{ + using df::global::ui; + using df::global::world; + using df::global::ui_selected_unit; + + if (!dwarfmode_hotkey(c,top)) + return false; + if (ui->main.mode != ui_sidebar_mode::ViewUnits) + return false; + if (!ui_selected_unit) // allow missing + return false; + + return vector_get(world->units.other[0], *ui_selected_unit) != NULL; +} + +bool DFHack::unit_inventory_hotkey(Core *c, df::viewscreen *top) +{ + using df::global::ui_unit_view_mode; + + if (!view_unit_hotkey(c,top)) + return false; + if (!ui_unit_view_mode) + return false; + + return ui_unit_view_mode->value == df::ui_unit_view_mode::Inventory; +} + df::job *DFHack::getSelectedWorkshopJob(Core *c, bool quiet) { using df::global::world; @@ -170,6 +218,166 @@ df::job *DFHack::getSelectedWorkshopJob(Core *c, bool quiet) return selected->jobs[idx]; } +bool DFHack::any_job_hotkey(Core *c, df::viewscreen *top) +{ + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitjobsst, top)) + return vector_get(screen->jobs, screen->cursor_pos) != NULL; + + return workshop_job_hotkey(c,top); +} + +df::job *DFHack::getSelectedJob(Core *c, bool quiet) +{ + df::viewscreen *top = c->getTopViewscreen(); + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitjobsst, top)) + { + df::job *job = vector_get(screen->jobs, screen->cursor_pos); + + if (!job && !quiet) + c->con.printerr("Selected unit has no job\n"); + + return job; + } + else + return getSelectedWorkshopJob(c, quiet); +} + +static df::unit *getAnyUnit(Core *c, df::viewscreen *top) +{ + using namespace ui_sidebar_mode; + using df::global::ui; + using df::global::world; + using df::global::ui_look_cursor; + using df::global::ui_look_list; + using df::global::ui_selected_unit; + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitjobsst, top)) + return vector_get(screen->units, screen->cursor_pos); + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_itemst, top)) + { + df::general_ref *ref = vector_get(screen->entry_ref, screen->cursor_pos); + return ref ? ref->getUnit() : NULL; + } + + if (!dwarfmode_hotkey(c,top)) + return NULL; + + switch (ui->main.mode) { + case ViewUnits: + { + if (!ui_selected_unit) + return NULL; + + return vector_get(world->units.other[0], *ui_selected_unit); + } + 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; + } + default: + return NULL; + } +} + +bool DFHack::any_unit_hotkey(Core *c, df::viewscreen *top) +{ + return getAnyUnit(c, top) != NULL; +} + +df::unit *DFHack::getSelectedUnit(Core *c, bool quiet) +{ + df::unit *unit = getAnyUnit(c, c->getTopViewscreen()); + + if (!unit && !quiet) + c->con.printerr("No unit is selected in the UI.\n"); + + return unit; +} + +static df::item *getAnyItem(Core *c, df::viewscreen *top) +{ + using namespace ui_sidebar_mode; + using df::global::ui; + using df::global::world; + using df::global::ui_look_cursor; + using df::global::ui_look_list; + using df::global::ui_unit_view_mode; + using df::global::ui_building_item_cursor; + using df::global::ui_sidebar_menus; + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_itemst, top)) + { + df::general_ref *ref = vector_get(screen->entry_ref, screen->cursor_pos); + return ref ? ref->getItem() : NULL; + } + + if (!dwarfmode_hotkey(c,top)) + return NULL; + + switch (ui->main.mode) { + case ViewUnits: + { + if (!ui_unit_view_mode || !ui_look_cursor || !ui_sidebar_menus) + return NULL; + + if (ui_unit_view_mode->value != df::ui_unit_view_mode::Inventory) + return NULL; + + auto inv_item = vector_get(ui_sidebar_menus->unit.inv_items, *ui_look_cursor); + return inv_item ? inv_item->item : 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::Item) + return item->item; + else + return NULL; + } + case BuildingItems: + { + if (!ui_building_item_cursor) + return NULL; + + VIRTUAL_CAST_VAR(selected, df::building_actual, world->selected_building); + if (!selected) + return NULL; + + auto inv_item = vector_get(selected->contained_items, *ui_building_item_cursor); + return inv_item ? inv_item->item : NULL; + } + default: + return NULL; + } +} + +bool DFHack::any_item_hotkey(Core *c, df::viewscreen *top) +{ + return getAnyItem(c, top) != NULL; +} + +df::item *DFHack::getSelectedItem(Core *c, bool quiet) +{ + df::item *item = getAnyItem(c, c->getTopViewscreen()); + + if (!item && !quiet) + c->con.printerr("No item is selected in the UI.\n"); + + return item; +} + // Module* DFHack::createGui() diff --git a/library/xml b/library/xml index 91b6531e1..f9c6d105a 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 91b6531e1a66e98f7c0ae7f81b5496ccde584b73 +Subproject commit f9c6d105af74cd4e307f513a7df674e685dc9ff0 diff --git a/plugins/cleaners.cpp b/plugins/cleaners.cpp index c25a1ed33..d0b780b4f 100644 --- a/plugins/cleaners.cpp +++ b/plugins/cleaners.cpp @@ -12,6 +12,8 @@ #include "df/unit.h" #include "df/matter_state.h" #include "df/cursor.h" +#include "df/contaminant.h" +#include "df/unit_spatter.h" #include "modules/Materials.h" diff --git a/plugins/rename.cpp b/plugins/rename.cpp index 17841c5fa..8ffc3af05 100644 --- a/plugins/rename.cpp +++ b/plugins/rename.cpp @@ -3,10 +3,16 @@ #include #include +#include + #include #include #include #include +#include +#include +#include +#include #include @@ -30,7 +36,13 @@ DFhackCExport command_result plugin_init (Core *c, std::vector & { commands.clear(); if (world && ui) { - commands.push_back(PluginCommand("rename", "Rename various things.", rename)); + commands.push_back(PluginCommand( + "rename", "Rename various things.", rename, false, + " rename squad \"name\"\n" + " rename hotkey \"name\"\n" + " rename unit \"nickname\"\n" + " (a unit must be highlighted in the ui)\n" + )); } return CR_OK; } @@ -40,12 +52,17 @@ DFhackCExport command_result plugin_shutdown ( Core * c ) return CR_OK; } -static command_result usage(Core *c) +static void set_nickname(df::language_name *name, std::string nick) { - c->con << "Usage:" << endl - << " rename squad \"name\"" << endl - << " rename hotkey \"name\"" << endl; - return CR_OK; + if (!name->has_name) + { + *name = df::language_name(); + + name->language = 0; + name->has_name = true; + } + + name->nickname = nick; } static command_result rename(Core * c, vector ¶meters) @@ -56,34 +73,61 @@ static command_result rename(Core * c, vector ¶meters) if (!parameters.empty()) cmd = parameters[0]; - if (cmd == "squad") { + if (cmd == "squad") + { if (parameters.size() != 3) - return usage(c); - + return CR_WRONG_USAGE; + std::vector &squads = world->squads.all; int id = atoi(parameters[1].c_str()); if (id < 1 || id > squads.size()) { c->con.printerr("Invalid squad index\n"); - return usage(c); + return CR_WRONG_USAGE; } squads[id-1]->alias = parameters[2]; - } else if (cmd == "hotkey") { + } + else if (cmd == "hotkey") + { if (parameters.size() != 3) - return usage(c); + return CR_WRONG_USAGE; int id = atoi(parameters[1].c_str()); if (id < 1 || id > 16) { c->con.printerr("Invalid hotkey index\n"); - return usage(c); + return CR_WRONG_USAGE; } ui->main.hotkeys[id-1].name = parameters[2]; - } else { + } + else if (cmd == "unit") + { + if (parameters.size() != 2) + return CR_WRONG_USAGE; + + df::unit *unit = getSelectedUnit(c); + if (!unit) + return CR_WRONG_USAGE; + + // There are 3 copies of the name, and the one + // in the unit is not the authoritative one. + // This is the reason why military units often + // lose nicknames set from Dwarf Therapist. + set_nickname(&unit->name, parameters[1]); + + if (unit->status.current_soul) + set_nickname(&unit->status.current_soul->name, parameters[1]); + + df::historical_figure *figure = df::historical_figure::find(unit->hist_figure_id); + if (figure) + set_nickname(&figure->name, parameters[1]); + } + else + { if (!parameters.empty() && cmd != "?") c->con.printerr("Invalid command: %s\n", cmd.c_str()); - return usage(c); + return CR_WRONG_USAGE; } return CR_OK;