diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 6ebe3ad6d..35b7ca52d 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -156,6 +156,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(stocks stocks.cpp) DFHACK_PLUGIN(strangemood strangemood.cpp) DFHACK_PLUGIN(tiletypes tiletypes.cpp Brushes.h) + DFHACK_PLUGIN(trackstop trackstop.cpp) # DFHACK_PLUGIN(treefarm treefarm.cpp) DFHACK_PLUGIN(tubefill tubefill.cpp) DFHACK_PLUGIN(tweak tweak.cpp) diff --git a/plugins/trackstop.cpp b/plugins/trackstop.cpp new file mode 100644 index 000000000..54e0b56d4 --- /dev/null +++ b/plugins/trackstop.cpp @@ -0,0 +1,195 @@ +/* + * Trackstop plugin. + * Shows track stop friction and direction in its 'q' menu. + */ + +#include "uicommon.h" +#include "LuaTools.h" + +#include "df/building_trapst.h" +#include "df/viewscreen_dwarfmodest.h" + +#include "modules/Gui.h" + +using namespace DFHack; +using namespace std; + +using df::global::world; +using df::global::ui; +using df::building_trapst; +using df::enums::trap_type::trap_type; + +DFHACK_PLUGIN("trackstop"); + +#define AUTOENABLE false +DFHACK_PLUGIN_IS_ENABLED(enabled); + + +/* + * Interface hooks + */ +struct trackstop_hook : public df::viewscreen_dwarfmodest { + typedef df::viewscreen_dwarfmodest interpose_base; + + enum Friction { + Lowest = 10, + Low = 50, + Medium = 500, + High = 10000, + Highest = 50000 + }; + + building_trapst *get_selected_trackstop() { + if (!Gui::dwarfmode_hotkey(Core::getTopViewscreen()) || ui->main.mode != ui_sidebar_mode::QueryBuilding) { + return nullptr; + } + + building_trapst *ts = virtual_cast(world->selected_building); + if (ts && ts->trap_type == trap_type::TrackStop && ts->construction_stage) { + return ts; + } + + return nullptr; + } + + bool handleInput(set *input) { + building_trapst *ts = get_selected_trackstop(); + if (!ts) { + return false; + } + + if (input->count(interface_key::BUILDING_TRACK_STOP_DUMP)) { + // Change track stop dump direction. + // There might be a more elegant way to do this. + + if (!ts->use_dump) { + // No -> North + ts->use_dump = 1; + ts->dump_x_shift = 0; + ts->dump_y_shift = -1; + } else if (ts->dump_x_shift == 0 && ts->dump_y_shift == -1) { + // North -> South + ts->dump_x_shift = 0; + ts->dump_y_shift = 1; + } else if (ts->dump_x_shift == 0 && ts->dump_y_shift == 1) { + // South -> East + ts->dump_x_shift = 1; + ts->dump_y_shift = 0; + } else if (ts->dump_x_shift == 1 && ts->dump_y_shift == 0) { + // East -> West + ts->dump_x_shift = -1; + ts->dump_y_shift = 0; + } else { + // West (or Elsewhere) -> No + ts->use_dump = 0; + ts->dump_x_shift = 0; + ts->dump_y_shift = 0; + } + + return true; + } else if (input->count(interface_key::BUILDING_TRACK_STOP_FRICTION_UP)) { + ts->friction = ( + (ts->friction < Friction::Lowest)? Friction::Lowest: + (ts->friction < Friction::Low)? Friction::Low: + (ts->friction < Friction::Medium)? Friction::Medium: + (ts->friction < Friction::High)? Friction::High: + (ts->friction < Friction::Highest)? Friction::Highest: + ts->friction + ); + + return true; + } else if (input->count(interface_key::BUILDING_TRACK_STOP_FRICTION_DOWN)) { + ts->friction = ( + (ts->friction > Friction::Highest)? Friction::Highest: + (ts->friction > Friction::High)? Friction::High: + (ts->friction > Friction::Medium)? Friction::Medium: + (ts->friction > Friction::Low)? Friction::Low: + (ts->friction > Friction::Lowest)? Friction::Lowest: + ts->friction + ); + + return true; + } + + return false; + } + + DEFINE_VMETHOD_INTERPOSE(void, feed, (set *input)) { + if (!handleInput(input)) { + INTERPOSE_NEXT(feed)(input); + } + } + + DEFINE_VMETHOD_INTERPOSE(void, render, ()) { + INTERPOSE_NEXT(render)(); + + building_trapst *ts = get_selected_trackstop(); + if (ts) { + auto dims = Gui::getDwarfmodeViewDims(); + int left_margin = dims.menu_x1 + 1; + int x = left_margin; + int y = dims.y1 + 1; + + OutputString(COLOR_WHITE, x, y, "Track Stop", true, left_margin); + + y += 3; + OutputString(COLOR_WHITE, x, y, "Friction: ", false); + OutputString(COLOR_WHITE, x, y, ( + (ts->friction <= Friction::Lowest)? "Lowest": + (ts->friction <= Friction::Low)? "Low": + (ts->friction <= Friction::Medium)? "Medium": + (ts->friction <= Friction::High)? "High": + "Highest" + ), true, left_margin); + OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(interface_key::BUILDING_TRACK_STOP_FRICTION_DOWN)); + OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(interface_key::BUILDING_TRACK_STOP_FRICTION_UP)); + OutputString(COLOR_WHITE, x, y, ": Change Friction", true, left_margin); + + y += 1; + + OutputString(COLOR_WHITE, x, y, "Dump on arrival: ", false); + OutputString(COLOR_WHITE, x, y, ( + (!ts->use_dump)? "No": + (ts->dump_x_shift == 0 && ts->dump_y_shift == -1)? "North": + (ts->dump_x_shift == 0 && ts->dump_y_shift == 1)? "South": + (ts->dump_x_shift == 1 && ts->dump_y_shift == 0)? "East": + (ts->dump_x_shift == -1 && ts->dump_y_shift == 0)? "West": + "Elsewhere" + ), true, left_margin); + OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(interface_key::BUILDING_TRACK_STOP_DUMP)); + OutputString(COLOR_WHITE, x, y, ": Activate/change direction", true, left_margin); + } + } +}; + +IMPLEMENT_VMETHOD_INTERPOSE(trackstop_hook, feed); +IMPLEMENT_VMETHOD_INTERPOSE(trackstop_hook, render); + + +DFhackCExport command_result plugin_enable(color_ostream& out, bool enable) { + // Accept the "enable trackstop" / "disable trackstop" commands. + if (enable != enabled) { + if (enable && !gps) { + out.printerr("The trackstop module needs graphics.\n"); + return CR_FAILURE; + } + + if (!INTERPOSE_HOOK(trackstop_hook, feed).apply(enable) || + !INTERPOSE_HOOK(trackstop_hook, render).apply(enable)) { + out.printerr("Could not %s trackstop hooks!\n", enable? "insert": "remove"); + return CR_FAILURE; + } + + enabled = enable; + } + + return CR_OK; +} + +DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { + return plugin_enable(out, AUTOENABLE); +} + +DFhackCExport command_result plugin_shutdown(color_ostream &out) { + return plugin_enable(out, false); +}