From df6bd590068eb060f1e4e04e09506cfbeacd3258 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Wed, 29 Feb 2012 17:06:05 +0400 Subject: [PATCH 01/10] Fix advtools: player_id is an array index, not nemesis id. In most worlds they happen to be the same, but not always. --- plugins/advtools.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp index 6b2787ea8..7ccb4302d 100644 --- a/plugins/advtools.cpp +++ b/plugins/advtools.cpp @@ -201,7 +201,7 @@ bool bodySwap(Core *c, df::unit *player) df::nemesis_record *getPlayerNemesis(Core *c, bool restore_swap) { - auto real_nemesis = df::nemesis_record::find(ui_advmode->player_id); + auto real_nemesis = vector_get(world->nemesis.all, ui_advmode->player_id); if (!real_nemesis || !real_nemesis->unit) { c->con.printerr("Invalid player nemesis id: %d\n", ui_advmode->player_id); @@ -274,7 +274,11 @@ void sortCompanionNemesis(std::vector *list, int player_id = -1 output.reserve(list->size()); if (player_id < 0) - player_id = ui_advmode->player_id; + { + auto real_nemesis = vector_get(world->nemesis.all, ui_advmode->player_id); + if (real_nemesis) + player_id = real_nemesis->id; + } // Index records; find the player for (size_t i = 0; i < list->size(); i++) @@ -570,7 +574,7 @@ command_result adv_bodyswap (Core * c, std::vector & parameters) // Permanently re-link everything if (permanent) { - ui_advmode->player_id = new_nemesis->id; + ui_advmode->player_id = linear_index(world->nemesis.all, new_nemesis); // Flag 0 appears to be the 'active adventurer' flag, and // the player_id field above seems to be computed using it From 5019af038bd84ff5a224edb175d1a7def4c99572 Mon Sep 17 00:00:00 2001 From: Quietust Date: Thu, 1 Mar 2012 22:52:40 -0600 Subject: [PATCH 02/10] Allow Reveal to be used in Adventurer mode --- plugins/reveal.cpp | 45 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/plugins/reveal.cpp b/plugins/reveal.cpp index fd9b65c93..647ad21d5 100644 --- a/plugins/reveal.cpp +++ b/plugins/reveal.cpp @@ -120,6 +120,26 @@ command_result nopause (Core * c, std::vector & parameters) return CR_OK; } +void revealAdventure(DFHack::Core * c) +{ + for (size_t i = 0; i < world->map.map_blocks.size(); i++) + { + df::map_block *block = world->map.map_blocks[i]; + // in 'no-hell'/'safe' mode, don't reveal blocks with hell and adamantine + if (!isSafe(block->map_pos)) + continue; + DFHack::designations40d & designations = block->designation; + // for each tile in block + for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) + { + // set to revealed + designations[x][y].bits.hidden = 0; + // and visible + designations[x][y].bits.pile = 1; + } + } + c->con.print("Local map revealed.\n"); +} command_result reveal(DFHack::Core * c, std::vector & params) { @@ -157,16 +177,21 @@ command_result reveal(DFHack::Core * c, std::vector & params) CoreSuspender suspend(c); DFHack::World *World =c->getWorld(); + if (!Maps::IsValid()) + { + c->con.printerr("Map is not available!\n"); + return CR_FAILURE; + } t_gamemodes gm; World->ReadGameMode(gm); - if(gm.g_mode != GAMEMODE_DWARF) + if(gm.g_mode == GAMEMODE_ADVENTURE) { - con.printerr("Only in fortress mode.\n"); - return CR_FAILURE; + revealAdventure(c); + return CR_OK; } - if (!Maps::IsValid()) + if(gm.g_mode != GAMEMODE_DWARF) { - c->con.printerr("Map is not available!\n"); + con.printerr("Only in fortress mode.\n"); return CR_FAILURE; } @@ -231,6 +256,11 @@ command_result unreveal(DFHack::Core * c, std::vector & params) CoreSuspender suspend(c); DFHack::World *World =c->getWorld(); + if (!Maps::IsValid()) + { + c->con.printerr("Map is not available!\n"); + return CR_FAILURE; + } t_gamemodes gm; World->ReadGameMode(gm); if(gm.g_mode != GAMEMODE_DWARF) @@ -238,11 +268,6 @@ command_result unreveal(DFHack::Core * c, std::vector & params) con.printerr("Only in fortress mode.\n"); return CR_FAILURE; } - if (!Maps::IsValid()) - { - c->con.printerr("Map is not available!\n"); - return CR_FAILURE; - } // Sanity check: map size uint32_t x_max_b, y_max_b, z_max_b; From ae655daf1afde907d8e8e796c88fbc299cdb4900 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 2 Mar 2012 11:10:34 +0400 Subject: [PATCH 03/10] Add an advtool for detecting metal stuff in shops. Inspired by Q's advmode reveal. Obviously doesn't work in travel mode. --- plugins/advtools.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp index 7ccb4302d..a1329d1a6 100644 --- a/plugins/advtools.cpp +++ b/plugins/advtools.cpp @@ -11,12 +11,15 @@ #include "DataDefs.h" #include "df/world.h" #include "df/ui_advmode.h" +#include "df/item.h" #include "df/unit.h" #include "df/unit_inventory_item.h" +#include "df/map_block.h" #include "df/nemesis_record.h" #include "df/historical_figure.h" #include "df/general_ref_is_nemesisst.h" #include "df/general_ref_contains_itemst.h" +#include "df/general_ref_building_civzone_assignedst.h" #include "df/material.h" #include "df/craft_material_class.h" #include "df/viewscreen_optionst.h" @@ -59,6 +62,9 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector " list-equipped [all]\n" " List armor and weapons equipped by your companions.\n" " If all is specified, also lists non-metal clothing.\n" + " metal-detector [all-types] [non-trader]\n" + " Reveal metal armor and weapons in shops. The options\n" + " disable the checks on item type and being in shop.\n" )); commands.push_back(PluginCommand( @@ -384,6 +390,36 @@ void listUnitInventory(std::vector *list, df::unit *unit) } } +bool isShopItem(df::item *item) +{ + for (size_t k = 0; k < item->itemrefs.size(); k++) + { + auto ref = item->itemrefs[k]; + if (virtual_cast(ref)) + return true; + } + + return false; +} + +bool isWeaponArmor(df::item *item) +{ + using namespace df::enums::item_type; + + switch (item->getType()) { + case HELM: + case ARMOR: + case WEAPON: + case AMMO: + case GLOVES: + case PANTS: + case SHOES: + return true; + default: + return false; + } +} + /********************* * FORMATTING * *********************/ @@ -640,6 +676,67 @@ command_result adv_tools (Core * c, std::vector & parameters) return CR_OK; } + else if (command == "metal-detector") + { + bool all = false, non_trader = false; + for (size_t i = 1; i < parameters.size(); i++) + { + if (parameters[i] == "all-types") + all = true; + else if (parameters[i] == "non-trader") + non_trader = true; + else + return CR_WRONG_USAGE; + } + + auto *player = getPlayerNemesis(c, false); + if (!player) + return CR_FAILURE; + + df::coord player_pos = player->unit->pos; + + int total = 0; + std::map counts; + + for (size_t i = 0; i < world->map.map_blocks.size(); i++) + { + df::map_block *block = world->map.map_blocks[i]; + + for (size_t j = 0; j < block->items.size(); j++) + { + df::item *item = df::item::find(block->items[j]); + if (!item) + continue; + + if (!non_trader && !isShopItem(item)) + continue; + if (!all && !isWeaponArmor(item)) + continue; + + MaterialInfo minfo(item); + if (minfo.getCraftClass() != craft_material_class::Metal) + continue; + + total++; + counts[(item->pos - player_pos)/10]++; + + auto &designations = block->designation; + auto &dgn = designations[item->pos.x%16][item->pos.y%16]; + + dgn.bits.hidden = 0; // revealed + dgn.bits.pile = 1; // visible + } + } + + c->con.print("%d items of metal merchandise found in the vicinity.\n", total); + for (auto it = counts.begin(); it != counts.end(); it++) + { + df::coord delta = it->first * 10; + c->con.print(" %+d,%+d,%+d: %d\n", delta.x, delta.y, delta.z, it->second); + } + + return CR_OK; + } else return CR_WRONG_USAGE; } From da3ac54af78a081c4a1fd9bb1ed9301398b2371a Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 2 Mar 2012 11:19:30 +0400 Subject: [PATCH 04/10] Don't put clothing held in hands into the first 3 columns of list-equipped. For some reason that stuff has INV_WEAPON and shows up in the report, so since it does, put it in the weapon column. --- plugins/advtools.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp index a1329d1a6..c69fb6a47 100644 --- a/plugins/advtools.cpp +++ b/plugins/advtools.cpp @@ -505,6 +505,12 @@ static void printEquipped(Core *c, df::unit *unit, bool all) // Add to the right table int count = item->getStackSize(); + if (is_weapon) + { + weapons[name] += count; + continue; + } + switch (iinfo.type) { case item_type::HELM: head[name] += count; From 3dd27c8d1d60f44987c26fa0a5aef6df7df1bad3 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 2 Mar 2012 17:46:44 +0400 Subject: [PATCH 05/10] 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; From 5d4114f5b797f302b903116d1439e6d94fa6d7f5 Mon Sep 17 00:00:00 2001 From: Quietust Date: Fri, 2 Mar 2012 09:35:49 -0600 Subject: [PATCH 06/10] Add "bprobe" command, describes the buildings located under the cursor --- plugins/probe.cpp | 67 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/plugins/probe.cpp b/plugins/probe.cpp index 970a07350..7849c33b7 100644 --- a/plugins/probe.cpp +++ b/plugins/probe.cpp @@ -19,10 +19,12 @@ using namespace std; #include "modules/Gui.h" #include "modules/Materials.h" #include "modules/MapCache.h" +#include "modules/Buildings.h" #include "MiscUtils.h" #include "df/world.h" - +#include "df/world_raws.h" +#include "df/building_def.h" using std::vector; using std::string; @@ -30,9 +32,11 @@ using namespace DFHack; using namespace DFHack::Simple; using namespace df::enums; using df::global::world; +using df::global::cursor; command_result df_probe (Core * c, vector & parameters); command_result df_cprobe (Core * c, vector & parameters); +command_result df_bprobe (Core * c, vector & parameters); DFHACK_PLUGIN("probe"); @@ -45,6 +49,9 @@ DFhackCExport command_result plugin_init ( Core * c, std::vector commands.push_back(PluginCommand("cprobe", "A creature probe", df_cprobe)); + commands.push_back(PluginCommand("bprobe", + "A simple building probe", + df_bprobe)); return CR_OK; } @@ -273,3 +280,61 @@ command_result df_probe (Core * c, vector & parameters) con << std::endl; return CR_OK; } + +command_result df_bprobe (Core * c, vector & parameters) +{ + CoreSuspender suspend(c); + + if(cursor->x == -30000) + { + c->con.printerr("No cursor; place cursor over tile to probe.\n"); + return CR_FAILURE; + } + + for (size_t i = 0; i < world->buildings.all.size(); i++) + { + Buildings::t_building building; + if (!Buildings::Read(i, building)) + continue; + if (!(building.x1 <= cursor->x && cursor->x <= building.x2 && + building.y1 <= cursor->y && cursor->y <= building.y2 && + building.z == cursor->z)) + continue; + string name; + building.origin->getName(&name); + c->con.print("Building %i - \"%s\" - type %s", building.origin->id, name.c_str(), ENUM_KEY_STR(building_type, building.type)); + + switch (building.type) + { + case building_type::Furnace: + c->con.print(", subtype %s", ENUM_KEY_STR(furnace_type, building.furnace_type)); + if (building.furnace_type == furnace_type::Custom) + c->con.print(", custom type %i (%s)", building.custom_type, world->raws.buildings.all[building.custom_type]->code.c_str()); + break; + case building_type::Workshop: + c->con.print(", subtype %s", ENUM_KEY_STR(workshop_type, building.workshop_type)); + if (building.workshop_type == workshop_type::Custom) + c->con.print(", custom type %i (%s)", building.custom_type, world->raws.buildings.all[building.custom_type]->code.c_str()); + break; + case building_type::Construction: + c->con.print(", subtype %s", ENUM_KEY_STR(construction_type, building.construction_type)); + break; + case building_type::Shop: + c->con.print(", subtype %s", ENUM_KEY_STR(shop_type, building.shop_type)); + break; + case building_type::SiegeEngine: + c->con.print(", subtype %s", ENUM_KEY_STR(siegeengine_type, building.siegeengine_type)); + break; + case building_type::Trap: + c->con.print(", subtype %s", ENUM_KEY_STR(trap_type, building.trap_type)); + break; + default: + if (building.subtype != -1) + c->con.print(", subtype %i", building.subtype); + break; + } + c->con.print("\n"); + + } + return CR_OK; +} From 3ae622b0ffb9002a053664bad9ebb57532515be7 Mon Sep 17 00:00:00 2001 From: Quietust Date: Sat, 3 Mar 2012 14:14:09 -0600 Subject: [PATCH 07/10] BaseClassDescriptor includes a pointer back to ClassHierarchyDescriptor - parse it --- reversing/ms_rtti.idc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/reversing/ms_rtti.idc b/reversing/ms_rtti.idc index 052751f29..658645f20 100644 --- a/reversing/ms_rtti.idc +++ b/reversing/ms_rtti.idc @@ -293,6 +293,7 @@ struct _s_RTTIBaseClassDescriptor DWORD numContainedBases; //number of nested classes following in the array struct PMD where; //some displacement info DWORD attributes; //usually 0, sometimes 10h + struct _s_RTTIClassHierarchyDescriptor *pClassHierarchyDescriptor; //of this base class }; struct PMD @@ -314,6 +315,15 @@ struct PMD DwordCmt(x+4, "numContainedBases"); DwordArrayCmt(x+8, 3, "PMD where"); DwordCmt(x+20, "attributes"); + OffCmt(x+24, "pClassHierarchyDescriptor"); + + if(substr(Name(Dword(x+24)),0,5) != "??_R3") + { + // assign dummy name to prevent infinite recursion + MakeName(Dword(x+24),"??_R3"+form("%06x",x)+"@@8"); + // a proper name will be assigned shortly + Parse_CHD(Dword(x+24),indent-1); + } s = Parse_TD(Dword(x), indent+1); //??_R1A@?0A@A@B@@8 = B::`RTTI Base Class Descriptor at (0,-1,0,0)' @@ -414,9 +424,11 @@ static Parse_CHD(x, indent) i=0; DumpNestedClass(a, indent, n); indent=indent+1; - while(i Date: Sat, 3 Mar 2012 14:14:31 -0600 Subject: [PATCH 08/10] Properly handle the variety of exception handlers that MSVC 2010 generates --- reversing/ms_ehseh.idc | 90 ++++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 38 deletions(-) diff --git a/reversing/ms_ehseh.idc b/reversing/ms_ehseh.idc index 317012117..1d25e1369 100644 --- a/reversing/ms_ehseh.idc +++ b/reversing/ms_ehseh.idc @@ -71,50 +71,64 @@ static ParseCxxHandler(func, handler, fixFunc) y = x; z = x; EHCookieOffset=0; GSCookieOffset=0; - if (matchBytes(x,"8B5424088D420C")) - // 8B 54 24 08 mov edx, [esp+8] - // 8D 42 0C lea eax, [edx+0Ch] + // 8B 54 24 08 mov edx, [esp+8] + if (matchBytes(x,"8B5424088D02")) + x = x+6; + // 8D 02 lea eax, [edx] + else if (matchBytes(x,"8B5424088D42")) + x = x+7; + // 8D 42 xx lea eax, [edx+XXh] + else if (matchBytes(x,"8B5424088D82")) + x = x+10; + // 8D 82 xx xx xx xx lea eax, [edx+XXh] + else { + Message("Function at %08X not recognized as exception handler!\n",x); + return; + } + //EH cookie check: + // 8B 4A xx mov ecx, [edx-XXh] + // OR + // 8B 8A xx xx xx xx mov ecx, [edx-XXh] + // 33 C8 xor ecx, eax + // E8 xx xx xx xx call __security_check_cookie + if (matchBytes(x,"8B4A??33C8E8")) + { + //byte argument + EHCookieOffset = (~Byte(x+2)+1)&0xFF; + EHCookieOffset = 12 + EHCookieOffset; + x = x+10; + } + else if (matchBytes(x,"8B8A????????33C8E8")) + { + //dword argument + EHCookieOffset = (~Dword(x+2)+1); + EHCookieOffset = 12 + EHCookieOffset; + x = x+13; + } + if (matchBytes(x,"83C0")) + x = x + 3; + // 8B 4A xx add eax, XXh + if (matchBytes(x,"8B4A??33C8E8")) { - //EH cookie check: // 8B 4A xx mov ecx, [edx-XXh] - // OR - // 8B 8A xx xx xx xx mov ecx, [edx-XXh] // 33 C8 xor ecx, eax // E8 xx xx xx xx call __security_check_cookie - x = x+7; - if (matchBytes(x,"8B4A??33C8E8")) - { - //byte argument - EHCookieOffset = (~Byte(x+2)+1)&0xFF; - EHCookieOffset = 12 + EHCookieOffset; - x = x+10; - } - else if (matchBytes(x,"8B8A????????33C8E8")) - { - //dword argument - EHCookieOffset = (~Dword(x+2)+1); - EHCookieOffset = 12 + EHCookieOffset; - x = x+13; - } - if (matchBytes(x,"8B4A??33C8E8")) - { - // 8B 4A xx mov ecx, [edx-XXh] - // 33 C8 xor ecx, eax - // E8 xx xx xx xx call __security_check_cookie - GSCookieOffset = (~Byte(x+2)+1)&0xFF; - GSCookieOffset = 12 + GSCookieOffset; - x = x+10; - } - else if (matchBytes(x,"8B8A????????33C8E8")) - { - //dword argument - GSCookieOffset = (~Dword(x+9)+1); - GSCookieOffset = 12 + GSCookieOffset; - x = x+13; - } - //Message("EH3: EH Cookie=%02X, GSCookie=%02X\n",EHCookieOffset, GSCookieOffset); + GSCookieOffset = (~Byte(x+2)+1)&0xFF; + GSCookieOffset = 12 + GSCookieOffset; + x = x+10; + } + else if (matchBytes(x,"8B8A????????33C8E8")) + { + //dword argument + GSCookieOffset = (~Dword(x+9)+1); + GSCookieOffset = 12 + GSCookieOffset; + x = x+13; } + + //Message("EH3: EH Cookie=%02X, GSCookie=%02X\n",EHCookieOffset, GSCookieOffset); + if (Byte(x)==0xB8) { + // 8B 4A xx xx xx mov eax, offset FuncInfo x = Dword(x+1); } else { From 2b2c30ac43cf766df04074e88dd06a6896873670 Mon Sep 17 00:00:00 2001 From: Quietust Date: Sat, 3 Mar 2012 16:03:35 -0600 Subject: [PATCH 09/10] DEEP_ANY got renamed to SPECIAL --- library/modules/Materials.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index 5b6e8d77d..433b0b405 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -467,7 +467,7 @@ void MaterialInfo::getMatchBits(df::job_item_flags2 &ok, df::job_item_flags2 &ma TEST(fire_safe, material->heat.melting_point > 11000); TEST(magma_safe, material->heat.melting_point > 12000); - TEST(deep_material, FLAG(inorganic, inorganic_flags::DEEP_ANY)); + TEST(deep_material, FLAG(inorganic, inorganic_flags::SPECIAL)); TEST(non_economic, inorganic && !(ui && ui->economic_stone[index])); TEST(plant, plant); From a0b671b28948958349d5e6542b3f356e02844ee2 Mon Sep 17 00:00:00 2001 From: Quietust Date: Sat, 3 Mar 2012 16:06:31 -0600 Subject: [PATCH 10/10] sqrt() doesn't work on integers --- plugins/advtools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp index 40745cc32..15a7cad92 100644 --- a/plugins/advtools.cpp +++ b/plugins/advtools.cpp @@ -547,7 +547,7 @@ static std::string formatDirection(df::coord delta) else dir = "***"; - int dist = (int)sqrt(delta.x*delta.x + delta.y*delta.y); + int dist = (int)sqrt((double)(delta.x*delta.x + delta.y*delta.y)); return stl_sprintf("%d away %s %+d", dist, dir.c_str(), delta.z); }