Merge remote-tracking branch 'kmartin/master'
						commit
						d28d240dbd
					
				@ -1 +1 @@
 | 
			
		||||
Subproject commit f004804fd655efcb4bf9ea31bd95ae4f759937b4
 | 
			
		||||
Subproject commit 62fda323c5976fd51588d310a16cf442124d1412
 | 
			
		||||
@ -0,0 +1,457 @@
 | 
			
		||||
// forceequip plugin
 | 
			
		||||
// Moves local items from the ground into a unit's inventory
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include <iomanip>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <climits>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <set>
 | 
			
		||||
using namespace std;
 | 
			
		||||
 | 
			
		||||
#include "Core.h"
 | 
			
		||||
#include "Console.h"
 | 
			
		||||
#include "Export.h"
 | 
			
		||||
#include "PluginManager.h"
 | 
			
		||||
#include "modules/Maps.h"
 | 
			
		||||
#include "modules/Gui.h"
 | 
			
		||||
#include "modules/Items.h"
 | 
			
		||||
#include "modules/Materials.h"
 | 
			
		||||
#include "modules/MapCache.h"
 | 
			
		||||
#include "DataDefs.h"
 | 
			
		||||
#include "df/item.h"
 | 
			
		||||
#include "df/itemdef.h"
 | 
			
		||||
#include "df/world.h"
 | 
			
		||||
#include "df/general_ref.h"
 | 
			
		||||
#include "df/unit.h"
 | 
			
		||||
#include "df/body_part_raw.h"
 | 
			
		||||
#include "MiscUtils.h"
 | 
			
		||||
#include "df/unit_inventory_item.h"
 | 
			
		||||
#include "df/body_part_template_flags.h"
 | 
			
		||||
#include "df/creature_raw.h"
 | 
			
		||||
#include "df/caste_raw.h"
 | 
			
		||||
#include "df/body_detail_plan.h"
 | 
			
		||||
#include "df/body_template.h"
 | 
			
		||||
#include "df/body_part_template.h"
 | 
			
		||||
#include "df/unit_soul.h"
 | 
			
		||||
#include "df/unit_skill.h"
 | 
			
		||||
#include "df/general_ref.h"
 | 
			
		||||
#include "df/caste_raw.h"
 | 
			
		||||
 | 
			
		||||
#include "DFHack.h"
 | 
			
		||||
 | 
			
		||||
using namespace DFHack;
 | 
			
		||||
using namespace df::enums;
 | 
			
		||||
 | 
			
		||||
using MapExtras::Block;
 | 
			
		||||
using MapExtras::MapCache;
 | 
			
		||||
using df::global::world;
 | 
			
		||||
 | 
			
		||||
DFHACK_PLUGIN("forceequip");
 | 
			
		||||
 | 
			
		||||
command_result df_forceequip(color_ostream &out, vector <string> & parameters);
 | 
			
		||||
 | 
			
		||||
const string forceequip_help =
 | 
			
		||||
    "ForceEquip moves local items into a unit's inventory.  It is typically\n"
 | 
			
		||||
	"used to equip specific clothing/armor items onto a dwarf, but can also\n"
 | 
			
		||||
	"be used to put armor onto a war animal or to add unusual items (such\n"
 | 
			
		||||
	"as crowns) to any unit.\n"
 | 
			
		||||
	"This plugin can process multiple items in a single call, but will only\n"
 | 
			
		||||
	"work with a single unit (the first one it finds under the cursor).\n"
 | 
			
		||||
	"In order to minimize confusion, it is recommended that you use\n"
 | 
			
		||||
	"forceequip only when you have a unit standing alone atop a pile of\n"
 | 
			
		||||
	"gear that you would like it to wear.  Items which are stored in bins\n"
 | 
			
		||||
	"or other containers (e.g. chests, armor racks) may also work, but\n"
 | 
			
		||||
	"piling items on the floor (via a garbage dump activity zone, of the\n"
 | 
			
		||||
	"DFHack autodump command) is the most reliable way to do it.\n"
 | 
			
		||||
	"The plugin will ignore any items that are forbidden.  Hence, you\n"
 | 
			
		||||
	"can setup a large pile of surplus gear, walk a unit onto it (or\n"
 | 
			
		||||
	"pasture an animal on it), unforbid a few items and run forceequip.\n"
 | 
			
		||||
	"The (forbidden) majority of your gear will remain in-place, ready\n"
 | 
			
		||||
	"for the next passerby."
 | 
			
		||||
	"\n"
 | 
			
		||||
	"As mentioned above, this plugin can be used to equip items onto\n"
 | 
			
		||||
	"units (such as animals) which cannot normally equip gear.  There's\n"
 | 
			
		||||
	"an important caveat here - such creatures will automatically drop\n"
 | 
			
		||||
	"inappropriate gear almost immediately (within 10 game ticks).\n"
 | 
			
		||||
	"If you want them to retain their equipment, you must forbid it\n"
 | 
			
		||||
	"AFTER using forceequip to get it into their inventory.\n"
 | 
			
		||||
	"This technique can also be used to clothe dwarven infants, but\n"
 | 
			
		||||
	"only if you're able to separate them from their mothers.\n"
 | 
			
		||||
    "\n"
 | 
			
		||||
	"By default, the forceequip plugin will attempt to avoid\n"
 | 
			
		||||
	"conflicts and outright cheating.  For instance, it will skip\n"
 | 
			
		||||
	"any item which is flagged for use in a job, and will not\n"
 | 
			
		||||
	"equip more than one piece of clothing/armor onto any given\n"
 | 
			
		||||
	"body part.  These restrictions can be overridden via command\n"
 | 
			
		||||
	"switches (see examples below) but doing so puts you at greater\n"
 | 
			
		||||
	"risk of unexpected consequences.  For instance, a dwarf who\n"
 | 
			
		||||
	"is wearing three breastplates will not be able to move very\n"
 | 
			
		||||
	"quickly.\n"
 | 
			
		||||
	"\n"
 | 
			
		||||
	"Items equipped by this plugin DO NOT become owned by the\n"
 | 
			
		||||
	"recipient.  Adult dwarves are free to adjust their own\n"
 | 
			
		||||
	"wardrobe, and may promptly decide to doff your gear in\n"
 | 
			
		||||
	"favour of their owned items.  Animals, as described above,\n"
 | 
			
		||||
	"will tend to discard ALL clothing immediately unless it is\n"
 | 
			
		||||
	"manually forbidden.  Armor items seem to be an exception;\n"
 | 
			
		||||
	"an animal will tend to retain an equipped suit of mail\n"
 | 
			
		||||
	"even if you neglect to Forbid it.\n"
 | 
			
		||||
	"\n"
 | 
			
		||||
	"Please note that armored animals are quite vulnerable to ranged\n"
 | 
			
		||||
	"attacks.  Unlike dwarves, animals cannot block, dodge, or deflect\n"
 | 
			
		||||
	"arrows, and they are slowed by the weight of their armor.\n"
 | 
			
		||||
	"\n"
 | 
			
		||||
	"This plugin currently does not support weapons.\n"
 | 
			
		||||
	"\n"
 | 
			
		||||
	"Options:\n"
 | 
			
		||||
	"  here, h      - process the unit and item(s) under the cursor.\n"
 | 
			
		||||
	"               - This option is enabled by default since the plugin\n"
 | 
			
		||||
	"               - does not currently support remote equpping.\n"
 | 
			
		||||
    "  ignore, i    - bypasses the usual item eligibility checks (such as\n"
 | 
			
		||||
	"               - \"Never equip gear belonging to another dwarf\" and\n"
 | 
			
		||||
	"               - \"Nobody is allowed to equip a Hive\".)\n"
 | 
			
		||||
	"  multi, m     - bypasses the 1-item-per-bodypart limit, allowing\n"
 | 
			
		||||
	"               - the unit to receive an unlimited amount of gear.\n"
 | 
			
		||||
	"               - Can be used legitimately (e.g. mitten + gauntlet)\n"
 | 
			
		||||
	"               - or for cheating (e.g. twelve breastplates).\n"
 | 
			
		||||
	"  m2, m3, m4   - alters the 1-item-per-bodypart limit, allowing\n"
 | 
			
		||||
	"               - each part to receive 2, 3, or 4 pieces of gear.\n"
 | 
			
		||||
	"  selected, s  - rather than processing all items piled at a unit's\n"
 | 
			
		||||
	"               - feet, process only the one item currently selected.\n"
 | 
			
		||||
	"  bodypart, bp - must be followed by a bodypart code (e.g. LH).\n"
 | 
			
		||||
	"               - Instructs the plugin to equip all available items\n"
 | 
			
		||||
	"               - onto this body part only.  Typically used in\n"
 | 
			
		||||
	"               - conjunction with the f switch (to over-armor\n"
 | 
			
		||||
	"               - a particular bodypart) or the i switch (to equip\n"
 | 
			
		||||
	"               - an unusual item onto a specific slot).\n"
 | 
			
		||||
    "  verbose, v   - provides detailed narration and error messages.\n"
 | 
			
		||||
	"               - Can be helpful in resolving failures; not needed\n"
 | 
			
		||||
	"               - for casual use.\n"
 | 
			
		||||
	"\n"
 | 
			
		||||
    "Examples:\n"
 | 
			
		||||
	"  forceequip\n"
 | 
			
		||||
	"    attempts to equip all of the items under the cursor onto the unit\n"
 | 
			
		||||
	"    under the cursor.  Uses only clothing/armor items; ignores all\n"
 | 
			
		||||
	"    other types.  Equips a maximum of 1 item onto each bodypart,\n"
 | 
			
		||||
	"    and equips only \"appropriate\" items in each slot (e.g. glove\n"
 | 
			
		||||
	"    --> hand).  Bypasses any item which might cause a conflict,\n"
 | 
			
		||||
	"    such as a Boot belonging to a different dwarf.\n"
 | 
			
		||||
	"  forceequip bp LH\n"
 | 
			
		||||
	"    attempts to equip all local items onto the left hand of the local\n"
 | 
			
		||||
	"    unit.  If the hand is already equipped then nothing will happen,\n"
 | 
			
		||||
	"    and if it is not equipped then only one appropriate item (e.g. \n"
 | 
			
		||||
	"    a single mitten or gauntlet) will be equipped.  This command can\n"
 | 
			
		||||
	"    be useful if you don't want to selectively forbid individual items\n"
 | 
			
		||||
	"    and simply want the unit to equip, say, a Helmet while leaving\n"
 | 
			
		||||
	"    the rest of the pile alone.\n"
 | 
			
		||||
	"  forceequip m bp LH\n"
 | 
			
		||||
	"    as above, but will equip ALL appropriate items onto the unit's\n"
 | 
			
		||||
	"    left hand.  After running this command, it might end up wearing\n"
 | 
			
		||||
	"    a dozen left-handed mittens.  Use with caution, and remember\n"
 | 
			
		||||
	"    that dwarves will tend to drop supernumary items ASAP.\n"
 | 
			
		||||
	"  forceequip m\n"
 | 
			
		||||
	"    as above, but will equip ALL appropriate items onto any\n"
 | 
			
		||||
	"    appropriate bodypart.  Tends to put several boots onto the right\n"
 | 
			
		||||
	"    foot while leaving the left foot bare.\n"
 | 
			
		||||
	"  forceequip m2\n"
 | 
			
		||||
	"    as above, but will equip up to two appropriate items onto each\n"
 | 
			
		||||
	"    bodypart.  Helps to balance footwear, but doesn't ensure proper\n"
 | 
			
		||||
	"    placement (e.g. left foot gets two socks, right foot gets two\n"
 | 
			
		||||
	"    shoes).  For best results, use \"selected bp LH\" and\n"
 | 
			
		||||
	"    \"selected bp RH\" instead.\n"
 | 
			
		||||
	"  forceequip i\n"
 | 
			
		||||
	"    performs the standard \"equip appropriate items onto appropriate\n"
 | 
			
		||||
	"    bodyparts\" logic, but also includes items that would normally\n"
 | 
			
		||||
	"    be considered ineligible (such as a sock which is owned by\n"
 | 
			
		||||
	"    a different dwarf).\n"
 | 
			
		||||
	"  forceequip bp NECK\n"
 | 
			
		||||
	"    attempts to equip any appropriate gear onto the Neck of the\n"
 | 
			
		||||
	"    local unit.  Since the plugin believes that no items are actually\n"
 | 
			
		||||
	"    appropriate for the Neck slot, this command does nothing.\n"
 | 
			
		||||
	"  forceequip i bp NECK\n"
 | 
			
		||||
	"    attempts to equip items from the local pile onto the Neck\n"
 | 
			
		||||
	"    of the local unit.  Ignores appropriateness restrictions.\n"
 | 
			
		||||
	"    If there's a millstone or an albatross carcass sitting on\n"
 | 
			
		||||
	"    the same square as the targeted unit, then there's a good\n"
 | 
			
		||||
	"    chance that it will end up around his neck.  For precise\n"
 | 
			
		||||
	"    control, remember that you can selectively forbid some of\n"
 | 
			
		||||
	"    the items that are piled on the ground.\n"
 | 
			
		||||
	"  forceequip i m bp NECK\n"
 | 
			
		||||
	"    as above, but equips an unlimited number of items onto the\n"
 | 
			
		||||
	"    targeted bodypart.  Effectively, all unforbidden items\n"
 | 
			
		||||
	"    (including helms, millstones, boulders, etc) will be\n"
 | 
			
		||||
	"    moved from the local pile and placed in the dwarf's\n"
 | 
			
		||||
	"    inventory (specifically, on his neck).  When used with\n"
 | 
			
		||||
	"    a large pile of goods, this will leave the dwarf heavily\n"
 | 
			
		||||
	"    encumbered and very slow to move.\n"
 | 
			
		||||
	"  forceequip s\n"
 | 
			
		||||
	"    requires that a single item be selected using the k menu.\n"
 | 
			
		||||
	"    This item must occupy the same square as the target unit,\n"
 | 
			
		||||
	"    and must be unforbidden.  Attempts to equip this single\n"
 | 
			
		||||
	"    item onto an appropriate slot in the unit's inventory.\n"
 | 
			
		||||
	"    Can serve as a quicker alternative to the selective-\n"
 | 
			
		||||
	"    unforbidding approach described above.\n"
 | 
			
		||||
	"  forceequip s m i bp HD\n"
 | 
			
		||||
	"    equips the selected item onto the unit's head.  Ignores\n"
 | 
			
		||||
	"    all possible restrictions and conflicts.  If you know\n"
 | 
			
		||||
	"    exactly what you want to equip, and exactly where you\n"
 | 
			
		||||
	"    want it to go, then this is the most straightforward\n"
 | 
			
		||||
	"    and reliable option.\n"
 | 
			
		||||
	"  forceequip v bp QQQ\n"
 | 
			
		||||
	"    guaranteed to fail (and accomplish nothing) because\n"
 | 
			
		||||
	"    there are no bodyparts called QQQ.  However, since the\n"
 | 
			
		||||
	"    verbose switch is used, the resulting error messages\n"
 | 
			
		||||
	"    will list every bodypart that the unit DOES possess.\n"
 | 
			
		||||
	"    May be useful if you're unfamiliar with the BP codes\n"
 | 
			
		||||
	"    used by Dwarf Fortress, or if you're experimenting\n"
 | 
			
		||||
	"    with an exotic creature.\n"
 | 
			
		||||
	"\n"
 | 
			
		||||
	;
 | 
			
		||||
 | 
			
		||||
DFhackCExport command_result plugin_init ( color_ostream &out, vector <PluginCommand> &commands)
 | 
			
		||||
{
 | 
			
		||||
    commands.push_back(PluginCommand(
 | 
			
		||||
        "forceequip", "Moves local items from the ground into a unit's inventory",
 | 
			
		||||
        df_forceequip, false,
 | 
			
		||||
        forceequip_help.c_str()
 | 
			
		||||
    ));
 | 
			
		||||
 | 
			
		||||
    return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DFhackCExport command_result plugin_shutdown ( color_ostream &out )
 | 
			
		||||
{
 | 
			
		||||
    return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
command_result df_forceequip(color_ostream &out, vector <string> & parameters)
 | 
			
		||||
{
 | 
			
		||||
	// The "here" option is hardcoded to true, because the plugin currently doesn't support
 | 
			
		||||
	// equip-at-a-distance (e.g. grab items within 10 squares of the targeted unit)
 | 
			
		||||
    bool here = true;
 | 
			
		||||
	// For balance (anti-cheating) reasons, the plugin applies a limit on the number of
 | 
			
		||||
	// item that can be equipped on any bodypart.  This limit defaults to 1 but can be 
 | 
			
		||||
	// overridden with cmdline switches.
 | 
			
		||||
    int multiEquipLimit = 1;
 | 
			
		||||
	// The plugin applies several pre-checks in order to reduce the risk of conflict
 | 
			
		||||
	// and unintended side-effects.  Most of these checks can be disabled via cmdline
 | 
			
		||||
	bool ignore = false;
 | 
			
		||||
	// By default, the plugin uses all gear piled on the selected square.  Optionally,
 | 
			
		||||
	// it can target only a single item (selected on the k menu) instead
 | 
			
		||||
	bool selected = false;
 | 
			
		||||
	// Most of the plugin's text output is suppressed by default.  It can be enabled
 | 
			
		||||
	// to provide insight into errors, and/or for debugging purposes.
 | 
			
		||||
	bool verbose = false;
 | 
			
		||||
	// By default, the plugin will mate each item to an appropriate bodypart.  This
 | 
			
		||||
	// behaviour can be skipped if the user specifies a particular BP in the cmdline input.
 | 
			
		||||
    std::string targetBodyPartCode;
 | 
			
		||||
 | 
			
		||||
	// Parse the input
 | 
			
		||||
    for (size_t i = 0; i < parameters.size(); i++)
 | 
			
		||||
    {
 | 
			
		||||
        string & p = parameters[i];
 | 
			
		||||
        
 | 
			
		||||
        if (p == "help" || p == "?" || p == "h" || p == "/?" || p == "info" || p == "man")
 | 
			
		||||
        {
 | 
			
		||||
            out << forceequip_help << endl;
 | 
			
		||||
            return CR_OK;
 | 
			
		||||
        }
 | 
			
		||||
        else if (p == "here" || p == "h")
 | 
			
		||||
        {
 | 
			
		||||
            here = true;
 | 
			
		||||
        }
 | 
			
		||||
		else if (p == "ignore" || p == "i")
 | 
			
		||||
		{
 | 
			
		||||
			ignore = true;
 | 
			
		||||
		}
 | 
			
		||||
        else if (p == "multi" || p == "m")
 | 
			
		||||
        {
 | 
			
		||||
			multiEquipLimit = INT_MAX;
 | 
			
		||||
        }
 | 
			
		||||
		else if (p == "m2")
 | 
			
		||||
		{
 | 
			
		||||
			multiEquipLimit = 2;
 | 
			
		||||
		}
 | 
			
		||||
		else if (p == "m3")
 | 
			
		||||
		{
 | 
			
		||||
			multiEquipLimit = 3;
 | 
			
		||||
		}
 | 
			
		||||
		else if (p == "m4")
 | 
			
		||||
		{
 | 
			
		||||
			multiEquipLimit = 4;
 | 
			
		||||
		}
 | 
			
		||||
		else if (p == "selected" || p == "s")
 | 
			
		||||
		{
 | 
			
		||||
			selected = true;
 | 
			
		||||
		}
 | 
			
		||||
		else if (p == "verbose" || p == "v")
 | 
			
		||||
		{
 | 
			
		||||
			verbose = true;
 | 
			
		||||
		}
 | 
			
		||||
        else if (p == "bodypart" || p == "bp" )
 | 
			
		||||
        {
 | 
			
		||||
            // must be followed by bodypart code (e.g. NECK)
 | 
			
		||||
            if(i == parameters.size()-1 || parameters[i+1].size() == 0)
 | 
			
		||||
            {
 | 
			
		||||
                out.printerr("The bp switch must be followed by a bodypart code!\n");
 | 
			
		||||
                return CR_FAILURE;
 | 
			
		||||
            }
 | 
			
		||||
            targetBodyPartCode = parameters[i+1];
 | 
			
		||||
            i++;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            out << p << ": Unknown command!  Type \"forceequip help\" for assistance." << endl;
 | 
			
		||||
            return CR_FAILURE;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	// Ensure that the map information is available (e.g. a game is actually in-progress)
 | 
			
		||||
    if (!Maps::IsValid())
 | 
			
		||||
    {
 | 
			
		||||
        out.printerr("Map is not available!\n");
 | 
			
		||||
        return CR_FAILURE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
	// Lookup the cursor position
 | 
			
		||||
	int cx, cy, cz;
 | 
			
		||||
	DFCoord pos_cursor;
 | 
			
		||||
 | 
			
		||||
	// needs a cursor
 | 
			
		||||
	if (!Gui::getCursorCoords(cx,cy,cz))
 | 
			
		||||
	{
 | 
			
		||||
		out.printerr("Cursor position not found. Please enable the cursor.\n");
 | 
			
		||||
		return CR_FAILURE;
 | 
			
		||||
	}
 | 
			
		||||
	pos_cursor = DFCoord(cx,cy,cz);
 | 
			
		||||
 | 
			
		||||
	// Iterate over all units, process the first one whose pos == pos_cursor
 | 
			
		||||
	df::unit * targetUnit;
 | 
			
		||||
	size_t numUnits = world->units.all.size();
 | 
			
		||||
	for(size_t i=0; i< numUnits; i++)
 | 
			
		||||
	{
 | 
			
		||||
		targetUnit = world->units.all[i];	// tentatively assume that we have a match; then verify
 | 
			
		||||
		DFCoord pos_unit(targetUnit->pos.x, targetUnit->pos.y, targetUnit->pos.z);
 | 
			
		||||
 | 
			
		||||
		if (pos_unit == pos_cursor)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		if (i + 1 == numUnits)
 | 
			
		||||
		{
 | 
			
		||||
			out.printerr("No unit found at cursor!\n");
 | 
			
		||||
			return CR_FAILURE;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Assert: unit found.
 | 
			
		||||
 | 
			
		||||
	// If a specific bodypart was included in the command arguments, then search for it now
 | 
			
		||||
	df::body_part_raw * targetBodyPart = NULL;
 | 
			
		||||
	if (targetBodyPartCode.size() > 0) {
 | 
			
		||||
		for (int bpIndex = 0; bpIndex < targetUnit->body.body_plan->body_parts.size(); bpIndex ++)
 | 
			
		||||
		{
 | 
			
		||||
			// Tentatively assume that the part is a match
 | 
			
		||||
			targetBodyPart = targetUnit->body.body_plan->body_parts.at(bpIndex);
 | 
			
		||||
			if (targetBodyPart->part_code.compare(targetBodyPartCode) == 0) 
 | 
			
		||||
			{
 | 
			
		||||
				// It is indeed a match; exit the loop (while leaving the variable populated)
 | 
			
		||||
				if (verbose) { out.print("Matching bodypart (%s) found.\n", targetBodyPart->part_name.c_str()); }
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			else 
 | 
			
		||||
			{
 | 
			
		||||
				// Not a match; nullify the variable (it will get re-populated on the next pass through the loop)
 | 
			
		||||
				if (verbose) { out.printerr("Bodypart \"%s\" does not match \"%s\".\n", targetBodyPart->part_code.c_str(), targetBodyPartCode.c_str()); }
 | 
			
		||||
				targetBodyPart = NULL;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (!targetBodyPart)
 | 
			
		||||
		{
 | 
			
		||||
			// Loop iteration is complete but no match was found.
 | 
			
		||||
			out.printerr("The unit does not possess a bodypart of type \"%s\".  Please check the spelling or choose a different unit.\n", targetBodyPartCode.c_str());
 | 
			
		||||
			return CR_FAILURE;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Search for item(s)
 | 
			
		||||
	MapCache mc;
 | 
			
		||||
 | 
			
		||||
	// iterate over all items, process those where pos == pos_cursor
 | 
			
		||||
	int itemsEquipped = 0;
 | 
			
		||||
	int itemsFound = 0;
 | 
			
		||||
	int numItems = world->items.all.size();		// Normally, we iterate through EVERY ITEM in the world.  This is expensive, but currently necessary.
 | 
			
		||||
	if (selected) { numItems = 1; }				// If the user wants to process only the selected item, then the loop is trivialized (only one pass is needed).
 | 
			
		||||
	for(int i=0; i< numItems; i++)
 | 
			
		||||
	{
 | 
			
		||||
		df::item * currentItem;
 | 
			
		||||
 | 
			
		||||
		// Search behaviour depends on whether the operation is driven by cursor location or UI selection
 | 
			
		||||
		if (selected)
 | 
			
		||||
		{
 | 
			
		||||
			// The "search" is trivial - the selection must always cover either one or zero items
 | 
			
		||||
			currentItem = Gui::getSelectedItem(out);
 | 
			
		||||
			if (!currentItem) { return CR_FAILURE; }
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// Lookup the current item in the world-space
 | 
			
		||||
			currentItem = world->items.all[i];
 | 
			
		||||
			// Test the item's position
 | 
			
		||||
			DFCoord pos_item(currentItem->pos.x, currentItem->pos.y, currentItem->pos.z);
 | 
			
		||||
			if (pos_item != pos_cursor)
 | 
			
		||||
			{
 | 
			
		||||
				// The item is in the wrong place; skip it
 | 
			
		||||
				// Note: we do not emit any notification, even with the "verbose" switch, because the search space is enormous and we'd invariably flood the UI with useless text
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			// Bypass any forbidden items
 | 
			
		||||
			else if (currentItem->flags.bits.forbid == 1)
 | 
			
		||||
			{
 | 
			
		||||
				// The item is forbidden; skip it
 | 
			
		||||
				if (verbose) { out.printerr("Forbidden item encountered; skipping to next item.\n"); }
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Test the item; check whether we have any grounds to disqualify/reject it
 | 
			
		||||
		if (currentItem->flags.bits.in_inventory == 1)
 | 
			
		||||
		{
 | 
			
		||||
			// The item is in a unit's inventory; skip it
 | 
			
		||||
			if (verbose) { out.printerr("Inventory item encountered; skipping to next item.\n"); }
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			itemsFound ++;						// Track the number of items found under the cursor (for feedback purposes)
 | 
			
		||||
			if (Items::moveToInventory(mc, currentItem, targetUnit, targetBodyPart, ignore, multiEquipLimit, verbose))
 | 
			
		||||
			{
 | 
			
		||||
//				// TODO TEMP EXPERIMENTAL - try to alter the item size in order to conform to its wearer
 | 
			
		||||
//				currentItem->getRace();
 | 
			
		||||
//				out.print("Critter size: %d| %d | Armor size: %d", world->raws.creatures.all[targetUnit->race]->caste[targetUnit->caste]->body_size_1, world->raws.creatures.all[targetUnit->race]->caste[targetUnit->caste]->body_size_2, currentItem->getTotalDimension());
 | 
			
		||||
 | 
			
		||||
				itemsEquipped++;				// Track the number of items successfully processed (for feedback purposes)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (itemsFound == 0) {
 | 
			
		||||
		out.printerr("No usable items found at the cursor position.  Please choose a different location and try again.\n");
 | 
			
		||||
		return CR_OK;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	if (itemsEquipped == 0 && !verbose) { out.printerr("Some items were found but no equipment changes could be made.  Use the /verbose switch to display the reasons for failure.\n"); }
 | 
			
		||||
	if (itemsEquipped > 0) { out.print("%d items equipped.\n", itemsEquipped); }
 | 
			
		||||
	// At this point, some changes may have been made (such as detaching items from their original position), regardless of whether any equipment changes succeeded.
 | 
			
		||||
	// Therefore, we must update the map.
 | 
			
		||||
	mc.WriteAll();
 | 
			
		||||
 | 
			
		||||
	// Note: we might expect to recalculate the unit's weight at this point, in order to account for the 
 | 
			
		||||
	// added items.  In fact, this recalculation occurs automatically during each dwarf's "turn".
 | 
			
		||||
	// The slight delay in recalculation is probably not worth worrying about.
 | 
			
		||||
	
 | 
			
		||||
	// Work complete; report success
 | 
			
		||||
	return CR_OK;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,27 @@
 | 
			
		||||
-- Makes item appear on the table (just like in shops). '-a' or '--all' for all items.
 | 
			
		||||
local pos=df.global.cursor
 | 
			
		||||
local args={...}
 | 
			
		||||
local doall
 | 
			
		||||
if args[1]=="-a" or args[1]=="--all" then
 | 
			
		||||
    doall=true
 | 
			
		||||
end
 | 
			
		||||
local build,items
 | 
			
		||||
items={}
 | 
			
		||||
build=dfhack.buildings.findAtTile(pos.x,pos.y,pos.z)
 | 
			
		||||
if not df.building_tablest:is_instance(build) then
 | 
			
		||||
    error("No table found at cursor")
 | 
			
		||||
end
 | 
			
		||||
for k,v in pairs(df.global.world.items.all) do
 | 
			
		||||
    if pos.x==v.pos.x and pos.y==v.pos.y and pos.z==v.pos.z and v.flags.on_ground then
 | 
			
		||||
        table.insert(items,v)
 | 
			
		||||
        if not doall then
 | 
			
		||||
            break
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end
 | 
			
		||||
if #items==0 then
 | 
			
		||||
    error("No items found!")
 | 
			
		||||
end
 | 
			
		||||
for k,v in pairs(items) do
 | 
			
		||||
    dfhack.items.moveToBuilding(v,build,1)
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
		Reference in New Issue