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);}
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);}
returnfalse;
}
elseif(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);}
returnfalse;
}
elseif(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);}
returnfalse;
}
elseif(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);}
returnfalse;
}
// 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
// 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
}
elseif(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)
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",targetBodyPart->token.c_str());}
// The BP in question would normally be considered ineligible for equipment. But since it was deliberately specified by the user, we'll proceed anyways.
// 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");}
// 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::printerr(" but it already carries %d piece(s) of equipment. Either remove the existing equipment or use the Multi option.\n",multiEquipLimit);}
// 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");}
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");}
// 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->token.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());
returnCR_FAILURE;
}
}
// Search for item(s)
MapCachemc;
// iterate over all items, process those where pos == pos_cursor
intitemsEquipped=0;
intitemsFound=0;
intnumItems=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(inti=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
// 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
elseif(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)
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");
returnCR_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");}
// 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.