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.
develop
Alexander Gavrilov 2012-01-14 19:31:43 +04:00
parent 53e9a1659b
commit a31542862a
7 changed files with 310 additions and 18 deletions

@ -1095,6 +1095,11 @@
<Address name='ui_workshop_job_cursor'/>
<Address name='ui_workshop_in_add'/>
<Address name='job_next_id'/>
<Address name='ui_building_item_cursor'/>
<Address name='ui_selected_unit'/>
<Address name='ui_unit_view_mode'/>
<Address name='cur_year'/>
<Address name='cur_year_tick'/>
</Group>
</Offsets>
</Base>
@ -2348,6 +2353,12 @@
<Address name='ui_workshop_in_add' value='0xeb0992'/>
<Address name='job_next_id' value='0xe18290'/>
<Address name='ui_building_item_cursor' value='0xef7264'/>
<Address name='ui_selected_unit' value='0xef2430'/>
<Address name='ui_unit_view_mode' value='0xec4a5c'/>
<Address name='cur_year' value='0xef7268'/>
<Address name='cur_year_tick' value='0xec5170'/>
</Group>
</Offsets>
cmake
@ -3230,11 +3241,17 @@
<Address name='ui_sidebar_menus' value='0x958aa40'/>
<Address name='ui_build_selector' value='0x8df9b20'/>
<Address name='ui_look_list' value='0x961d840'/>
<!--<Address name='ui_look_cursor' value=''/>-->
<Address name='ui_look_cursor' value='0x93f06dc'/>
<Address name='ui_workshop_job_cursor' value='0x93f0644'/>
<Address name='ui_workshop_in_add' value='0x93f0651'/>
<Address name='job_next_id' value='0x961d940'/>
<Address name='ui_building_item_cursor' value='0x93f0648'/>
<Address name='ui_selected_unit' value='0x93f06d0'/>
<Address name='ui_unit_view_mode' value='0x93f06d8'/>
<Address name='cur_year' value='0x93f0600'/>
<Address name='cur_year_tick' value='0x93f0620'/>
</Group>
</Offsets>
</Version>

@ -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; }

@ -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

@ -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<df::viewscreen_dwarfmodest>(top);
}
bool DFHack::unitjobs_hotkey(Core *, df::viewscreen *top)
{
// Require the main dwarf mode screen
return !!strict_virtual_cast<df::viewscreen_unitjobsst>(top);
}
bool DFHack::item_details_hotkey(Core *, df::viewscreen *top)
{
// Require the main dwarf mode screen
return !!strict_virtual_cast<df::viewscreen_itemst>(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()

@ -1 +1 @@
Subproject commit 91b6531e1a66e98f7c0ae7f81b5496ccde584b73
Subproject commit f9c6d105af74cd4e307f513a7df674e685dc9ff0

@ -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"

@ -3,10 +3,16 @@
#include <Export.h>
#include <PluginManager.h>
#include <modules/Gui.h>
#include <DataDefs.h>
#include <df/ui.h>
#include <df/world.h>
#include <df/squad.h>
#include <df/unit.h>
#include <df/unit_soul.h>
#include <df/historical_figure.h>
#include <df/language_name.h>
#include <stdlib.h>
@ -30,7 +36,13 @@ DFhackCExport command_result plugin_init (Core *c, std::vector <PluginCommand> &
{
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 <index> \"name\"\n"
" rename hotkey <index> \"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 <index> \"name\"" << endl
<< " rename hotkey <index> \"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 <string> &parameters)
@ -56,34 +73,61 @@ static command_result rename(Core * c, vector <string> &parameters)
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<df::squad*> &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;