diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 0b958f37c..471dba640 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -446,6 +446,13 @@ Lua::ObjectClass Lua::IsDFObject(lua_State *state, int val_index) return ok ? cls : Lua::OBJ_INVALID; } +static const char *const primitive_types[] = { + "string", NULL +}; +static type_identity *const primitive_identities[] = { + df::identity_traits::get(), NULL +}; + /** * Given a DF object reference or type, safely retrieve its identity pointer. */ @@ -453,6 +460,12 @@ type_identity *LuaWrapper::get_object_identity(lua_State *state, int objidx, const char *ctx, bool allow_type, bool keep_metatable) { + if (allow_type && !keep_metatable && lua_isstring(state, objidx)) + { + int idx = luaL_checkoption(state, objidx, NULL, primitive_types); + return primitive_identities[idx]; + } + if (!lua_getmetatable(state, objidx)) luaL_error(state, "Invalid object in %s", ctx); diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index f042e85cd..55e838987 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -2,9 +2,11 @@ local _ENV = mkmodule('plugins.sort') local utils = require('utils') local units = require('plugins.sort.units') +local items = require('plugins.sort.items') orders = orders or {} orders.units = units.orders +orders.items = items.orders function parse_ordering_spec(type,...) local group = orders[type] diff --git a/plugins/lua/sort/items.lua b/plugins/lua/sort/items.lua new file mode 100644 index 000000000..2e1b3fd1f --- /dev/null +++ b/plugins/lua/sort/items.lua @@ -0,0 +1,62 @@ +local _ENV = mkmodule('plugins.sort.items') + +local utils = require('utils') + +orders = orders or {} + +-- Relies on NULL being auto-translated to NULL, and then sorted +orders.exists = { + key = function(item) + return 1 + end +} + +orders.type = { + key = function(item) + return item:getType() + end +} + +orders.description = { + key = function(item) + return dfhack.with_temp_object( + df.new "string", + function(str,item) + item:getItemDescription(str,0) + return str.value + end, + item + ) + end +} + +orders.quality = { + key = function(item) + return item:getQuality() + end +} + +orders.improvement = { + key = function(item) + return item:getImprovementQuality() + end +} + +orders.wear = { + key = function(item) + return item:getWear() + end +} + +orders.material = { + key = function(item) + local mattype = item:getActualMaterial() + local matindex = item:getActualMaterialIndex() + local info = dfhack.matinfo.decode(mattype, matindex) + if info then + return info:toString() + end + end +} + +return _ENV \ No newline at end of file diff --git a/plugins/lua/sort/units.lua b/plugins/lua/sort/units.lua index 35795502d..d8ae83a38 100644 --- a/plugins/lua/sort/units.lua +++ b/plugins/lua/sort/units.lua @@ -109,4 +109,10 @@ orders.squad_position = { end } +orders.happiness = { + key = function(unit) + return unit.status.happiness + end +} + return _ENV \ No newline at end of file diff --git a/plugins/sort.cpp b/plugins/sort.cpp index 9d63b2c6c..430fb7192 100644 --- a/plugins/sort.cpp +++ b/plugins/sort.cpp @@ -18,9 +18,12 @@ #include "df/viewscreen_layer_workshop_profilest.h" #include "df/viewscreen_layer_noblelistst.h" #include "df/viewscreen_layer_overall_healthst.h" +#include "df/viewscreen_layer_assigntradest.h" +#include "df/viewscreen_tradegoodsst.h" #include "df/viewscreen_dwarfmodest.h" #include "df/viewscreen_petst.h" #include "df/layer_object_listst.h" +#include "df/assign_trade_status.h" #include "MiscUtils.h" @@ -42,8 +45,10 @@ using df::global::ui_building_assign_units; using df::global::ui_building_assign_items; static bool unit_list_hotkey(df::viewscreen *top); +static bool item_list_hotkey(df::viewscreen *top); static command_result sort_units(color_ostream &out, vector & parameters); +static command_result sort_items(color_ostream &out, vector & parameters); DFHACK_PLUGIN("sort"); @@ -59,6 +64,16 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector ' prefix reverses the sort order for defined values.\n" + " Item order examples:\n" + " description, material, wear, type, quality\n" + "The orderings are defined in hack/lua/plugins/sort/*.lua\n" + )); return CR_OK; } @@ -179,7 +194,7 @@ bool compute_order(color_ostream &out, lua_State *L, int base, std::vector ¶ms) { - if (!parse_ordering_spec(out, L, "units", params)) + if (!parse_ordering_spec(out, L, type, params)) { out.printerr("Invalid ordering specification for %s.\n", type); return false; @@ -191,6 +206,20 @@ static bool ParseSpec(color_ostream &out, lua_State *L, const char *type, vector #define PARSE_SPEC(type, params) \ if (!ParseSpec(*pout, L, type, params)) return false; +static bool prepare_sort(color_ostream *pout, lua_State *L) +{ + if (L) + { + if (!Lua::PushModulePublic(*pout, L, "plugins.sort", "make_sort_order")) + { + pout->printerr("Cannot access the sorter function.\n"); + return false; + } + } + + return true; +} + static void sort_null_first(vector ¶meters) { vector_insert_at(parameters, 0, std::string("printerr("Cannot access the sorter function.\n"); - return false; - } - } + if (!prepare_sort(pout, L)) + return false; std::vector order; @@ -526,3 +549,96 @@ static command_result sort_units(color_ostream &out, vector ¶meters return CR_OK; } + +static bool maybe_sort_items(color_ostream *pout, lua_State *L, + df::viewscreen *screen, vector ¶meters) +{ + Lua::StackUnwinder top(L); + + if (!prepare_sort(pout, L)) + return false; + + std::vector order; + + if (auto trade = strict_virtual_cast(screen)) + { + if (!L) return true; + + PARSE_SPEC("items", parameters); + + if (trade->in_right_pane) + { + if (compute_order(*pout, L, top, &order, trade->broker_items)) + { + reorder_cursor(&trade->broker_cursor, order); + reorder_vector(&trade->broker_items, order); + reorder_vector(&trade->broker_selected, order); + reorder_vector(&trade->broker_count, order); + } + } + else + { + if (compute_order(*pout, L, top, &order, trade->trader_items)) + { + reorder_cursor(&trade->trader_cursor, order); + reorder_vector(&trade->trader_items, order); + reorder_vector(&trade->trader_selected, order); + reorder_vector(&trade->trader_count, order); + } + } + + return true; + } + else if (auto bring = strict_virtual_cast(screen)) + { + auto list1 = getLayerList(bring, 0); + auto list2 = getLayerList(bring, 1); + if (!list1 || !list2 || !list2->bright) + return false; + + int list_idx = vector_get(bring->visible_lists, list1->cursor, (int16_t)-1); + unsigned num_lists = sizeof(bring->lists)/sizeof(std::vector); + if (unsigned(list_idx) >= num_lists) + return false; + + if (!L) return true; + + PARSE_SPEC("items", parameters); + + auto &vec = bring->lists[list_idx]; + + std::vector items; + for (size_t i = 0; i < vec.size(); i++) + items.push_back(bring->info[vec[i]]->item); + + if (compute_order(*pout, L, top, &order, items)) + { + reorder_cursor(&list2->cursor, order); + reorder_vector(&vec, order); + } + + return true; + } + else + return false; +} + +static bool item_list_hotkey(df::viewscreen *screen) +{ + vector dummy; + return maybe_sort_items(NULL, NULL, screen, dummy); +} + +static command_result sort_items(color_ostream &out, vector ¶meters) +{ + if (parameters.empty()) + return CR_WRONG_USAGE; + + auto L = Lua::Core::State; + auto screen = Core::getInstance().getTopViewscreen(); + + if (!maybe_sort_items(&out, L, screen, parameters)) + return CR_WRONG_USAGE; + + return CR_OK; +}