Pick Pocket script

How would someone write a script that will cause the target to attack if they catch the PC pick pocketing them? I seem to be having trouble getting this OnDisturbed() event from firing.

I’m getting very unsatisfactory results from the OnDisturbed event using SleightOfHand against a creature.

My script doesn’t fire often, maybe once in 10 tries. clue: The pickpocket animation always (and only) plays when it does fire.

but regardless of the animation and event-script, a check is made every time and loot is gained (as long as target still has loot) if successful.

here’s a script if you want to investigate … (full debug left in)

// 'creature_disturbed'
/*
    OnDisturbed event script for a creature.
*/
// kevL 2019 may 12

#include "nw_i0_generic"

//
void main()
{
    SendMessageToPC(GetFirstPC(FALSE), "creature_disturbed iType= " + IntToString(GetInventoryDisturbType()));

    object oSelf = OBJECT_SELF;

    switch (GetInventoryDisturbType())
    {
        case INVENTORY_DISTURB_TYPE_ADDED:
        case INVENTORY_DISTURB_TYPE_REMOVED:
        case INVENTORY_DISTURB_TYPE_STOLEN:

            SendMessageToPC(GetFirstPC(FALSE), ". action= " + IntToString(GetCurrentAction()));
            SendMessageToPC(GetFirstPC(FALSE), ". dialog= " + IntToString(IsInConversation(oSelf)));

            if (GetCurrentAction() == ACTION_INVALID && !IsInConversation(oSelf))
            {
                object oThief = GetLastDisturbed();
                SendMessageToPC(GetFirstPC(FALSE), ". . thief= " + GetName(oThief));

                if (GetIsObjectValid(oThief))
                {
                    SendMessageToPC(GetFirstPC(FALSE), ". . . VALID");

                    if (GetObjectSeen(oThief))
                    {
                        SendMessageToPC(GetFirstPC(FALSE), ". . . . Seen");

                        ClearAllActions(TRUE);
                        SpeakString("Got you !");

// void SetIsTemporaryEnemy(object oTarget, object oSource=OBJECT_SELF, int bDecays=FALSE, float fDurationInSeconds=180.0f);

//                      ChangeToStandardFaction(oSelf, STANDARD_FACTION_HOSTILE);
                        DetermineCombatRound(oThief);
                    }
                    else
                    {
                        SendMessageToPC(GetFirstPC(FALSE), ". . . . Unseen");

                        ClearAllActions(TRUE);
                        SpeakString("huh");

                        PlayCustomAnimation(oSelf, "scratchhead", FALSE);
                    }
                }
            }
            break;
    }

    if (GetSpawnInCondition(NW_FLAG_DISTURBED_EVENT))
    {
        SignalEvent(oSelf, EventUserDefined(EVENT_DISTURBED));
    }
}

further, i notice that the disturb-type registers as ADDED … (no, i’m not adding anything) … and i notice that the event is fired even when nothing has actually been taken/disturbed.

so am chalking this up to Nwn2 glitchiness, unless someone can say how to fire the OnDisturbed event of a creature consistently,

:\

2 Likes

In NWN1, a workaround might be to use the module’s OnAcquireItem event, checking for who the former possessor of the acquired item is. :open_mouth: Not a clue if this’ll be helpful here, but fingers crossed, y’guys.

1 Like

I’m getting very unsatisfactory results from the OnDisturbed event

Dare I say… DISTURBING results?
badum-tshh

3 Likes

Perhaps first check if the acquired item is flagged as stolen?

1 Like

Thank you everyone.

2 Likes

Did you ever get this sorted out? I have an encounter I’d like to use this logic to start a Hollywood style bar fight without permanently changing anyone’s faction.

based on my earlier investigation, i’d think a total workaround is req’d

(just) one idea:
start a recursive script on any creatures in the bar who have stuff that can be stolen, that checks if their inventories are intact (with a delay of a few seconds), and if something is missing check which party-member has it, and make that party-member roll a SleightofHand DC, then if that fails have the creature go hostile and call DetermineCombatRound() on the party-member … or start a dialog that could lead to combat …

such creatures should not have an OnDisturbed script slotted,
handle how disturbed they are with a pseudo-heartbeat (a recursive script) instead

this approach’d be a fair bit of time & effort: eg, the items in creatures’ inventories would likely need unique tags, etc. And you might need to concoct some sort of string-array for the HB to check against, or an object-array … but it seems to me a fair bit of effort for something that might never happen,

… start and stop the script(s) based on whether there is a PC in the Area (perhaps OnAreaEnter, OnAreaExit) …

 
hostile creatures (or better to use custom factions, so the barmaid doesn’t go aggro on the patrons, lul), so now you’re looking at faction-pigs also … creatures can eventually be set back to their starting faction(s) if no PC is in the Area,

i admit it’d be fun to set up and see working, but to make it worth the effort perhaps have more cases that can start the brawl than just a failed SleightofHand check. Like, give some of the patrons insulting dialogs so that they’re trying to pick a fight …

leave all weapons at the door? Then you could be looking at setting all creatures Immortal with OnDamaged script for surrender …

/and so it goes

1 Like

Yikes! I was hoping for something a lot simpler. I’ll have to take a look at how much of the existing area I want to change.

Thanks!

1 Like

I mean, GC, don’t take my word for it. (during my experiment I could have had something funky affecting the result that i didn’t think about, eg.) So, if you like, just try to set things up the way that you believe they should work … and only if you start getting weird/borky behavior think, yeh ok confirmed …

1 Like

Looking at my notes, it was a single player who didn’t like the fact that getting caught picking a half orcs’ pocket did not start a fight. Your solution would work in that instance because the target has a specific dagger the player might like. For the bar fight, it might be easier to just put in a trigger for a cut scene just for the laughs.

Low priority work for a cold winter weekend.

yeh

ps. for a specific item, TheBarbarian’s suggestion of a tag-based OnAcquireItem script strikes me as the best idea

1 Like

Hi All,

Not a lot to add, except I had this note in my own code regarding the OnDisturbed:

“// ON DISTURBED APEARS TO FIRE EVEN WHEN PC FAILS TO STEAL AN OBJECT FROM IT (NPC DETECTS/SPOTS THE ATTEMPT)
// MEANING oITEM WILL ALWAYS BE AN INVALID OBJECT & ONLY EVER VALID IF THE THIEF IS SUCCESSFUL”

Cheers, Lance.

For the record, here is my full script, but it does use some custom functions, but may be of some guidance …

NOTE: This is some REALLY OLD code and I have not looked over it for some time, but it should probably still work, even if a little inefficient compared to something I may have done more recently. :wink:

#include "alb_functions_core"

void main()
{	
	// ON DISTURBED APEARS TO FIRE EVEN WHEN PC FAILS TO STEAL AN OBJECT FROM IT (NPC DETECTS/SPOTS THE ATTEMPT)
	// MEANING oITEM WILL ALWAYS BE AN INVALID OBJECT & ONLY EVER VALID IF THE THIEF IS SUCCESSFUL

	object oPC = GetLastDisturbed();
	object oItem = GetInventoryDisturbItem();
	object oMainPC = GetMainPC(oPC);
	
	// SendMessageToAllPCs("INV: " + GetName(oItem)); // DEBUG
	
	// ONLY FOR PLAYER THIEVES
	if(oMainPC != OBJECT_INVALID)
    {		
		// EVIL/CHAOTIC ONLY IF OPPOSED ALIGNMENTS
		if(GetAlignmentGoodEvil(OBJECT_SELF) == ALIGNMENT_GOOD){EvilChaoticActivity(oPC, 3, 3);}
	
		// CALL "THIEF" BY HUMANOIDS ONLY
		int RACETYPE = GetRacialType(OBJECT_SELF);
		
		if(RACETYPE == RACIAL_TYPE_DWARF || RACETYPE == RACIAL_TYPE_ELF || RACETYPE == RACIAL_TYPE_FEY
		|| RACETYPE == RACIAL_TYPE_GIANT || RACETYPE == RACIAL_TYPE_GNOME || RACETYPE == RACIAL_TYPE_GRAYORC
		|| RACETYPE == RACIAL_TYPE_HALFELF || RACETYPE == RACIAL_TYPE_HALFLING || RACETYPE == RACIAL_TYPE_HALFORC
		|| RACETYPE == RACIAL_TYPE_HUMAN || RACETYPE == RACIAL_TYPE_HUMANOID_GOBLINOID || RACETYPE == RACIAL_TYPE_HUMANOID_MONSTROUS
		|| RACETYPE == RACIAL_TYPE_HUMANOID_ORC || RACETYPE == RACIAL_TYPE_HUMANOID_REPTILIAN || RACETYPE == RACIAL_TYPE_OUTSIDER
		|| RACETYPE == RACIAL_TYPE_SHAPECHANGER || RACETYPE == RACIAL_TYPE_YUANTI)
		{						
			// ONE WARNING
			if(GetLocalInt(OBJECT_SELF, "PickDetected") == 0)
			{
				SpeakString("Hey! I'm warning you thief! Back off!");
						
				SendMessageToPC(oPC, "<c=orange><i>Your pick pocket attempt has been detected. Continued attempts may attract hostility.</i>" );				
				SetLocalInt(OBJECT_SELF, "PickDetected", 1);
				return;
			}
			
			// NOW FULL ON ATTACK
			SpeakString("THIEF!", TALKVOLUME_SHOUT);				
			SendMessageToPC(oPC, "<c=orange><i>Your pick pocket attempt has been detected again. " + GetName(OBJECT_SELF) + " now considers you a thief.</i>" );				
			
			// ENSURE ATTACKED CREATURE REMAINS A TEMPORARY ENEMY (SET INFLUENCE)
			object AntiParty = GetObjectByTag("SETFACTION_ANTIPARTY");
			
			ChangeFaction(OBJECT_SELF, AntiParty);
			if(GetLocalInt(OBJECT_SELF, "CoolDown") > -1){SetLocalInt(OBJECT_SELF, "CoolDown", 1);}
			int CurrentInfluence = GetLocalInt(OBJECT_SELF, "PartyInfluence"); 
			int NewInfluence = CurrentInfluence - 200; 
			if(NewInfluence < -100){NewInfluence = -100;}	// CANNOT GO LESS THAN -100
			SetLocalInt(OBJECT_SELF, "PartyInfluence", NewInfluence);  

			AssignCommand(OBJECT_SELF, HenchDetermineCombatRound());
			
				// KEEP FRIENDS HELPING AN ATTACKED NPC
				int Count = 1;
				object oNPCFriend = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, OBJECT_SELF, Count, CREATURE_TYPE_IS_ALIVE, CREATURE_ALIVE_TRUE);
				
				while(oNPCFriend != OBJECT_INVALID)
				{	
					// DONT INCLUDE OWN PARTY IN SEARCH
					if(GetMainPC(oNPCFriend) == OBJECT_INVALID)		
					{
						if(GetIsFriend(oNPCFriend, OBJECT_SELF) && !GetIsInCombat(oNPCFriend))
						{	
						if(d4()==1){AssignCommand(oNPCFriend, SpeakString("Thieves are not tolerated here!", TALKVOLUME_SHOUT));}		
						if(GetLocalInt(oNPCFriend, "Suspicion") == 1){SetLocalInt(oNPCFriend, "Suspicion", 2);} // ORDER MATTERS HERE
						if(GetLocalInt(oNPCFriend, "Suspicion") == 0){SetLocalInt(oNPCFriend, "Suspicion", 1);}	// WITH HERE
						}
						
						// PREVENT WALKING STOPPING THE FIGHT BY USING WAITING VARIABLE (CLEAR ALL FOR WALK)
						AssignCommand(oNPCFriend, ClearAllActions(TRUE));  
						if(GetDistanceToObject(oNPCFriend) > 10.00){AssignCommand(oNPCFriend, ActionEquipMostDamagingRanged());}
						if(GetDistanceToObject(oNPCFriend) <= 10.00){AssignCommand(oNPCFriend, ActionEquipMostDamagingMelee());}

						AssignCommand(oNPCFriend, HenchDetermineCombatRound());
					}
				
				Count = Count + 1;
				oNPCFriend = GetNearestCreature(CREATURE_TYPE_PERCEPTION, PERCEPTION_HEARD, OBJECT_SELF, Count, CREATURE_TYPE_IS_ALIVE, CREATURE_ALIVE_TRUE);
				}				
             } // END RACE CHECK	
		} // END MAIN PC CHECK
	
	if(GetSpawnInCondition(NW_FLAG_DISTURBED_EVENT))
    {
        SignalEvent(OBJECT_SELF, EventUserDefined(EVENT_DISTURBED));
    }
}
2 Likes

the event “on inventory disturbed” only fires when the creature spots the attempt of pick pocketing (a spot skill versus a sleight of hand skill check), regardless of the success of the sleight of hand skill check - the actual theft of an item. placeables always detect the theft, therefore always fire this event.

1 Like