From 3dd27c8d1d60f44987c26fa0a5aef6df7df1bad3 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 2 Mar 2012 17:46:44 +0400 Subject: [PATCH] Support items in bags, and tweak the output format in metal-detector. --- plugins/advtools.cpp | 103 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 10 deletions(-) diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp index c69fb6a47..0ab056294 100644 --- a/plugins/advtools.cpp +++ b/plugins/advtools.cpp @@ -26,6 +26,7 @@ #include "df/viewscreen_dungeonmodest.h" #include "df/viewscreen_dungeon_monsterstatusst.h" +#include using namespace DFHack; using namespace df::enums; @@ -420,6 +421,57 @@ bool isWeaponArmor(df::item *item) } } +int containsMetalItems(df::item *item, bool all, bool non_trader) +{ + int cnt = 0; + + auto &refs = item->itemrefs; + for (size_t i = 0; i < refs.size(); i++) + { + auto ref = refs[i]; + if (!strict_virtual_cast(ref)) + continue; + + df::item *child = ref->getItem(); + if (!child) continue; + + cnt += containsMetalItems(child, all, non_trader); + } + + if (!non_trader && !isShopItem(item)) + return cnt; + if (!all && !isWeaponArmor(item)) + return cnt; + + MaterialInfo minfo(item); + if (minfo.getCraftClass() != craft_material_class::Metal) + return cnt; + + return ++cnt; +} + +void joinCounts(std::map &counts) +{ + for (auto it = counts.begin(); it != counts.end(); it++) + { + df::coord pt = it->first; + while (pt.x > 0 && counts.count(pt - df::coord(1,0,0))) + pt.x--; + while (pt.y > 0 &&counts.count(pt - df::coord(0,1,0))) + pt.y--; + while (pt.x < 0 && counts.count(pt + df::coord(1,0,0))) + pt.x++; + while (pt.y < 0 &&counts.count(pt + df::coord(0,1,0))) + pt.y++; + + if (pt == it->first) + continue; + + counts[pt] += it->second; + it->second = 0; + } +} + /********************* * FORMATTING * *********************/ @@ -468,6 +520,37 @@ static size_t formatSize(std::vector *out, const std::map 0) + ew = "E"; + else if (delta.x < 0) + ew = "W"; + + if (delta.y > 0) + ns = "S"; + else if (delta.y < 0) + ns = "N"; + + if (abs(delta.x) > abs(delta.y)*5) + dir = ew; + else if (abs(delta.y) > abs(delta.x)*5) + dir = ns; + else if (abs(delta.x) > abs(delta.y)*2) + dir = ew + ns + ew; + else if (abs(delta.y) > abs(delta.x)*2) + dir = ns + ns + ew; + else if (delta.x || delta.y) + dir = ns + ew; + else + dir = "***"; + + int dist = (int)sqrt(delta.x*delta.x + delta.y*delta.y); + return stl_sprintf("%d away %s %+d", dist, dir.c_str(), delta.z); +} + static void printEquipped(Core *c, df::unit *unit, bool all) { std::vector items; @@ -714,17 +797,12 @@ command_result adv_tools (Core * c, std::vector & parameters) if (!item) continue; - if (!non_trader && !isShopItem(item)) - continue; - if (!all && !isWeaponArmor(item)) - continue; - - MaterialInfo minfo(item); - if (minfo.getCraftClass() != craft_material_class::Metal) + int num = containsMetalItems(item, all, non_trader); + if (!num) continue; - total++; - counts[(item->pos - player_pos)/10]++; + total += num; + counts[(item->pos - player_pos)/10] += num; auto &designations = block->designation; auto &dgn = designations[item->pos.x%16][item->pos.y%16]; @@ -734,11 +812,16 @@ command_result adv_tools (Core * c, std::vector & parameters) } } + joinCounts(counts); + c->con.print("%d items of metal merchandise found in the vicinity.\n", total); for (auto it = counts.begin(); it != counts.end(); it++) { + if (!it->second) + continue; + df::coord delta = it->first * 10; - c->con.print(" %+d,%+d,%+d: %d\n", delta.x, delta.y, delta.z, it->second); + c->con.print(" %s: %d\n", formatDirection(delta).c_str(), it->second); } return CR_OK;