commit
324360f474
@ -1,21 +0,0 @@
|
|||||||
confirm
|
|
||||||
=======
|
|
||||||
|
|
||||||
.. dfhack-tool::
|
|
||||||
:summary: Adds confirmation dialogs for destructive actions.
|
|
||||||
:tags: fort interface
|
|
||||||
|
|
||||||
In the base game, it is frightenly easy to destroy hours of work with a single
|
|
||||||
misclick. Now you can avoid the consequences of accidentally disbanding a squad
|
|
||||||
(for example), or deleting a hauling route.
|
|
||||||
|
|
||||||
Usage
|
|
||||||
-----
|
|
||||||
|
|
||||||
``enable confirm``, ``confirm enable all``
|
|
||||||
Enable all confirmation options. Replace with ``disable`` to disable all.
|
|
||||||
``confirm enable option1 [option2...]``
|
|
||||||
Enable (or ``disable``) specific confirmation dialogs.
|
|
||||||
|
|
||||||
When run without parameters, ``confirm`` will report which confirmation dialogs
|
|
||||||
are currently enabled.
|
|
@ -1,728 +0,0 @@
|
|||||||
#include <map>
|
|
||||||
#include <set>
|
|
||||||
#include <queue>
|
|
||||||
|
|
||||||
#include "Console.h"
|
|
||||||
#include "Core.h"
|
|
||||||
#include "DataDefs.h"
|
|
||||||
#include "Debug.h"
|
|
||||||
#include "Error.h"
|
|
||||||
#include "Export.h"
|
|
||||||
#include "LuaTools.h"
|
|
||||||
#include "LuaWrapper.h"
|
|
||||||
#include "PluginManager.h"
|
|
||||||
#include "VTableInterpose.h"
|
|
||||||
#include "modules/Gui.h"
|
|
||||||
#include "uicommon.h"
|
|
||||||
|
|
||||||
#include "df/gamest.h"
|
|
||||||
#include "df/general_ref.h"
|
|
||||||
#include "df/general_ref_contained_in_itemst.h"
|
|
||||||
#include "df/interfacest.h"
|
|
||||||
#include "df/viewscreen_dwarfmodest.h"
|
|
||||||
|
|
||||||
using namespace DFHack;
|
|
||||||
using namespace df::enums;
|
|
||||||
using std::map;
|
|
||||||
using std::queue;
|
|
||||||
using std::string;
|
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
DFHACK_PLUGIN("confirm");
|
|
||||||
DFHACK_PLUGIN_IS_ENABLED(is_enabled);
|
|
||||||
REQUIRE_GLOBAL(game);
|
|
||||||
REQUIRE_GLOBAL(gps);
|
|
||||||
|
|
||||||
typedef std::set<df::interface_key> ikey_set;
|
|
||||||
command_result df_confirm (color_ostream &out, vector <string> & parameters);
|
|
||||||
|
|
||||||
struct conf_wrapper;
|
|
||||||
static map<string, conf_wrapper*> confirmations;
|
|
||||||
string active_id;
|
|
||||||
queue<string> cmds;
|
|
||||||
|
|
||||||
namespace DFHack {
|
|
||||||
DBG_DECLARE(confirm,status);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename VT, typename FT>
|
|
||||||
inline bool in_vector (std::vector<VT> &vec, FT item)
|
|
||||||
{
|
|
||||||
return std::find(vec.begin(), vec.end(), item) != vec.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
string char_replace (string s, char a, char b)
|
|
||||||
{
|
|
||||||
string res = s;
|
|
||||||
size_t i = res.size();
|
|
||||||
while (i--)
|
|
||||||
if (res[i] == a)
|
|
||||||
res[i] = b;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool set_conf_state (string name, bool state);
|
|
||||||
bool set_conf_paused (string name, bool pause);
|
|
||||||
|
|
||||||
class confirmation_base {
|
|
||||||
public:
|
|
||||||
bool dirty = false;
|
|
||||||
enum cstate { INACTIVE, ACTIVE, SELECTED };
|
|
||||||
virtual string get_id() = 0;
|
|
||||||
virtual string get_focus_string() = 0;
|
|
||||||
virtual bool set_state(cstate) = 0;
|
|
||||||
|
|
||||||
static bool set_state(string id, cstate state)
|
|
||||||
{
|
|
||||||
if (active && active->get_id() == id)
|
|
||||||
{
|
|
||||||
active->set_state(state);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
protected:
|
|
||||||
static confirmation_base *active;
|
|
||||||
};
|
|
||||||
confirmation_base *confirmation_base::active = nullptr;
|
|
||||||
|
|
||||||
struct conf_wrapper {
|
|
||||||
private:
|
|
||||||
bool enabled;
|
|
||||||
bool paused;
|
|
||||||
std::set<VMethodInterposeLinkBase*> hooks;
|
|
||||||
public:
|
|
||||||
conf_wrapper()
|
|
||||||
:enabled(false),
|
|
||||||
paused(false)
|
|
||||||
{}
|
|
||||||
void add_hook(VMethodInterposeLinkBase *hook)
|
|
||||||
{
|
|
||||||
if (!hooks.count(hook))
|
|
||||||
hooks.insert(hook);
|
|
||||||
}
|
|
||||||
bool apply (bool state) {
|
|
||||||
if (state == enabled)
|
|
||||||
return true;
|
|
||||||
for (auto hook : hooks)
|
|
||||||
{
|
|
||||||
if (!hook->apply(state))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
enabled = state;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool set_paused (bool pause) {
|
|
||||||
paused = pause;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
inline bool is_enabled() { return enabled; }
|
|
||||||
inline bool is_paused() { return paused; }
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace trade {
|
|
||||||
static bool goods_selected (std::vector<uint8_t> &selected)
|
|
||||||
{
|
|
||||||
if(!game->main_interface.trade.open)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (uint8_t sel : selected)
|
|
||||||
if (sel == 1)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
inline bool trader_goods_selected ()
|
|
||||||
{
|
|
||||||
return goods_selected(game->main_interface.trade.goodflag[0]);
|
|
||||||
}
|
|
||||||
inline bool broker_goods_selected ()
|
|
||||||
{
|
|
||||||
return goods_selected(game->main_interface.trade.goodflag[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*static bool goods_all_selected(const std::vector<char>& selected, const std::vector<df::item*>& items) \
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < selected.size(); ++i)
|
|
||||||
{
|
|
||||||
if (!selected[i])
|
|
||||||
{
|
|
||||||
// check to see if item is in a container
|
|
||||||
// (if the container is not selected, it will be detected separately)
|
|
||||||
bool in_container = false;
|
|
||||||
for (auto ref : items[i]->general_refs)
|
|
||||||
{
|
|
||||||
if (virtual_cast<df::general_ref_contained_in_itemst>(ref))
|
|
||||||
{
|
|
||||||
in_container = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!in_container)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
inline bool trader_goods_all_selected()
|
|
||||||
{
|
|
||||||
return goods_all_selected(screen->trader_selected, screen->trader_items);
|
|
||||||
}
|
|
||||||
inline bool broker_goods_all_selected()
|
|
||||||
{
|
|
||||||
return goods_all_selected(screen->broker_selected, screen->broker_items);
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace conf_lua {
|
|
||||||
static color_ostream_proxy *out;
|
|
||||||
static lua_State *l_state;
|
|
||||||
bool init (color_ostream &dfout)
|
|
||||||
{
|
|
||||||
out = new color_ostream_proxy(Core::getInstance().getConsole());
|
|
||||||
l_state = Lua::Open(*out);
|
|
||||||
return l_state;
|
|
||||||
}
|
|
||||||
void cleanup()
|
|
||||||
{
|
|
||||||
if (out)
|
|
||||||
{
|
|
||||||
delete out;
|
|
||||||
out = nullptr;
|
|
||||||
}
|
|
||||||
lua_close(l_state);
|
|
||||||
}
|
|
||||||
bool call (const char *func, int nargs = 0, int nres = 0)
|
|
||||||
{
|
|
||||||
if (!Lua::PushModulePublic(*out, l_state, "plugins.confirm", func))
|
|
||||||
return false;
|
|
||||||
if (nargs > 0)
|
|
||||||
lua_insert(l_state, lua_gettop(l_state) - nargs);
|
|
||||||
return Lua::SafeCall(*out, l_state, nargs, nres);
|
|
||||||
}
|
|
||||||
bool simple_call (const char *func)
|
|
||||||
{
|
|
||||||
Lua::StackUnwinder top(l_state);
|
|
||||||
return call(func, 0, 0);
|
|
||||||
}
|
|
||||||
template <typename T>
|
|
||||||
void push (T val)
|
|
||||||
{
|
|
||||||
Lua::Push(l_state, val);
|
|
||||||
}
|
|
||||||
namespace api {
|
|
||||||
int get_ids (lua_State *L)
|
|
||||||
{
|
|
||||||
lua_newtable(L);
|
|
||||||
for (auto item : confirmations)
|
|
||||||
Lua::TableInsert(L, item.first, true);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
int get_conf_data (lua_State *L)
|
|
||||||
{
|
|
||||||
lua_newtable(L);
|
|
||||||
int i = 1;
|
|
||||||
for (auto item : confirmations)
|
|
||||||
{
|
|
||||||
Lua::Push(L, i++);
|
|
||||||
lua_newtable(L);
|
|
||||||
Lua::TableInsert(L, "id", item.first);
|
|
||||||
Lua::TableInsert(L, "enabled", item.second->is_enabled());
|
|
||||||
Lua::TableInsert(L, "paused", item.second->is_paused());
|
|
||||||
lua_settable(L, -3);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
int get_active_id (lua_State *L)
|
|
||||||
{
|
|
||||||
if (active_id.size())
|
|
||||||
Lua::Push(L, active_id);
|
|
||||||
else
|
|
||||||
lua_pushnil(L);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CONF_LUA_FUNC(ns, name) {#name, df::wrap_function(ns::name, true)}
|
|
||||||
DFHACK_PLUGIN_LUA_FUNCTIONS {
|
|
||||||
CONF_LUA_FUNC( , set_conf_state),
|
|
||||||
CONF_LUA_FUNC( , set_conf_paused),
|
|
||||||
CONF_LUA_FUNC(trade, broker_goods_selected),
|
|
||||||
//CONF_LUA_FUNC(trade, broker_goods_all_selected),
|
|
||||||
CONF_LUA_FUNC(trade, trader_goods_selected),
|
|
||||||
//CONF_LUA_FUNC(trade, trader_goods_all_selected),
|
|
||||||
DFHACK_LUA_END
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CONF_LUA_CMD(name) {#name, conf_lua::api::name}
|
|
||||||
DFHACK_PLUGIN_LUA_COMMANDS {
|
|
||||||
CONF_LUA_CMD(get_ids),
|
|
||||||
CONF_LUA_CMD(get_conf_data),
|
|
||||||
CONF_LUA_CMD(get_active_id),
|
|
||||||
DFHACK_LUA_END
|
|
||||||
};
|
|
||||||
|
|
||||||
void show_options()
|
|
||||||
{
|
|
||||||
cmds.push("gui/confirm");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class confirmation : public confirmation_base {
|
|
||||||
public:
|
|
||||||
typedef T screen_type;
|
|
||||||
screen_type *screen;
|
|
||||||
|
|
||||||
bool set_state (cstate s) override
|
|
||||||
{
|
|
||||||
if (confirmation_base::active && confirmation_base::active != this)
|
|
||||||
{
|
|
||||||
// Stop this confirmation from appearing over another one
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
state = s;
|
|
||||||
dirty = true;
|
|
||||||
if (s == INACTIVE) {
|
|
||||||
active_id = "";
|
|
||||||
confirmation_base::active = nullptr;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
active_id = get_id();
|
|
||||||
confirmation_base::active = this;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool feed (ikey_set *input) {
|
|
||||||
bool mouseExit = false;
|
|
||||||
if(df::global::enabler->mouse_rbut) {
|
|
||||||
mouseExit = true;
|
|
||||||
}
|
|
||||||
bool mouseSelect = false;
|
|
||||||
if(df::global::enabler->mouse_lbut) {
|
|
||||||
mouseSelect = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
conf_wrapper *wrapper = confirmations[this->get_id()];
|
|
||||||
if(wrapper->is_paused()) {
|
|
||||||
std::string concernedFocus = this->get_focus_string();
|
|
||||||
if(!Gui::matchFocusString(this->get_focus_string()))
|
|
||||||
wrapper->set_paused(false);
|
|
||||||
return false;
|
|
||||||
} else if (state == INACTIVE)
|
|
||||||
{
|
|
||||||
if(mouseExit) {
|
|
||||||
if(intercept_key("MOUSE_RIGHT") && set_state(ACTIVE)) {
|
|
||||||
df::global::enabler->mouse_rbut = 0;
|
|
||||||
df::global::enabler->mouse_rbut_down = 0;
|
|
||||||
mouse_pos = df::coord2d(df::global::gps->mouse_x, df::global::gps->mouse_y);
|
|
||||||
last_key_is_right_click = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
last_key_is_right_click = false;
|
|
||||||
|
|
||||||
if(mouseSelect) {
|
|
||||||
if(intercept_key("MOUSE_LEFT") && set_state(ACTIVE)) {
|
|
||||||
df::global::enabler->mouse_lbut = 0;
|
|
||||||
df::global::enabler->mouse_lbut_down = 0;
|
|
||||||
mouse_pos = df::coord2d(df::global::gps->mouse_x, df::global::gps->mouse_y);
|
|
||||||
last_key_is_left_click = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
last_key_is_left_click = false;
|
|
||||||
|
|
||||||
for (df::interface_key key : *input)
|
|
||||||
{
|
|
||||||
if (intercept_key(key) && set_state(ACTIVE))
|
|
||||||
{
|
|
||||||
last_key = key;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (state == ACTIVE)
|
|
||||||
{
|
|
||||||
if (input->count(df::interface_key::LEAVESCREEN) || mouseExit) {
|
|
||||||
if(mouseExit) {
|
|
||||||
df::global::enabler->mouse_rbut = 0;
|
|
||||||
df::global::enabler->mouse_rbut_down = 0;
|
|
||||||
}
|
|
||||||
set_state(INACTIVE);
|
|
||||||
} else if (input->count(df::interface_key::SELECT))
|
|
||||||
set_state(SELECTED);
|
|
||||||
else if (input->count(df::interface_key::CUSTOM_P))
|
|
||||||
{
|
|
||||||
DEBUG(status).print("pausing\n");
|
|
||||||
|
|
||||||
wrapper->set_paused(true);
|
|
||||||
set_state(INACTIVE);
|
|
||||||
}
|
|
||||||
else if (input->count(df::interface_key::CUSTOM_S))
|
|
||||||
show_options();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool key_conflict (df::interface_key key)
|
|
||||||
{
|
|
||||||
if (key == df::interface_key::SELECT || key == df::interface_key::LEAVESCREEN)
|
|
||||||
return false;
|
|
||||||
return state == ACTIVE;
|
|
||||||
}
|
|
||||||
void render() {
|
|
||||||
if (state == ACTIVE)
|
|
||||||
{
|
|
||||||
static vector<string> lines;
|
|
||||||
static const std::string pause_message =
|
|
||||||
"Pause confirmations until you exit this screen";
|
|
||||||
Screen::Pen corner_ul = Screen::Pen((char)201, COLOR_GREY, COLOR_BLACK);
|
|
||||||
Screen::Pen corner_ur = Screen::Pen((char)187, COLOR_GREY, COLOR_BLACK);
|
|
||||||
Screen::Pen corner_dl = Screen::Pen((char)200, COLOR_GREY, COLOR_BLACK);
|
|
||||||
Screen::Pen corner_dr = Screen::Pen((char)188, COLOR_GREY, COLOR_BLACK);
|
|
||||||
Screen::Pen border_ud = Screen::Pen((char)205, COLOR_GREY, COLOR_BLACK);
|
|
||||||
Screen::Pen border_lr = Screen::Pen((char)186, COLOR_GREY, COLOR_BLACK);
|
|
||||||
|
|
||||||
split_string(&lines, get_message(), "\n");
|
|
||||||
size_t max_length = 40;
|
|
||||||
for (string line : lines)
|
|
||||||
max_length = std::max(max_length, line.size());
|
|
||||||
int width = max_length + 4;
|
|
||||||
vector<string> pause_message_lines;
|
|
||||||
word_wrap(&pause_message_lines, pause_message, max_length - 3);
|
|
||||||
int height = lines.size() + pause_message_lines.size() + 5;
|
|
||||||
int x1 = (gps->dimx / 2) - (width / 2);
|
|
||||||
int x2 = x1 + width - 1;
|
|
||||||
int y1 = (gps->dimy / 2) - (height / 2);
|
|
||||||
int y2 = y1 + height - 1;
|
|
||||||
for (int x = x1; x <= x2; x++)
|
|
||||||
{
|
|
||||||
Screen::paintTile(border_ud, x, y1);
|
|
||||||
Screen::paintTile(border_ud, x, y2);
|
|
||||||
}
|
|
||||||
for (int y = y1; y <= y2; y++)
|
|
||||||
{
|
|
||||||
Screen::paintTile(border_lr, x1, y);
|
|
||||||
Screen::paintTile(border_lr, x2, y);
|
|
||||||
}
|
|
||||||
Screen::paintTile(corner_ul, x1, y1);
|
|
||||||
Screen::paintTile(corner_ur, x2, y1);
|
|
||||||
Screen::paintTile(corner_dl, x1, y2);
|
|
||||||
Screen::paintTile(corner_dr, x2, y2);
|
|
||||||
string title = ' ' + get_title() + ' ';
|
|
||||||
Screen::paintString(Screen::Pen(' ', COLOR_DARKGREY, COLOR_BLACK),
|
|
||||||
x2 - 6, y1, "DFHack");
|
|
||||||
Screen::paintString(Screen::Pen(' ', COLOR_BLACK, COLOR_GREY),
|
|
||||||
(gps->dimx / 2) - (title.size() / 2), y1, title);
|
|
||||||
int x = x1 + 2;
|
|
||||||
int y = y2;
|
|
||||||
OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(df::interface_key::LEAVESCREEN));
|
|
||||||
OutputString(COLOR_WHITE, x, y, ": Cancel");
|
|
||||||
x = (gps->dimx - (Screen::getKeyDisplay(df::interface_key::CUSTOM_S) + ": Settings").size()) / 2 + 1;
|
|
||||||
OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(df::interface_key::CUSTOM_S));
|
|
||||||
OutputString(COLOR_WHITE, x, y, ": Settings");
|
|
||||||
x = x2 - 2 - 3 - Screen::getKeyDisplay(df::interface_key::SELECT).size();
|
|
||||||
OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(df::interface_key::SELECT));
|
|
||||||
OutputString(COLOR_WHITE, x, y, ": Ok");
|
|
||||||
Screen::fillRect(Screen::Pen(' ', COLOR_BLACK, COLOR_BLACK), x1 + 1, y1 + 1, x2 - 1, y2 - 1);
|
|
||||||
for (size_t i = 0; i < lines.size(); i++)
|
|
||||||
{
|
|
||||||
Screen::paintString(Screen::Pen(' ', get_color(), COLOR_BLACK), x1 + 2, y1 + 2 + i, lines[i]);
|
|
||||||
}
|
|
||||||
y = y1 + 3 + lines.size();
|
|
||||||
for (size_t i = 0; i < pause_message_lines.size(); i++)
|
|
||||||
{
|
|
||||||
Screen::paintString(Screen::Pen(' ', COLOR_WHITE, COLOR_BLACK), x1 + 5, y + i, pause_message_lines[i]);
|
|
||||||
}
|
|
||||||
x = x1 + 2;
|
|
||||||
OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(df::interface_key::CUSTOM_P));
|
|
||||||
OutputString(COLOR_WHITE, x, y, ":");
|
|
||||||
}
|
|
||||||
else if (state == SELECTED)
|
|
||||||
{
|
|
||||||
ikey_set tmp;
|
|
||||||
if(last_key_is_left_click) {
|
|
||||||
long prevx = df::global::gps->mouse_x;
|
|
||||||
long prevy = df::global::gps->mouse_y;
|
|
||||||
df::global::gps->mouse_x = mouse_pos.x;
|
|
||||||
df::global::gps->mouse_y = mouse_pos.y;
|
|
||||||
df::global::enabler->mouse_lbut = 1;
|
|
||||||
df::global::enabler->mouse_lbut_down = 1;
|
|
||||||
screen->feed(&tmp);
|
|
||||||
df::global::enabler->mouse_lbut = 0;
|
|
||||||
df::global::enabler->mouse_lbut_down = 0;
|
|
||||||
df::global::gps->mouse_x = prevx;
|
|
||||||
df::global::gps->mouse_y = prevy;
|
|
||||||
}
|
|
||||||
else if(last_key_is_right_click) {
|
|
||||||
tmp.insert(df::interface_key::LEAVESCREEN);
|
|
||||||
screen->feed(&tmp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tmp.insert(last_key);
|
|
||||||
screen->feed(&tmp);
|
|
||||||
}
|
|
||||||
set_state(INACTIVE);
|
|
||||||
}
|
|
||||||
if(dirty) {
|
|
||||||
dirty = false;
|
|
||||||
df::global::gps->force_full_display_count = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string get_id() override = 0;
|
|
||||||
string get_focus_string() override = 0;
|
|
||||||
#define CONF_LUA_START using namespace conf_lua; Lua::StackUnwinder unwind(l_state); push(screen); push(get_id());
|
|
||||||
bool intercept_key (df::interface_key key)
|
|
||||||
{
|
|
||||||
CONF_LUA_START;
|
|
||||||
push(key);
|
|
||||||
if (call("intercept_key", 3, 1))
|
|
||||||
return lua_toboolean(l_state, -1);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
bool intercept_key (std::string mouse_button = "MOUSE_LEFT")
|
|
||||||
{
|
|
||||||
CONF_LUA_START;
|
|
||||||
push(mouse_button);
|
|
||||||
if (call("intercept_key", 3, 1))
|
|
||||||
return lua_toboolean(l_state, -1);
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
string get_title()
|
|
||||||
{
|
|
||||||
CONF_LUA_START;
|
|
||||||
if (call("get_title", 2, 1) && lua_isstring(l_state, -1))
|
|
||||||
return lua_tostring(l_state, -1);
|
|
||||||
else
|
|
||||||
return "Confirm";
|
|
||||||
}
|
|
||||||
string get_message()
|
|
||||||
{
|
|
||||||
CONF_LUA_START;
|
|
||||||
if (call("get_message", 2, 1) && lua_isstring(l_state, -1))
|
|
||||||
return lua_tostring(l_state, -1);
|
|
||||||
else
|
|
||||||
return "<Message generation failed>";
|
|
||||||
};
|
|
||||||
UIColor get_color()
|
|
||||||
{
|
|
||||||
CONF_LUA_START;
|
|
||||||
if (call("get_color", 2, 1) && lua_isnumber(l_state, -1))
|
|
||||||
return lua_tointeger(l_state, -1) % 16;
|
|
||||||
else
|
|
||||||
return COLOR_YELLOW;
|
|
||||||
}
|
|
||||||
#undef CONF_LUA_START
|
|
||||||
protected:
|
|
||||||
cstate state;
|
|
||||||
df::interface_key last_key;
|
|
||||||
bool last_key_is_left_click;
|
|
||||||
bool last_key_is_right_click;
|
|
||||||
df::coord2d mouse_pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
int conf_register(confirmation<T> *c, const vector<VMethodInterposeLinkBase*> &hooks)
|
|
||||||
{
|
|
||||||
conf_wrapper *w = new conf_wrapper();
|
|
||||||
confirmations[c->get_id()] = w;
|
|
||||||
for (auto hook : hooks)
|
|
||||||
w->add_hook(hook);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define IMPLEMENT_CONFIRMATION_HOOKS(cls, prio) \
|
|
||||||
static cls cls##_instance; \
|
|
||||||
struct cls##_hooks : cls::screen_type { \
|
|
||||||
typedef cls::screen_type interpose_base; \
|
|
||||||
DEFINE_VMETHOD_INTERPOSE(void, feed, (ikey_set *input)) \
|
|
||||||
{ \
|
|
||||||
cls##_instance.screen = this; \
|
|
||||||
if (!cls##_instance.feed(input)) \
|
|
||||||
INTERPOSE_NEXT(feed)(input); \
|
|
||||||
} \
|
|
||||||
DEFINE_VMETHOD_INTERPOSE(void, render, ()) \
|
|
||||||
{ \
|
|
||||||
cls##_instance.screen = this; \
|
|
||||||
INTERPOSE_NEXT(render)(); \
|
|
||||||
cls##_instance.render(); \
|
|
||||||
} \
|
|
||||||
}; \
|
|
||||||
IMPLEMENT_VMETHOD_INTERPOSE_PRIO(cls##_hooks, feed, prio); \
|
|
||||||
IMPLEMENT_VMETHOD_INTERPOSE_PRIO(cls##_hooks, render, prio); \
|
|
||||||
static int conf_register_##cls = conf_register(&cls##_instance, {\
|
|
||||||
&INTERPOSE_HOOK(cls##_hooks, feed), \
|
|
||||||
&INTERPOSE_HOOK(cls##_hooks, render), \
|
|
||||||
});
|
|
||||||
|
|
||||||
#define DEFINE_CONFIRMATION(cls, screen, focusString) \
|
|
||||||
class confirmation_##cls : public confirmation<df::screen> { \
|
|
||||||
virtual string get_id() { static string id = char_replace(#cls, '_', '-'); return id; } \
|
|
||||||
virtual string get_focus_string() { return focusString; } \
|
|
||||||
}; \
|
|
||||||
IMPLEMENT_CONFIRMATION_HOOKS(confirmation_##cls, 0);
|
|
||||||
|
|
||||||
/* This section defines stubs for all confirmation dialogs, with methods
|
|
||||||
implemented in plugins/lua/confirm.lua.
|
|
||||||
IDs (used in the "confirm enable/disable" command, by Lua, and in the docs)
|
|
||||||
are obtained by replacing '_' with '-' in the first argument to DEFINE_CONFIRMATION
|
|
||||||
|
|
||||||
The second argument to DEFINE_CONFIRMATION determines the viewscreen that any
|
|
||||||
intercepted input will be fed to.
|
|
||||||
|
|
||||||
The third argument to DEFINE_CONFIRMATION determines the focus string that will
|
|
||||||
be used to determine if the confirmation should be unpaused. If a confirmation is paused
|
|
||||||
and the focus string is no longer found in the current focus, the confirmation will be
|
|
||||||
unpaused. Focus strings ending in "*" will use prefix matching e.g. "dwarfmode/Info*" would
|
|
||||||
match "dwarfmode/Info/Foo", "dwarfmode/Info/Bar" and so on. All matching is case insensitive.
|
|
||||||
*/
|
|
||||||
|
|
||||||
DEFINE_CONFIRMATION(trade_cancel, viewscreen_dwarfmodest, "dwarfmode/Trade");
|
|
||||||
DEFINE_CONFIRMATION(haul_delete_route, viewscreen_dwarfmodest, "dwarfmode/Hauling");
|
|
||||||
DEFINE_CONFIRMATION(haul_delete_stop, viewscreen_dwarfmodest, "dwarfmode/Hauling");
|
|
||||||
DEFINE_CONFIRMATION(depot_remove, viewscreen_dwarfmodest, "dwarfmode/ViewSheets/BUILDING");
|
|
||||||
DEFINE_CONFIRMATION(squad_disband, viewscreen_dwarfmodest, "dwarfmode/Squads");
|
|
||||||
DEFINE_CONFIRMATION(order_remove, viewscreen_dwarfmodest, "dwarfmode/Info/WORK_ORDERS");
|
|
||||||
DEFINE_CONFIRMATION(zone_remove, viewscreen_dwarfmodest, "dwarfmode/Zone");
|
|
||||||
DEFINE_CONFIRMATION(burrow_remove, viewscreen_dwarfmodest, "dwarfmode/Burrow");
|
|
||||||
DEFINE_CONFIRMATION(stockpile_remove, viewscreen_dwarfmodest, "dwarfmode/Some/Stockpile");
|
|
||||||
|
|
||||||
// these are more complex to implement
|
|
||||||
//DEFINE_CONFIRMATION(convict, viewscreen_dwarfmodest);
|
|
||||||
//DEFINE_CONFIRMATION(trade, viewscreen_dwarfmodest);
|
|
||||||
//DEFINE_CONFIRMATION(trade_seize, viewscreen_dwarfmodest);
|
|
||||||
//DEFINE_CONFIRMATION(trade_offer, viewscreen_dwarfmodest);
|
|
||||||
//DEFINE_CONFIRMATION(trade_select_all, viewscreen_dwarfmodest);
|
|
||||||
//DEFINE_CONFIRMATION(uniform_delete, viewscreen_dwarfmodest);
|
|
||||||
//DEFINE_CONFIRMATION(note_delete, viewscreen_dwarfmodest);
|
|
||||||
//DEFINE_CONFIRMATION(route_delete, viewscreen_dwarfmodest);
|
|
||||||
|
|
||||||
// locations can't be retired currently
|
|
||||||
//DEFINE_CONFIRMATION(location_retire, viewscreen_locationsst);
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_init (color_ostream &out, vector <PluginCommand> &commands)
|
|
||||||
{
|
|
||||||
if (!conf_lua::init(out))
|
|
||||||
return CR_FAILURE;
|
|
||||||
commands.push_back(PluginCommand(
|
|
||||||
"confirm",
|
|
||||||
"Add confirmation dialogs for destructive actions.",
|
|
||||||
df_confirm));
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_enable (color_ostream &out, bool enable)
|
|
||||||
{
|
|
||||||
is_enabled = enable;
|
|
||||||
if (is_enabled)
|
|
||||||
{
|
|
||||||
conf_lua::simple_call("check");
|
|
||||||
}
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_shutdown (color_ostream &out)
|
|
||||||
{
|
|
||||||
if (plugin_enable(out, false) != CR_OK)
|
|
||||||
return CR_FAILURE;
|
|
||||||
conf_lua::cleanup();
|
|
||||||
|
|
||||||
for (auto item : confirmations)
|
|
||||||
{
|
|
||||||
delete item.second;
|
|
||||||
}
|
|
||||||
confirmations.clear();
|
|
||||||
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
DFhackCExport command_result plugin_onupdate (color_ostream &out)
|
|
||||||
{
|
|
||||||
while (!cmds.empty())
|
|
||||||
{
|
|
||||||
Core::getInstance().runCommand(out, cmds.front());
|
|
||||||
cmds.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool set_conf_state (string name, bool state)
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (auto it : confirmations)
|
|
||||||
{
|
|
||||||
if (it.first == name)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
it.second->apply(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == false)
|
|
||||||
{
|
|
||||||
// dismiss the confirmation too
|
|
||||||
confirmation_base::set_state(name, confirmation_base::INACTIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool set_conf_paused (string name, bool pause)
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (auto it : confirmations)
|
|
||||||
{
|
|
||||||
if (it.first == name)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
it.second->set_paused(pause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pause == true)
|
|
||||||
{
|
|
||||||
// dismiss the confirmation too
|
|
||||||
confirmation_base::set_state(name, confirmation_base::INACTIVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
void enable_conf (color_ostream &out, string name, bool state)
|
|
||||||
{
|
|
||||||
if (!set_conf_state(name, state))
|
|
||||||
out.printerr("Unrecognized option: %s\n", name.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
command_result df_confirm (color_ostream &out, vector <string> & parameters)
|
|
||||||
{
|
|
||||||
CoreSuspender suspend;
|
|
||||||
bool state = true;
|
|
||||||
if (parameters.empty() || in_vector(parameters, "help") || in_vector(parameters, "status"))
|
|
||||||
{
|
|
||||||
out << "Available options: \n";
|
|
||||||
for (auto it : confirmations)
|
|
||||||
out.print(" %20s: %s\n", it.first.c_str(), it.second->is_enabled() ? "enabled" : "disabled");
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
||||||
for (string param : parameters)
|
|
||||||
{
|
|
||||||
if (param == "enable")
|
|
||||||
state = true;
|
|
||||||
else if (param == "disable")
|
|
||||||
state = false;
|
|
||||||
else if (param == "all")
|
|
||||||
{
|
|
||||||
for (auto it : confirmations)
|
|
||||||
it.second->apply(state);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
enable_conf(out, param, state);
|
|
||||||
}
|
|
||||||
return CR_OK;
|
|
||||||
}
|
|
@ -1,287 +0,0 @@
|
|||||||
local _ENV = mkmodule('plugins.confirm')
|
|
||||||
|
|
||||||
local confs = {}
|
|
||||||
-- Wraps df.interface_key[foo] functionality but fails with invalid keys
|
|
||||||
keys = {}
|
|
||||||
setmetatable(keys, {
|
|
||||||
__index = function(self, k)
|
|
||||||
return df.interface_key[k] or error('Invalid key: ' .. tostring(k))
|
|
||||||
end,
|
|
||||||
__newindex = function() error('Table is read-only') end
|
|
||||||
})
|
|
||||||
-- Mouse keys will be sent as a string instead of interface_key
|
|
||||||
local MOUSE_LEFT = "MOUSE_LEFT"
|
|
||||||
local MOUSE_RIGHT = "MOUSE_RIGHT"
|
|
||||||
|
|
||||||
--[[ The screen where a confirmation has been triggered
|
|
||||||
Note that this is *not* necessarily the topmost viewscreen, so do not use
|
|
||||||
gui.getCurViewscreen() or related functions. ]]
|
|
||||||
--screen = nil
|
|
||||||
|
|
||||||
function if_nil(obj, default)
|
|
||||||
if obj == nil then
|
|
||||||
return default
|
|
||||||
else
|
|
||||||
return obj
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function defconf(id)
|
|
||||||
if not get_ids()[id] then
|
|
||||||
error('Bad confirmation ID (not defined in plugin): ' .. id)
|
|
||||||
end
|
|
||||||
local cls = {}
|
|
||||||
cls.intercept_key = function(key) return false end
|
|
||||||
cls.get_title = function() return if_nil(cls.title, '<No title>') end
|
|
||||||
cls.get_message = function() return if_nil(cls.message, '<No message>') end
|
|
||||||
cls.get_color = function() return if_nil(cls.color, COLOR_YELLOW) end
|
|
||||||
confs[id] = cls
|
|
||||||
return cls
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[ Beginning of confirmation definitions
|
|
||||||
All confirmations declared in confirm.cpp must have a corresponding call to
|
|
||||||
defconf() here, and should implement intercept_key(), get_title(), and
|
|
||||||
get_message(). get_color() can also be implemented here, but the default should
|
|
||||||
be sufficient.
|
|
||||||
|
|
||||||
In cases where getter functions always return the same value (e.g. get_title()),
|
|
||||||
they can be replaced with a field named after the method without the "get_"
|
|
||||||
prefix:
|
|
||||||
|
|
||||||
trade.title = "Confirm trade"
|
|
||||||
|
|
||||||
is equivalent to:
|
|
||||||
|
|
||||||
function trade.get_title() return "Confirm trade" end
|
|
||||||
|
|
||||||
]]
|
|
||||||
|
|
||||||
trade_cancel = defconf('trade-cancel')
|
|
||||||
function trade_cancel.intercept_key(key)
|
|
||||||
return dfhack.gui.matchFocusString("dwarfmode/Trade") and
|
|
||||||
(key == keys.LEAVESCREEN or key == MOUSE_RIGHT) and
|
|
||||||
(trader_goods_selected() or broker_goods_selected())
|
|
||||||
end
|
|
||||||
trade_cancel.title = "Cancel trade"
|
|
||||||
trade_cancel.message = "Are you sure you want leave this screen?\nSelected items will not be saved."
|
|
||||||
|
|
||||||
haul_delete_route = defconf('haul-delete-route')
|
|
||||||
function haul_delete_route.intercept_key(key)
|
|
||||||
return df.global.game.main_interface.current_hover == 180 and key == MOUSE_LEFT
|
|
||||||
end
|
|
||||||
haul_delete_route.title = "Confirm deletion"
|
|
||||||
haul_delete_route.message = "Are you sure you want to delete this route?"
|
|
||||||
|
|
||||||
haul_delete_stop = defconf('haul-delete-stop')
|
|
||||||
function haul_delete_stop.intercept_key(key)
|
|
||||||
return df.global.game.main_interface.current_hover == 185 and key == MOUSE_LEFT
|
|
||||||
end
|
|
||||||
haul_delete_stop.title = "Confirm deletion"
|
|
||||||
haul_delete_stop.message = "Are you sure you want to delete this stop?"
|
|
||||||
|
|
||||||
depot_remove = defconf('depot-remove')
|
|
||||||
function depot_remove.intercept_key(key)
|
|
||||||
if df.global.game.main_interface.current_hover == 301 and
|
|
||||||
key == MOUSE_LEFT and
|
|
||||||
df.building_tradedepotst:is_instance(dfhack.gui.getSelectedBuilding(true)) then
|
|
||||||
for _, caravan in pairs(df.global.plotinfo.caravans) do
|
|
||||||
if caravan.time_remaining > 0 then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
depot_remove.title = "Confirm depot removal"
|
|
||||||
depot_remove.message = "Are you sure you want to remove this depot?\n" ..
|
|
||||||
"Merchants are present and will lose profits."
|
|
||||||
|
|
||||||
squad_disband = defconf('squad-disband')
|
|
||||||
function squad_disband.intercept_key(key)
|
|
||||||
return key == MOUSE_LEFT and df.global.game.main_interface.current_hover == 343
|
|
||||||
end
|
|
||||||
squad_disband.title = "Disband squad"
|
|
||||||
squad_disband.message = "Are you sure you want to disband this squad?"
|
|
||||||
|
|
||||||
order_remove = defconf('order-remove')
|
|
||||||
function order_remove.intercept_key(key)
|
|
||||||
return key == MOUSE_LEFT and df.global.game.main_interface.current_hover == 222
|
|
||||||
end
|
|
||||||
order_remove.title = "Remove manager order"
|
|
||||||
order_remove.message = "Are you sure you want to remove this order?"
|
|
||||||
|
|
||||||
zone_remove = defconf('zone-remove')
|
|
||||||
function zone_remove.intercept_key(key)
|
|
||||||
return key == MOUSE_LEFT and df.global.game.main_interface.current_hover == 130
|
|
||||||
end
|
|
||||||
zone_remove.title = "Remove zone"
|
|
||||||
zone_remove.message = "Are you sure you want to remove this zone?"
|
|
||||||
|
|
||||||
burrow_remove = defconf('burrow-remove')
|
|
||||||
function burrow_remove.intercept_key(key)
|
|
||||||
return key == MOUSE_LEFT and
|
|
||||||
(df.global.game.main_interface.current_hover == 171 or
|
|
||||||
df.global.game.main_interface.current_hover == 168)
|
|
||||||
end
|
|
||||||
burrow_remove.title = "Remove burrow"
|
|
||||||
burrow_remove.message = "Are you sure you want to remove this burrow?"
|
|
||||||
|
|
||||||
stockpile_remove = defconf('stockpile-remove')
|
|
||||||
function stockpile_remove.intercept_key(key)
|
|
||||||
return key == MOUSE_LEFT and df.global.game.main_interface.current_hover == 118
|
|
||||||
end
|
|
||||||
stockpile_remove.title = "Remove stockpile"
|
|
||||||
stockpile_remove.message = "Are you sure you want to remove this stockpile?"
|
|
||||||
|
|
||||||
-- these confirmations have more complex button detection requirements
|
|
||||||
--[[
|
|
||||||
trade = defconf('trade')
|
|
||||||
function trade.intercept_key(key)
|
|
||||||
dfhack.gui.matchFocusString("dwarfmode/Trade") and key == MOUSE_LEFT and hovering over trade button?
|
|
||||||
end
|
|
||||||
trade.title = "Confirm trade"
|
|
||||||
function trade.get_message()
|
|
||||||
if trader_goods_selected() and broker_goods_selected() then
|
|
||||||
return "Are you sure you want to trade the selected goods?"
|
|
||||||
elseif trader_goods_selected() then
|
|
||||||
return "You are not giving any items. This is likely\n" ..
|
|
||||||
"to irritate the merchants.\n" ..
|
|
||||||
"Attempt to trade anyway?"
|
|
||||||
elseif broker_goods_selected() then
|
|
||||||
return "You are not receiving any items. You may want to\n" ..
|
|
||||||
"offer these items instead or choose items to receive.\n" ..
|
|
||||||
"Attempt to trade anyway?"
|
|
||||||
else
|
|
||||||
return "No items are selected. This is likely\n" ..
|
|
||||||
"to irritate the merchants.\n" ..
|
|
||||||
"Attempt to trade anyway?"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
trade_seize = defconf('trade-seize')
|
|
||||||
function trade_seize.intercept_key(key)
|
|
||||||
return screen.in_edit_count == 0 and
|
|
||||||
trader_goods_selected() and
|
|
||||||
key == keys.TRADE_SEIZE
|
|
||||||
end
|
|
||||||
trade_seize.title = "Confirm seize"
|
|
||||||
trade_seize.message = "Are you sure you want to seize these goods?"
|
|
||||||
|
|
||||||
trade_offer = defconf('trade-offer')
|
|
||||||
function trade_offer.intercept_key(key)
|
|
||||||
return screen.in_edit_count == 0 and
|
|
||||||
broker_goods_selected() and
|
|
||||||
key == keys.TRADE_OFFER
|
|
||||||
end
|
|
||||||
trade_offer.title = "Confirm offer"
|
|
||||||
trade_offer.message = "Are you sure you want to offer these goods?\nYou will receive no payment."
|
|
||||||
|
|
||||||
trade_select_all = defconf('trade-select-all')
|
|
||||||
function trade_select_all.intercept_key(key)
|
|
||||||
if screen.in_edit_count == 0 and key == keys.SEC_SELECT then
|
|
||||||
if screen.in_right_pane and broker_goods_selected() and not broker_goods_all_selected() then
|
|
||||||
return true
|
|
||||||
elseif not screen.in_right_pane and trader_goods_selected() and not trader_goods_all_selected() then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
trade_select_all.title = "Confirm selection"
|
|
||||||
trade_select_all.message = "Selecting all goods will overwrite your current selection\n" ..
|
|
||||||
"and cannot be undone. Continue?"
|
|
||||||
|
|
||||||
uniform_delete = defconf('uniform-delete')
|
|
||||||
function uniform_delete.intercept_key(key)
|
|
||||||
return key == keys.D_MILITARY_DELETE_UNIFORM and
|
|
||||||
screen.page == screen._type.T_page.Uniforms and
|
|
||||||
#screen.equip.uniforms > 0 and
|
|
||||||
not screen.equip.in_name_uniform
|
|
||||||
end
|
|
||||||
uniform_delete.title = "Delete uniform"
|
|
||||||
uniform_delete.message = "Are you sure you want to delete this uniform?"
|
|
||||||
|
|
||||||
note_delete = defconf('note-delete')
|
|
||||||
function note_delete.intercept_key(key)
|
|
||||||
return key == keys.D_NOTE_DELETE and
|
|
||||||
ui.main.mode == df.ui_sidebar_mode.NotesPoints and
|
|
||||||
not ui.waypoints.in_edit_name_mode and
|
|
||||||
not ui.waypoints.in_edit_text_mode
|
|
||||||
end
|
|
||||||
note_delete.title = "Delete note"
|
|
||||||
note_delete.message = "Are you sure you want to delete this note?"
|
|
||||||
|
|
||||||
route_delete = defconf('route-delete')
|
|
||||||
function route_delete.intercept_key(key)
|
|
||||||
return key == keys.D_NOTE_ROUTE_DELETE and
|
|
||||||
ui.main.mode == df.ui_sidebar_mode.NotesRoutes and
|
|
||||||
not ui.waypoints.in_edit_name_mode
|
|
||||||
end
|
|
||||||
route_delete.title = "Delete route"
|
|
||||||
route_delete.message = "Are you sure you want to delete this route?"
|
|
||||||
|
|
||||||
convict = defconf('convict')
|
|
||||||
convict.title = "Confirm conviction"
|
|
||||||
function convict.intercept_key(key)
|
|
||||||
return key == keys.SELECT and
|
|
||||||
screen.cur_column == df.viewscreen_justicest.T_cur_column.ConvictChoices
|
|
||||||
end
|
|
||||||
function convict.get_message()
|
|
||||||
name = dfhack.TranslateName(dfhack.units.getVisibleName(screen.convict_choices[screen.cursor_right]))
|
|
||||||
if name == "" then
|
|
||||||
name = "this creature"
|
|
||||||
end
|
|
||||||
return "Are you sure you want to convict " .. name .. "?\n" ..
|
|
||||||
"This action is irreversible."
|
|
||||||
end
|
|
||||||
]]--
|
|
||||||
|
|
||||||
-- locations cannot be retired currently
|
|
||||||
--[[
|
|
||||||
location_retire = defconf('location-retire')
|
|
||||||
function location_retire.intercept_key(key)
|
|
||||||
return key == keys.LOCATION_RETIRE and
|
|
||||||
(screen.menu == df.viewscreen_locationsst.T_menu.Locations or
|
|
||||||
screen.menu == df.viewscreen_locationsst.T_menu.Occupations) and
|
|
||||||
screen.in_edit == df.viewscreen_locationsst.T_in_edit.None and
|
|
||||||
screen.locations[screen.location_idx]
|
|
||||||
end
|
|
||||||
location_retire.title = "Retire location"
|
|
||||||
location_retire.message = "Are you sure you want to retire this location?"
|
|
||||||
]]--
|
|
||||||
|
|
||||||
-- End of confirmation definitions
|
|
||||||
|
|
||||||
function check()
|
|
||||||
local undefined = {}
|
|
||||||
for id in pairs(get_ids()) do
|
|
||||||
if not confs[id] then
|
|
||||||
table.insert(undefined, id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #undefined > 0 then
|
|
||||||
error('Confirmation definitions missing: ' .. table.concat(undefined, ', '))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
The C++ plugin invokes methods of individual confirmations through four
|
|
||||||
functions (corresponding to method names) which receive the relevant screen,
|
|
||||||
the confirmation ID, and extra arguments in some cases, but these don't have to
|
|
||||||
do aything unique.
|
|
||||||
]]
|
|
||||||
|
|
||||||
function define_wrapper(name)
|
|
||||||
_ENV[name] = function(scr, id, ...)
|
|
||||||
_ENV.screen = scr
|
|
||||||
if not confs[id] then
|
|
||||||
error('Bad confirmation ID: ' .. id)
|
|
||||||
end
|
|
||||||
return confs[id][name](...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
define_wrapper('intercept_key')
|
|
||||||
define_wrapper('get_title')
|
|
||||||
define_wrapper('get_message')
|
|
||||||
define_wrapper('get_color')
|
|
||||||
return _ENV
|
|
@ -1 +1 @@
|
|||||||
Subproject commit 53fdcd89fc1bf4a6d1ea72112f31ef25ec11625b
|
Subproject commit b41f1ec482255428166722bec6904a779a0ad02f
|
Loading…
Reference in New Issue