Conflicts:
	library/Core.cpp
	library/PluginManager.cpp
	library/include/Core.h
	library/include/PluginManager.h
	library/modules/Gui.cpp
	plugins/stockpiles.cpp
develop
Petr Mrázek 2011-12-31 13:09:12 +01:00
commit f35cdb84cd
9 changed files with 158 additions and 72 deletions

@ -217,6 +217,27 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
" reload PLUGIN|all - Reload a plugin or all loaded plugins.\n"
);
}
else if (parts.size() == 1)
{
Plugin *plug = plug_mgr->getPluginByCommand(parts[0]);
if (plug) {
for (int j = 0; j < plug->size();j++)
{
const PluginCommand & pcmd = (plug->operator[](j));
if (pcmd.name != parts[0])
continue;
if (pcmd.isHotkeyCommand())
con.color(Console::COLOR_CYAN);
con.print("%s: %s\n",pcmd.name.c_str(), pcmd.description.c_str());
con.reset_color();
if (!pcmd.usage.empty())
con << "Usage:\n" << pcmd.usage << flush;
return;
}
}
con.printerr("Unknown command: %s\n", parts[0].c_str());
}
else
{
con.printerr("not implemented yet\n");
@ -316,7 +337,10 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
else for (int j = 0; j < plug->size();j++)
{
const PluginCommand & pcmd = (plug->operator[](j));
if (pcmd.isHotkeyCommand())
con.color(Console::COLOR_CYAN);
con.print(" %-22s - %s\n",pcmd.name.c_str(), pcmd.description.c_str());
con.reset_color();
}
}
else
@ -344,7 +368,10 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
for (int j = 0; j < plug->size();j++)
{
const PluginCommand & pcmd = (plug->operator[](j));
if (pcmd.isHotkeyCommand())
con.color(Console::COLOR_CYAN);
con.print(" %-22s- %s\n",pcmd.name.c_str(), pcmd.description.c_str());
con.reset_color();
}
}
}
@ -384,9 +411,18 @@ static void runInteractiveCommand(Core *core, PluginManager *plug_mgr, int &clue
}
}
}
else if (parts.size() == 2 && parts[0] == "list")
{
std::vector<std::string> list = core->ListKeyBindings(parts[1]);
if (list.empty())
con << "No bindings." << endl;
for (unsigned i = 0; i < list.size(); i++)
con << " " << list[i] << endl;
}
else
{
con << "Usage:" << endl
<< " keybinding list <key>" << endl
<< " keybinding clear <key> <key>..." << endl
<< " keybinding set <key> \"cmdline\" \"cmdline\"..." << endl
<< " keybinding add <key> \"cmdline\" \"cmdline\"..." << endl
@ -968,18 +1004,35 @@ bool Core::AddKeyBinding(std::string keyspec, std::string cmdline)
tthread::lock_guard<tthread::mutex> lock(*HotkeyMutex);
// Don't add duplicates
std::vector<KeyBinding> &bindings = key_bindings[sym];
for (int i = bindings.size()-1; i >= 0; --i) {
if (bindings[i].modifiers == binding.modifiers &&
bindings[i].cmdline == cmdline)
return true;
}
binding.cmdline = cmdline;
key_bindings[sym].push_back(binding);
bindings.push_back(binding);
return true;
}
bool DFHack::default_hotkey(Core *, df::viewscreen *top)
std::vector<std::string> Core::ListKeyBindings(std::string keyspec)
{
// Default hotkey guard function
for (;top ;top = top->parent)
if (strict_virtual_cast<df::viewscreen_dwarfmodest>(top))
return true;
return false;
int sym, mod;
std::vector<std::string> rv;
if (!parseKeySpec(keyspec, &sym, &mod))
return rv;
tthread::lock_guard<tthread::mutex> lock(*HotkeyMutex);
std::vector<KeyBinding> &bindings = key_bindings[sym];
for (int i = bindings.size()-1; i >= 0; --i) {
if (bindings[i].modifiers == mod)
rv.push_back(bindings[i].cmdline);
}
return rv;
}
////////////////

@ -29,7 +29,6 @@ distribution.
#include "Console.h"
#include "DataDefs.h"
#include "df/viewscreen.h"
using namespace DFHack;
@ -292,21 +291,22 @@ command_result Plugin::invoke( std::string & command, std::vector <std::string>
CoreSuspender suspend(&c);
df::viewscreen *top = c.getTopViewscreen();
if ((cmd.viewscreen_type && !cmd.viewscreen_type->is_instance(top))
|| !cmd.guard(&c, top))
if (!cmd.guard(&c, top))
{
c.con.printerr("Could not invoke %s: unsuitable UI state.\n", command.c_str());
cr = CR_FAILURE;
cr = CR_WRONG_USAGE;
}
else
else
{
cr = cmd.function(&c, parameters);
}
}
else
else
{
cr = cmd.function(&c, parameters);
}
if (cr == CR_WRONG_USAGE && !cmd.usage.empty())
c.con << "Usage:\n" << cmd.usage << flush;
break;
}
}
@ -325,20 +325,14 @@ bool Plugin::can_invoke_hotkey( std::string & command, df::viewscreen *top )
for (int i = 0; i < commands.size();i++)
{
PluginCommand &cmd = commands[i];
if(cmd.name == command)
{
if (cmd.interactive)
cr = false;
else if (cmd.guard)
{
cr = (!cmd.viewscreen_type || cmd.viewscreen_type->is_instance(top))
&& cmd.guard(&c, top);
}
else
{
cr = cmd.guard(&c, top);
else
cr = default_hotkey(&c, top);
}
break;
}
}

@ -141,6 +141,7 @@ namespace DFHack
bool ClearKeyBindings(std::string keyspec);
bool AddKeyBinding(std::string keyspec, std::string cmdline);
std::vector<std::string> ListKeyBindings(std::string keyspec);
bool isWorldLoaded() { return (last_world_data_ptr != NULL); }
df::viewscreen *getTopViewscreen() { return top_viewscreen; }

@ -50,7 +50,8 @@ namespace DFHack
CR_WOULD_BREAK = -2,
CR_NOT_IMPLEMENTED = -1,
CR_FAILURE = 0,
CR_OK = 1
CR_OK = 1,
CR_WRONG_USAGE = 2
};
enum state_change_event
{
@ -62,18 +63,19 @@ namespace DFHack
{
typedef command_result (*command_function)(Core *, std::vector <std::string> &);
typedef bool (*command_hotkey_guard)(Core *, df::viewscreen *);
/// create a command with a name, description, function pointer to its code
/// and saying if it needs an interactive terminal
/// Most commands shouldn't require an interactive terminal!
PluginCommand(const char * _name,
const char * _description,
command_function function_,
bool interactive_ = false
bool interactive_ = false,
const char * usage_ = ""
)
: name(_name), description(_description),
function(function_), interactive(interactive_),
guard(NULL), viewscreen_type(NULL)
guard(NULL), usage(usage_)
{
}
@ -81,19 +83,21 @@ namespace DFHack
const char * _description,
command_function function_,
command_hotkey_guard guard_,
virtual_identity *viewscreen_type_ = NULL)
const char * usage_ = "")
: name(_name), description(_description),
function(function_), interactive(false),
guard(guard_), viewscreen_type(viewscreen_type_)
guard(guard_), usage(usage_)
{
}
bool isHotkeyCommand() const { return guard != NULL; }
std::string name;
std::string description;
command_function function;
bool interactive;
command_hotkey_guard guard;
virtual_identity *viewscreen_type;
std::string usage;
};
class Plugin
{
@ -177,6 +181,9 @@ namespace DFHack
std::string plugin_path;
};
// Predefined hotkey guards
DFHACK_EXPORT bool default_hotkey(Core *, df::viewscreen *);
DFHACK_EXPORT bool dwarfmode_hotkey(Core *, df::viewscreen *);
DFHACK_EXPORT bool cursor_hotkey(Core *, df::viewscreen *);
}

@ -37,8 +37,44 @@ using namespace std;
#include "Error.h"
#include "ModuleFactory.h"
#include "Core.h"
#include "PluginManager.h"
using namespace DFHack;
#include "DataDefs.h"
#include "df/cursor.h"
#include "df/viewscreen_dwarfmodest.h"
// Predefined common guard functions
bool DFHack::default_hotkey(Core *, df::viewscreen *top)
{
// Default hotkey guard function
for (;top ;top = top->parent)
if (strict_virtual_cast<df::viewscreen_dwarfmodest>(top))
return true;
return false;
}
bool DFHack::dwarfmode_hotkey(Core *, df::viewscreen *top)
{
// Require the main dwarf mode screen
return !!strict_virtual_cast<df::viewscreen_dwarfmodest>(top);
}
bool DFHack::cursor_hotkey(Core *c, df::viewscreen *top)
{
if (!dwarfmode_hotkey(c, top))
return false;
// Also require the cursor.
if (!df::global::cursor || df::global::cursor->x == -30000)
return false;
return true;
}
//
Module* DFHack::createGui()
{
return new Gui();

@ -27,7 +27,7 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand>
{
commands.clear();
commands.push_back(PluginCommand("clean","Removes contaminants from map tiles, items and creatures.",clean));
commands.push_back(PluginCommand("spotclean","Cleans map tile under cursor.",spotclean));
commands.push_back(PluginCommand("spotclean","Cleans map tile under cursor.",spotclean,cursor_hotkey));
return CR_OK;
}
@ -165,7 +165,7 @@ command_result cleanunits (Core * c)
DFhackCExport command_result spotclean (Core * c, vector <string> & parameters)
{
c->Suspend();
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
vector<DFHack::t_spattervein *> splatter;
DFHack::Maps *Mapz = c->getMaps();
DFHack::Gui *Gui = c->getGui();
@ -173,7 +173,6 @@ DFhackCExport command_result spotclean (Core * c, vector <string> & parameters)
if(!Mapz->Start())
{
c->con.printerr("Can't init map.\n");
c->Resume();
return CR_FAILURE;
}
int32_t cursorX, cursorY, cursorZ;
@ -181,7 +180,6 @@ DFhackCExport command_result spotclean (Core * c, vector <string> & parameters)
if(cursorX == -30000)
{
c->con.printerr("The cursor is not active.\n");
c->Resume();
return CR_FAILURE;
}
int32_t blockX = cursorX / 16, blockY = cursorY / 16;
@ -193,7 +191,6 @@ DFhackCExport command_result spotclean (Core * c, vector <string> & parameters)
{
spatters[i]->intensity[tileX][tileY] = 0;
}
c->Resume();
return CR_OK;
}

@ -26,8 +26,10 @@ DFhackCExport command_result plugin_init (Core *c, std::vector <PluginCommand> &
{
commands.clear();
if (d_init) {
commands.push_back(PluginCommand("twaterlvl", "Toggle display of water/magma depth.", twaterlvl));
commands.push_back(PluginCommand("tidlers", "Toggle display of idlers.", tidlers));
commands.push_back(PluginCommand("twaterlvl", "Toggle display of water/magma depth.",
twaterlvl, dwarfmode_hotkey));
commands.push_back(PluginCommand("tidlers", "Toggle display of idlers.",
tidlers, dwarfmode_hotkey));
}
std::cerr << "d_init: " << sizeof(df::d_init) << endl;
return CR_OK;
@ -40,21 +42,19 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
DFhackCExport command_result twaterlvl(Core * c, vector <string> & parameters)
{
c->Suspend();
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
df::global::d_init->flags1.toggle(d_init_flags1::SHOW_FLOW_AMOUNTS);
c->con << "Toggled the display of water/magma depth." << endl;
c->Resume();
return CR_OK;
}
DFhackCExport command_result tidlers(Core * c, vector <string> & parameters)
{
c->Suspend();
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
df::d_init_idlers iv = df::d_init_idlers(int(d_init->idlers) + 1);
if (!d_init_idlers::is_valid(iv))
iv = ENUM_FIRST_ITEM(d_init_idlers);
d_init->idlers = iv;
c->con << "Toggled the display of idlers to " << ENUM_KEY_STR(d_init_idlers, iv) << endl;
c->Resume();
return CR_OK;
}

@ -36,8 +36,12 @@ DFhackCExport command_result plugin_init (Core *c, std::vector <PluginCommand> &
if (world && ui) {
commands.push_back(
PluginCommand(
"copystock", "Copy stockpile under cursor.", copystock,
copystock_guard, &df::viewscreen_dwarfmodest::_identity
"copystock", "Copy stockpile under cursor.",
copystock, copystock_guard,
" - In 'q' or 't' mode: select a stockpile and invoke in order\n"
" to switch to the 'p' stockpile creation mode, and initialize\n"
" the custom settings from the selected stockpile.\n"
" - In 'p': invoke in order to switch back to 'q'.\n"
)
);
}
@ -51,10 +55,13 @@ DFhackCExport command_result plugin_shutdown ( Core * c )
return CR_OK;
}
static bool copystock_guard(Core *c, df::viewscreen *)
static bool copystock_guard(Core *c, df::viewscreen *top)
{
using namespace ui_sidebar_mode;
if (!dwarfmode_hotkey(c,top))
return false;
switch (ui->main.mode) {
case Stockpiles:
return true;
@ -63,12 +70,12 @@ static bool copystock_guard(Core *c, df::viewscreen *)
return !!virtual_cast<building_stockpilest>(world->selected_building);
default:
return false;
}
}
}
static command_result copystock(Core * c, vector <string> & parameters)
{
/* HOTKEY COMMAND: CORE ALREADY SUSPENDED */
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
// For convenience: when used in the stockpiles mode, switch to 'q'
if (ui->main.mode == ui_sidebar_mode::Stockpiles) {
@ -81,9 +88,10 @@ static command_result copystock(Core * c, vector <string> & parameters)
}
building_stockpilest *sp = virtual_cast<building_stockpilest>(world->selected_building);
if (!sp) {
if (!sp)
{
c->con.printerr("Selected building isn't a stockpile.\n");
return CR_FAILURE;
return CR_WRONG_USAGE;
}
ui->stockpile.custom_settings = sp->settings;

@ -30,8 +30,17 @@ DFhackCExport const char * plugin_name ( void )
DFhackCExport command_result plugin_init ( Core * c, std::vector <PluginCommand> &commands)
{
commands.clear();
commands.push_back(PluginCommand("vdig","Dig a whole vein.",vdig));
commands.push_back(PluginCommand("vdigx","Dig a whole vein, follow vein through z-levels with stairs.",vdigx));
commands.push_back(PluginCommand(
"vdig","Dig a whole vein.",vdig,cursor_hotkey,
" Designates a whole vein under the cursor for digging.\n"
"Options:\n"
" x - follow veins through z-levels with stairs.\n"
));
commands.push_back(PluginCommand(
"vdigx","Dig a whole vein, following through z-levels.",vdigx,cursor_hotkey,
" Designates a whole vein under the cursor for digging.\n"
" Also follows the vein between z-levels with stairs, like 'vdig x' would.\n"
));
commands.push_back(PluginCommand("expdig","Select or designate an exploratory pattern. Use 'expdig ?' for help.",expdig));
commands.push_back(PluginCommand("digcircle","Dig desingate a circle (filled or hollow) with given radius.",digcircle));
//commands.push_back(PluginCommand("autodig","Mark a tile for continuous digging.",autodig));
@ -760,18 +769,10 @@ DFhackCExport command_result expdig (Core * c, vector <string> & parameters)
c->Resume();
return CR_OK;
}
DFhackCExport command_result vdigx (Core * c, vector <string> & parameters)
{
for(int i = 0; i < parameters.size();i++)
{
if(parameters[i] == "help" || parameters[i] == "?")
{
c->con.print("Designates a whole vein under the cursor for digging.\n"
"Also follows the vein between z-levels with stairs, like 'vdig x' would.\n"
);
return CR_OK;
}
}
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
vector <string> lol;
lol.push_back("x");
return vdig(c,lol);
@ -779,32 +780,25 @@ DFhackCExport command_result vdigx (Core * c, vector <string> & parameters)
DFhackCExport command_result vdig (Core * c, vector <string> & parameters)
{
// HOTKEY COMMAND: CORE ALREADY SUSPENDED
uint32_t x_max,y_max,z_max;
bool updown = false;
for(int i = 0; i < parameters.size();i++)
{
if(parameters.size() && parameters[0]=="x")
updown = true;
else if(parameters[i] == "help" || parameters[i] == "?")
{
c->con.print("Designates a whole vein under the cursor for digging.\n"
"Options:\n"
"x - follow veins through z-levels with stairs.\n"
);
return CR_OK;
}
else
return CR_WRONG_USAGE;
}
Console & con = c->con;
c->Suspend();
DFHack::Maps * Maps = c->getMaps();
DFHack::Gui * Gui = c->getGui();
// init the map
if(!Maps->Start())
{
con.printerr("Can't init map. Make sure you have a map loaded in DF.\n");
c->Resume();
return CR_FAILURE;
}
@ -816,14 +810,12 @@ DFhackCExport command_result vdig (Core * c, vector <string> & parameters)
while(cx == -30000)
{
con.printerr("Cursor is not active. Point the cursor at a vein.\n");
c->Resume();
return CR_FAILURE;
}
DFHack::DFCoord xy ((uint32_t)cx,(uint32_t)cy,cz);
if(xy.x == 0 || xy.x == tx_max - 1 || xy.y == 0 || xy.y == ty_max - 1)
{
con.printerr("I won't dig the borders. That would be cheating!\n");
c->Resume();
return CR_FAILURE;
}
MapExtras::MapCache * MCache = new MapExtras::MapCache(Maps);
@ -834,7 +826,6 @@ DFhackCExport command_result vdig (Core * c, vector <string> & parameters)
{
con.printerr("This tile is not a vein.\n");
delete MCache;
c->Resume();
return CR_FAILURE;
}
con.print("%d/%d/%d tiletype: %d, veinmat: %d, designation: 0x%x ... DIGGING!\n", cx,cy,cz, tt, veinmat, des.whole);
@ -944,7 +935,6 @@ DFhackCExport command_result vdig (Core * c, vector <string> & parameters)
}
}
MCache->WriteAll();
c->Resume();
return CR_OK;
}