Weird bug with transfering items

So, I have encountered a really weird thing. Ok, this will be a handful to explain:

  1. The PC and the party encounter a being that turns the PC into a chicken.
  2. The PCs inventory is stripped and put into a bag that is placed on the ground.
  3. One of the companions can pick up the bag with all the items. So far everything works.
  4. Now, I have a script that @Lance_Botelle helped me with, a custom version of gb_player_ud to prevent the player from being able to click on the PC.
  5. The weird bug: After I have looted the bag with the PCs stuff when in the inventory of one of the companions. If I then click on the portrait of the PC, it switches back to the companion. BUT, now when I look in the inventory of the companion almost all the PC items are gone. What the heck is going on?!?!

The custom gb_player_ud script looks like this:

// gb_player_ud
/* 
	 user defined events template
*/  
// ChazM 9/5/06 don't have leader follow himself
// BMA-OEI 09/12/06 -- Added EVENT_PLAYER_CONTROL_CHANGED handler
// MDiekmann 8/7/07 - Modified to run a custom user defined script based on the tag if one exists

#include "ginc_companion"
#include "ginc_debug"
#include "ginc_overland"
#include "x0_i0_assoc"
#include "hench_i0_assoc"
// 		this includes: GetFollowDistance()

void ResetPC(object oNewMain)
{
	object oPC = SetOwnersControlledCompanion(OBJECT_SELF, oNewMain);		
}

void SwitchPC()
{

object oPC = GetFirstPC();
object oNewActor;

object oSabrina = GetObjectByTag("sabrina");
object oCatherine = GetObjectByTag("catherine");
object oNankun = GetObjectByTag("nankun");
object oTeala = GetObjectByTag("teala");
object oFreya = GetObjectByTag("freya");
object oEsfiza = GetObjectByTag("esfiza");
object oAstaxos = GetObjectByTag("astaxos");
object oBargoram = GetObjectByTag("bargoram");

	if(GetFactionEqual(oPC,oSabrina))
	{
	
		 oNewActor = oSabrina;	

	}

	else if(GetFactionEqual(oPC,oCatherine))
	{
	
		 oNewActor = oCatherine;	

	}
	
	else if(GetFactionEqual(oPC,oTeala))
	{
	
		 oNewActor = oTeala;	

	}
	
	else if(GetFactionEqual(oPC,oFreya))
	{
	
		 oNewActor = oFreya;	

	}
	
	else if(GetFactionEqual(oPC,oEsfiza))
	{
	
		 oNewActor = oEsfiza;	

	}
	
	else if(GetFactionEqual(oPC,oAstaxos))
	{
	
		 oNewActor = oAstaxos;	

	}
	
	else if(GetFactionEqual(oPC,oBargoram))
	{
	
		 oNewActor = oBargoram;	

	}
	
	else
	{
	
		SendMessageToPC(oPC,"You have created a serious bug by not having companions in your party!! Please reload!!");
		return;
	}
	
	if(GetIsObjectValid(oNewActor))
	{
		SetOwnersControlledCompanion(oPC,oNewActor);
	}


}
	
void main()
{
	string sMyTag = GetTag(OBJECT_SELF);		
	
    int iEvent = GetUserDefinedEventNumber();
//	Jug_Debug(GetName(OBJECT_SELF) + " event num " + IntToString(iEvent));

	//execute custom user-defined script from local string if it exists
	string sUDScript=GetLocalString(OBJECT_SELF, "ud_script");
	if (sUDScript != "")
	{
		ExecuteScript(sUDScript, OBJECT_SELF);
	}
	
    switch (iEvent)
	{
		case EVENT_HEARTBEAT: 	// 1001
			break;	

		case EVENT_PERCEIVE: 	// 1002
			break;	

		case EVENT_END_COMBAT_ROUND: 	// 1003
			break;	

		case EVENT_DIALOGUE: 	// 1004
			break;	

		case EVENT_ATTACKED: 	// 1005
			break;	

		case EVENT_DAMAGED: 	// 1006
			break;
	
		case EVENT_DISTURBED: 	// 1008
			break;	

		case EVENT_SPELL_CAST_AT: 	// 1011
			break;	
			
		case EVENT_PLAYER_CONTROL_CHANGED:
		{
		
			if(GetGlobalInt("chicken") && !GetGlobalInt("gems"))
			{
				//object oOldActor = GetFirstPC();
				SwitchPC();
				object oNewMain = GetFirstPC(FALSE);
				DelayCommand(0.1, ResetPC(oNewMain)); 	
					
			}
			break;
		}
		
		 // 2052
		case EVENT_TRANSFER_PARTY_LEADER:
		{
			if(GetIsOverlandMap(GetArea(OBJECT_SELF)))
			{
				PrettyDebug("gb_player_ud firing for" + GetName(OBJECT_SELF));
				object oOldActor = GetLocalObject(GetModule(), "oPartyLeader");
				if(GetIsPC(OBJECT_SELF) && oOldActor != OBJECT_SELF)
				{
				
					if(GetCommandable(OBJECT_SELF) && !GetIsDead(OBJECT_SELF) &&
				  	  (GetIsRosterMember(OBJECT_SELF) || GetIsOwnedByPlayer(OBJECT_SELF)) ) 
					{
						SetPartyActor(OBJECT_SELF);
					}
				
					else
						SetPartyActor(oOldActor, OBJECT_SELF);
				}
			}
			
			if(GetAssociateState(NW_ASC_MODE_PUPPET) == TRUE)
				break;
				
//			Jug_Debug(GetName(OBJECT_SELF) + " handle player control change");
			HenchHandlePlayerControlChanged(OBJECT_SELF);
			break;
		}			
	}
}

The stripping of the PC items script looks like this (it is run from a dialogue):

#include "ginc_item"
#include "x2_inc_itemprop"

void CreateBag(object oWP)
{

location lLocation = GetLocation(oWP);
CreateObject(OBJECT_TYPE_ITEM,"bagwithpc2",lLocation);


}

void TransferItems(object oPC)
{

	object oBag = GetObjectByTag("bagwithpc2");
	object oItem;	
	int n;
			
		oItem = GetFirstItemInInventory(oPC);
			
	 	while(GetIsObjectValid(oItem))
	 	{
			if (!IPGetIsProjectile(oItem) && !GetItemCursedFlag(oItem))
			{
				TransferItem(oPC, oBag, oItem, FALSE);
			}
	 		oItem = GetNextItemInInventory(oPC);
 	 	}

}


void main()
{
	object oPC = GetPCSpeaker();
	object oWP = GetObjectByTag("fairydrwp");
	
	CreateBag(oWP);
	DelayCommand(0.5,TransferItems(oPC));
	 	

}

Does anyone with deeper knowledge of NWN2 (like @travus, @kevL_s , @4760, @Shallina or @Lance_Botelle or someone else) help me here? Do you know what’s going on?

I have found a clue as to what’s going on, I think. I remember unequipping items in another script for a module that’s been put on hold for about a year or two. There among my scripts I discovered a note where I wrote this:

/*
	Script by andgalf with excerpts from a script by travus. Original script was buggy because of
	the use of action based functions like ActionGiveItem() in this case. I even tried with stock
	scripts, like the stock script ga_give_inventory, which was just as buggy. Apparently the action 
	based functions can go awry when a lot of items are involved in quick succession on multiple player 
	characters. With suggestions from Shallina and Lance Botelle, I changed it to using CopyItem() and 
	DestroyObject() instead.
*/

I’ll see if this will solve my problem.

EDIT: Yep, that was the whole issue. Now everything works again. I changed my stripping of items script to this:

#include "ginc_item"
#include "x2_inc_itemprop"

void CreateBag(object oWP)
{

location lLocation = GetLocation(oWP);
CreateObject(OBJECT_TYPE_ITEM,"bagwithpc2",lLocation);


}

void TransferItemsToBag(object oPC)
{

	object oBag = GetObjectByTag("bagwithpc2");
	object oItem = GetFirstItemInInventory(oPC);

	while (GetIsObjectValid(oItem))
	{
 	    if (!GetItemCursedFlag(oItem)) 
		{
			CopyItem(oItem,oBag,TRUE);
		}
			
		oItem = GetNextItemInInventory(oPC);
	}

}

void DestroyInventory(object oPC)
{

	object oItem = GetFirstItemInInventory(oPC);

	while (GetIsObjectValid(oItem))
	{
     	if (!GetItemCursedFlag(oItem)) 
		{
			DestroyObject(oItem);
		}
			
		oItem = GetNextItemInInventory(oPC);
	}
	

}

void main()
{
	object oPC = GetPCSpeaker();
	object oWP = GetObjectByTag("fairydrwp");
	
	CreateBag(oWP);
	
	DelayCommand(0.5,TransferItemsToBag(oPC));
	DelayCommand(0.7, DestroyInventory(oPC));
	 	

}
1 Like

@andgalf

(Now I am back at my computer, I’m currently taking a closer look at the other script.)

I see that you have resolved this issue, but just wanted to check something …

Does the PC need to drop the items?

I ask because unless any other PCs require access to the items, aren’t the items “polymorphed” alongside the PC, so that they remain inaccessible anyway?

This is more of a technical accessibility question about how you have it work for the player, and your reasoning here to require the drop in the first place.

Yes, the PC does indeed need to drop the items mainly because of one thing: The PC might have items required to turn him back from a chicken to a normal person.

You are otherwise correct in that when he’s polymorphed the player has no access to the items in his inventory.

2 Likes