Lockpicking trap Disarming UI

I was found this yesterday and thought to try it out:
https://neverwintervault.org/project/nwn2/other/gui/lockpicking-trap-disarming-uis

It’s a really nice mini game with a custom GUI when picking locks and disarming traps. It works really well when using the testing module that this is shipped with. However, when trying to implement this into my own module, at first I thought it didn’t work, but then I realized that it did, but only if the PC is a rogue. I looked at the script and trying to make sense of things but I can’t get it to work with a companion being the rogue. If you use a companion, it just directly says the trap is disarmed although the GUI shows up. Can anyone of you masters of scripting take a look at this and help me perhaps? It’s a really nice system that I would have liked to use. Here’s the script that is used on a Trigger Trap:

// script_name: gui_open_trappicking
/*
	Description:
	
*/
// LittleBaron 10/08
#include "x0_i0_position" 
void main()
{
 object opc = GetLastUsedBy();
 if (!GetIsObjectValid(opc))
 	opc = GetEnteringObject();
 int abd = GetLocalInt(OBJECT_SELF,"abd");
 //SpeakString("script fired"+IntToString(abd));
 if (abd == 2)//trap is jammed or disabled already.
 	{
 	 if (GetObjectType(OBJECT_SELF)==OBJECT_TYPE_TRIGGER)
	 	DestroyObject(OBJECT_SELF);
	 return;
	} 
 // get trap DC from Object, if DC = 0, assign it.
 int pclvl =GetTotalLevels(opc,FALSE);
 int DC = GetTrapDisarmDC(OBJECT_SELF);
 if (DC==0)
 	{	 
	 DC = 14+(pclvl+Random(pclvl/2));
	 SetTrapDisarmDC(OBJECT_SELF,DC);//if you no like, you fix.
	}	
 // get trap detect DC from object, ""
 int DDC = GetTrapDetectDC(OBJECT_SELF);
 if (DDC == 0)
 	{
	 DDC = (DC/2)+Random(DC/2);
	 SetTrapDetectDC(OBJECT_SELF,DDC);	
	 // again, you no like... you fix.
	}
 int traptype = GetLocalInt(OBJECT_SELF,"traptype");
 if (traptype == 0)
 	{
 	 traptype = GetTrapBaseType(OBJECT_SELF);
	}
 // because minor spike = 0 (grr) we must use a local int instead of getting base type, and add 1 and then always subtract it later
 if (traptype == 0&&abd==0)//0 is actually a minor spike trap, but we'll roll a random one anyway =(
 	{
 	 int level = (pclvl/5);
	 if (level < 1)
	 	level = 1;
	 if (level > 4)
	 	level = 4;
	 level=level-1;		
	 traptype = Random(11);
	 traptype = traptype*4;
	 traptype = traptype + level;	
 	}
 //if this is a trigger, make the real trap now!
 if (GetObjectType(OBJECT_SELF)==OBJECT_TYPE_TRIGGER)
	 	{
		 location loc = GetAheadLocation(opc,2.0);
		 object ntrap = CreateTrapAtLocation(traptype,loc,2.5,"",STANDARD_FACTION_HOSTILE);
	 	 SetLocalObject(OBJECT_SELF,"ntrap",ntrap);
		 SetTrapRecoverable(ntrap, FALSE);	
	     SetTrapActive(ntrap,TRUE);
		 SetTrapDetectable(ntrap,TRUE);
		 SetTrapDisarmable(ntrap,FALSE);
		}
 
 //see if the PC notices the trap!
 int spot = GetSkillRank(SKILL_SPOT,opc,FALSE);
 int srch = GetSkillRank(SKILL_SEARCH,opc,FALSE);
 int droll;
 int roll;
 int x;
 while (x < 3)//3 chances to more closely emulate the approach
 	{
	 droll = (Random(20)+1)+spot;
	 if (roll < droll)
	 	roll = droll;
	 x++;
	}
 x=0;
 //and if the PC is in active search mode he/she can try three times against search skill also
 while (x<3&&GetDetectMode(opc)==DETECT_MODE_ACTIVE)
 	{
	 droll = (Random(20)+1)+srch;
	 if (roll < droll)
	 	roll = droll;
	 x++;
	} 	
 droll = roll;//this will be the highest roll made.	
 object trap = OBJECT_SELF;
 if (droll<DDC&&abd==0)//PC did NOT notice there was a trap...
 	{
	 if (GetLocalInt(OBJECT_SELF,"lockedalso")==0)
	 	{
		 SetLocked(OBJECT_SELF,FALSE);
		 SetLockKeyRequired(OBJECT_SELF,FALSE);
		}
	 if (GetObjectType(OBJECT_SELF)==OBJECT_TYPE_TRIGGER)
	 	{
		 DestroyObject(OBJECT_SELF,2.0);
		}
	 else	
	 	{		 
	 	 CreateTrapOnObject(traptype,OBJECT_SELF,STANDARD_FACTION_HOSTILE,"","");
	 	 SetTrapRecoverable(OBJECT_SELF, FALSE);	
	 	 SetTrapActive(OBJECT_SELF,TRUE);
		 SetTrapDisarmable(OBJECT_SELF,FALSE);
		 SetTrapDetectable(OBJECT_SELF,TRUE);
		} 
	 SetLocalInt(OBJECT_SELF,"abd",2);
	 AssignCommand(opc,ClearAllActions());
 	 AssignCommand(opc,ActionInteractObject(trap));
	 AssignCommand(opc,SpeakString("I should really pay more attention..."));
	 return;
	}
 else
 	{
	 AssignCommand(opc,ClearAllActions());
	 AssignCommand(opc,SpeakString("TRAP!"));
	 PlayCustomAnimation(OBJECT_SELF,"search",TRUE,3.0);	
	}		
 SetLocalInt(OBJECT_SELF,"traptype",traptype);			
 SetLocalObject(opc,"oTrap",OBJECT_SELF);
 SetLocalInt(OBJECT_SELF,"abd",1);
 if (GetObjectType(OBJECT_SELF)==OBJECT_TYPE_TRIGGER)
		 SetLocalInt(OBJECT_SELF,"abd",2);//b/c if it's a trigger there is no second chance
 DisplayGuiScreen(opc,"SCREEN_TRAPPICKER",FALSE,"trappicker.xml");
 SetGUIObjectText(OBJECT_SELF,"SCREEN_TRAPPICKER","RecoveryButton",-1,"");	
 int bonus;
 //
 // this is geared toward general use
 //
 object pickexists;
 object pick = GetItemPossessedBy(opc,"NW_IT_PICKS001");
 if(GetIsObjectValid(pick))
 	{
 	 bonus = 1; 
 	 pickexists = pick;
	}
 pick = GetItemPossessedBy(opc,"NW_IT_PICKS002");
 if(GetIsObjectValid(pick))
 	{
 	 bonus = 3; 
 	 pickexists = pick;
	}	
 pick = GetItemPossessedBy(opc,"NW_IT_PICKS003");
 if(GetIsObjectValid(pick))
 	{
 	 bonus = 6; 
 	 pickexists = pick;
	}
 pick = GetItemPossessedBy(opc,"NW_IT_PICKS004");
 if(GetIsObjectValid(pick))
 	{
 	 bonus = 10; 
 	 pickexists = pick;
	}
 if(GetIsObjectValid(pickexists)) 
	DestroyObject(pickexists);
 //
 SetLocalInt(opc,"tdbonus",bonus);
 //
 //deactivate all buttons & Trap Pic to begin with 
 SetGUITexture(opc,"SCREEN_TRAPPICKER","TRAP_TOP","temp0.tga");
 x=0;
 string button;
 while (x<14)
 	{
	 button="PICK_"+IntToString(x);
	 SetGUIObjectDisabled(opc,"SCREEN_TRAPPICKER",button,TRUE);
 	 SetGUITexture(opc,"SCREEN_TRAPPICKER",button,"sigil_slot.tga");
	 x++;
	}
 if (abd==0)
 	SetTrapRecoverable(OBJECT_SELF,FALSE);	 
 if (GetTrapRecoverable(OBJECT_SELF)==FALSE)
 	SetGUIObjectDisabled(opc,"SCREEN_TRAPPICKER","RecoveryButton",TRUE);	 
 //show buttons, if this is not the first opening and there was another session with this object
 string buttonv;
 string trapname=GetLocalString(OBJECT_SELF,"trapname");
 SetGUIObjectText(opc,"SCREEN_TRAPPICKER","TRAP_FEEDBACK",-1,GetLocalString(OBJECT_SELF,"trapname"));	   	 	 	 	 	 	 				
  //and the progress bars
 SetGUIProgressBarPosition(opc,"SCREEN_TRAPPICKER","TRAP_PROG_GOOD",0.0);
 SetGUIProgressBarPosition(opc,"SCREEN_TRAPPICKER","TRAP_PROG_BAD",0.0);
 if (abd == 1)//show the buttons that were discovered, etc.
  	{
	 //progress bar functions
	 int x;
	 int y;
	 while (x < 14)
	 	{
		 if ((GetLocalInt(OBJECT_SELF,"PICK_"+IntToString(x)+"T")>0)&&(GetLocalInt(trap,"PICK_"+IntToString(x)+"I")<2))
		 	y++;
		 x++;	
		}
	 float ndvc = IntToFloat(GetLocalInt(OBJECT_SELF,"ndevices"));
	 float disarmed = ndvc-IntToFloat(y);
	 float percent = disarmed/ndvc;
	 SetGUIProgressBarPosition(opc,"SCREEN_TRAPPICKER","TRAP_PROG_GOOD",percent);	 
	 float failure = GetLocalFloat(OBJECT_SELF,"failure");
	 SetGUIProgressBarPosition(opc,"SCREEN_TRAPPICKER","TRAP_PROG_GOOD",failure);	 
	 //
	 if (GetTrapRecoverable(OBJECT_SELF))
	 	{
	 	 SetGUIObjectDisabled(opc,"SCREEN_TRAPPICKER","RecoveryButton",FALSE);	 		
		 //SetGUIObjectText(OBJECT_SELF,"SCREEN_TRAPPICKER","RecoveryButton",-1,"Recover");	
		}
	  if (!(trapname == ""||trapname == "Trap Type Unkown"))
	  	SetGUITexture(opc,"SCREEN_TRAPPICKER","TRAP_TOP",GetLocalString(OBJECT_SELF,"trapimage"));							
	  x =0;
	  while (x < 15)
	  	{
		 button = "PICK_"+IntToString(x);
		 x++;
		 if (GetLocalInt(OBJECT_SELF,button+"I")>0)//button identified
		 	{
			 SetGUIObjectDisabled(opc,"SCREEN_TRAPPICKER",button,FALSE);			 
			 buttonv = "DD";
			 buttonv = buttonv+(IntToString(GetLocalInt(OBJECT_SELF,button+"T")-1));
			 if (buttonv == "DD4")
			 	{
				 buttonv = buttonv+GetLocalString(OBJECT_SELF,"addon");
				}
			 if (GetLocalInt(OBJECT_SELF,button+"I")==1)
			 	{
			 	SetGUITexture(opc,"SCREEN_TRAPPICKER",button,buttonv+"_idle.tga");
				}
			 if (GetLocalInt(OBJECT_SELF,button+"I")==2)
			 	SetGUITexture(opc,"SCREEN_TRAPPICKER",button,buttonv+"_press.tga");
			}
		}	
	 return;
	}	
 //since this is the first opening everything must be set up.
 int initialc;
 string initialimg;
 string trapimg;
 string addon;
 int buttontype;
 if (traptype>11&&traptype<16)//acid trap
 	{
	 trapname = "Acid Blob";
	 trapimg = "it_kit_acidblobtrap";
	 initialimg = "DD4G_";
	 addon = "G";
	 buttontype = 5;
	}
  if (traptype>39&&traptype<44)//acid splash trap
 	{
	 trapname = "Acid Splash";
	 trapimg = "it_kit_acidsplashtrap";
	 initialimg = "DD4G_";
	 addon = "G";
	 buttontype = 5;
	}
  if ((traptype>19&&traptype<24)||traptype==44)//electrical trap
 	{
	 trapname = "Electric";
	 trapimg = "it_kit_electricaltrap";
	 initialimg = "DD0_";
	 buttontype = 1;
	}
  if ((traptype>15&&traptype<20)||traptype==45)//fire trap
 	{
	 trapname = "Fire";
	 trapimg = "it_kit_firetrap";
	 initialimg = "DD1_";
	 buttontype = 2;
	}
  if ((traptype>27&&traptype<32)||traptype==46)//frost trap
 	{
	 trapname = "Frost";
	 trapimg = "it_kit_frosttrap";
	 initialimg = "DD2_";
	 buttontype = 3;
	}
  if ((traptype>23&&traptype<28))//gas trap
 	{
	 trapname = "Gas";
	 trapimg = "it_kit_gastrap";
	 initialimg = "DD1_";
	 buttontype = 4;
	}
  if ((traptype>3&&traptype<7))//holy trap
 	{
	 trapname = "Holy Energy";
	 trapimg = "it_kit_holytrap";
	 initialimg = "DD4Y_";
	 addon = "Y";
	 buttontype = 5;
	} 
  if ((traptype>31&&traptype<36))//Neg trap
 	{
	 trapname = "Negative Energy";
	 trapimg = "it_kit_negativetrap";
	 initialimg = "DD4R_";
	 addon = "R";
	 buttontype = 5;
	}
  if ((traptype>35&&traptype<40)||traptype==47)//Sonic trap
 	{
	 trapname = "Sonic";
	 trapimg = "it_kit_sonictrap";
	 initialimg = "DD2_";
	 buttontype = 3;
	}
  if ((traptype>-1&&traptype<4))//spike trap
 	{
	 trapname = "Spike";
	 trapimg = "it_kit_spiketrap";
	 initialimg = "DD3_";
	 buttontype = 17;
	}
  if ((traptype>7&&traptype<11))//tangle trap
 	{
	 trapname = "Tangle";
	 trapimg = "it_kit_tangletrap";
	 initialimg = "DD3_";
	 buttontype = 18;
	}
  trapname = trapname + " Trap";
  string idtrapname = trapname;
  SetLocalString(OBJECT_SELF,"idtrapname",idtrapname);
  trapimg = trapimg+".tga";	
  SetLocalString(OBJECT_SELF,"trapimage",trapimg);
  if (!(addon == ""))
     SetLocalString(OBJECT_SELF,"addon",addon);
  trapname = "Trap Type Unkown"; 	
  SetLocalString(OBJECT_SELF,"trapname",trapname);
  SetGUIObjectText(opc,"SCREEN_TRAPPICKER","TRAP_FEEDBACK",-1,trapname);	   	 	 	 	 	 	 										
  initialc = Random(14);
  button = "PICK_"+IntToString(initialc); 
  //string buttonv;
  SetLocalInt(OBJECT_SELF,button+"T",buttontype);
  //asign the dc to this button;  	 
  SetLocalInt(OBJECT_SELF,button+"DC",DC+5);//assign the difficulty  
  //The inital object counts for 10 DC points
  //the DC here is simply for set-up purposes.
  //
  //Determine the remaining buttons	
  //Anything with a DC >14 will have at least one extra button.
  if (abd==0)// set up the remaining buttons
  	{
	 x = (DC-10)/5;
  	 int y;
	 x++;
  	 if (x > 13)
  		x = 13;
	 SetLocalInt(OBJECT_SELF,"ndevices",x);
  	 while (x > 0)
  		{
	 	 y = Random(14);
	 	 button = "PICK_"+IntToString(y);
	 	 if (GetLocalInt(OBJECT_SELF,button+"T")==0)//this button has not been chosen yet
	 		{
		 	 x=x-1;
		 	 y =Random(11)+6;
			 if (y > 16)
			 	y=16;
			 SetLocalInt(OBJECT_SELF,button+"T",y);
		 	 roll = Random(DC/2)-1;
  		 	 roll = (DC/2)+roll;
		 	 SetLocalInt(OBJECT_SELF,button+"DC",roll);		 	
			}
		}
 			 
	}
 		
}	

What I did when trying to fix this was that I tried with changing opc to GetFirstPC(FALSE); but unfortunately that did nothing. I suspect it not working having something to do with that the companion automatically disarms the trap?

EDIT: I tried with changing the behaviour of the companion to not automatcally disarm traps but that still gave the same result: The trap was disarmed when the UI shows up.

EDIT 2: If noone has any answers or thoughts, I think I just have to give up on this. I’ve tried to think of everything, but I can’t see how to change anything in the script for it to work. I’ll take a look in the xml files too, but…xml coding is even harder to understand so I doubt I’ll have more luck there…

EDIT3: So, there’s no way to get this to work? Noone that could help?

I use the lock picking GUI, but with my own scripts in The Scroll. I don’t use the trap one.

My point is that in the lock picking script, I don’t recall any restriction. Except, and this may be the point, make sure the PCs have appropriate pick lock or disable device skills so the pc is allowed interaction with the object.

Not at toolset at the moment, so cannot confirm if this is all you need. Let me know.

PS l may not have fully understood what you specifically want from your question. Maybe try restating it.

EDIT: If you are just trying to stop a companion automatically bypassing the GUI, then that may require further checks and a clearallactions if not being controlled by a player. I do things like that by increasing a Hb check as a pc gets close to the object… stopping the action if it is not a player controlled pc.

Ok , rephrasing…

I would want to be able to use either the PC (if he’s a rogue) OR one of the companions, who is a rogue, when trying to disarm the trap and getting the GUI and the system.

I have looked at the scripts over and over, and while they are a bit over my head, I can see no restrictions for using a companion rather than the PC. Still, somehow, when I try using the companion, when entering the triggering area, the GUI shows up, BUT it says immediately that the trap is disarmed without me doing anything.

To try to fix this I tried with changing the behaviour of the companion (in the behaviour slot on the character sheet or what the heck you call it in english) by NOT having her automatically disarm traps. This had no effect whatsoever ingame. That’s why I have have no clue as to what’s going on.

I also tried with a bunch of SendMessageToPC but that didn’t clear things up for me either.

Maybe now you understand what I’m after? I don’t know how to rephrase it any more than that.

EDIT: I haven’t tested the lock picking stuff yet with the companion, since for me at the moment, it’s more important to get the trap disarming GUI through a trigger to work with a rogue companion trying to disarm the trap.

Thanks for clarifying.

Specifically, you are referring to the disable trap GUI by the sounds of it in this case.

Actually, give me a few minutes to get to my main computer.

1 Like

Thank you for trying to help!

Yes, I would like to use the GUI system as it is…with using a companion OR with the PC, if either of them are rogues. For now it works with the PC, no problems there, but with the companion it’s always: GUI shows up, but it says “Trap disarmed” even though I haven’t done anything.

Unfortunately I have to go to work now. I’ll be home later tonight. Hopefully you’ll have found something out through reading the scripts for the gui and the xml scripts for the trap handling.

Scripts moved to here for ease of reference …

1 Like

Thank you SO much for looking into this Lance!

I actually suspected there was some error somewhere with an OBJECT_SELF, but since the code was a bit too over my head to follow in all the steps, I just gave up. I will try and look at your solution. Thanks again!

@andgalf

You can try it, but the original code is such a mess (as far as I can tell) that I am trying to pick it to pieces to sort it fully.

I think your mileage will only go so far with what I have done so far, and then it will break again.

I still have some way to go before I am happy to release my own version of the scripts. I am trying to work out what is valid code and what is not. It’s quite a untangle required! :wink:

1 Like

Oh, that sounds ominous.

Yes, even though I found the script quite structured, it was very long and a bit hard to follow, at least for me. So maybe it is a mess, as you say.

I hope you manage to get a better version of it then. I only tested it with the test module, and I quite liked its simplicity. It is not that different from the vanilla style of opening locks and disarming traps, but I like that you have to do a tiny bit more than just click on a trap or lock and just fail or succeed. It is just a simple mini game for all this, but I guess you have quite a lot higher requirements for you to be satisfied with it? Or is it that it’s a bit buggy that you don’t like?

1 Like

@andgalf

Yes, this is what attracted me to the same GUIs originally … many years ago. BUT, I think I now know why I left this trap one to one side back then. The lock-picking one I managed to untangle quite easily by comparison.

I don’t know where to begin. At first I found what I thought was a minor discrepancy … and then I pulled the tiny thread … and now it’s falling apart all around - and I cannot escape a rewrite. There appears to be redundant or repeated code in many places.

Simply put … I don’t think there is much I am going to be able to salvage of the original, but will try to put together something that will work for both our needs … if I work from a point of my own campaign, it will then be easier for me to work backwards for you. i.e. Yes, I need more checks than you do due to SP/MP thing. BUT, we both need the companion difference.

3 Likes

Alright, I’ll test what you have fixed here in the meantime, but I’ll look forward to trying out your rewrites later. :slight_smile:

EDIT: By the way, coding-wise, I am a bit confused by the functions SetLocalObject and GetLocalObject. It seems to me that they are variables that you put on an object? Can that be correct? Still, when I look at the explanation of SetLocalObject it says this:

// Set oObject's local object variable sVarName to nValue
void SetLocalObject(object oObject, string sVarName, object oValue);

nValue to me sounds like an integer. Don’t know if that’s correct here, but then in the function itself it says oValue which is an object. That has me confused.

I tried your fixes and so far it seems to work with a companion on the trigger now. Only tested it two times though.

Don’t know what you thought was supposed to break…but I’ll test a few more times and see what happens. I’m thinking of maybe trying the lock picking thing too now. I guess I have to change similar stuff there too. I’ll take a look.

EDIT: I think I made a locked door work with this. Just as with the other scripts I noticed (in the gui_open_lockpicking) the
SetLocalObject(opc,"lock_object",OBJECT_SELF);
wich I changed to
SetLocalObject(GetModule(),"lock_object", OBJECT_SELF);
Then in gui_lockpicking I changed
object oLocked = GetLocalObject(OBJECT_SELF,"lock_object");
to
object oLocked = GetLocalObject(GetModule(),"lock_object");
I hope this was the right thing to do. It seems to work…(but I’ve only tested once)

Trigger traps.

Part of the tangled web …

There is so much to work through! :exploding_head:

One thing I’m wondering about, now that things (at least for now) seems to work ok, is that in this same area of mine I have two doors which I want to place the gui_open_lockpicking on. Will that really work then with the script SetLocalObject(opc,"lock_object",OBJECT_SELF); since I’ve already used that once? I’m don’t quite fully understand what this does, but I suspect that if I’ve already set this variable (that’s what it does, I take it?) maybe it won’t work a second time? Is that perhaps part of the tangled web too?

EDIT: @Lance_Botelle I’m sorry if I have put a lot of work on you. :open_mouth:

That’s OK. It was something I had intended to look at again at some point. Admittedly, if you had not been interested, it may have sat on the back burner for some time yet, as having started to delve into it, I realised just how bad it is.

I would say it may be best to hang on and see my new scripts, unless you want to play with the old just for fun and to see what happens. :slight_smile:

I still have some very weird loops to untangle first, but hopefully, if not today, then tomorrow … perhaps. It really is that bad for someone like me at least. Others may have sorted it sooner I guess, but I was trying to preserve the original flow. I just could not do that in the end.

Alright, I might play around with it for a bit, but I won’t make anything major in my module. I’ll wait for your version instead.

1 Like

yep. like Get/SetLocalInt() but instead of meaning “store this integer (on an object) i might want to access it later” it means “store this object (on another object) i might want to access it (for whatever reason) later”

it’s a mistake in the description

hey Lance,

i do that kind of thing a lot (or used to). just wrack yer brains until you’ve got it figured out, then rewrite from scratch. The result will be a bit to a lot simpler than the original code … no regrets :)

1 Like

You can say that again! :wink:

1 Like

Ok, but why is oValue an object? That cofuses me. We store a new object on oObject call it sVarName and then…the value of that object is an object? I can’t get my head around that.