summaryrefslogtreecommitdiff
path: root/plugins/forceequip.cpp
diff options
context:
space:
mode:
authorAlexander Gavrilov2012-05-20 21:57:45 +0400
committerAlexander Gavrilov2012-05-20 21:57:45 +0400
commitb992b04f0bb7ffef8e7fb152967d438f398543d7 (patch)
tree0b6dd0e193642d95df53ffb05f7fe9c3a63d0595 /plugins/forceequip.cpp
parentd28d240dbdce9ef38081826c76dad4268259a380 (diff)
downloaddfhack-b992b04f0bb7ffef8e7fb152967d438f398543d7.tar.gz
dfhack-b992b04f0bb7ffef8e7fb152967d438f398543d7.tar.bz2
dfhack-b992b04f0bb7ffef8e7fb152967d438f398543d7.tar.xz
Remove stuff that shouldn't be in the core, and expose to lua what's left.
Specifically, any "if (verbose) { Core::printerr("blah") }" kind of stuff definitely doesn't belong in the common API functions. Also, ref->getUnit() is very expensive. On the other hand, checks for crash-inducing conflicts with the ui should be in the core api, and not in client plugins.
Diffstat (limited to 'plugins/forceequip.cpp')
-rw-r--r--plugins/forceequip.cpp186
1 files changed, 185 insertions, 1 deletions
diff --git a/plugins/forceequip.cpp b/plugins/forceequip.cpp
index dd4e213a..0d493143 100644
--- a/plugins/forceequip.cpp
+++ b/plugins/forceequip.cpp
@@ -48,6 +48,9 @@ using MapExtras::Block;
using MapExtras::MapCache;
using df::global::world;
+const int const_GloveRightHandedness = 1;
+const int const_GloveLeftHandedness = 2;
+
DFHACK_PLUGIN("forceequip");
command_result df_forceequip(color_ostream &out, vector <string> & parameters);
@@ -226,6 +229,187 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out )
return CR_OK;
}
+static bool moveToInventory(MapExtras::MapCache &mc, df::item *item, df::unit *unit, df::body_part_raw * targetBodyPart, bool ignoreRestrictions, int multiEquipLimit, bool verbose)
+{
+ // Step 1: Check for anti-requisite conditions
+ df::unit * itemOwner = Items::getOwner(item);
+ if (ignoreRestrictions)
+ {
+ // If the ignoreRestrictions cmdline switch was specified, then skip all of the normal preventative rules
+ if (verbose) { Core::print("Skipping integrity checks...\n"); }
+ }
+ else if(!item->isClothing() && !item->isArmorNotClothing())
+ {
+ if (verbose) { Core::printerr("Item %d is not clothing or armor; it cannot be equipped. Please choose a different item (or use the Ignore option if you really want to equip an inappropriate item).\n", item->id); }
+ return false;
+ }
+ else if (item->getType() != df::enums::item_type::GLOVES &&
+ item->getType() != df::enums::item_type::HELM &&
+ item->getType() != df::enums::item_type::ARMOR &&
+ item->getType() != df::enums::item_type::PANTS &&
+ item->getType() != df::enums::item_type::SHOES &&
+ !targetBodyPart)
+ {
+ if (verbose) { Core::printerr("Item %d is of an unrecognized type; it cannot be equipped (because the module wouldn't know where to put it).\n", item->id); }
+ return false;
+ }
+ else if (itemOwner && itemOwner->id != unit->id)
+ {
+ if (verbose) { Core::printerr("Item %d is owned by someone else. Equipping it on this unit is not recommended. Please use DFHack's Confiscate plugin, choose a different item, or use the Ignore option to proceed in spite of this warning.\n", item->id); }
+ return false;
+ }
+ else if (item->flags.bits.in_inventory)
+ {
+ if (verbose) { Core::printerr("Item %d is already in a unit's inventory. Direct inventory transfers are not recommended; please move the item to the ground first (or use the Ignore option).\n", item->id); }
+ return false;
+ }
+ else if (item->flags.bits.in_job)
+ {
+ if (verbose) { Core::printerr("Item %d is reserved for use in a queued job. Equipping it is not recommended, as this might interfere with the completion of vital jobs. Use the Ignore option to ignore this warning.\n", item->id); }
+ return false;
+ }
+
+ // ASSERT: anti-requisite conditions have been satisfied (or disregarded)
+
+
+ // Step 2: Try to find a bodypart which is eligible to receive equipment AND which is appropriate for the specified item
+ df::body_part_raw * confirmedBodyPart = NULL;
+ int bpIndex;
+ for(bpIndex = 0; bpIndex < unit->body.body_plan->body_parts.size(); bpIndex++)
+ {
+ df::body_part_raw * currPart = unit->body.body_plan->body_parts[bpIndex];
+
+ // Short-circuit the search process if a BP was specified in the function call
+ // Note: this causes a bit of inefficient busy-looping, but the search space is tiny (<100) and we NEED to get the correct bpIndex value in order to perform inventory manipulations
+ if (!targetBodyPart)
+ {
+ // The function call did not specify any particular body part; proceed with normal iteration and evaluation of BP eligibility
+ }
+ else if (currPart == targetBodyPart)
+ {
+ // A specific body part was included in the function call, and we've found it; proceed with the normal BP evaluation (suitability, emptiness, etc)
+ }
+ else if (bpIndex < unit->body.body_plan->body_parts.size())
+ {
+ // The current body part is not the one that was specified in the function call, but we can keep searching
+ if (verbose) { Core::printerr("Found bodypart %s; not a match; continuing search.\n", currPart->part_code.c_str()); }
+ continue;
+ }
+ else
+ {
+ // The specified body part has not been found, and we've reached the end of the list. Report failure.
+ if (verbose) { Core::printerr("The specified body part (%s) does not belong to the chosen unit. Please double-check to ensure that your spelling is correct, and that you have not chosen a dismembered bodypart.\n"); }
+ return false;
+ }
+
+ if (verbose) { Core::print("Inspecting bodypart %s.\n", currPart->part_code.c_str()); }
+
+ // Inspect the current bodypart
+ if (item->getType() == df::enums::item_type::GLOVES && currPart->flags.is_set(df::body_part_template_flags::GRASP) &&
+ ((item->getGloveHandedness() == const_GloveLeftHandedness && currPart->flags.is_set(df::body_part_template_flags::LEFT)) ||
+ (item->getGloveHandedness() == const_GloveRightHandedness && currPart->flags.is_set(df::body_part_template_flags::RIGHT))))
+ {
+ if (verbose) { Core::print("Hand found (%s)...", currPart->part_code.c_str()); }
+ }
+ else if (item->getType() == df::enums::item_type::HELM && currPart->flags.is_set(df::body_part_template_flags::HEAD))
+ {
+ if (verbose) { Core::print("Head found (%s)...", currPart->part_code.c_str()); }
+ }
+ else if (item->getType() == df::enums::item_type::ARMOR && currPart->flags.is_set(df::body_part_template_flags::UPPERBODY))
+ {
+ if (verbose) { Core::print("Upper body found (%s)...", currPart->part_code.c_str()); }
+ }
+ else if (item->getType() == df::enums::item_type::PANTS && currPart->flags.is_set(df::body_part_template_flags::LOWERBODY))
+ {
+ if (verbose) { Core::print("Lower body found (%s)...", currPart->part_code.c_str()); }
+ }
+ else if (item->getType() == df::enums::item_type::SHOES && currPart->flags.is_set(df::body_part_template_flags::STANCE))
+ {
+ if (verbose) { Core::print("Foot found (%s)...", currPart->part_code.c_str()); }
+ }
+ else if (targetBodyPart && ignoreRestrictions)
+ {
+ // The BP in question would normally be considered ineligible for equipment. But since it was deliberately specified by the user, we'll proceed anyways.
+ if (verbose) { Core::print("Non-standard bodypart found (%s)...", targetBodyPart->part_code.c_str()); }
+ }
+ else if (targetBodyPart)
+ {
+ // The BP in question is not eligible for equipment and the ignore flag was not specified. Report failure.
+ if (verbose) { Core::printerr("Non-standard bodypart found, but it is ineligible for standard equipment. Use the Ignore flag to override this warning.\n"); }
+ return false;
+ }
+ else
+ {
+ if (verbose) { Core::print("Skipping ineligible bodypart.\n"); }
+ // This body part is not eligible for the equipment in question; skip it
+ continue;
+ }
+
+ // ASSERT: The current body part is able to support the specified equipment (or the test has been overridden). Check whether it is currently empty/available.
+
+ if (multiEquipLimit == INT_MAX)
+ {
+ // Note: this loop/check is skipped if the MultiEquip option is specified; we'll simply add the item to the bodyPart even if it's already holding a dozen gloves, shoes, and millstones (or whatever)
+ if (verbose) { Core::print(" inventory checking skipped..."); }
+ confirmedBodyPart = currPart;
+ break;
+ }
+ else
+ {
+ confirmedBodyPart = currPart; // Assume that the bodypart is valid; we'll invalidate it if we detect too many collisions while looping
+ int collisions = 0;
+ for (int inventoryID=0; inventoryID < unit->inventory.size(); inventoryID++)
+ {
+ df::unit_inventory_item * currInvItem = unit->inventory[inventoryID];
+ if (currInvItem->body_part_id == bpIndex)
+ {
+ // Collision detected; have we reached the limit?
+ if (++collisions >= multiEquipLimit)
+ {
+ if (verbose) { Core::printerr(" but it already carries %d piece(s) of equipment. Either remove the existing equipment or use the Multi option.\n", multiEquipLimit); }
+ confirmedBodyPart = NULL;
+ break;
+ }
+ }
+ }
+
+ if (confirmedBodyPart)
+ {
+ // Match found; no need to examine any other BPs
+ if (verbose) { Core::print(" eligibility confirmed..."); }
+ break;
+ }
+ else if (!targetBodyPart)
+ {
+ // This body part is not eligible to receive the specified equipment; return to the loop and check the next BP
+ continue;
+ }
+ else
+ {
+ // A specific body part was designated in the function call, but it was found to be ineligible.
+ // Don't return to the BP loop; just fall-through to the failure-reporting code a few lines below.
+ break;
+ }
+ }
+ }
+
+ if (!confirmedBodyPart) {
+ // No matching body parts found; report failure
+ if (verbose) { Core::printerr("\nThe item could not be equipped because the relevant body part(s) of the unit are missing or already occupied. Try again with the Multi option if you're like to over-equip a body part, or choose a different unit-item combination (e.g. stop trying to put shoes on a trout).\n" ); }
+ return false;
+ }
+
+ if (!Items::moveToInventory(mc, item, unit, df::unit_inventory_item::Worn, bpIndex))
+ {
+ if (verbose) { Core::printerr("\nEquipping failed - failed to retrieve item from its current location/container/inventory. Please move it to the ground and try again.\n"); }
+ return false;
+ }
+
+ if (verbose) { Core::print(" Success!\n"); }
+ return true;
+}
+
+
command_result df_forceequip(color_ostream &out, vector <string> & parameters)
{
// The "here" option is hardcoded to true, because the plugin currently doesn't support
@@ -425,7 +609,7 @@ command_result df_forceequip(color_ostream &out, vector <string> & parameters)
else
{
itemsFound ++; // Track the number of items found under the cursor (for feedback purposes)
- if (Items::moveToInventory(mc, currentItem, targetUnit, targetBodyPart, ignore, multiEquipLimit, verbose))
+ if (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();