// A container for random minor tweaks that don't fit anywhere else, // in order to avoid creating lots of plugins and polluting the namespace. #include "Core.h" #include "Console.h" #include "Export.h" #include "PluginManager.h" #include "modules/Gui.h" #include "modules/Units.h" #include "modules/Items.h" #include "MiscUtils.h" #include "DataDefs.h" #include "df/ui.h" #include "df/world.h" #include "df/squad.h" #include "df/unit.h" #include "df/unit_soul.h" #include "df/historical_entity.h" #include "df/historical_figure.h" #include "df/historical_figure_info.h" #include "df/assumed_identity.h" #include "df/language_name.h" #include "df/death_info.h" #include "df/criminal_case.h" #include "df/unit_inventory_item.h" #include using std::vector; using std::string; using std::endl; using namespace DFHack; using namespace df::enums; using df::global::ui; using df::global::world; using namespace DFHack::Gui; static command_result tweak(color_ostream &out, vector & parameters); DFHACK_PLUGIN("tweak"); DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) { commands.push_back(PluginCommand( "tweak", "Various tweaks for minor bugs.", tweak, false, " tweak clear-missing\n" " Remove the missing status from the selected unit.\n" " tweak clear-ghostly\n" " Remove the ghostly status from the selected unit.\n" " Intended to fix the case where you can't engrave memorials for ghosts.\n" " Note that this is very dirty and possibly dangerous!\n" " Most probably does not have the positive effect of a proper burial.\n" " tweak fixmigrant\n" " Remove the resident/merchant flag from the selected unit.\n" " Intended to fix bugged migrants/traders who stay at the\n" " map edge and don't enter your fort. Only works for\n" " dwarves (or generally the player's race in modded games).\n" " tweak makeown\n" " Force selected unit to become a member of your fort.\n" " Can be abused to grab caravan merchants and escorts, even if\n" " they don't belong to the player's race. Foreign sentients\n" " (humans, elves) can be put to work, but you can't assign rooms\n" " to them and they don't show up in DwarfTherapist because the\n" " game treats them like pets.\n" )); return CR_OK; } DFhackCExport command_result plugin_shutdown (color_ostream &out) { return CR_OK; } static command_result lair(color_ostream &out, std::vector & params); // to be called by tweak-fixmigrant // units forced into the fort by removing the flags do not own their clothes // which has the result that they drop all their clothes and become unhappy because they are naked // so we need to make them own their clothes and add them to their uniform command_result fix_clothing_ownership(color_ostream &out, df::unit* unit) { // first, find one owned item to initialize the vtable bool vt_initialized = false; size_t numItems = world->items.all.size(); for(size_t i=0; i< numItems; i++) { df::item * item = world->items.all[i]; if(Items::getOwner(item)) { vt_initialized = true; break; } } if(!vt_initialized) { out << "fix_clothing_ownership: could not initialize vtable!" << endl; return CR_FAILURE; } int fixcount = 0; for(size_t j=0; jinventory.size(); j++) { df::unit_inventory_item* inv_item = unit->inventory[j]; df::item* item = inv_item->item; // unforbid items (for the case of kidnapping caravan escorts who have their stuff forbidden by default) inv_item->item->flags.bits.forbid = 0; if(inv_item->mode == df::unit_inventory_item::T_mode::Worn) { // ignore armor? // it could be leather boots, for example, in which case it would not be nice to forbid ownership //if(item->getEffectiveArmorLevel() != 0) // continue; if(!Items::getOwner(item)) { if(Items::setOwner(item, unit)) { // add to uniform, so they know they should wear their clothes insert_into_vector(unit->military.uniforms[0], item->id); fixcount++; } else out << "could not change ownership for item!" << endl; } } } // clear uniform_drop (without this they would drop their clothes and pick them up some time later) unit->military.uniform_drop.clear(); out << "ownership for " << fixcount << " clothes fixed" << endl; return CR_OK; } static command_result tweak(color_ostream &out, vector ¶meters) { CoreSuspender suspend; if (parameters.empty()) return CR_WRONG_USAGE; string cmd = parameters[0]; if (cmd == "clear-missing") { df::unit *unit = getSelectedUnit(out, true); if (!unit) return CR_FAILURE; auto death = df::death_info::find(unit->counters.death_id); if (death) { death->flags.bits.discovered = true; auto crime = df::criminal_case::find(death->crime_id); if (crime) crime->flags.bits.discovered = true; } } else if (cmd == "clear-ghostly") { df::unit *unit = getSelectedUnit(out, true); if (!unit) return CR_FAILURE; // don't accidentally kill non-ghosts! if (unit->flags3.bits.ghostly) { // remove ghostly, set to dead instead unit->flags3.bits.ghostly = 0; unit->flags1.bits.dead = 1; } else { out.print("That's not a ghost!\n"); return CR_FAILURE; } } else if (cmd == "fixmigrant") { df::unit *unit = getSelectedUnit(out, true); if (!unit) return CR_FAILURE; if(unit->race != df::global::ui->race_id) { out << "Selected unit does not belong to your race!" << endl; return CR_FAILURE; } // case #1: migrants who have the resident flag set // see http://dffd.wimbli.com/file.php?id=6139 for a save if (unit->flags2.bits.resident) unit->flags2.bits.resident = 0; // case #2: migrants who have the merchant flag // happens on almost all maps after a few migrant waves if(unit->flags1.bits.merchant) unit->flags1.bits.merchant = 0; // this one is a cheat, but bugged migrants usually have the same civ_id // so it should not be triggered in most cases // if it happens that the player has 'foreign' units of the same race // (vanilla df: dwarves not from mountainhome) on his map, just grab them if(unit->civ_id != df::global::ui->civ_id) unit->civ_id = df::global::ui->civ_id; return fix_clothing_ownership(out, unit); } else if (cmd == "makeown") { // force a unit into your fort, regardless of civ or race // allows to "steal" caravan guards etc df::unit *unit = getSelectedUnit(out, true); if (!unit) return CR_FAILURE; if (unit->flags2.bits.resident) unit->flags2.bits.resident = 0; if(unit->flags1.bits.merchant) unit->flags1.bits.merchant = 0; if(unit->flags1.bits.forest) unit->flags1.bits.forest = 0; if(unit->civ_id != df::global::ui->civ_id) unit->civ_id = df::global::ui->civ_id; if(unit->profession == df::profession::MERCHANT) unit->profession = df::profession::TRADER; if(unit->profession2 == df::profession::MERCHANT) unit->profession2 = df::profession::TRADER; return fix_clothing_ownership(out, unit); } else return CR_WRONG_USAGE; return CR_OK; }