Destroy complete inventory except one item

if i remember correctly I believe that the Plot flag on an item can be TRUE and it still gets destroyed. If so there’s no need to prep Items at all …

 
but since it’s just something that whizzed by me one day
scripters who want to go that route’d better test it

NOTE: is nwn2 / could be different for nwn1

looks like some missing braces …

    oNextItem = GetItemInSlot(INVENTORY_SLOT_ARMS, oEnter);
    if(oNextItem != OBJECT_INVALID)
    {
	PrepForDestruction(oNextItem);
        DestroyObject(oNextItem);
    }
    // etc.

Yes, now that you mention it…But it compiled anyway. And that’s how it’s written in the script found in the script archive.

Since MillaJ said that the plot items where still there…That’s why I added the function of PrepForDestruction.

Edit: I changed the code to include the braces.

By the way, I was trying to think of a way to do a function or a loop so that you don’t have to go through all the GetItemInSlot stuff but I haven’t been able to figure out a smart sollution yet.
The best I could come up with was to change the script to this (and it’s hardly any better or more compact):

void Destruction(object oTarget)
{
   if(oTarget != OBJECT_INVALID)
  {
    SetPlotFlag(oTarget,FALSE);
    SetImmortal(oTarget,FALSE);
    AssignCommand(oTarget,SetIsDestroyable(TRUE,FALSE,FALSE));
	
    DestroyObject(oTarget);
   }
}

void main()
{
    // Get entering object
    object oEnter = GetEnteringObject();

    // Only fire for (real) PCs.
    if ( !GetIsPC(oEnter)  ||  GetIsDMPossessed(oEnter) )
        return;

 
    // Rob and strip the player
    if( GetIsPC(oEnter) && !(GetLocalInt(oEnter, "GotRobbed")) )
    {
        // Ensure that the robbing only happens once
        SetLocalInt(oEnter, "GotRobbed", TRUE);
        // Take away gold
        TakeGoldFromCreature(GetGold(oEnter), oEnter, TRUE);
        // Take away all inventory items
        object oNextItem = GetNextItemInInventory(oEnter);
        // This is the object you don't want to destroy. Insert the tag of the object you don't want to destroy.
	object oDontdestroy = GetObjectByTag("donotdestroy");
        while(oNextItem != OBJECT_INVALID)
        {
	    	if (oNextItem == oDontdestroy)
			{
		
		 	oNextItem = GetNextItemInInventory(oEnter);

			}
			Destruction(oNextItem);
            oNextItem = GetNextItemInInventory(oEnter);
        }
        // Take away all worn equipments
        oNextItem = GetItemInSlot(INVENTORY_SLOT_ARMS, oEnter);
        {
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_ARROWS, oEnter);
       	{
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_BOLTS, oEnter);
        {
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_BELT, oEnter);
       	{
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_BOOTS, oEnter);
       	{
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_BULLETS, oEnter);
        {
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oEnter);
        {
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_CHEST, oEnter);
       	{
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_CLOAK, oEnter);
        {
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oEnter);
        {
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oEnter);
       	{
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_HEAD, oEnter);
      	{
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oEnter);
       	{
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_LEFTRING, oEnter);
      	{
	Destruction(oNextItem);
	}
        oNextItem = GetItemInSlot(INVENTORY_SLOT_NECK, oEnter);
       	{
	Destruction(oNextItem);
	}
    }
}

the INVENTORY_SLOT_* constants are a consecutive series of ascending integers …

write a for loop that starts at the lowest slot and, on each loop, increments until it hits the stop condition: the highest slot you want checked. on each loop, redefine oItem, using current value of the incrementor, and do an if check for its validity; if true call DestroyObject(). Then move on to the next iteration …

hint: filter ScriptAssist “INVENTORY_SLOT” and you should see a nice, orderly progression of values that can be plugged directly into GetItemInSlot() – you don’t have to use integer-constants like “INVENTORY_SLOT_HEAD”, integer-literals work also: “0”
 

int i;
for (i = 0; i != 17; ++i)
{
    //GetItemInSlot(i) etc
}

So, you mean like this then (I still don’t grasp it totally yet, not used to for loops)?:

void Destruction(object oTarget)
{
	if(oTarget != OBJECT_INVALID)
	{
	SetPlotFlag(oTarget,FALSE);
    	SetImmortal(oTarget,FALSE);
        SetItemCursedFlag(oTarget,FALSE);
    	AssignCommand(oTarget,SetIsDestroyable(TRUE,FALSE,FALSE));
	
	DestroyObject(oTarget);
	}
}

void main()
{
    // Get entering object
    object oEnter = GetEnteringObject();

    // Only fire for (real) PCs.
    if ( !GetIsPC(oEnter)  ||  GetIsDMPossessed(oEnter) )
        return;

 
    // Rob and strip the player
    if( GetIsPC(oEnter) && !(GetLocalInt(oEnter, "GotRobbed")) )
    {
        // Ensure that the robbing only happens once
        SetLocalInt(oEnter, "GotRobbed", TRUE);
        // Take away gold
        TakeGoldFromCreature(GetGold(oEnter), oEnter, TRUE);
        // Take away all inventory items
        object oNextItem = GetNextItemInInventory(oEnter);
	// This is the object you don't want to destroy. Insert the tag of the object you don't want to destroy.
	object oDontdestroy = GetObjectByTag("donotdestroy");
        while(oNextItem != OBJECT_INVALID)
        {
	    	if (oNextItem == oDontdestroy)
		{
		oNextItem = GetNextItemInInventory(oEnter);
                }
	Destruction(oNextItem);
        oNextItem = GetNextItemInInventory(oEnter);
        }
        // Take away all worn equipments
       int i;
       for (i = 0; i != 17; ++i)
       {
       object oItemInSlot = GetItemInSlot(i, oEnter);
       Destruction(oItemInSlot);
       }
      
    }
}

Edit: Added SetItemCursedFlag.

bingo

 
i wonder if prep should remove Cursed flag also

1 Like

Right. Normally in C like languages the idiom for for loops though would be
for (i = 0; i < INVENTORY_SLOT_CARMOUR; i++ ) {

I think in this case using the constant makes it more readable. And you don’t want to destroy that one since the horse code and other things may be using it (which yours did right too). What you have has the same effect but it just doesn’t scan right if you are used to looking at code.

@andgalf Your “laziness” made you use the cut and pasted lines mine would have made me say I don’t want to write the same lines of code over and over :wink:

One more nit while we’re here… indentation. Indent the code in the brackets. Makes it easier to read.

Only SetIsDestroyable(TRUE...) is needed. DestroyObject ignores other flags (cursed, plot, immortal).

True, but it should be noted that not all constants belonging to the same group thematically are consecutive like these, i.e. OBJECT_TYPE_'s are powers of 2. Looping over them with i++ increment is a bad idea (i *= 2 is the way to go).

if (true) then

// 'destroyitems'
/*
    OnEnter script.

    Destroys all gold and items that an entering PC possesses.
    Except for item(s) defined by tag sDONTDESTROY.

    NOTE: Notifications are not sent to player.
*/

const string sDONTDESTROY = "dontdestroy"; // Tag of item to NOT destroy


void main()
{
    object oEnter = GetEnteringObject();

    if (GetIsPC(oEnter)
        && !GetIsDMPossessed(oEnter)
        && !GetIsDM(oEnter))
    {
        if (!GetLocalInt(oEnter, "GotRobbed"))
        {
            SetLocalInt(oEnter, "GotRobbed", TRUE);

            TakeGoldFromCreature(GetGold(oEnter), oEnter, TRUE, FALSE);

            object o = GetFirstItemInInventory(oEnter);
            while (GetIsObjectValid(o))
            {
                if (GetTag(o) != sDONTDESTROY)
                {
                    AssignCommand(o, SetIsDestroyable(TRUE));
                    DestroyObject(o, 0.0, FALSE);
                }
                o = GetNextItemInInventory(oEnter);
            }

            int i = INVENTORY_SLOT_HEAD;
            while (i != INVENTORY_SLOT_CARMOUR)
            {
                o = GetItemInSlot(i++, oEnter);
                if (GetIsObjectValid(o) && GetTag(o) != sDONTDESTROY)
                {
                    AssignCommand(o, SetIsDestroyable(TRUE));
                    DestroyObject(o, 0.0, FALSE);
                }
            }
        }
    }
}

/compiled in nwn2
/untested

EDIT: check object valid in equipment slots

I tested it, but plot items were not deleted…

I checked it before posting :slight_smile: knew about plot flag but had to be sure.

Here's my modular, easily customizable solution (CLICK ME).
// Destroys inventory, equipment and gold of the caller, except for items
// designated by a customizable function ShouldDestroy to be kept


// global setting: should gold be destroyed?
const int DESTROY_GOLD = TRUE;
// global setting: should inventory be destroyed?
const int DESTROY_INVENTORY = TRUE;
// global setting: should worn equipment be destroyed?
const int DESTROY_EQUIPMENT = TRUE;


// returns whether oItem should be destroyed
// customize this function to your needs
// return TRUE to destroy; return FALSE to not destroy
int ShouldDestroy(object oItem)
{
    // example: destroy every item except for potions and armor
    // note: both worn and carried armor is saved
    switch(GetBaseItemType(oItem))
    {
        case BASE_ITEM_INVALID:
        case BASE_ITEM_POTIONS:
        case BASE_ITEM_ARMOR:
        {
            return FALSE;
        }
    }

    // don't destroy items with tag DONT_DESTROY
    return GetTag(oItem) != "DONT_DESTROY";
}


void main()
{
    object oTarget = OBJECT_SELF;
    object oItem;
    int iSlot;

    /* DM-specific code block start

    // Get the creature who triggered this event.
    oTarget = GetEnteringObject();

    // Only fire for (real) PCs.
    if ( !GetIsPC(oTarget)  ||  GetIsDM(oTarget) || GetIsDMPossessed(oTarget) )
        return;

    // Only fire once per PC.
    if ( GetLocalInt(oTarget, "DO_ONCE__" + GetTag(OBJECT_SELF)) )
        return;
    SetLocalInt(oTarget, "DO_ONCE__" + GetTag(OBJECT_SELF), TRUE);

    DM-specific code block end */

    // destroy gold
    if(DESTROY_GOLD)
    {
        TakeGoldFromCreature(GetGold(oTarget), oTarget, TRUE);
    }

    // destroy inventory
    if(DESTROY_INVENTORY)
    {
        // scan inventory items one by one and destroy those for which
        // ShouldDestroy returns TRUE;
        oItem = GetFirstItemInInventory(oTarget);
        while(GetIsObjectValid(oItem))
        {
            if(ShouldDestroy(oItem))
            {
                AssignCommand(oItem, SetIsDestroyable(TRUE));
                DestroyObject(oItem);
            }
            oItem = GetNextItemInInventory(oTarget);
        }
    }

    // destroy equipment
    if(DESTROY_EQUIPMENT)
    {
        // scan equipment slots one by one and destroy items for which
        // ShouldDestroy returns TRUE;
        for(iSlot = INVENTORY_SLOT_HEAD; iSlot < INVENTORY_SLOT_CARMOUR; iSlot++)
        {
            oItem = GetItemInSlot(iSlot, oTarget);
            if(GetIsObjectValid(oItem) && ShouldDestroy(oItem))
            {
                AssignCommand(oItem, SetIsDestroyable(TRUE));
                DestroyObject(oItem);
            }
        }
    }
}

What about DMs? Script should not affect them

Yes, my code is generic - it just clears items from OBJECT_SELF. It’s meant to be customized for other circumstances (see the ShouldDestroy function).

You can use your code from here - just paste it at the beginning of main and replace all my OBJECT_SELFs with oPC.

Is it possible to have a complete working script? ^_^’’’

OK, I edited it. Told you, pretty much copy&paste.

To keep it generic, the DM-handler code is currently commented, just remove the /* & */ lines to get the functionality you seek.

See other comments in the code, too.

Thanks! I will test it and let you know! :slight_smile:

I just did a few corrections in the DM block - make sure to get the current version.

1 Like

Nothing. My armor and potions are still here.

Of course they are - check the ShouldDestroy function.

Hint.

Change it to:

int ShouldDestroy(object oItem) { return TRUE; }

to destroy EVERYTHING. Or just keep the GetTag line.

1 Like