Change Armor Appearance

Wanting to make an item, that when used on armor, it’ll change that armor’s appearance (while still keeping all the armor’s properties). Is this possible?

It’s possible to clone and modify the armour using CopyItemAndModify. It can only edit one slot at a time, though. :thinking: I don’t think there’s a function for altering multiple slots at once, though I’d love to be proven wrong.

More item modification functions in x2_inc_itemprop, including wrappers which tie in destruction of the original.

2 Likes

It might be easier to have a set of armor with no stats, but have a unique power (1 time use). When you use that on another set of armor, it’ll copy all the properties onto the blank armor and then delete the targeted armor?

That’d be one way to do it, sure.

// Transfers item properties from inventory item oSource to inventory item oTarget.
void TransferItemProperties(object oSource, object oTarget, int nDestroySource=TRUE);
void TransferItemProperties(object oSource, object oTarget, int nDestroySource=TRUE)
{
    itemproperty ip;

    // Erase properties on target.
    ip = GetFirstItemProperty(oTarget);
    while (GetIsItemPropertyValid(ip))
        {
        RemoveItemProperty(oTarget, ip);
        ip = GetNextItemProperty(oTarget);
        }

    // Apply properties of source to target.
    ip = GetFirstItemProperty(oSource);
    while (GetIsItemPropertyValid(ip))
        {
        AddItemProperty(GetItemPropertyDurationType(ip), ip, oTarget, IntToFloat(GetItemPropertyDurationRemaining(ip)));
        ip = GetNextItemProperty(oSource);
        }

    // Delete the source.
    if (nDestroySource)
        DestroyObject(oSource);
}

Or you can go through the armor part appearances one at a time with CopyItemAndModify, cloning the item a bunch of times to alter it one part at a time.

// Copies the armor appearance of armour item oSource onto armour item oTarget.
void CopyArmorAppearance(object oSource, object oTarget, int nDestroySource=TRUE);
void CopyArmorAppearance(object oSource, object oTarget, int nDestroySource=TRUE)
{
    object oNew, oPrev, oFinal, oOwner;
    int i;

    oOwner = GetItemPossessor(oTarget);
    oNew  = oTarget;
    oPrev = oTarget;

    // Copy armor colors.
    for (i=0; i<=6; i++)
        {
        oNew = CopyItemAndModify(oPrev, ITEM_APPR_TYPE_ARMOR_COLOR, i, GetItemAppearance(oSource, ITEM_APPR_TYPE_ARMOR_COLOR, i), TRUE);

        if (i < 6)
            DestroyObject(oPrev);

        oPrev = oNew;
        }

    // Copy armor part appearances.
    for (i=0; i<=19; i++)
        {
        oNew = CopyItemAndModify(oPrev, ITEM_APPR_TYPE_ARMOR_MODEL, i, GetItemAppearance(oSource, ITEM_APPR_TYPE_ARMOR_MODEL, i), TRUE);

        if (i < 19)
            DestroyObject(oPrev);
        else
            oFinal = oPrev;

        oPrev = oNew;
        }

    // Equip the new one.
    AssignCommand(oOwner, ActionEquipItem(oFinal, INVENTORY_SLOT_CHEST));

    // Destroy the source.
    if (nDestroySource)
        DestroyObject(oSource);
}

Disclaimer: Not tested very extensively. Probably needs sanity checks for aborting in case function is used on anything other than armour items, too.

1 Like

I’m attempting the second option, but I’m getting an invisible set of armor in return.

The armor (OBJECT_SELF) has the unique property (single use, so it deletes itself after using the unique property) and also has the look (created in the toolset) that I want to copy onto oTarget.
I want to keep the oTarget’s colors, so I’m not including that part.

#include "x2_inc_switches"
void main()
{
    int nEvent = GetUserDefinedItemEventNumber();
    if (nEvent != X2_ITEM_EVENT_ACTIVATE)
        return;

    object oPC = GetItemActivator();
    if (!GetIsPC(oPC))
        return;

    object oTarget = GetItemActivatedTarget();

    int i;

    object oNew  = oTarget;
    object oPrev = oTarget;
    object oFinal;

    if (GetObjectType(oTarget) != OBJECT_TYPE_ITEM)
    {
        SendMessageToPC(oPC, "You can only use this on an item.");
        return;
    }

    string sTarget = GetTag(oTarget);
    if (sTarget == "red040a" || sTarget == "red041a" || sTarget == "red042a" || sTarget == "red043a" || sTarget == "red047a" ||
        sTarget == "red040b" || sTarget == "red041b" || sTarget == "red042b" || sTarget == "red043b" || sTarget == "red047b" ||
        sTarget == "red040c" || sTarget == "red041c" || sTarget == "red042c" || sTarget == "red043c" || sTarget == "red047c" ||
        sTarget == "red040d" || sTarget == "red041d" || sTarget == "red042d" || sTarget == "red043d" || sTarget == "red047d")
    {
        for (i=0; i<=19; i++)
        {
        oNew = CopyItemAndModify(oPrev, ITEM_APPR_TYPE_ARMOR_MODEL, i, GetItemAppearance(OBJECT_SELF, ITEM_APPR_TYPE_ARMOR_MODEL, i), TRUE);

        if (i < 19)
            DestroyObject(oPrev);
        else
            oFinal = oPrev;

        oPrev = oNew;

        AssignCommand(oPC, ActionEquipItem(oFinal, INVENTORY_SLOT_CHEST));
        }
    }
    else
    {
        SendMessageToPC(oPC, "This is an invalid item.");
        return;
    }
}

Got it working… replaced OBJECT_SELF with GetItemActivated();