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);
}
}
}
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
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).
// '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);
}
}
}
}
}
I checked it before posting 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);
}
}
}
}