diff options
Diffstat (limited to 'plugins/tweak.cpp')
| -rw-r--r-- | plugins/tweak.cpp | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/plugins/tweak.cpp b/plugins/tweak.cpp index 6d0591d1..939c94b3 100644 --- a/plugins/tweak.cpp +++ b/plugins/tweak.cpp @@ -45,6 +45,7 @@ #include "df/reaction_reagent_flags.h" #include "df/viewscreen_layer_assigntradest.h" #include "df/viewscreen_tradegoodsst.h" +#include "df/viewscreen_layer_militaryst.h" #include <stdlib.h> @@ -61,6 +62,7 @@ using df::global::ui_menu_width; using df::global::ui_area_map_width; using namespace DFHack::Gui; +using Screen::Pen; static command_result tweak(color_ostream &out, vector <string> & parameters); @@ -114,6 +116,13 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector <Plugi " tweak fast-trade [disable]\n" " Makes Shift-Enter in the Move Goods to Depot and Trade screens select\n" " the current item (fully, in case of a stack), and scroll down one line.\n" + " tweak military-stable-assign [disable]\n" + " Preserve list order and cursor position when assigning to squad,\n" + " i.e. stop the rightmost list of the Positions page of the military\n" + " screen from constantly jumping to the top.\n" + " tweak military-color-assigned [disable]\n" + " Color squad candidates already assigned to other squads in brown/green\n" + " to make them stand out more in the list.\n" )); return CR_OK; } @@ -540,6 +549,101 @@ struct fast_trade_select_hook : df::viewscreen_tradegoodsst { IMPLEMENT_VMETHOD_INTERPOSE(fast_trade_select_hook, feed); +struct military_assign_hook : df::viewscreen_layer_militaryst { + typedef df::viewscreen_layer_militaryst interpose_base; + + inline bool inPositionsMode() { + return page == Positions && !(in_create_squad || in_new_squad); + } + + DEFINE_VMETHOD_INTERPOSE(void, feed, (set<df::interface_key> *input)) + { + if (inPositionsMode() && !layer_objects[0]->active) + { + auto pos_list = layer_objects[1]; + auto plist = layer_objects[2]; + auto &cand = positions.candidates; + + // Save the candidate list and cursors + std::vector<df::unit*> copy = cand; + int cursor = plist->getListCursor(); + int pos_cursor = pos_list->getListCursor(); + + INTERPOSE_NEXT(feed)(input); + + if (inPositionsMode() && !layer_objects[0]->active) + { + bool is_select = input->count(interface_key::SELECT); + + // Resort the candidate list and restore cursor + // on add to squad OR scroll in the position list. + if (!plist->active || is_select) + { + // Since we don't know the actual sorting order, preserve + // the ordering of the items in the list before keypress. + // This does the right thing even if the list was sorted + // with sort-units. + std::set<df::unit*> prev, next; + prev.insert(copy.begin(), copy.end()); + next.insert(cand.begin(), cand.end()); + std::vector<df::unit*> out; + + // (old-before-cursor) (new) |cursor| (old-after-cursor) + for (int i = 0; i < cursor && i < (int)copy.size(); i++) + if (next.count(copy[i])) out.push_back(copy[i]); + for (size_t i = 0; i < cand.size(); i++) + if (!prev.count(cand[i])) out.push_back(cand[i]); + int new_cursor = out.size(); + for (int i = cursor; i < (int)copy.size(); i++) + if (next.count(copy[i])) out.push_back(copy[i]); + + cand.swap(out); + plist->setListLength(cand.size()); + if (new_cursor < (int)cand.size()) + plist->setListCursor(new_cursor); + } + + // Preserve the position list index on remove from squad + if (pos_list->active && is_select) + pos_list->setListCursor(pos_cursor); + } + } + else + INTERPOSE_NEXT(feed)(input); + } + + DEFINE_VMETHOD_INTERPOSE(void, render, ()) + { + INTERPOSE_NEXT(render)(); + + if (inPositionsMode()) + { + auto plist = layer_objects[2]; + int x1 = plist->getX1(), y1 = plist->getY1(); + int x2 = plist->getX2(), y2 = plist->getY2(); + int i1 = plist->getFirstVisible(), i2 = plist->getLastVisible(); + + for (int y = y1, i = i1; i <= i2; i++, y++) + { + auto unit = vector_get(positions.candidates, i); + if (!unit || unit->military.squad_index < 0) + continue; + + for (int x = x1; x <= x2; x++) + { + Pen cur_tile = Screen::readTile(x, y); + if (!cur_tile.valid()) continue; + cur_tile.fg = (cur_tile.fg == COLOR_GREY ? COLOR_BROWN : COLOR_GREEN); + Screen::paintTile(cur_tile, x, y); + } + } + } + } +}; + +IMPLEMENT_VMETHOD_INTERPOSE(military_assign_hook, feed); +IMPLEMENT_VMETHOD_INTERPOSE(military_assign_hook, render); + static void enable_hook(color_ostream &out, VMethodInterposeLinkBase &hook, vector <string> ¶meters) { if (vector_get(parameters, 1) == "disable") @@ -704,6 +808,14 @@ static command_result tweak(color_ostream &out, vector <string> ¶meters) enable_hook(out, INTERPOSE_HOOK(fast_trade_assign_hook, feed), parameters); enable_hook(out, INTERPOSE_HOOK(fast_trade_select_hook, feed), parameters); } + else if (cmd == "military-stable-assign") + { + enable_hook(out, INTERPOSE_HOOK(military_assign_hook, feed), parameters); + } + else if (cmd == "military-color-assigned") + { + enable_hook(out, INTERPOSE_HOOK(military_assign_hook, render), parameters); + } else return CR_WRONG_USAGE; |
