From 0f5802af9f0487452599523b202b34f4617500e5 Mon Sep 17 00:00:00 2001 From: lethosor Date: Sun, 18 May 2014 11:51:49 -0400 Subject: [PATCH] Add embark-tools A collection of embark-related tools (currently implementations of embark anywhere and nano embark) --- Readme.rst | 13 ++ plugins/CMakeLists.txt | 1 + plugins/embark-tools.cpp | 317 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 plugins/embark-tools.cpp diff --git a/Readme.rst b/Readme.rst index 7491c4a0c..b2d98b599 100644 --- a/Readme.rst +++ b/Readme.rst @@ -2030,6 +2030,19 @@ See the bay12 thread for details: http://www.bay12forums.com/smf/index.php?topic * Some of the DFusion plugins aren't completely ported yet. This can lead to crashes. * The game will be suspended while you're using dfusion. Don't panic when it doesn't respond. +embark-tools +------------ +A collection of tools for embarking. + +Usage:: + + embark-tools enable/disable tool [tool]... + +Tools: + +* ``anywhere``: Allows embarking anywhere (including sites, mountain-only biomes, and oceans). Use with caution. +* ``nano``: An implementation of nano embark - allows resizing below 2x2 when enabled. + misery ------ When enabled, every new negative dwarven thought will be multiplied by a factor (2 by default). diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 650fe1e98..a73651608 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -165,6 +165,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(strangemood strangemood.cpp) DFHACK_PLUGIN(command-prompt command-prompt.cpp) DFHACK_PLUGIN(building-hacks building-hacks.cpp LINK_LIBRARIES lua) + DFHACK_PLUGIN(embark-tools embark-tools.cpp) endif() # this is the skeleton plugin. If you want to make your own, make a copy and then change it diff --git a/plugins/embark-tools.cpp b/plugins/embark-tools.cpp new file mode 100644 index 000000000..1a02e3e65 --- /dev/null +++ b/plugins/embark-tools.cpp @@ -0,0 +1,317 @@ +#include "Console.h" +#include "Core.h" +#include "DataDefs.h" +#include "Export.h" +#include "PluginManager.h" + +#include "modules/Screen.h" +#include "modules/Gui.h" +#include +#include + +#include +#include "ColorText.h" +#include "df/viewscreen_choose_start_sitest.h" +#include "df/interface_key.h" + +using namespace DFHack; + +struct EmbarkTool +{ + std::string id; + std::string name; + std::string desc; + bool enabled; +}; + +EmbarkTool embark_tools[] = { + {"anywhere", "Embark anywhere", "Allows embarking anywhere on the world map", false}, + {"nano", "Nano embark", "Allows the embark size to be decreased below 2x2", false}, +}; +#define NUM_TOOLS sizeof(embark_tools) / sizeof(EmbarkTool) + +command_result embark_tools_cmd (color_ostream &out, std::vector & parameters); + +bool tool_exists (std::string tool_name); +bool tool_enabled (std::string tool_name); +bool tool_enable (std::string tool_name, bool enable_state); + +/* + * Logic + */ + +void resize_embark (df::viewscreen_choose_start_sitest * screen, int dx, int dy) +{ + /* Reproduces DF's embark resizing functionality + * Local area resizes up and to the right, unless it's already touching the edge + */ + int x1 = screen->embark_pos_min.x, + x2 = screen->embark_pos_max.x, + y1 = screen->embark_pos_min.y, + y2 = screen->embark_pos_max.y, + width = x2 - x1 + dx, + height = y2 - y1 + dy; + if (x1 == x2 && dx == -1) + dx = 0; + if (y1 == y2 && dy == -1) + dy = 0; + + x2 += dx; // Resize right + while (x2 > 15) + { + x2--; + x1--; + } + x1 = std::max(0, x1); + + y1 -= dy; // Resize up + while (y1 < 0) + { + y1++; + y2++; + } + y2 = std::min(15, y2); + + screen->embark_pos_min.x = x1; + screen->embark_pos_max.x = x2; + screen->embark_pos_min.y = y1; + screen->embark_pos_max.y = y2; +} + +/* + * Viewscreen hooks + */ + +void OutputString (int8_t color, int &x, int y, const std::string &text) +{ + Screen::paintString(Screen::Pen(' ', color, 0), x, y, text); + x += text.length(); +} + +struct choose_start_site_hook : df::viewscreen_choose_start_sitest +{ + typedef df::viewscreen_choose_start_sitest interpose_base; + + DEFINE_VMETHOD_INTERPOSE(void, feed, (std::set *input)) + { + bool prevent_default = false; + df::viewscreen * top = Gui::getCurViewscreen(); + VIRTUAL_CAST_VAR(screen, df::viewscreen_choose_start_sitest, top); + if (tool_enabled("anywhere")) + { + for (auto iter = input->begin(); iter != input->end(); iter++) + { + df::interface_key key = *iter; + if (key == df::interface_key::SETUP_EMBARK) + { + prevent_default = true; + screen->in_embark_normal = 1; + } + } + } + if (tool_enabled("nano")) + { + for (auto iter = input->begin(); iter != input->end(); iter++) + { + df::interface_key key = *iter; + bool is_resize = true; + int dx = 0, dy = 0; + switch (key) + { + case df::interface_key::SETUP_LOCAL_Y_UP: + dy = 1; + break; + case df::interface_key::SETUP_LOCAL_Y_DOWN: + dy = -1; + break; + case df::interface_key::SETUP_LOCAL_X_UP: + dx = 1; + break; + case df::interface_key::SETUP_LOCAL_X_DOWN: + dx = -1; + break; + default: + is_resize = false; + } + if (is_resize) { + prevent_default = true; + resize_embark(screen, dx, dy); + } + } + } + if (!prevent_default) + INTERPOSE_NEXT(feed)(input); + } + + DEFINE_VMETHOD_INTERPOSE(void, render, ()) + { + INTERPOSE_NEXT(render)(); + + df::viewscreen * top = Gui::getCurViewscreen(); + VIRTUAL_CAST_VAR(screen, df::viewscreen_choose_start_sitest, top); + + auto dim = Screen::getWindowSize(); + int x = 1, + y = dim.y - 5; + OutputString(COLOR_LIGHTMAGENTA, x, y, "Enabled: "); + std::list tools; + for (int i = 0; i < NUM_TOOLS; i++) + { + if (embark_tools[i].enabled) + { + tools.push_back(embark_tools[i].name); + tools.push_back(", "); + } + } + if (tools.size()) + { + tools.pop_back(); // Remove last , + for (auto iter = tools.begin(); iter != tools.end(); iter++) + { + OutputString(COLOR_LIGHTMAGENTA, x, y, *iter); + } + } + else + { + OutputString(COLOR_LIGHTMAGENTA, x, y, "(none)"); + } + + if (tool_enabled("anywhere")) + { + x = 20; y = dim.y - 2; + if (screen->page == 0) + { + // Only display on main page (not site finder, notes, etc.) + OutputString(COLOR_WHITE, x, y, ": Embark!"); + } + } + } +}; + +IMPLEMENT_VMETHOD_INTERPOSE(choose_start_site_hook, feed); +IMPLEMENT_VMETHOD_INTERPOSE(choose_start_site_hook, render); + +/* + * Tool management + */ + +bool tool_exists (std::string tool_name) +{ + for (int i = 0; i < NUM_TOOLS; i++) + { + if (embark_tools[i].id == tool_name) + return true; + } + return false; +} + +bool tool_enabled (std::string tool_name) +{ + for (int i = 0; i < NUM_TOOLS; i++) + { + if (embark_tools[i].id == tool_name) + return embark_tools[i].enabled; + } + return false; +} + +bool tool_enable (std::string tool_name, bool enable_state) +{ + for (int i = 0; i < NUM_TOOLS; i++) + { + if (embark_tools[i].id == tool_name) + { + embark_tools[i].enabled = enable_state; + return true; + } + } + return false; +} + +/* + * Plugin management + */ + +DFHACK_PLUGIN("embark-tools"); +DFHACK_PLUGIN_IS_ENABLED(is_enabled); + +DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) +{ + std::string help = ""; + help += "embark-tools (enable/disable) tool [tool...]\n" + "Tools:\n"; + for (int i = 0; i < NUM_TOOLS; i++) + { + help += (" " + embark_tools[i].id + ": " + embark_tools[i].desc + "\n"); + } + commands.push_back(PluginCommand( + "embark-tools", + "A collection of embark tools", + embark_tools_cmd, + false, + help.c_str() + )); + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown (color_ostream &out) +{ + INTERPOSE_HOOK(choose_start_site_hook, feed).remove(); + INTERPOSE_HOOK(choose_start_site_hook, render).remove(); + return CR_OK; +} + +DFhackCExport command_result plugin_enable (color_ostream &out, bool enable) +{ + if (is_enabled != enable) + { + if (!INTERPOSE_HOOK(choose_start_site_hook, feed).apply(enable) || + !INTERPOSE_HOOK(choose_start_site_hook, render).apply(enable)) + return CR_FAILURE; + is_enabled = enable; + } + return CR_OK; +} + +command_result embark_tools_cmd (color_ostream &out, std::vector & parameters) +{ + CoreSuspender suspend; + if (parameters.size()) + { + // Set by "enable"/"disable" - allows for multiple commands, e.g. "enable nano disable anywhere" + bool enable_state = true; + for (size_t i = 0; i < parameters.size(); i++) + { + if (parameters[i] == "enable") + { + enable_state = true; + plugin_enable(out, true); // Enable plugin + } + else if (parameters[i] == "disable") + enable_state = false; + else if (tool_exists(parameters[i])) + { + tool_enable(parameters[i], enable_state); + } + else + return CR_WRONG_USAGE; + } + } + else + { + if (is_enabled) + { + out << "Tool status:" << std::endl; + for (int i = 0; i < NUM_TOOLS; i++) + { + EmbarkTool t = embark_tools[i]; + out << t.name << " (" << t.id << "): " << (t.enabled ? "Enabled" : "Disabled") << std::endl; + } + } + else + { + out << "Plugin not enabled" << std::endl; + } + } + return CR_OK; +}