summaryrefslogtreecommitdiff
path: root/plugins/sort.cpp
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-04-22 19:22:00 +0400
committerAlexander Gavrilov2012-04-22 19:22:00 +0400
commit125cd6622a1d2ce7a8dfa7caf40a85049baf4977 (patch)
tree033aa194ef7f969f88a2675337ca9cca2f27cd43 /plugins/sort.cpp
parent2ef321a2086f03de30d184c06c527f504893cd07 (diff)
downloaddfhack-125cd6622a1d2ce7a8dfa7caf40a85049baf4977.tar.gz
dfhack-125cd6622a1d2ce7a8dfa7caf40a85049baf4977.tar.bz2
dfhack-125cd6622a1d2ce7a8dfa7caf40a85049baf4977.tar.xz
Support sorting units in many more ui contexts.
Diffstat (limited to 'plugins/sort.cpp')
-rw-r--r--plugins/sort.cpp367
1 files changed, 315 insertions, 52 deletions
diff --git a/plugins/sort.cpp b/plugins/sort.cpp
index 48e4bcac..965702b5 100644
--- a/plugins/sort.cpp
+++ b/plugins/sort.cpp
@@ -14,7 +14,13 @@
#include "df/world.h"
#include "df/viewscreen_joblistst.h"
#include "df/viewscreen_unitlistst.h"
+#include "df/viewscreen_layer_militaryst.h"
+#include "df/viewscreen_layer_workshop_profilest.h"
+#include "df/viewscreen_layer_noblelistst.h"
+#include "df/viewscreen_layer_overall_healthst.h"
#include "df/viewscreen_dwarfmodest.h"
+#include "df/viewscreen_petst.h"
+#include "df/layer_object_listst.h"
#include "MiscUtils.h"
@@ -28,6 +34,9 @@ using namespace df::enums;
using df::global::ui;
using df::global::world;
+using df::global::ui_building_in_owner;
+using df::global::ui_building_item_cursor;
+using df::global::ui_owner_candidates;
static bool unit_list_hotkey(df::viewscreen *top);
@@ -65,6 +74,22 @@ void reorder_vector(std::vector<T> *pvec, const std::vector<unsigned> &order)
(*pvec)[i] = tmp[order[i]];
}
+template<class T>
+void reorder_cursor(T *cursor, const std::vector<unsigned> &order)
+{
+ if (*cursor == 0)
+ return;
+
+ for (size_t i = 0; i < order.size(); i++)
+ {
+ if (unsigned(*cursor) == order[i])
+ {
+ *cursor = T(i);
+ break;
+ }
+ }
+}
+
bool parse_ordering_spec(color_ostream &out, lua_State *L, std::string type, const std::vector<std::string> &params)
{
if (!lua_checkstack(L, params.size() + 2))
@@ -93,16 +118,18 @@ bool read_order(color_ostream &out, lua_State *L, std::vector<unsigned> *order,
{
std::vector<char> found;
+ Lua::StackUnwinder frame(L, 1);
+
if (!lua_istable(L, -1))
{
out.printerr("Not a table returned as ordering.\n");
- goto fail;
+ return false;
}
if (lua_rawlen(L, -1) != size)
{
out.printerr("Invalid ordering size: expected %d, actual %d\n", size, lua_rawlen(L, -1));
- goto fail;
+ return false;
}
order->clear();
@@ -111,38 +138,34 @@ bool read_order(color_ostream &out, lua_State *L, std::vector<unsigned> *order,
for (size_t i = 1; i <= size; i++)
{
- lua_rawgeti(L, -1, i);
+ lua_rawgeti(L, frame[1], i);
int v = lua_tointeger(L, -1);
lua_pop(L, 1);
if (v < 1 || size_t(v) > size)
{
out.printerr("Order value out of range: %d\n", v);
- goto fail;
+ return false;
}
if (found[v-1])
{
out.printerr("Duplicate order value: %d\n", v);
- goto fail;
+ return false;
}
found[v-1] = 1;
(*order)[i-1] = v-1;
}
- lua_pop(L, 1);
return true;
-fail:
- lua_pop(L, 1);
- return false;
}
template<class T>
bool compute_order(color_ostream &out, lua_State *L, int base, std::vector<unsigned> *order, const std::vector<T> &key)
{
lua_pushvalue(L, base+1);
- Lua::PushVector(L, key);
+ Lua::PushVector(L, key, true);
lua_pushvalue(L, base+2);
if (!Lua::SafeCall(out, L, 2, 1))
@@ -151,90 +174,330 @@ bool compute_order(color_ostream &out, lua_State *L, int base, std::vector<unsig
return read_order(out, L, order, key.size());
}
+static bool ParseSpec(color_ostream &out, lua_State *L, const char *type, vector<string> &params)
+{
+ if (!parse_ordering_spec(out, L, "units", params))
+ {
+ out.printerr("Invalid ordering specification for %s.\n", type);
+ return false;
+ }
+
+ return true;
+}
+
+#define PARSE_SPEC(type, params) \
+ if (!ParseSpec(*pout, L, type, params)) return false;
-static bool unit_list_hotkey(df::viewscreen *screen)
+static void sort_null_first(vector<string> &parameters)
{
- if (strict_virtual_cast<df::viewscreen_unitlistst>(screen))
- return true;
- if (strict_virtual_cast<df::viewscreen_joblistst>(screen))
- return true;
+ vector_insert_at(parameters, 0, std::string("<exists"));
+}
- if (strict_virtual_cast<df::viewscreen_dwarfmodest>(screen))
- {
- using namespace df::enums::ui_sidebar_mode;
+static df::layer_object_listst *getLayerList(df::viewscreen_layerst *layer, int idx)
+{
+ return virtual_cast<df::layer_object_listst>(vector_get(layer->layer_objects,idx));
+}
- switch (ui->main.mode)
+static bool maybe_sort_units(color_ostream *pout, lua_State *L,
+ df::viewscreen *screen, vector<string> &parameters)
+{
+ Lua::StackUnwinder top(L);
+
+ if (L)
+ {
+ if (!Lua::PushModulePublic(*pout, L, "plugins.sort", "make_sort_order"))
{
- case Burrows:
- return ui->burrows.in_add_units_mode;
- default:
+ pout->printerr("Cannot access the sorter function.\n");
return false;
}
}
- return false;
-}
+ std::vector<unsigned> order;
-static command_result sort_units(color_ostream &out, vector <string> &parameters)
-{
- if (parameters.empty())
- return CR_WRONG_USAGE;
+ if (auto units = strict_virtual_cast<df::viewscreen_unitlistst>(screen))
+ {
+ if (!L) return true;
- auto L = Lua::Core::State;
- int top = lua_gettop(L);
+ /*
+ * Sort units in the 'u'nit list screen.
+ */
+
+ PARSE_SPEC("units", parameters);
+
+ int page = units->page;
+
+ if (compute_order(*pout, L, top, &order, units->units[page]))
+ {
+ reorder_cursor(&units->cursor_pos[page], order);
+ reorder_vector(&units->units[page], order);
+ reorder_vector(&units->jobs[page], order);
+ }
- if (!Lua::Core::PushModulePublic(out, "plugins.sort", "make_sort_order"))
+ return true;
+ }
+ else if (auto jobs = strict_virtual_cast<df::viewscreen_joblistst>(screen))
{
- out.printerr("Cannot access the sorter function.\n");
- return CR_WRONG_USAGE;
+ if (!L) return true;
+
+ /*
+ * Sort units in the 'j'ob list screen.
+ */
+
+ PARSE_SPEC("units", parameters);
+
+ if (compute_order(*pout, L, top, &order, jobs->units))
+ {
+ reorder_cursor(&jobs->cursor_pos, order);
+ reorder_vector(&jobs->units, order);
+ reorder_vector(&jobs->jobs, order);
+ }
+
+ return true;
}
+ else if (auto military = strict_virtual_cast<df::viewscreen_layer_militaryst>(screen))
+ {
+ switch (military->page)
+ {
+ case df::viewscreen_layer_militaryst::Positions:
+ {
+ auto &candidates = military->positions.candidates;
+ auto list3 = getLayerList(military, 2);
+
+ /*
+ * Sort candidate units in the 'p'osition page of the 'm'ilitary screen.
+ */
+
+ if (list3 && !candidates.empty() && list3->bright)
+ {
+ if (!L) return true;
+
+ PARSE_SPEC("units", parameters);
+
+ if (compute_order(*pout, L, top, &order, candidates))
+ {
+ reorder_cursor(&list3->cursor, order);
+ reorder_vector(&candidates, order);
+ }
- if (!parse_ordering_spec(out, L, "units", parameters))
+ return true;
+ }
+
+ return false;
+ }
+
+ default:
+ return false;
+ }
+ }
+ else if (auto profile = strict_virtual_cast<df::viewscreen_layer_workshop_profilest>(screen))
{
- out.printerr("Invalid unit ordering specification.\n");
- lua_settop(L, top);
- return CR_WRONG_USAGE;
+ auto list1 = getLayerList(profile, 0);
+
+ if (!list1) return false;
+ if (!L) return true;
+
+ /*
+ * Sort units in the workshop 'q'uery 'P'rofile modification screen.
+ */
+
+ PARSE_SPEC("units", parameters);
+
+ if (compute_order(*pout, L, top, &order, profile->workers))
+ {
+ reorder_cursor(&list1->cursor, order);
+ reorder_vector(&profile->workers, order);
+ }
+
+ return true;
}
+ else if (auto nobles = strict_virtual_cast<df::viewscreen_layer_noblelistst>(screen))
+ {
+ switch (nobles->mode)
+ {
+ case df::viewscreen_layer_noblelistst::Appoint:
+ {
+ auto list2 = getLayerList(nobles, 1);
- auto screen = Core::getInstance().getTopViewscreen();
- std::vector<unsigned> order;
+ /*
+ * Sort units in the appointment candidate list of the 'n'obles screen.
+ */
- if (auto units = strict_virtual_cast<df::viewscreen_unitlistst>(screen))
+ if (list2)
+ {
+ if (!L) return true;
+
+ sort_null_first(parameters);
+ PARSE_SPEC("units", parameters);
+
+ std::vector<df::unit*> units;
+ for (size_t i = 0; i < nobles->candidates.size(); i++)
+ units.push_back(nobles->candidates[i]->unit);
+
+ if (compute_order(*pout, L, top, &order, units))
+ {
+ reorder_cursor(&list2->cursor, order);
+ reorder_vector(&nobles->candidates, order);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ default:
+ return false;
+ }
+ }
+ else if (auto animals = strict_virtual_cast<df::viewscreen_petst>(screen))
{
- for (int i = 0; i < 4; i++)
+ switch (animals->mode)
{
- if (compute_order(out, L, top, &order, units->units[i]))
+ case df::viewscreen_petst::List:
{
- reorder_vector(&units->units[i], order);
- reorder_vector(&units->jobs[i], order);
+ if (!L) return true;
+
+ /*
+ * Sort animal units in the Animal page of the 'z' status screen.
+ */
+
+ PARSE_SPEC("units", parameters);
+
+ std::vector<df::unit*> units;
+ for (size_t i = 0; i < animals->animal.size(); i++)
+ units.push_back(animals->is_vermin[i] ? NULL : (df::unit*)animals->animal[i]);
+
+ if (compute_order(*pout, L, top, &order, units))
+ {
+ reorder_cursor(&animals->cursor, order);
+ reorder_vector(&animals->animal, order);
+ reorder_vector(&animals->is_vermin, order);
+ reorder_vector(&animals->pet_info, order);
+ reorder_vector(&animals->is_tame, order);
+ reorder_vector(&animals->is_adopting, order);
+ }
+
+ return true;
}
+
+ case df::viewscreen_petst::SelectTrainer:
+ {
+ if (!L) return true;
+
+ /*
+ * Sort candidate trainers in the Animal page of the 'z' status screen.
+ */
+
+ sort_null_first(parameters);
+ PARSE_SPEC("units", parameters);
+
+ if (compute_order(*pout, L, top, &order, animals->trainer_unit))
+ {
+ reorder_cursor(&animals->trainer_cursor, order);
+ reorder_vector(&animals->trainer_unit, order);
+ reorder_vector(&animals->trainer_mode, order);
+ }
+
+ return true;
+ }
+
+ default:
+ return false;
}
}
- else if (auto jobs = strict_virtual_cast<df::viewscreen_joblistst>(screen))
+ else if (auto health = strict_virtual_cast<df::viewscreen_layer_overall_healthst>(screen))
{
- if (compute_order(out, L, top, &order, jobs->units))
+ auto list1 = getLayerList(health, 0);
+
+ if (!list1) return false;
+ if (!L) return true;
+
+ /*
+ * Sort units in the Health page of the 'z' status screen.
+ */
+
+ PARSE_SPEC("units", parameters);
+
+ if (compute_order(*pout, L, top, &order, health->unit))
{
- reorder_vector(&jobs->units, order);
- reorder_vector(&jobs->jobs, order);
+ reorder_cursor(&list1->cursor, order);
+ reorder_vector(&health->unit, order);
+ reorder_vector(&health->bits1, order);
+ reorder_vector(&health->bits2, order);
+ reorder_vector(&health->bits3, order);
}
+
+ return true;
}
else if (strict_virtual_cast<df::viewscreen_dwarfmodest>(screen))
{
switch (ui->main.mode)
{
case ui_sidebar_mode::Burrows:
- if (compute_order(out, L, top, &order, ui->burrows.list_units))
+ if (!L) return true;
+
+ /*
+ * Sort burrow member candidate units in the 'w' sidebar mode.
+ */
+
+ PARSE_SPEC("units", parameters);
+
+ if (compute_order(*pout, L, top, &order, ui->burrows.list_units))
{
+ reorder_cursor(&ui->burrows.unit_cursor_pos, order);
reorder_vector(&ui->burrows.list_units, order);
reorder_vector(&ui->burrows.sel_units, order);
}
- break;
+
+ return true;
+
+ case ui_sidebar_mode::QueryBuilding:
+ if (ui_building_in_owner && *ui_building_in_owner &&
+ ui_owner_candidates && ui_building_item_cursor)
+ {
+ if (!L) return true;
+
+ /*
+ * Sort building owner candidate units in the 'q' sidebar mode.
+ */
+
+ sort_null_first(parameters);
+ PARSE_SPEC("units", parameters);
+
+ if (compute_order(*pout, L, top, &order, *ui_owner_candidates))
+ {
+ reorder_cursor(ui_building_item_cursor, order);
+ reorder_vector(ui_owner_candidates, order);
+ }
+
+ return true;
+ }
+ return false;
default:
- break;;
+ return false;
}
}
+ else
+ return false;
+}
+
+static bool unit_list_hotkey(df::viewscreen *screen)
+{
+ vector<string> dummy;
+ return maybe_sort_units(NULL, NULL, screen, dummy);
+}
+
+static command_result sort_units(color_ostream &out, vector <string> &parameters)
+{
+ if (parameters.empty())
+ return CR_WRONG_USAGE;
+
+ auto L = Lua::Core::State;
+ auto screen = Core::getInstance().getTopViewscreen();
+
+ if (!maybe_sort_units(&out, L, screen, parameters))
+ return CR_WRONG_USAGE;
- lua_settop(L, top);
return CR_OK;
}