Aller au contenu

Photo

Script to Steal Equipment and Put it in a Box


  • Veuillez vous connecter pour répondre
10 réponses à ce sujet

#1
Sabranic

Sabranic
  • Members
  • 306 messages

Currently in Morbane's Tomb of Horrors, (the foundation we branched from), there is a script that takes a player's - or even the entire party's - equipment, destroys it, and then places a copy in a chest tagged as rip_off_box.

 

Here is the code:


void main()
{
	object oPC =(GetPCSpeaker()==OBJECT_INVALID?GetEnteringObject():GetPCSpeaker());
	object oItem = GetFirstItemInInventory(oPC);
	object oTarget = GetObjectByTag("rip_off_box");
	
	while (GetIsObjectValid(oPC))
	{	
		while (GetIsObjectValid(oItem))
		{
			CopyItem(oItem, oTarget);
			DestroyObject(oItem, 0.0f, FALSE);
			
			oItem = GetNextItemInInventory(oPC);
		}
		
		int nSlot = 0;
		while ( nSlot <= NUM_INVENTORY_SLOTS )
		{
			object oItem = GetItemInSlot(nSlot, oPC);
			if (GetIsObjectValid(oItem))
			{
				CopyItem(oItem, oTarget);
				DestroyObject(oItem, 0.0f, 0);
			}
			nSlot++;	
		}
	}
	oItem = GetFirstItemInInventory(oTarget);
	while (GetIsObjectValid(GetObjectByTag("throne_scepter")))
	{
		DestroyObject(GetObjectByTag("throne_scepter"));
		
		oItem = GetNextItemInInventory(oTarget);
	}
	if(GetLocalInt(GetObjectByTag("throne_scepter"), "cruel") == 1)
		CreateObject(OBJECT_TYPE_PLACEABLE, "scepter", GetLocation(GetWaypointByTag("wp_scepter_return")));
}

Some problems that came up in testing:

 

1: The player might lose irreplaceable keys, runestones and other objects necessary to proceed in the module. 

2: If the player being targeted by the "cruelty" script has a packed inventory and/or a few bags of holding, they are going to lose gear *forever*.  Anything over the maximum a chest can hold is apparently discarded.

 

The first option explored was to make a series of rip-off chests for each place the Tomb can steal a player's gear... but that didn't solve the problem of destroyed items when a pack-rat hits the trap - or the designated vendor-trash-player, since the script starts with inventory and then works it's way to worn gear, (it empty's bags of holding into rip_off_box) - which will make it almost certain the player will have his items permanently destroyed and be left with stacks of Kobold Short swords, beetle legs and leather armor when they finally open the chest.

 

Given these problems, I've been working all afternoon and evening on a script which will ONLY take equipped items - here is what I have so far: (Yes, I am slow. I am learning, but at a glacial pace - my degree says "fine art" and it shows).

//Script to strip equipment and place it in a chest based on dialog.  Sabranic 5/7/16

void main()
{
    object oPC = GetPCSpeaker();
    object oItem0 = GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oPC);
    object oItem1 = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
    object oItem2 = GetItemInSlot(INVENTORY_SLOT_LEFTRING, oPC);
    object oItem3 = GetItemInSlot(INVENTORY_SLOT_HEAD, oPC);
    object oItem4 = GetItemInSlot(INVENTORY_SLOT_ARMS, oPC);
    object oItem5 = GetItemInSlot(INVENTORY_SLOT_CLOAK, oPC);
    object oItem6 = GetItemInSlot(INVENTORY_SLOT_BOOTS, oPC);
    object oItem7 = GetItemInSlot(INVENTORY_SLOT_BELT, oPC);
    object oItem8 = GetItemInSlot(INVENTORY_SLOT_CHEST, oPC);
    object oItem9 = GetItemInSlot(INVENTORY_SLOT_NECK, oPC);
    object oTarget = GetObjectByTag("rip_off_box");
    
    while (GetIsObjectValid(oItem0))
        {
            CopyItem(oItem0, oTarget);
            DestroyObject(oItem0, 0.0f, FALSE);
        }
    while (GetIsObjectValid(oItem1))
        {    
            CopyItem(oItem1, oTarget);
            DestroyObject(oItem1, 0.0f, FALSE);
        }
    while (GetIsObjectValid(oItem2))
        {    
            CopyItem(oItem2, oTarget);
            DestroyObject(oItem2, 0.0f, FALSE);
        }
    while (GetIsObjectValid(oItem3))
        {    
            CopyItem(oItem3, oTarget);
            DestroyObject(oItem3, 0.0f, FALSE);
        }    
    while (GetIsObjectValid(oItem4))
        {
            CopyItem(oItem4, oTarget);
            DestroyObject(oItem4, 0.0f, FALSE);
        }
    while (GetIsObjectValid(oItem5))
        {    
            CopyItem(oItem5, oTarget);
            DestroyObject(oItem5, 0.0f, FALSE);
        }
    while (GetIsObjectValid(oItem6))
        {    
            CopyItem(oItem6, oTarget);
            DestroyObject(oItem6, 0.0f, FALSE);
        }
    while (GetIsObjectValid(oItem7))
        {    
            CopyItem(oItem7, oTarget);
            DestroyObject(oItem7, 0.0f, FALSE);
        }
    while (GetIsObjectValid(oItem8))
        {    
            CopyItem(oItem8, oTarget);
            DestroyObject(oItem8, 0.0f, FALSE);
        }
    while (GetIsObjectValid(oItem9))
        {    
            CopyItem(oItem9, oTarget);
            DestroyObject(oItem9, 0.0f, FALSE);            
        }
//Prevents the Scepter from being destroyed and thus making the module unwinnable.
    while (GetIsObjectValid(GetObjectByTag("throne_scepter")))
        {
            DestroyObject(GetObjectByTag("throne_scepter"));
            oItem1 = GetNextItemInInventory(oTarget);
        }
    while (GetIsObjectValid(GetObjectByTag("throne_scepter")))
        {
            DestroyObject(GetObjectByTag("throne_scepter"));
            oItem2 = GetNextItemInInventory(oTarget);
        }
    if(GetLocalInt(GetObjectByTag("throne_scepter"), "cruel") == 1)
    CreateObject(OBJECT_TYPE_PLACEABLE, "scepter", GetLocation(GetWaypointByTag("wp_scepter_return")));
}

Instead of the expected result, the script takes only the right ring, destroys it, and then creates 142 of them and dumps them in the rip_off_box.

 

 

I can destroy individual items as I made a pile of scripts to do just that - but I am missing how I need to increment through the whole process so that each step only fires once.  I also need to create a version of this that fires for the whole group - including NPC's and other players in the game at the same time, for both the Tomb and the Larger campaign it will be attached to. (The party will have a chance of being captures and tossed in a dungeon).

 

Thanks for any advice or tips, I am trying to get better at this.



#2
kevL

kevL
  • Members
  • 4 052 messages
the DestroyObject() function does not destroy anything until after the script ends. So
    while (GetIsObjectValid(oItem0))
    {
        CopyItem(oItem0, oTarget);
        DestroyObject(oItem0, 0.0f, FALSE);
    }
is an infinite loop. Fortunately the engine throws a TMI (too many instructions) and stops. solution: Replace while with if

To avoid destroying the scepter:
    if (GetIsObjectValid(oItem0) && GetTag(oItem0) != "throne_scepter")
    {
        CopyItem(oItem0, oTarget);
        DestroyObject(oItem0, 0.0f, FALSE);
    }
repeat for oItem1.


To use a loop instead of all those definitions and if-statements:
int i;
for (i = 0;      // INVENTORY_SLOT_HEAD
        i != 14; // INVENTORY_SLOT_CWEAPON_L
        i++)
{
    object oItem = GetItemInSlot(i, oPC);
    if (GetIsObjectValid(oItem))
    {
        if (GetTag(oItem) == "throne_scepter")
        {
            location lLoc = GetLocation(GetObjectByTag("wp_scepter_return"));
            CreateObject(OBJECT_TYPE_PLACEABLE, "scepter", lLoc); // is "scepter" really a Placeable?
        }
        else
        {
            CopyItem(oItem, oTarget);
        }

        DestroyObject(oItem, 0.f, FALSE);
    }
}
hth
  • GCoyote et Sabranic aiment ceci

#3
Sabranic

Sabranic
  • Members
  • 306 messages

Thank you, I will adapt the code based on your recommendations!!

 

And yeah, the crown and scepter are actually placeables - they are made to teleport back to a throne room under certain circumstances.



#4
kevL

kevL
  • Members
  • 4 052 messages
ah ok.
 

I also need to create a version of this that fires for the whole group - including NPC's and other players in the game at the same time, for both the Tomb and the Larger campaign it will be attached to.


Once you have a script that works for one character, copy-paste its appropriate-parts into the spot specified
object oParty = GetFirstFactionMember(oPC, FALSE);
while (GetIsObjectValid(oParty))
{
    // spot specified.

    oParty = GetNextFactionMember(oPC, FALSE);
}
That will catch henchmen but *not* non-party NPCs. For the latter, you'd need to loop over all areas w/ GetFirst/NextArea() then over all objects-in-area w/ GetFirst/NextObjectInArea(), testing each object for if (GetObjectType() == OBJECT_TYPE_CREATURE). I think that excludes party-members but am unsure.

Multi-player has ambiguities that I'd need two computers w/ NwN2 installed on to test. The loops for MP, however, use GetFirst/NextPC().


btw. For campaigns that have more than one module ... you can't touch a module that is not loaded. What you could do is set what's called a campaign variable, that each module would check when it's loading, and run applicable code .... but That's sorta involved and i'd suggest getting comfortable with intermediate scripting/events 1st.

anyway, i'm Interested in this stuff and when it works I think its great, so ...
  • Sabranic aime ceci

#5
Sabranic

Sabranic
  • Members
  • 306 messages

Thank you very much, you've gone above and beyond the call! 



#6
Sabranic

Sabranic
  • Members
  • 306 messages

The Finished Script for the single player cruelty:

//Script to strip equipment and place it in a chest based on dialog.  
// Sabranic & kevL 5/9/16

void main()
{
    object oPC = GetPCSpeaker();
    object oItem0 = GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oPC);
    object oItem1 = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
    object oItem2 = GetItemInSlot(INVENTORY_SLOT_LEFTRING, oPC);
    object oItem3 = GetItemInSlot(INVENTORY_SLOT_HEAD, oPC);
    object oItem4 = GetItemInSlot(INVENTORY_SLOT_ARMS, oPC);
    object oItem5 = GetItemInSlot(INVENTORY_SLOT_CLOAK, oPC);
    object oItem6 = GetItemInSlot(INVENTORY_SLOT_BOOTS, oPC);
    object oItem7 = GetItemInSlot(INVENTORY_SLOT_BELT, oPC);
    object oItem8 = GetItemInSlot(INVENTORY_SLOT_CHEST, oPC);
    object oItem9 = GetItemInSlot(INVENTORY_SLOT_NECK, oPC);
    object oItem10 = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
    object oTarget = GetObjectByTag("rip_off_box");
    
//Prevents the Scepter from being destroyed and thus making the module unwinable.
    if (GetIsObjectValid(oItem10) && GetTag(oItem10) != "throne_scepter")
    {
        CopyItem(oItem10, oTarget);
        DestroyObject(oItem10, 0.0f, FALSE);
    }    
    if (GetIsObjectValid(oItem1) && GetTag(oItem1) != "throne_scepter")
    {
        CopyItem(oItem1, oTarget);
        DestroyObject(oItem1, 0.0f, FALSE);
    }
//Steals Gear and puts it in a box.
    if (GetIsObjectValid(oItem0))
        {    
            CopyItem(oItem0, oTarget);
            DestroyObject(oItem0, 0.0f, FALSE);
        }    
    if (GetIsObjectValid(oItem2))
        {    
            CopyItem(oItem2, oTarget);
            DestroyObject(oItem2, 0.0f, FALSE);
        }
    if (GetIsObjectValid(oItem3))
        {    
            CopyItem(oItem3, oTarget);
            DestroyObject(oItem3, 0.0f, FALSE);
        }    
    if (GetIsObjectValid(oItem4))
        {
            CopyItem(oItem4, oTarget);
            DestroyObject(oItem4, 0.0f, FALSE);
        }
    if (GetIsObjectValid(oItem5))
        {    
            CopyItem(oItem5, oTarget);
            DestroyObject(oItem5, 0.0f, FALSE);
        }
    if (GetIsObjectValid(oItem6))
        {    
            CopyItem(oItem6, oTarget);
            DestroyObject(oItem6, 0.0f, FALSE);
        }
    if (GetIsObjectValid(oItem7))
        {    
            CopyItem(oItem7, oTarget);
            DestroyObject(oItem7, 0.0f, FALSE);
        }
    if (GetIsObjectValid(oItem8))
        {    
            CopyItem(oItem8, oTarget);
            DestroyObject(oItem8, 0.0f, FALSE);
        }
    if (GetIsObjectValid(oItem9))
        {    
            CopyItem(oItem9, oTarget);
            DestroyObject(oItem9, 0.0f, FALSE);            
        }
}

I will try to set up a loop as practice for the group version.

 

EDIT: Fixed a multiple Typos and logic errors!



#7
kevL

kevL
  • Members
  • 4 052 messages
    if (GetIsObjectValid(oItem1) && GetTag(oItem1) != "throne_scepter")
    {
        CopyItem(oItem0, oTarget);
        DestroyObject(oItem1, 0.0f, FALSE);
    }
looks like a typo ...

cat4_kittenpounce.jpg
  • ArtemisJ, GCoyote et Sabranic aiment ceci

#8
Sabranic

Sabranic
  • Members
  • 306 messages

And tests like one too!  Thanks!



#9
Sabranic

Sabranic
  • Members
  • 306 messages
//Script to strip entire party's equipment and place it in a chest based on dialog.  
// Sabranic & kevL 5/9/16

void main()
{
	object oPC = GetPCSpeaker();
	object oItem0 = GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oPC);
	object oItem1 = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
	object oItem2 = GetItemInSlot(INVENTORY_SLOT_LEFTRING, oPC);
	object oItem3 = GetItemInSlot(INVENTORY_SLOT_HEAD, oPC);
	object oItem4 = GetItemInSlot(INVENTORY_SLOT_ARMS, oPC);
	object oItem5 = GetItemInSlot(INVENTORY_SLOT_CLOAK, oPC);
	object oItem6 = GetItemInSlot(INVENTORY_SLOT_BOOTS, oPC);
	object oItem7 = GetItemInSlot(INVENTORY_SLOT_BELT, oPC);
	object oItem8 = GetItemInSlot(INVENTORY_SLOT_CHEST, oPC);
	object oItem9 = GetItemInSlot(INVENTORY_SLOT_NECK, oPC);
	object oItem10 = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
	object oTarget = GetObjectByTag("rip_off_box2");
	object oParty = GetFirstFactionMember(oPC, FALSE);
	
	while (GetIsObjectValid(oParty))
	{
	  	//Prevents the Scepter from being destroyed and thus making the module unwinable.
		if (GetIsObjectValid(oItem10) && GetTag(oItem10) != "throne_scepter")
 	  		{
			CopyItem(oItem10, oTarget);
	        DestroyObject(oItem10, 0.0f, FALSE);
	    	}	
		if (GetIsObjectValid(oItem1) && GetTag(oItem1) != "throne_scepter")
  	  		{
			CopyItem(oItem1, oTarget);
 	      	DestroyObject(oItem1, 0.0f, FALSE);
 	   		}
	    //Steals Gear and puts it in a box.
		if (GetIsObjectValid(oItem0))
			{	
				CopyItem(oItem0, oTarget);
				DestroyObject(oItem0, 0.0f, FALSE);
			}	
		if (GetIsObjectValid(oItem2))
			{	
				CopyItem(oItem2, oTarget);
				DestroyObject(oItem2, 0.0f, FALSE);
			}
		if (GetIsObjectValid(oItem3))
			{	
				CopyItem(oItem3, oTarget);
				DestroyObject(oItem3, 0.0f, FALSE);
			}	
		if (GetIsObjectValid(oItem4))
			{
				CopyItem(oItem4, oTarget);
				DestroyObject(oItem4, 0.0f, FALSE);
			}
		if (GetIsObjectValid(oItem5))
			{	
				CopyItem(oItem5, oTarget);
				DestroyObject(oItem5, 0.0f, FALSE);
			}
		if (GetIsObjectValid(oItem6))
			{	
				CopyItem(oItem6, oTarget);
				DestroyObject(oItem6, 0.0f, FALSE);
			}
		if (GetIsObjectValid(oItem7))
			{	
				CopyItem(oItem7, oTarget);
				DestroyObject(oItem7, 0.0f, FALSE);
			}
		if (GetIsObjectValid(oItem8))
			{	
				CopyItem(oItem8, oTarget);
				DestroyObject(oItem8, 0.0f, FALSE);
			}
		if (GetIsObjectValid(oItem9))
			{	
				CopyItem(oItem9, oTarget);
				DestroyObject(oItem9, 0.0f, FALSE);			
			}

		oParty = GetNextFactionMember(oPC, FALSE);
	}

}

It compiled just fine, but I've set up another infinite loop somehow, since it just steals the first player's gear over and over again until it fills the chest.  The NPC's are untouched.



#10
kevL

kevL
  • Members
  • 4 052 messages
Because each oItem* is the item in the original, PCSpeaker's inventory ... the items need to be re-defined at the start of each iteration.
void main()
{
    object oPC = GetPCSpeaker();
    SendMessageToPC(GetFirstPC(FALSE), "run Cruelty ( " + GetName(oPC) + " )"); // debug

    object oItem0, oItem1, oItem2, oItem3, oItem4, oItem5,
           oItem6, oItem7, oItem8, oItem9, oItem10;

    object oTarget = GetObjectByTag("rip_off_box2");

    object oParty = GetFirstFactionMember(oPC, FALSE);
    while (GetIsObjectValid(oParty))
    {
        SendMessageToPC(GetFirstPC(FALSE), ". oParty= " + GetName(oParty)); // debug

        oItem0  = GetItemInSlot(INVENTORY_SLOT_RIGHTRING, oParty);
        oItem1  = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oParty);
        oItem2  = GetItemInSlot(INVENTORY_SLOT_LEFTRING, oParty);
        oItem3  = GetItemInSlot(INVENTORY_SLOT_HEAD, oParty);
        oItem4  = GetItemInSlot(INVENTORY_SLOT_ARMS, oParty);
        oItem5  = GetItemInSlot(INVENTORY_SLOT_CLOAK, oParty);
        oItem6  = GetItemInSlot(INVENTORY_SLOT_BOOTS, oParty);
        oItem7  = GetItemInSlot(INVENTORY_SLOT_BELT, oParty);
        oItem8  = GetItemInSlot(INVENTORY_SLOT_CHEST, oParty);
        oItem9  = GetItemInSlot(INVENTORY_SLOT_NECK, oParty);
        oItem10 = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oParty);

        //Prevents the Scepter from being destroyed and thus making the module unwinable.
        if (GetIsObjectValid(oItem1) && GetTag(oItem1) != "throne_scepter")
        {
            CopyItem(oItem1, oTarget);
            DestroyObject(oItem1, 0.0f, FALSE);
        }

        if (GetIsObjectValid(oItem10) && GetTag(oItem10) != "throne_scepter")
        {
            CopyItem(oItem10, oTarget);
            DestroyObject(oItem10, 0.0f, FALSE);
        }

        //Steals Gear and puts it in a box.
        if (GetIsObjectValid(oItem0))
        {
            CopyItem(oItem0, oTarget);
            DestroyObject(oItem0, 0.0f, FALSE);
        }

        if (GetIsObjectValid(oItem2))
        {
            CopyItem(oItem2, oTarget);
            DestroyObject(oItem2, 0.0f, FALSE);
        }

        if (GetIsObjectValid(oItem3))
        {
            CopyItem(oItem3, oTarget);
            DestroyObject(oItem3, 0.0f, FALSE);
        }

        if (GetIsObjectValid(oItem4))
        {
            CopyItem(oItem4, oTarget);
            DestroyObject(oItem4, 0.0f, FALSE);
        }

        if (GetIsObjectValid(oItem5))
        {
            CopyItem(oItem5, oTarget);
            DestroyObject(oItem5, 0.0f, FALSE);
        }

        if (GetIsObjectValid(oItem6))
        {
            CopyItem(oItem6, oTarget);
            DestroyObject(oItem6, 0.0f, FALSE);
        }

        if (GetIsObjectValid(oItem7))
        {
            CopyItem(oItem7, oTarget);
            DestroyObject(oItem7, 0.0f, FALSE);
        }

        if (GetIsObjectValid(oItem8))
        {
            CopyItem(oItem8, oTarget);
            DestroyObject(oItem8, 0.0f, FALSE);
        }

        if (GetIsObjectValid(oItem9))
        {
            CopyItem(oItem9, oTarget);
            DestroyObject(oItem9, 0.0f, FALSE);
        }

        oParty = GetNextFactionMember(oPC, FALSE);
    }

    SendMessageToPC(GetFirstPC(FALSE), ". cruelty EXIT"); // debug
}

  • Sabranic aime ceci

#11
Sabranic

Sabranic
  • Members
  • 306 messages

Ahh - thanks again - hrm... I didn't know you could do this:

object oItem0, oItem1, oItem2, oItem3, oItem4, oItem5,
oItem6, oItem7, oItem8, oItem9, oItem10;

Interesting.