// Show details of currently active strange mood, if any #include "Core.h" #include "Console.h" #include "Export.h" #include "PluginManager.h" #include "modules/Materials.h" #include "modules/Translation.h" #include "modules/Items.h" #include "modules/Units.h" #include "DataDefs.h" #include "df/world.h" #include "df/job.h" #include "df/job_item.h" #include "df/job_item_ref.h" #include "df/general_ref.h" #include "df/builtin_mats.h" #include "df/inorganic_raw.h" #include "df/matter_state.h" #include "df/unit.h" #include "df/building.h" using std::string; using std::vector; using namespace DFHack; using namespace df::enums; DFHACK_PLUGIN("showmood"); REQUIRE_GLOBAL(world); command_result df_showmood (color_ostream &out, vector & parameters) { if (!parameters.empty()) return CR_WRONG_USAGE; if (!Translation::IsValid()) { out.printerr("Translation data unavailable!\n"); return CR_FAILURE; } CoreSuspender suspend; bool found = false; for (df::job_list_link *cur = world->jobs.list.next; cur != NULL; cur = cur->next) { df::job *job = cur->item; if ((job->job_type < job_type::StrangeMoodCrafter) || (job->job_type > job_type::StrangeMoodMechanics)) continue; found = true; df::unit *unit = NULL; df::building *building = NULL; for (size_t i = 0; i < job->general_refs.size(); i++) { df::general_ref *ref = job->general_refs[i]; if (ref->getType() == general_ref_type::UNIT_WORKER) unit = ref->getUnit(); if (ref->getType() == general_ref_type::BUILDING_HOLDER) building = ref->getBuilding(); } if (!unit) { out.printerr("Found strange mood not attached to any dwarf!\n"); continue; } if (unit->mood == mood_type::None) { out.printerr("Dwarf with strange mood does not have a mood type!\n"); continue; } out.print("%s is currently ", DF2CONSOLE(out, Translation::TranslateName(&unit->name, false)).c_str()); switch (unit->mood) { case mood_type::Macabre: out.print("in a macabre mood"); if (job->job_type != job_type::StrangeMoodBrooding) out.print(" (but isn't actually in a macabre mood?)"); break; case mood_type::Fell: out.print("in a fell mood"); if (job->job_type != job_type::StrangeMoodFell) out.print(" (but isn't actually in a fell mood?)"); break; case mood_type::Fey: case mood_type::Secretive: case mood_type::Possessed: switch (unit->mood) { case mood_type::Fey: out.print("in a fey mood"); break; case mood_type::Secretive: out.print("in a secretive mood"); break; case mood_type::Possessed: out.print("possessed"); break; default: break; } out.print(" with intent to "); switch (job->job_type) { case job_type::StrangeMoodCrafter: out.print("claim a Craftsdwarf's Workshop"); break; case job_type::StrangeMoodJeweller: out.print("claim a Jeweler's Workshop"); break; case job_type::StrangeMoodForge: out.print("claim a Metalsmith's Forge"); break; case job_type::StrangeMoodMagmaForge: out.print("claim a Magma Forge"); break; case job_type::StrangeMoodCarpenter: out.print("claim a Carpenter's Workshop"); break; case job_type::StrangeMoodMason: out.print("claim a Mason's Workshop"); break; case job_type::StrangeMoodBowyer: out.print("claim a Boywer's Workshop"); break; case job_type::StrangeMoodTanner: out.print("claim a Leather Works"); break; case job_type::StrangeMoodWeaver: out.print("claim a Clothier's Shop"); break; case job_type::StrangeMoodGlassmaker: out.print("claim a Glass Furnace"); break; case job_type::StrangeMoodMechanics: out.print("claim a Mechanic's Workshop"); break; case job_type::StrangeMoodBrooding: out.print("enter a macabre mood?"); break; case job_type::StrangeMoodFell: out.print("enter a fell mood?"); break; default: out.print("do something else..."); break; } out.print(" and become a legendary %s", ENUM_ATTR_STR(job_skill, caption_noun, unit->job.mood_skill)); if (unit->mood == mood_type::Possessed) out.print(" (but not really)"); break; default: out.print("insane?"); break; } out.print(".\n"); if (Units::isMale(unit)) out.print("He has "); else out.print("She has "); if (building) { string name; building->getName(&name); out.print("claimed a %s and wants", name.c_str()); } else out.print("not yet claimed a workshop but will want"); out.print(" the following items:\n"); for (size_t i = 0; i < job->job_items.size(); i++) { df::job_item *item = job->job_items[i]; out.print("Item %zu: ", i + 1); MaterialInfo matinfo(item->mat_type, item->mat_index); string mat_name = matinfo.toString(); switch (item->item_type) { case item_type::BOULDER: out.print("%s boulder", mat_name.c_str()); break; case item_type::BLOCKS: out.print("%s blocks", mat_name.c_str()); break; case item_type::WOOD: out.print("%s logs", mat_name.c_str()); break; case item_type::BAR: if (matinfo.isInorganicWildcard()) mat_name = "metal"; if (matinfo.inorganic && matinfo.inorganic->flags.is_set(inorganic_flags::WAFERS)) out.print("%s wafers", mat_name.c_str()); else out.print("%s bars", mat_name.c_str()); break; case item_type::SMALLGEM: out.print("%s cut gems", mat_name.c_str()); break; case item_type::ROUGH: if (matinfo.isAnyInorganic()) { if (matinfo.isInorganicWildcard()) mat_name = "any"; out.print("%s rough gems", mat_name.c_str()); } else out.print("raw %s", mat_name.c_str()); break; case item_type::SKIN_TANNED: out.print("%s leather", mat_name.c_str()); break; case item_type::CLOTH: if (matinfo.isNone()) { if (item->flags2.bits.plant) mat_name = "any plant fiber"; else if (item->flags2.bits.silk) mat_name = "any silk"; else if (item->flags2.bits.yarn) mat_name = "any yarn"; } out.print("%s cloth", mat_name.c_str()); break; case item_type::REMAINS: out.print("%s remains", mat_name.c_str()); break; case item_type::CORPSE: out.print("%s %scorpse", mat_name.c_str(), (item->flags1.bits.murdered ? "murdered " : "")); break; case item_type::NONE: if (item->flags2.bits.body_part) { if (item->flags2.bits.bone) out.print("%s bones", mat_name.c_str()); else if (item->flags2.bits.shell) out.print("%s shells", mat_name.c_str()); else if (item->flags2.bits.horn) out.print("%s horns", mat_name.c_str()); else if (item->flags2.bits.pearl) out.print("%s pearls", mat_name.c_str()); else if (item->flags2.bits.ivory_tooth) out.print("%s ivory/teeth", mat_name.c_str()); else out.print("%s unknown body parts (%s:%s:%s)", mat_name.c_str(), bitfield_to_string(item->flags1).c_str(), bitfield_to_string(item->flags2).c_str(), bitfield_to_string(item->flags3).c_str()); } else out.print("indeterminate %s item (%s:%s:%s)", mat_name.c_str(), bitfield_to_string(item->flags1).c_str(), bitfield_to_string(item->flags2).c_str(), bitfield_to_string(item->flags3).c_str()); break; default: { ItemTypeInfo itinfo(item->item_type, item->item_subtype); out.print("item %s material %s flags (%s:%s:%s)", itinfo.toString().c_str(), mat_name.c_str(), bitfield_to_string(item->flags1).c_str(), bitfield_to_string(item->flags2).c_str(), bitfield_to_string(item->flags3).c_str()); break; } } // count how many items of this type the crafter already collected { int count_got = 0; for (size_t j = 0; j < job->items.size(); j++) { if(job->items[j]->job_item_idx == int32_t(i)) { if (item->item_type == item_type::BAR || item->item_type == item_type::CLOTH) count_got += job->items[j]->item->getTotalDimension(); else count_got += 1; } } out.print(", quantity %i (got %i)\n", item->quantity, count_got); } } } if (!found) out.print("No strange moods currently active.\n"); return CR_OK; } DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( "showmood", "Shows all items needed for active strange mood.", df_showmood)); return CR_OK; } DFhackCExport command_result plugin_shutdown ( color_ostream &out ) { return CR_OK; }