From 0fad63bba79997db5f7fbb23a6ca8c62549a83c7 Mon Sep 17 00:00:00 2001
From: Eric Wald
Date: Sun, 28 Sep 2014 18:24:07 -0600
Subject: [PATCH 1/5] New trackstop plugin.
Simply adds a menu to track stops, showing and changing friction and dump direction.
---
plugins/CMakeLists.txt | 1 +
plugins/trackstop.cpp | 195 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 196 insertions(+)
create mode 100644 plugins/trackstop.cpp
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);
+}
From c9cdc041778bbcb4037ff0502b0c47da0af194bb Mon Sep 17 00:00:00 2001
From: Eric Wald
Date: Sun, 28 Sep 2014 18:43:19 -0600
Subject: [PATCH 2/5] Trackstop plugin documentation.
---
NEWS | 3 +++
Readme.html | 15 +++++++++++++++
Readme.rst | 13 +++++++++++++
3 files changed, 31 insertions(+)
diff --git a/NEWS b/NEWS
index bf4f7adf2..8fe274019 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
DFHack future
+ New plugins:
+ - trackstop: Shows track stop friction and dump direction in its 'q' menu
+
DFHack 0.40.13-r1
Internals:
- unified spatter structs
diff --git a/Readme.html b/Readme.html
index 10bc3b6c1..e1c693522 100644
--- a/Readme.html
+++ b/Readme.html
@@ -529,6 +529,7 @@ access DF memory and allow for easier development of new tools.
Search
AutoMaterial
Stockpile Automation
+Track Stop Menu
gui/advfort
gui/assign-rack
gui/choose-weapons
@@ -3275,6 +3276,20 @@ enable automelt
When querying a stockpile an option will appear to toggle automelt for this stockpile.
Any items placed in this stockpile will be designated to be melted.
+
This script allows to perform jobs in adventure mode. For more complete help
diff --git a/Readme.rst b/Readme.rst
index b143b0c54..dc92b577b 100644
--- a/Readme.rst
+++ b/Readme.rst
@@ -2655,6 +2655,19 @@ Enable the automelt plugin in your dfhack.init with::
When querying a stockpile an option will appear to toggle automelt for this stockpile.
Any items placed in this stockpile will be designated to be melted.
+Track Stop Menu
+===============
+
+The `q` menu of track stops is completely blank by default. To enable one::
+
+ enable trackstop
+
+This allows you to view and/or change the track stop's friction and dump direction settings.
+It re-uses the keybindings from the track stop building interface:
+
+* BUILDING_TRACK_STOP_FRICTION_UP
+* BUILDING_TRACK_STOP_FRICTION_DOWN
+* BUILDING_TRACK_STOP_DUMP
gui/advfort
===========
From 11d08518d6e1c7f857efb99cc953676f317bf755 Mon Sep 17 00:00:00 2001
From: Eric Wald
Date: Sun, 28 Sep 2014 18:45:47 -0600
Subject: [PATCH 3/5] Adding trackstop to the example init file.
---
dfhack.init-example | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dfhack.init-example b/dfhack.init-example
index f0f380095..5338f9448 100644
--- a/dfhack.init-example
+++ b/dfhack.init-example
@@ -183,7 +183,7 @@ enable search
enable automaterial
# Other interface improvement tools
-enable dwarfmonitor mousequery automelt autotrade buildingplan resume zone
+enable dwarfmonitor mousequery automelt autotrade buildingplan resume trackstop zone
# allow the fortress bookkeeper to queue jobs through the manager
stockflow enable
From 4af9b7a0546f30583d979011d13f7c969bfdf108 Mon Sep 17 00:00:00 2001
From: Eric Wald
Date: Sun, 28 Sep 2014 21:34:42 -0600
Subject: [PATCH 4/5] Checking for more required variables.
Trying to use trackstop without ui or world results in a hard crash.
---
plugins/trackstop.cpp | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/plugins/trackstop.cpp b/plugins/trackstop.cpp
index 54e0b56d4..455b53774 100644
--- a/plugins/trackstop.cpp
+++ b/plugins/trackstop.cpp
@@ -169,8 +169,11 @@ 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");
+ // Check for global variables that, if missing, result in total failure.
+ // Missing enabler and ui_menu_width also produce visible effects, but not nearly as severe.
+ // This could be moved to the plugin_init step, but that's louder for no real benefit.
+ if (!(gps && ui && world)) {
+ out.printerr("trackstop: Missing required global variables.\n");
return CR_FAILURE;
}
From aafa3a5f91b2a0516c64ace071b74d965a42c9ab Mon Sep 17 00:00:00 2001
From: Eric Wald
Date: Thu, 2 Oct 2014 22:00:40 -0600
Subject: [PATCH 5/5] Expanding on the rollers menu.
As requested by fricy.
---
plugins/trackstop.cpp | 105 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 104 insertions(+), 1 deletion(-)
diff --git a/plugins/trackstop.cpp b/plugins/trackstop.cpp
index 455b53774..4676a1b52 100644
--- a/plugins/trackstop.cpp
+++ b/plugins/trackstop.cpp
@@ -6,6 +6,7 @@
#include "uicommon.h"
#include "LuaTools.h"
+#include "df/building_rollersst.h"
#include "df/building_trapst.h"
#include "df/viewscreen_dwarfmodest.h"
@@ -16,8 +17,10 @@ using namespace std;
using df::global::world;
using df::global::ui;
+using df::building_rollersst;
using df::building_trapst;
using df::enums::trap_type::trap_type;
+using df::enums::screw_pump_direction::screw_pump_direction;
DFHACK_PLUGIN("trackstop");
@@ -162,8 +165,106 @@ struct trackstop_hook : public df::viewscreen_dwarfmodest {
}
};
+struct roller_hook : public df::viewscreen_dwarfmodest {
+ typedef df::viewscreen_dwarfmodest interpose_base;
+
+ enum Speed {
+ Lowest = 10000,
+ Low = 20000,
+ Medium = 30000,
+ High = 40000,
+ Highest = 50000
+ };
+
+ building_rollersst *get_selected_roller() {
+ if (!Gui::dwarfmode_hotkey(Core::getTopViewscreen()) || ui->main.mode != ui_sidebar_mode::QueryBuilding) {
+ return nullptr;
+ }
+
+ building_rollersst *roller = virtual_cast(world->selected_building);
+ if (roller && roller->construction_stage) {
+ return roller;
+ }
+
+ return nullptr;
+ }
+
+ bool handleInput(set *input) {
+ building_rollersst *roller = get_selected_roller();
+ if (!roller) {
+ return false;
+ }
+
+ if (input->count(interface_key::BUILDING_ORIENT_NONE)) {
+ // Flip roller orientation.
+ // Long rollers can only be oriented along their length.
+ // Todo: Only add 1 to 1x1 rollers: x ^= ((x&1)<<1)|1
+ // Todo: This could have been elegant without all the casting,
+ // but as an enum it might be better off listing each case.
+ roller->direction = (df::enums::screw_pump_direction::screw_pump_direction)(((int8_t)roller->direction) ^ 2);
+ return true;
+ } else if (input->count(interface_key::BUILDING_ROLLERS_SPEED_UP)) {
+ if (roller->speed < Speed::Highest) {
+ roller->speed += Speed::Lowest;
+ }
+
+ return true;
+ } else if (input->count(interface_key::BUILDING_ROLLERS_SPEED_DOWN)) {
+ if (roller->speed > Speed::Lowest) {
+ roller->speed -= Speed::Lowest;
+ }
+
+ 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_rollersst *roller = get_selected_roller();
+ if (roller) {
+ auto dims = Gui::getDwarfmodeViewDims();
+ int left_margin = dims.menu_x1 + 1;
+ int x = left_margin;
+ int y = dims.y1 + 6;
+
+ OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(interface_key::BUILDING_ORIENT_NONE));
+ OutputString(COLOR_WHITE, x, y, ": Rolls ", false);
+ OutputString(COLOR_WHITE, x, y, (
+ (roller->direction == screw_pump_direction::FromNorth)? "Southward":
+ (roller->direction == screw_pump_direction::FromEast)? "Westward":
+ (roller->direction == screw_pump_direction::FromSouth)? "Northward":
+ (roller->direction == screw_pump_direction::FromWest)? "Eastward":
+ ""
+ ), true, left_margin);
+
+ OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(interface_key::BUILDING_ROLLERS_SPEED_DOWN));
+ OutputString(COLOR_LIGHTRED, x, y, Screen::getKeyDisplay(interface_key::BUILDING_ROLLERS_SPEED_UP));
+ OutputString(COLOR_WHITE, x, y, ": ");
+ OutputString(COLOR_WHITE, x, y, (
+ (roller->speed <= Speed::Lowest)? "Lowest":
+ (roller->speed <= Speed::Low)? "Low":
+ (roller->speed <= Speed::Medium)? "Medium":
+ (roller->speed <= Speed::High)? "High":
+ "Highest"
+ ));
+ OutputString(COLOR_WHITE, x, y, " Speed", true, left_margin);
+ }
+ }
+};
+
IMPLEMENT_VMETHOD_INTERPOSE(trackstop_hook, feed);
IMPLEMENT_VMETHOD_INTERPOSE(trackstop_hook, render);
+IMPLEMENT_VMETHOD_INTERPOSE(roller_hook, feed);
+IMPLEMENT_VMETHOD_INTERPOSE(roller_hook, render);
DFhackCExport command_result plugin_enable(color_ostream& out, bool enable) {
@@ -178,7 +279,9 @@ DFhackCExport command_result plugin_enable(color_ostream& out, bool enable) {
}
if (!INTERPOSE_HOOK(trackstop_hook, feed).apply(enable) ||
- !INTERPOSE_HOOK(trackstop_hook, render).apply(enable)) {
+ !INTERPOSE_HOOK(trackstop_hook, render).apply(enable) ||
+ !INTERPOSE_HOOK(roller_hook, feed).apply(enable) ||
+ !INTERPOSE_HOOK(roller_hook, render).apply(enable)) {
out.printerr("Could not %s trackstop hooks!\n", enable? "insert": "remove");
return CR_FAILURE;
}