Пример #1
0
command_result Plugin::invoke(color_ostream &out, const std::string & command, std::vector <std::string> & parameters)
{
    Core & c = Core::getInstance();
    command_result cr = CR_NOT_IMPLEMENTED;
    access->lock_add();
    if(state == PS_LOADED)
    {
        for (size_t i = 0; i < commands.size();i++)
        {
            PluginCommand &cmd = commands[i];
            if(cmd.name == command)
            {
                // running interactive things from some other source than the console would break it
                if(!out.is_console() && cmd.interactive)
                    cr = CR_NEEDS_CONSOLE;
                else if (cmd.guard)
                {
                    // Execute hotkey commands in a way where they can
                    // expect their guard conditions to be matched,
                    // so as to avoid duplicating checks.
                    // This means suspending the core beforehand.
                    CoreSuspender suspend(&c);
                    df::viewscreen *top = c.getTopViewscreen();

                    if (!cmd.guard(top))
                    {
                        out.printerr("Could not invoke %s: unsuitable UI state.\n", command.c_str());
                        cr = CR_WRONG_USAGE;
                    }
                    else
                    {
                        cr = cmd.function(out, parameters);
                    }
                }
                else
                {
                    cr = cmd.function(out, parameters);
                }
                if (cr == CR_WRONG_USAGE && !cmd.usage.empty())
                    out << "Usage:\n" << cmd.usage << flush;
                break;
            }
        }
    }
    access->lock_sub();
    return cr;
}
Пример #2
0
bool DFHack::Lua::InterpreterLoop(color_ostream &out, lua_State *state,
                                  const char *prompt, const char *hfile)
{
    if (!out.is_console())
        return false;

    if (!hfile)
        hfile = "lua.history";
    if (!prompt)
        prompt = "lua";

    InterpreterArgs args;
    args.prompt = prompt;
    args.hfile = hfile;

    return RunCoreQueryLoop(out, state, init_interpreter, &args);
}
Пример #3
0
command_result df_liquids (color_ostream &out_, vector <string> & parameters)
{
    if(!out_.is_console())
        return CR_FAILURE;
    Console &out = static_cast<Console&>(out_);

    for(size_t i = 0; i < parameters.size();i++)
    {
        if(parameters[i] == "help" || parameters[i] == "?")
        {
            out.print(  "This tool allows placing magma, water and other similar things.\n"
                        "It is interactive and further help is available when you run it.\n"
                        "The settings will be remembered until dfhack is closed and you can call\n"
                        "'liquids-here' (mapped to a hotkey) to paint liquids at the cursor position\n"
                        "without the need to go back to the dfhack console.\n");
            return CR_OK;
        }
    }

    if (!Maps::IsValid())
    {
        out.printerr("Map is not available!\n");
        return CR_FAILURE;
    }

    bool end = false;

    out << "Welcome to the liquid spawner.\nType 'help' or '?' for a list of available commands, 'q' to quit.\nPress return after a command to confirm." << std::endl;

    while(!end)
    {
        string command = "";

        std::stringstream str;
        str <<"[" << mode << ":" << brushname;
        if (brushname == "range")
            str << "(w" << width << ":h" << height << ":z" << z_levels << ")";
        str << ":" << amount << ":" << flowmode << ":" << setmode << "]#";
        if(out.lineedit(str.str(),command,liquids_hist) == -1)
            return CR_FAILURE;
        liquids_hist.add(command);

        if(command=="help" || command == "?")
        {
            out << "Modes:" << endl
                 << "m             - switch to magma" << endl
                 << "w             - switch to water" << endl
                 << "o             - make obsidian wall instead" << endl
                 << "of            - make obsidian floors" << endl
                 << "rs            - make a river source" << endl
                 << "f             - flow bits only" << endl
                 << "wclean        - remove salt and stagnant flags from tiles" << endl
                 << "Set-Modes (only for magma/water):" << endl
                 << "s+            - only add" << endl
                 << "s.            - set" << endl
                 << "s-            - only remove" << endl
                 << "Properties (only for magma/water):" << endl
                 << "f+            - make the spawned liquid flow" << endl
                 << "f.            - don't change flow state (read state in flow mode)" << endl
                 << "f-            - make the spawned liquid static" << endl
                 << "0-7           - set liquid amount" << endl
                 << "Brush:" << endl
                 << "point         - single tile [p]" << endl
                 << "range         - block with cursor at bottom north-west [r]" << endl
                 << "                (any place, any size)" << endl
                 << "block         - DF map block with cursor in it" << endl
                 << "                (regular spaced 16x16x1 blocks)" << endl
                 << "column        - Column from cursor, up through free space" << endl
                 << "flood         - Flood-fill water tiles from cursor" << endl
                 << "                (only makes sense with wclean)" << endl
                 << "Other:" << endl
                 << "q             - quit" << endl
                 << "help or ?     - print this list of commands" << endl
                 << "empty line    - put liquid" << endl
                 << endl
                 << "Usage: point the DF cursor at a tile you want to modify" << endl
                 << "and use the commands available :)" << endl;
            out << endl << "Settings will be remembered until you quit DF. You can call liquids-here to execute the last configured action. Useful in combination with keybindings." << endl;
        }
        else if(command == "m")
        {
            mode = "magma";
        }
        else if(command == "o")
        {
            mode = "obsidian";
        }
        else if(command == "of")
        {
            mode = "obsidian_floor";
        }
        else if(command == "w")
        {
            mode = "water";
        }
        else if(command == "f")
        {
            mode = "flowbits";
        }
        else if(command == "rs")
        {
            mode = "riversource";
        }
        else if(command == "wclean")
        {
            mode = "wclean";
        }
        else if(command == "point" || command == "p")
        {
            brushname = "point";
        }
        else if(command == "range" || command == "r")
        {
            std::stringstream str;
            CommandHistory range_hist;
            str << " :set range width<" << width << "># ";
            out.lineedit(str.str(),command,range_hist);
            range_hist.add(command);
            width = command == "" ? width : atoi (command.c_str());
            if(width < 1) width = 1;

            str.str("");
            str << " :set range height<" << height << "># ";
            out.lineedit(str.str(),command,range_hist);
            range_hist.add(command);
            height = command == "" ? height : atoi (command.c_str());
            if(height < 1) height = 1;

            str.str("");
            str << " :set range z-levels<" << z_levels << "># ";
            out.lineedit(str.str(),command,range_hist);
            range_hist.add(command);
            z_levels = command == "" ? z_levels : atoi (command.c_str());
            if(z_levels < 1) z_levels = 1;
            if(width == 1 && height == 1 && z_levels == 1)
            {
                brushname = "point";
            }
            else
            {
                brushname = "range";
            }
        }
        else if(command == "block")
        {
            brushname = "block";
        }
        else if(command == "column")
        {
            brushname = "column";
        }
        else if(command == "flood")
        {
            brushname = "flood";
        }
        else if(command == "q")
        {
            end = true;
        }
        else if(command == "f+")
        {
            flowmode = "f+";
        }
        else if(command == "f-")
        {
            flowmode = "f-";
        }
        else if(command == "f.")
        {
            flowmode = "f.";
        }
        else if(command == "s+")
        {
            setmode = "s+";
        }
        else if(command == "s-")
        {
            setmode = "s-";
        }
        else if(command == "s.")
        {
            setmode = "s.";
        }
        // blah blah, bad code, bite me.
        else if(command == "0")
            amount = 0;
        else if(command == "1")
            amount = 1;
        else if(command == "2")
            amount = 2;
        else if(command == "3")
            amount = 3;
        else if(command == "4")
            amount = 4;
        else if(command == "5")
            amount = 5;
        else if(command == "6")
            amount = 6;
        else if(command == "7")
            amount = 7;
        else if(command.empty())
        {
            df_liquids_execute(out);
        }
        else
        {
            out << command << " : unknown command." << endl;
        }
    }
    return CR_OK;
}
Пример #4
0
command_result kittens (color_ostream &out, vector <string> & parameters)
{
    if (parameters.size() >= 1)
    {
        if (parameters[0] == "stop")
        {
            shutdown_flag = true;
            while(!final_flag)
            {
                Core::getInstance().getConsole().msleep(60);
            }
            shutdown_flag = false;
            return CR_OK;
        }
    }
    final_flag = false;
    if (!out.is_console())
        return CR_FAILURE;
    Console &con = static_cast<Console&>(out);
    // http://evilzone.org/creative-arts/nyan-cat-ascii/
    const char * nyan []=
    {
        "NYAN NYAN NYAN NYAN NYAN NYAN NYAN",
        "+      o     +              o   ",
        "    +             o     +       +",
        "o          +",
        "    o  +           +        +",
        "+        o     o       +        o",
        "-_-_-_-_-_-_-_,------,      o ",
        "_-_-_-_-_-_-_-|   /\\_/\\  ",
        "-_-_-_-_-_-_-~|__( ^ .^)  +     +  ",
        "_-_-_-_-_-_-_-\"\"  \"\"      ",
        "+      o         o   +       o",
        "    +         +",
        "o        o         o      o     +",
        "    o           +",
        "+      +     o        o      +    ",
        "NYAN NYAN NYAN NYAN NYAN NYAN NYAN",
        0
    };
    const char * kittenz1 []=
    {
        "   ____",
        "  (.   \\",
        "    \\  |  ",
        "     \\ |___(\\--/)",
        "   __/    (  . . )",
        "  \"'._.    '-.O.'",
        "       '-.  \\ \"|\\",
        "          '.,,/'.,,mrf",
        0
    };
    con.cursor(false);
    con.clear();
    Console::color_value color = COLOR_BLUE;
    while(1)
    {
        if(shutdown_flag)
        {
            final_flag = true;
            con.reset_color();
            con << std::endl << "NYAN!" << std::endl << std::flush;
            return CR_OK;
        }
        con.color(color);
        int index = 0;
        const char * kit = nyan[index];
        con.gotoxy(1,1);
        //con << "Your DF is now full of kittens!" << std::endl;
        while (kit != 0)
        {
            con.gotoxy(1,1+index);
            con << kit << std::endl;
            index++;
            kit = nyan[index];
        }
        con.flush();
        con.msleep(60);
        ((int&)color) ++;
        if(color > COLOR_MAX)
            color = COLOR_BLUE;
    }
}
Пример #5
0
command_result df_liquids (color_ostream &out_, vector <string> & parameters)
{
    if(!out_.is_console())
        return CR_FAILURE;
    Console &out = static_cast<Console&>(out_);

    for(size_t i = 0; i < parameters.size();i++)
    {
        if(parameters[i] == "help" || parameters[i] == "?")
            return CR_WRONG_USAGE;
    }

    if (!Maps::IsValid())
    {
        out.printerr("Map is not available!\n");
        return CR_FAILURE;
    }

    std::vector<std::string> commands;
    bool end = false;

    out << "Welcome to the liquid spawner.\nType 'help' or '?' for a list of available commands, 'q' to quit.\nPress return after a command to confirm." << std::endl;

    while(!end)
    {
        string input = "";

        std::stringstream str;
        print_prompt(str, cur_mode);
        str << "# ";
        if(out.lineedit(str.str(),input,liquids_hist) == -1)
            return CR_FAILURE;
        liquids_hist.add(input);

        commands.clear();
        Core::cheap_tokenise(input, commands);
        string command =  commands.empty() ? "" : commands[0];

        if(command=="help" || command == "?")
        {
            out << "Modes:" << endl
                 << "m             - switch to magma" << endl
                 << "w             - switch to water" << endl
                 << "o             - make obsidian wall instead" << endl
                 << "of            - make obsidian floors" << endl
                 << "rs            - make a river source" << endl
                 << "f             - flow bits only" << endl
                 << "wclean        - remove salt and stagnant flags from tiles" << endl
                 << "Set-Modes (only for magma/water):" << endl
                 << "s+            - only add" << endl
                 << "s.            - set" << endl
                 << "s-            - only remove" << endl
                 << "Properties (only for magma/water):" << endl
                 << "f+            - make the spawned liquid flow" << endl
                 << "f.            - don't change flow state (read state in flow mode)" << endl
                 << "f-            - make the spawned liquid static" << endl
                 << "Permaflow (only for water):" << endl
                 << "pf.           - don't change permaflow state" << endl
                 << "pf-           - make the spawned liquid static" << endl
                 << "pf[NS][EW]    - make the spawned liquid permanently flow" << endl
                 << "0-7           - set liquid amount" << endl
                 << "Brush:" << endl
                 << "point         - single tile [p]" << endl
                 << "range         - block with cursor at bottom north-west [r]" << endl
                 << "                (any place, any size)" << endl
                 << "block         - DF map block with cursor in it" << endl
                 << "                (regular spaced 16x16x1 blocks)" << endl
                 << "column        - Column from cursor, up through free space" << endl
                 << "flood         - Flood-fill water tiles from cursor" << endl
                 << "                (only makes sense with wclean)" << endl
                 << "Other:" << endl
                 << "q             - quit" << endl
                 << "help or ?     - print this list of commands" << endl
                 << "empty line    - put liquid" << endl
                 << endl
                 << "Usage: point the DF cursor at a tile you want to modify" << endl
                 << "and use the commands available :)" << endl;
            out << endl << "Settings will be remembered until you quit DF. You can call liquids-here to execute the last configured action. Useful in combination with keybindings." << endl;
        }
        else if(command == "m")
        {
            cur_mode.paint = P_MAGMA;
        }
        else if(command == "o")
        {
            cur_mode.paint = P_OBSIDIAN;
        }
        else if(command == "of")
        {
            cur_mode.paint = P_OBSIDIAN_FLOOR;
        }
        else if(command == "w")
        {
            cur_mode.paint = P_WATER;
        }
        else if(command == "f")
        {
            cur_mode.paint = P_FLOW_BITS;
        }
        else if(command == "rs")
        {
            cur_mode.paint = P_RIVER_SOURCE;
        }
        else if(command == "wclean")
        {
            cur_mode.paint = P_WCLEAN;
        }
        else if(command == "point" || command == "p")
        {
            cur_mode.brush = B_POINT;
        }
        else if(command == "range" || command == "r")
        {
            int width, height, z_levels;
            command_result res = parseRectangle(out, commands, 1, commands.size(),
                                                width, height, z_levels);
            if (res != CR_OK)
            {
                return res;
            }

            if (width == 1 && height == 1 && z_levels == 1)
            {
                cur_mode.brush = B_POINT;
                cur_mode.size = df::coord(1, 1, 1);
            }
            else
            {
                cur_mode.brush = B_RANGE;
                cur_mode.size = df::coord(width, height, z_levels);
            }
        }
        else if(command == "block")
        {
            cur_mode.brush = B_BLOCK;
        }
        else if(command == "column")
        {
            cur_mode.brush = B_COLUMN;
        }
        else if(command == "flood")
        {
            cur_mode.brush = B_FLOOD;
        }
        else if(command == "q")
        {
            end = true;
        }
        else if(command == "f+")
        {
            cur_mode.flowmode = M_INC;
        }
        else if(command == "f-")
        {
            cur_mode.flowmode = M_DEC;
        }
        else if(command == "f.")
        {
            cur_mode.flowmode = M_KEEP;
        }
        else if(command == "s+")
        {
            cur_mode.setmode = M_INC;
        }
        else if(command == "s-")
        {
            cur_mode.setmode = M_DEC;
        }
        else if(command == "s.")
        {
            cur_mode.setmode = M_KEEP;
        }
        else if (command.size() > 2 && memcmp(command.c_str(), "pf", 2) == 0)
        {
            auto *tail = command.c_str()+2;
            for (int pm = PF_KEEP; pm <= PF_SOUTHWEST; pm++)
            {
                if (strcmp(tail, permaflow_name[pm]) != 0)
                    continue;
                cur_mode.permaflow = PermaflowMode(pm);
                tail = NULL;
                break;
            }
            if (tail)
                out << command << " : invalid permaflow mode" << endl;
        }
        // blah blah, bad code, bite me.
        else if(command == "0")
            cur_mode.amount = 0;
        else if(command == "1")
            cur_mode.amount = 1;
        else if(command == "2")
            cur_mode.amount = 2;
        else if(command == "3")
            cur_mode.amount = 3;
        else if(command == "4")
            cur_mode.amount = 4;
        else if(command == "5")
            cur_mode.amount = 5;
        else if(command == "6")
            cur_mode.amount = 6;
        else if(command == "7")
            cur_mode.amount = 7;
        else if(command.empty())
        {
            df_liquids_execute(out);
        }
        else
        {
            out << command << " : unknown command." << endl;
        }
    }
    return CR_OK;
}
Пример #6
0
bool DFHack::Lua::RunCoreQueryLoop(color_ostream &out, lua_State *state,
                                   bool (*init)(color_ostream&, lua_State*, void*),
                                   void *arg)
{
    if (!lua_checkstack(state, 20))
        return false;

    lua_State *thread;
    int rv;
    std::string prompt;
    std::string histfile;

    DFHack::CommandHistory hist;
    std::string histname;

    {
        CoreSuspender suspend;

        int base = lua_gettop(state);

        if (!init(out, state, arg))
        {
            lua_settop(state, base);
            return false;
        }

        // If not interactive, run without coroutine and bail out
        if (!out.is_console())
            return SafeCall(out, state, lua_gettop(state)-base-1, 0);

        lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_QUERY_COROTABLE_TOKEN);
        lua_pushvalue(state, base+1);
        lua_remove(state, base+1);
        thread = Lua::NewCoroutine(state);
        lua_rawsetp(state, -2, thread);
        lua_pop(state, 1);

        rv = resume_query_loop(out, thread, state, lua_gettop(state)-base, prompt, histfile);
    }

    Console &con = static_cast<Console&>(out);

    while (rv == LUA_YIELD)
    {
        if (histfile != histname)
        {
            if (!histname.empty())
                hist.save(histname.c_str());

            hist.clear();
            histname = histfile;

            if (!histname.empty())
                hist.load(histname.c_str());
        }

        if (prompt.empty())
            prompt = ">> ";

        std::string curline;
        con.lineedit(prompt,curline,hist);
        hist.add(curline);

        {
            CoreSuspender suspend;

            lua_pushlstring(state, curline.data(), curline.size());
            rv = resume_query_loop(out, thread, state, 1, prompt, histfile);
        }
    }

    if (!histname.empty())
        hist.save(histname.c_str());

    {
        CoreSuspender suspend;

        lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_QUERY_COROTABLE_TOKEN);
        lua_pushnil(state);
        lua_rawsetp(state, -2, thread);
        lua_pop(state, 1);
    }

    return (rv == LUA_OK);
}
Пример #7
0
command_result Core::runCommand(color_ostream &con, const std::string &first, vector<string> &parts)
{
    if (!first.empty())
    {
        // let's see what we actually got
        if(first=="help" || first == "?" || first == "man")
        {
            if(!parts.size())
            {
                if (con.is_console())
                {
                    con.print("This is the DFHack console. You can type commands in and manage DFHack plugins from it.\n"
                              "Some basic editing capabilities are included (single-line text editing).\n"
                              "The console also has a command history - you can navigate it with Up and Down keys.\n"
                              "On Windows, you may have to resize your console window. The appropriate menu is accessible\n"
                              "by clicking on the program icon in the top bar of the window.\n\n");
                }
                con.print("Basic commands:\n"
                          "  help|?|man            - This text.\n"
                          "  help COMMAND          - Usage help for the given command.\n"
                          "  ls|dir [PLUGIN]       - List available commands. Optionally for single plugin.\n"
                          "  cls                   - Clear the console.\n"
                          "  fpause                - Force DF to pause.\n"
                          "  die                   - Force DF to close immediately\n"
                          "  keybinding            - Modify bindings of commands to keys\n"
                          "Plugin management (useful for developers):\n"
                          "  plug [PLUGIN|v]       - List plugin state and description.\n"
                          "  load PLUGIN|all       - Load a plugin by name or load all possible plugins.\n"
                          "  unload PLUGIN|all     - Unload a plugin or all loaded plugins.\n"
                          "  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 (size_t j = 0; j < plug->size(); j++)
                    {
                        const PluginCommand & pcmd = (plug->operator[](j));
                        if (pcmd.name != parts[0])
                            continue;

                        if (pcmd.isHotkeyCommand())
                            con.color(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 CR_OK;
                    }
                }
                auto filename = getHackPath() + "scripts/" + parts[0];
                if (fileExists(filename + ".lua"))
                {
                    string help = getScriptHelp(filename + ".lua", "-- ");
                    con.print("%s: %s\n", parts[0].c_str(), help.c_str());
                    return CR_OK;
                }
                if (plug_mgr->eval_ruby && fileExists(filename + ".rb"))
                {
                    string help = getScriptHelp(filename + ".rb", "# ");
                    con.print("%s: %s\n", parts[0].c_str(), help.c_str());
                    return CR_OK;
                }
                con.printerr("Unknown command: %s\n", parts[0].c_str());
            }
            else
            {
                con.printerr("not implemented yet\n");
            }
        }
        else if( first == "load" )
        {
            if(parts.size())
            {
                string & plugname = parts[0];
                if(plugname == "all")
                {
                    for(size_t i = 0; i < plug_mgr->size(); i++)
                    {
                        Plugin * plug = (plug_mgr->operator[](i));
                        plug->load(con);
                    }
                }
                else
                {
                    Plugin * plug = plug_mgr->getPluginByName(plugname);
                    if(!plug)
                    {
                        con.printerr("No such plugin\n");
                    }
                    else
                    {
                        plug->load(con);
                    }
                }
            }
        }
        else if( first == "reload" )
        {
            if(parts.size())
            {
                string & plugname = parts[0];
                if(plugname == "all")
                {
                    for(size_t i = 0; i < plug_mgr->size(); i++)
                    {
                        Plugin * plug = (plug_mgr->operator[](i));
                        plug->reload(con);
                    }
                }
                else
                {
                    Plugin * plug = plug_mgr->getPluginByName(plugname);
                    if(!plug)
                    {
                        con.printerr("No such plugin\n");
                    }
                    else
                    {
                        plug->reload(con);
                    }
                }
            }
        }
        else if( first == "unload" )
        {
            if(parts.size())
            {
                string & plugname = parts[0];
                if(plugname == "all")
                {
                    for(size_t i = 0; i < plug_mgr->size(); i++)
                    {
                        Plugin * plug = (plug_mgr->operator[](i));
                        plug->unload(con);
                    }
                }
                else
                {
                    Plugin * plug = plug_mgr->getPluginByName(plugname);
                    if(!plug)
                    {
                        con.printerr("No such plugin\n");
                    }
                    else
                    {
                        plug->unload(con);
                    }
                }
            }
        }
        else if(first == "ls" || first == "dir")
        {
            if(parts.size())
            {
                string & plugname = parts[0];
                const Plugin * plug = plug_mgr->getPluginByName(plugname);
                if(!plug)
                {
                    con.printerr("There's no plugin called %s!\n",plugname.c_str());
                }
                else for (size_t j = 0; j < plug->size(); j++)
                    {
                        const PluginCommand & pcmd = (plug->operator[](j));
                        if (pcmd.isHotkeyCommand())
                            con.color(COLOR_CYAN);
                        con.print("  %-22s - %s\n",pcmd.name.c_str(), pcmd.description.c_str());
                        con.reset_color();
                    }
            }
            else
            {
                con.print(
                    "builtin:\n"
                    "  help|?|man            - This text or help specific to a plugin.\n"
                    "  ls [PLUGIN]           - List available commands. Optionally for single plugin.\n"
                    "  cls                   - Clear the console.\n"
                    "  fpause                - Force DF to pause.\n"
                    "  die                   - Force DF to close immediately\n"
                    "  keybinding            - Modify bindings of commands to keys\n"
                    "  script FILENAME       - Run the commands specified in a file.\n"
                    "  plug [PLUGIN|v]       - List plugin state and detailed description.\n"
                    "  load PLUGIN|all       - Load a plugin by name or load all possible plugins.\n"
                    "  unload PLUGIN|all     - Unload a plugin or all loaded plugins.\n"
                    "  reload PLUGIN|all     - Reload a plugin or all loaded plugins.\n"
                    "\n"
                    "plugins:\n"
                );
                std::set <sortable> out;
                for(size_t i = 0; i < plug_mgr->size(); i++)
                {
                    const Plugin * plug = (plug_mgr->operator[](i));
                    if(!plug->size())
                        continue;
                    for (size_t j = 0; j < plug->size(); j++)
                    {
                        const PluginCommand & pcmd = (plug->operator[](j));
                        out.insert(sortable(pcmd.isHotkeyCommand(),pcmd.name,pcmd.description));
                    }
                }
                for(auto iter = out.begin(); iter != out.end(); iter++)
                {
                    if ((*iter).recolor)
                        con.color(COLOR_CYAN);
                    con.print("  %-22s- %s\n",(*iter).name.c_str(), (*iter).description.c_str());
                    con.reset_color();
                }
                auto scripts = listScripts(plug_mgr, getHackPath() + "scripts/");
                if (!scripts.empty())
                {
                    con.print("\nscripts:\n");
                    for (auto iter = scripts.begin(); iter != scripts.end(); ++iter)
                        con.print("  %-22s- %s\n", iter->first.c_str(), iter->second.c_str());
                }
            }
        }
        else if(first == "plug")
        {
            for(size_t i = 0; i < plug_mgr->size(); i++)
            {
                const Plugin * plug = (plug_mgr->operator[](i));
                if(!plug->size())
                    continue;
                con.print("%s\n", plug->getName().c_str());
            }
        }
        else if(first == "keybinding")
        {
            if (parts.size() >= 3 && (parts[0] == "set" || parts[0] == "add"))
            {
                std::string keystr = parts[1];
                if (parts[0] == "set")
                    ClearKeyBindings(keystr);
                for (int i = parts.size()-1; i >= 2; i--)
                {
                    if (!AddKeyBinding(keystr, parts[i])) {
                        con.printerr("Invalid key spec: %s\n", keystr.c_str());
                        break;
                    }
                }
            }
            else if (parts.size() >= 2 && parts[0] == "clear")
            {
                for (size_t i = 1; i < parts.size(); i++)
                {
                    if (!ClearKeyBindings(parts[i])) {
                        con.printerr("Invalid key spec: %s\n", parts[i].c_str());
                        break;
                    }
                }
            }
            else if (parts.size() == 2 && parts[0] == "list")
            {
                std::vector<std::string> list = ListKeyBindings(parts[1]);
                if (list.empty())
                    con << "No bindings." << endl;
                for (size_t i = 0; i < list.size(); i++)
                    con << "  " << list[i] << endl;
            }
            else
            {
                con << "Usage:" << endl
                    << "  keybinding list <key>" << endl
                    << "  keybinding clear <key>[@context]..." << endl
                    << "  keybinding set <key>[@context] \"cmdline\" \"cmdline\"..." << endl
                    << "  keybinding add <key>[@context] \"cmdline\" \"cmdline\"..." << endl
                    << "Later adds, and earlier items within one command have priority." << endl
                    << "Supported keys: [Ctrl-][Alt-][Shift-](A-Z, or F1-F9, or Enter)." << endl
                    << "Context may be used to limit the scope of the binding, by" << endl
                    << "requiring the current context to have a certain prefix." << endl
                    << "Current UI context is: "
                    << Gui::getFocusString(Core::getTopViewscreen()) << endl;
            }
        }
        else if(first == "fpause")
        {
            World * w = getWorld();
            w->SetPauseState(true);
            con.print("The game was forced to pause!\n");
        }
        else if(first == "cls")
        {
            if (con.is_console())
                ((Console&)con).clear();
            else
            {
                con.printerr("No console to clear.\n");
                return CR_NEEDS_CONSOLE;
            }
        }
        else if(first == "die")
        {
            _exit(666);
        }
        else if(first == "script")
        {
            if(parts.size() == 1)
            {
                loadScriptFile(con, parts[0], false);
            }
            else
            {
                con << "Usage:" << endl
                    << "  script <filename>" << endl;
                return CR_WRONG_USAGE;
            }
        }
        else
        {
            command_result res = plug_mgr->InvokeCommand(con, first, parts);
            if(res == CR_NOT_IMPLEMENTED)
            {
                auto filename = getHackPath() + "scripts/" + first;
                if (fileExists(filename + ".lua"))
                    res = runLuaScript(con, first, parts);
                else if (plug_mgr->eval_ruby && fileExists(filename + ".rb"))
                    res = runRubyScript(con, plug_mgr, first, parts);
                else
                    con.printerr("%s is not a recognized command.\n", first.c_str());
            }
            else if (res == CR_NEEDS_CONSOLE)
                con.printerr("%s needs interactive console to work.\n", first.c_str());
            return res;
        }

        return CR_OK;
    }

    return CR_NOT_IMPLEMENTED;
}