IsKeyPressed equipunequip

Post » Thu Jun 21, 2012 9:25 am

Hey folks,

I'm having some trouble getting the SKSE isKeyPressed to work like I want it to. I want it so, if I press the key the first time an item gets equiped, and if I press it a second time the item gets unequiped. So far the script does what it says, but unfortunately only as long as I hold down the key. Here's the script:

Spoiler
Scriptname SI_HotkeyScript extends Quest  GlobalVariable Property SI_HotkeyTorch AutoLight Property Torch01 Autoint TorchHotkeyPressedEvent OnInit()	RegisterForUpdate(0.1)EndEventEvent OnUpdate()	If Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 1 && TorchHotkeyPressed == 0		TorchHotkeyPressed = 1		Game.GetPlayer().EquipItem(Torch01)	Elseif  Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 0		TorchHotkeyPressed = 0		Game.GetPlayer().UnequipItem(Torch01)	EndIfEndEvent

I know what I'm doing wrong since one of my NewVegas scripts looked like that:

Spoiler
String:	scn FSEasyToggleCollisionScriptShort KeyPressedBegin GameMode	If IsKeyPressed FSToggleCollisionKey == 1 && KeyPressed == 0		Set KeyPressed to 1		con_ToggleCollision	ElseIf IsKeyPressed FSToggleCollisionKey == 0		Set KeyPressed to 0	EndIfEndBegin MenuMode	If IsKeyPressed FSToggleCollisionKey == 1 && KeyPressed == 0		Set KeyPressed to 1		con_ToggleCollision	ElseIf IsKeyPressed FSToggleCollisionKey == 0		Set KeyPressed to 0	EndIfEnd

But I can't seem to understand how to do this in Papyrus.
User avatar
Tom Flanagan
 
Posts: 3522
Joined: Sat Jul 21, 2007 1:51 am

Post » Thu Jun 21, 2012 5:05 pm

You scripted it so that while the key is held down it is equiped but it gets unequiped when you release the key.

It should be more like this:
Event OnUpdate()	If Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 1 && TorchHotkeyPressed == 0		 TorchHotkeyPressed = 1		 Game.GetPlayer().EquipItem(Torch01)	Elseif  Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 1 && TorchHotkeypressed == 1		 TorchHotkeyPressed = 0		 Game.GetPlayer().UnequipItem(Torch01)	EndIfEndEvent

Although if you hold the key down long enough it will unequip again the next script run. With a little more work you can prevent that (do a check that the key needs to be released first), but I think you should do that yourself (else someone else will be making your mods for you).
User avatar
Cathrine Jack
 
Posts: 3329
Joined: Sat Dec 02, 2006 1:29 am

Post » Thu Jun 21, 2012 5:10 am

Although if you hold the key down long enough it will unequip again the next script run. With a little more work you can prevent that (do a check that the key needs to be released first), but I think you should do that yourself (else someone else will be making your mods for you).

Thanks for the tip friend. I've got it working, by changing the int with a bool, script looks like that now:

Scriptname SI_HotkeyScript extends Quest  GlobalVariable Property SI_HotkeyTorch AutoLight Property Torch01 Autobool TorchHotkeyPressedEvent OnInit()	RegisterForUpdate(0.1)EndEventEvent OnUpdate()	If Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 1 && TorchHotkeyPressed == 0				 TorchHotkeyPressed = 1				 Game.GetPlayer().EquipItem(Torch01)	Elseif  Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 1 && TorchHotkeypressed == 1				 TorchHotkeyPressed = 0				 Game.GetPlayer().UnequipItem(Torch01)	EndIfEndEvent
User avatar
Genocidal Cry
 
Posts: 3357
Joined: Fri Jun 22, 2007 10:02 pm

Post » Thu Jun 21, 2012 4:07 am

Your OnUpdate is not refined yet. As every OnUpdate run, the VM create a new thread to run your OnUpdate block. This results in 2-3 keypressed sent for single keystroke
Some oddities might happen in a long run.

Try to use States to eliminate unwanted threads
User avatar
Eric Hayes
 
Posts: 3392
Joined: Mon Oct 29, 2007 1:57 am

Post » Thu Jun 21, 2012 2:00 pm

Try:
Spoiler
ScriptName SI_HotkeyScript extends Quest ConditionalBool bEquipTorchActor Property PlayerREF AutoInt Property iTorchHotkey Auto ConditionalLight Property Torch01 AutoEvent OnInit()        RegisterForUpdate(0.1)EndEventEvent OnUpdate()	If !Input.IsKeyPressed(iTorchHotkey)	ElseIf PlayerREF.GetItemCount(Torch01)		bEquipTorch = !bEquipTorch		If bEquipTorch			PlayerREF.EquipItem(Torch01)		Else			PlayerREF.UnequipItem(Torch01)		EndIf		Utility.Wait(1)	EndIfEndEvent

Edit: Better code below

With the hotkey as a property, it'll be 'cheaper than using GetValueInt. Same with PlayerREF. Also, as it was, http://www.creationkit.com/EquipItem_-_Actor would have given the player a torch in the event they didn't have one.
User avatar
Dona BlackHeart
 
Posts: 3405
Joined: Fri Dec 22, 2006 4:05 pm

Post » Thu Jun 21, 2012 6:19 am

Yeah, I've tried it with function blocks, I've tried it with state blocks. The result is always the same, I get multiple keyhits in one stroke. I've solved it by setting the RegisterForUpdate to 1 instead of 0.1. You'll just have to press the key for a second, but that prevents the whole script from creating weird behaviour.

@Justin

Your script has the same effect. I also get multiple keyhits in one stroke. Apart from that, my script has a check if you have more then 0 torches equiped. If you don't have any torch equiped aka in your inventory, you won't equip a torch. It's basically the same what you did with !bEquipTorch, just a little more complicated... :biggrin:

Think we'll have to wait for SKSE OnIsKeyPressed.
User avatar
:)Colleenn
 
Posts: 3461
Joined: Thu Aug 31, 2006 9:03 am

Post » Thu Jun 21, 2012 6:30 pm

Well, its up to you if you wish to wait for SKSE ;)
My mod use RegisterForUpdate(0.1), and I got no multiple keyhits for single stroke problem.

You probably should read this note on threading
http://www.creationkit.com/Threading_Notes_(Papyrus)
Proper use of States will eliminates the unnecessary threads for each OnUpdate Event.

SKSE's OnKeyDown Event will also suffer the same multiple threads problem if your Event could not finish before the next OnKeyDown is sent. (If player pressing that button mindlessly, your script will end up having dozens of OnKeyDown threads pilling up, waiting to be executed) So waiting for SKSE will most likely not solve your problem
User avatar
Georgine Lee
 
Posts: 3353
Joined: Wed Oct 04, 2006 11:50 am

Post » Thu Jun 21, 2012 11:58 am

The reason why I don't do this is not because I don't want to. he reason is, I can't get it done. I've read the whole threading page, but most of it is weird giberish for me. I understand the problem is my scripts updates every 0.1 seconds and so if I press a key, every 0.1 seconds the script gets fired. So, if I press the hotkey longer then 0.1 seconds it gets fired a second time.

I've really tried with states and/or functions but I don't have a clue how to exactly arrange the script in order to make it work. Does the isKeyPressed function has to be inside the event block, or the state/function block? And how does a state block refines the OnUpdate if I have to put it inside the state block? It's still updating every 0.1 seconds inside that state block.

You see, I don't have a reasonable clue about what am I doing here. My whole scripting skills rely on copypasta from the wiki, trying stuff and see if it works. I'm doing this since 4 weeks, don't expect wonders...:D
User avatar
carla
 
Posts: 3345
Joined: Wed Aug 23, 2006 8:36 am

Post » Thu Jun 21, 2012 3:16 pm

Hmm, ok, I will just give you a sample code then

Auto State Default_State  Event OnUpdate()    GoToState("deathState")    if(IsKeyPressed(19))       ;do something    endif    GoToState("Default_State")  EndEventEndState;{empty state of DEATH}State deathState  ; Die, stupid threadsEndState

The empty state of death will kill any unwanted threads. You still have to use key trap like the one you posted in the first post (used in Vegas?!) to read your input once.

The reason behind this is, as soon as you enter the state, you shut it, send any sub-sequence Event to the empty state (GoToState("death-state"))
User avatar
Jade Barnes-Mackey
 
Posts: 3418
Joined: Thu Jul 13, 2006 7:29 am

Post » Thu Jun 21, 2012 4:24 am

Fix'd:
ScriptName TorchHotkeyScript extends Quest ConditionalBool bEquipTorchBool bHotkeyPressedActor Property PlayerREF AutoInt Property iTorchHotkey Auto ConditionalLight Property Torch01 AutoEvent OnInit()        RegisterForUpdate(0.1)EndEventEvent OnUpdate()	If bHotkeyPressed != Input.IsKeyPressed(iTorchHotkey)		bHotkeyPressed = !bHotkeyPressed		If bHotkeyPressed			bEquipTorch = !bEquipTorch			If bEquipTorch				PlayerREF.EquipItem(Torch01)			Else				PlayerREF.UnequipItem(Torch01)			EndIf		EndIf	EndIfEndEvent

Even if the key is held, it'll not equip/unequip 'til released and pressed again.
User avatar
Sudah mati ini Keparat
 
Posts: 3605
Joined: Mon Jul 23, 2007 6:14 pm

Post » Thu Jun 21, 2012 6:43 pm

Fix'd:
Even if the key is held, it'll not receive another input 'til released and pressed again.

What if, just say, a normal human's keystroke take about 0.2 second. During that time frame, OnUpdate fires 2 times, and creates 2 separated threads. These 2 threads both satisfy these conditions

If bHotkeyPressed != Input.IsKeyPressed(iTorchHotkey)

successfully, hence return 2 IsKeyPressed-es for one single keystroke. If you don't believe it, you could use an integer for counter, see how many IsKeyPressed are sent for single keystroke for the above code :wink:
User avatar
Eve Booker
 
Posts: 3300
Joined: Thu Jul 20, 2006 7:53 pm

Post » Thu Jun 21, 2012 1:46 pm

It only runs on press or release. The bool gets flipped the first iteration, so the condition isn't true 'til the key is no longer pressed.
User avatar
SWagg KId
 
Posts: 3488
Joined: Sat Nov 17, 2007 8:26 am

Post » Thu Jun 21, 2012 4:54 am

You are correct if this is single threaded like Oblivion, my friend.
In multi-threaded, each thread has its own instance of the script. Multi-thread <=> multi-instances of the script running

The bool get flipped on first instance of the script, but not (yet) the other instances
User avatar
SiLa
 
Posts: 3447
Joined: Tue Jun 13, 2006 7:52 am

Post » Thu Jun 21, 2012 5:25 am

It verifiably iterates once when the key is pressed and once when it is released (no more or less), even at such tight intervals.
Spoiler
ScriptName TorchHotkeyScript extends Quest ConditionalInt iCountBool bEquipTorchBool bHotkeyPressedActor Property PlayerREF AutoInt Property iTorchHotkey Auto ConditionalLight Property Torch01 AutoEvent OnInit()	RegisterForUpdate(0.1)EndEventEvent OnUpdate()	If bHotkeyPressed != Input.IsKeyPressed(iTorchHotkey)		bHotkeyPressed = !bHotkeyPressed ; Set bool to whatever it is not		iCount += 1		Debug.Trace("iCount: " + iCount)		If bHotkeyPressed			bEquipTorch = !bEquipTorch			If bEquipTorch				PlayerREF.EquipItem(Torch01)			Else				PlayerREF.UnequipItem(Torch01)			EndIf		EndIf	EndIfEndEvent
Three times pressed+released/torch equipped twice
[05/21/2012 - 10:34:58PM] VM is thawing...[05/21/2012 - 10:35:02PM] iCount: 1[05/21/2012 - 10:35:03PM] iCount: 2[05/21/2012 - 10:35:07PM] iCount: 3[05/21/2012 - 10:35:09PM] iCount: 4[05/21/2012 - 10:35:11PM] iCount: 5[05/21/2012 - 10:35:14PM] iCount: 6[05/21/2012 - 10:35:20PM] VM is freezing...[05/21/2012 - 10:35:20PM] VM is frozen[05/21/2012 - 10:35:21PM] Log closed

If you don't believe it, you could use an integer for counter, see how many IsKeyPressed are sent for single keystroke for the above code :wink:
User avatar
Melly Angelic
 
Posts: 3461
Joined: Wed Aug 15, 2007 7:58 am

Post » Thu Jun 21, 2012 8:25 am

You are correct if this is single threaded like Oblivion, my friend.
In multi-threaded, each thread has its own instance of the script. Multi-thread <=> multi-instances of the script running

The bool get flipped on first instance of the script, but not (yet) the other instances

Pretty sure he's right, Justin. Unless SKSE is sharing local members across all instances.The other way of doing this might be cleaner. Use RegisterForSingleUpdate in the OnInit. That way only one event is fired regardless of how busy the Papyrus engine is. At the end of your flaming (lol) logic, do another RegisterForSingleUpdate. Voila.
User avatar
sunny lovett
 
Posts: 3388
Joined: Thu Dec 07, 2006 4:59 am

Post » Thu Jun 21, 2012 12:11 pm

Pretty sure he's right, Justin. Unless SKSE is sharing local members across all instances.The other way of doing this might be cleaner. Use RegisterForSingleUpdate in the OnInit. That way only one event is fired regardless of how busy the Papyrus engine is. At the end of your flaming (lol) logic, do another RegisterForSingleUpdate. Voila.
What other instance of such a script would be running? Were there more instances, the iCount variable in the log would have been higher or each count would have been logged multiple times, right? I'm not seeing what the problem is and the script works precisely as desired, although (0.1) is unnecessarily tight.
User avatar
Amelia Pritchard
 
Posts: 3445
Joined: Mon Jul 24, 2006 2:40 am

Post » Thu Jun 21, 2012 4:44 pm

It verifiably iterates once when the key is pressed and once when it is released (no more or less), even at such tight intervals.

Oh blah blah blah. Look at you and your integer. But do you know why this is? After I posted above I remembered RFU acts like a function. Another Update event will not fire until the executed one finishes. I got into a discussion about this somewhere. Only http://www.creationkit.com/Latent_Functions specifically spawn new instances within functions and events. AFAIK *sigh*I still like my suggestion better. It reads cleaner. And you didn't think of it. Like casting objectRefs as scripts... ;^)
User avatar
Markie Mark
 
Posts: 3420
Joined: Tue Dec 04, 2007 7:24 am

Post » Thu Jun 21, 2012 8:10 pm

What other instance of such a script would be running? Were there more instances, the iCount variable in the log would have been higher or each count would have been logged multiple times, right? I'm not seeing what the problem is and the script works precisely as desired, although (0.1) is unnecessarily tight.

Chatty tonight, aren't we? It's a matter of perception based on what other oop coding you've done. I got hung up on this too. Papyrus isn't "truly" threaded... only enough to be confusing.
User avatar
rheanna bruining
 
Posts: 3415
Joined: Fri Dec 22, 2006 11:00 am

Post » Thu Jun 21, 2012 5:29 am

Chatty tonight, aren't we? It's a matter of perception based on what other oop coding you've done. I got hung up on this too. Papyrus isn't "truly" threaded... only enough to be confusing.
Somewhat chatty :P Today's been... grrr! Lost an important doc while moving stuff :( Oh well.

Topic: Haven't really done any other coding, but the script is behaving exactly as intended, so I can only surmise there's only one instance. RegisterForSingleUpdate behaves identically.
User avatar
saxon
 
Posts: 3376
Joined: Wed Sep 19, 2007 2:45 am

Post » Thu Jun 21, 2012 6:06 pm

I really don't wanna spoil your little conversation, but since results count more for me then theorys, I have to unfortunately tell @JustinOther, @rongphale and @Aenara were right. I've tested Justins script, and while it was acting much better then mine, it still itched with multiple keystrokes. Not as much as with the default script, but still noticeable. Using states however completely resolved it. The script looks now like that:

Spoiler
Scriptname SI_HotkeyScript extends Quest  GlobalVariable Property SI_HotkeyTorch AutoGlobalVariable Property SI_HotkeyTorch2 AutoGlobalVariable Property SI_HotkeyQuitGame AutoGlobalVariable Property SI_HotkeyToggleMenus AutoLight Property Torch01 Autobool TorchHotkeyPressedEvent OnInit()	RegisterForUpdate(0.1)EndEventAuto State InitState	Event OnUpdate()		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 1 && TorchHotkeyPressed == 0 && (Game.GetPlayer().GetItemCount(Torch01) > 0)			TorchHotkeyPressed = 1			Game.GetPlayer().EquipItem(Torch01)		Elseif  Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 1 && TorchHotkeypressed == 1			TorchHotkeyPressed = 0			Game.GetPlayer().UnequipItem(Torch01)		EndIf		GoToState("InitState")		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotKeyTorch2.GetValueInt()) == 1 && TorchHotkeyPressed == 0 && (Game.GetPlayer().GetItemCount(Torch01) > 0)			TorchHotkeyPressed = 1			Game.GetPlayer().EquipItem(Torch01)		Elseif  Input.IsKeyPressed(SI_HotKeyTorch2.GetValueInt()) == 1 && TorchHotkeypressed == 1			TorchHotkeyPressed = 0			Game.GetPlayer().UnequipItem(Torch01)		EndIf		GoToState("InitState")		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotkeyQuitGame.GetValueInt())			Debug.QuitGame()		Endif		GoToState("InitState")		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotkeyToggleMenus.GetValueInt())			Debug.ToggleMenus()		Endif		GoToState("InitState")	EndEventEndStateState DieThreadState  ; rongphale said die you stupid threads and dead you areEndState

The weird thing was I forgot to rename the deathState to DieThreadState before and this was acting even better, I assumed, could be wrong, was just a feelt response to how the hotkey was acting:

Spoiler
Scriptname SI_HotkeyScript extends Quest  GlobalVariable Property SI_HotkeyTorch AutoGlobalVariable Property SI_HotkeyTorch2 AutoGlobalVariable Property SI_HotkeyQuitGame AutoGlobalVariable Property SI_HotkeyToggleMenus AutoLight Property Torch01 Autobool TorchHotkeyPressedEvent OnInit()	RegisterForUpdate(0.1)EndEventAuto State InitState	Event OnUpdate()		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 1 && TorchHotkeyPressed == 0 && (Game.GetPlayer().GetItemCount(Torch01) > 0)			TorchHotkeyPressed = 1			Game.GetPlayer().EquipItem(Torch01)		Elseif  Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 1 && TorchHotkeypressed == 1			TorchHotkeyPressed = 0			Game.GetPlayer().UnequipItem(Torch01)		EndIf		GoToState("InitState")		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotKeyTorch2.GetValueInt()) == 1 && TorchHotkeyPressed == 0 && (Game.GetPlayer().GetItemCount(Torch01) > 0)			TorchHotkeyPressed = 1			Game.GetPlayer().EquipItem(Torch01)		Elseif  Input.IsKeyPressed(SI_HotKeyTorch2.GetValueInt()) == 1 && TorchHotkeypressed == 1			TorchHotkeyPressed = 0			Game.GetPlayer().UnequipItem(Torch01)		EndIf		GoToState("InitState")		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotkeyQuitGame.GetValueInt())			Debug.QuitGame()		Endif		GoToState("InitState")		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotkeyToggleMenus.GetValueInt())			Debug.ToggleMenus()		Endif		GoToState("InitState")	EndEventEndStateState deathState; <--------------------- difference right here!!!  ; rongphale said die you stupid threads and dead you areEndState

The only left over problem now was that the hotkey wasn't responding as good as the default hotkeys and kept on auto euipping/unequipping the torch when I hold the hotkey. But suddenly an enlightment lead my brain, and I was like "Why not put a function in there that prevents isKeyPressed from holding the key?" and I searched and found 'ReleaseKey' inside the input.psc. I put it inside the script, and while it didn't solved the auot equip/unequip, it felt like the key had a much more improved response. However, this seems to create the best result now:

Spoiler
Scriptname SI_HotkeyScript extends Quest  GlobalVariable Property SI_HotkeyTorch AutoGlobalVariable Property SI_HotkeyTorch2 AutoGlobalVariable Property SI_HotkeyQuitGame AutoGlobalVariable Property SI_HotkeyToggleMenus AutoLight Property Torch01 Autobool TorchHotkeyPressedEvent OnInit()	RegisterForUpdate(0.01)EndEventAuto State InitState	Event OnUpdate()		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 1 && TorchHotkeyPressed == 0 && (Game.GetPlayer().GetItemCount(Torch01) > 0)			Input.ReleaseKey(SI_HotKeyTorch.GetValueInt()); <------------------------- function to remove auto equip/unequip			TorchHotkeyPressed = 1			Game.GetPlayer().EquipItem(Torch01)		Elseif  Input.IsKeyPressed(SI_HotKeyTorch.GetValueInt()) == 1 && TorchHotkeypressed == 1			Input.ReleaseKey(SI_HotKeyTorch.GetValueInt())			TorchHotkeyPressed = 0			Game.GetPlayer().UnequipItem(Torch01)		EndIf		GoToState("InitState")		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotKeyTorch2.GetValueInt()) == 1 && TorchHotkeyPressed == 0 && (Game.GetPlayer().GetItemCount(Torch01) > 0)			Input.ReleaseKey(SI_HotKeyTorch2.GetValueInt())			TorchHotkeyPressed = 1			Game.GetPlayer().EquipItem(Torch01)		Elseif  Input.IsKeyPressed(SI_HotKeyTorch2.GetValueInt()) == 1 && TorchHotkeypressed == 1			Input.ReleaseKey(SI_HotKeyTorch2.GetValueInt())			TorchHotkeyPressed = 0			Game.GetPlayer().UnequipItem(Torch01)		EndIf		GoToState("InitState")		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotkeyQuitGame.GetValueInt())			Input.ReleaseKey(SI_HotKeyQuitGame.GetValueInt())			Debug.QuitGame()		Endif		GoToState("InitState")		GoToState("DieThreadState")		If Input.IsKeyPressed(SI_HotkeyToggleMenus.GetValueInt())			Input.ReleaseKey(SI_HotKeyToggleMenus.GetValueInt())			Debug.ToggleMenus()		Endif		GoToState("InitState")	EndEventEndStateState DieThreadState  ; rongphale said die you stupid threads and dead you areEndState

I'm still certain there's something wrong inside this script. I think the left over problems are because 'DieThreadState' is directly following the 'InitState', but since I've rely on results as mentioned before, this is how the script should do it's intented job right now. I'm open for improvements as always guys... :biggrin:

Oh yeah, and I probably have to extend the two additional hotkeys, as the toggle menu still seems to act weird. The quit game however works perfectly normal... :biggrin:

Edit: Oh yeah, and I forgot to mention, while yesterday I was a simple copypasta scripter, you guys catapulted me to apprentice level. Just listening to your conversations created so much enlightment, I couldn't even remotely get to understand this through numerous walls of text on the CI Wiki. I specially thank you for making me understand how "blind" threads work in such that they stop scripts from permanently auto updating. This will help a lot in future script developments...off to do some strongly needed code improvement on my Mod... :biggrin:
User avatar
Farrah Lee
 
Posts: 3488
Joined: Fri Aug 17, 2007 10:32 pm

Post » Thu Jun 21, 2012 3:40 am

I really don't wanna spoil your little conversation, but since results count more for me then theorys, I have to unfortunately tell @JustinOther, @rongphale and @Aenara were right. I've tested Justins script, and while it was acting much better then mine, it still itched with multiple keystrokes. Not as much as with the default script, but still noticeable.
Eh...? I tested it at 0.1 intervals ind it http://www.gamesas.com/topic/1375262-iskeypressed-equipunequip/page__view__findpost__p__20813045 responded to each keypress/release exactly once, although 0.5 would probably be fast enough. I GUARANTEEE it works and is far 'cheaper' than your current iteration, but, whatever...

"Another Update event will not fire until the executed one finishes. I got into a discussion about this somewhere. Only http://www.creationkit.com/Latent_Functions specifically spawn new instances within functions and events." -- http://www.gamesas.com/topic/1375262-iskeypressed-equipunequip/page__view__findpost__p__20813103

My code did not iterate more than once per keypress/release, under any circumstances. That's not theory, but observed fact.

With the below, all three keys work perfectly, no stuttering.
Spoiler
ScriptName TorchHotkeyScript extends Quest ConditionalBool bEquipTorchBool bMenuHotkeyPressedBool bTorchHotkeyPressedActor Property PlayerREF AutoInt Property iMenuHotkey Auto ConditionalInt Property iQuitGameHotkey Auto ConditionalInt Property iTorchHotkey Auto ConditionalLight Property Torch01 AutoEvent OnInit()	RegisterForUpdate(0.2)EndEventEvent OnUpdate()	If bTorchHotkeyPressed != Input.IsKeyPressed(iTorchHotkey)		bTorchHotkeyPressed = !bTorchHotkeyPressed		If bTorchHotkeyPressed			bEquipTorch = !bEquipTorch			If bEquipTorch				PlayerREF.EquipItem(Torch01)			Else				PlayerREF.UnequipItem(Torch01)			EndIf		EndIf	ElseIf bMenuHotkeyPressed != Input.IsKeyPressed(iMenuHotkey)		bMenuHotkeyPressed = !bMenuHotkeyPressed		If bMenuHotkeyPressed			Debug.ToggleMenus()		EndIf	ElseIf Input.IsKeyPressed(iQuitGameHotkey)		Debug.QuitGame()	EndIfEndEvent
...or...
ScriptName TorchHotkeyScript extends Quest ConditionalBool bEquipTorchBool bMenuHotkeyPressedBool bTorchHotkeyPressedActor Property PlayerREF AutoInt Property iMenuHotkey Auto ConditionalInt Property iQuitGameHotkey Auto ConditionalInt Property iTorchHotkey Auto ConditionalLight Property Torch01 AutoEvent OnInit()	RegisterForSingleUpdate(0.2)EndEventEvent OnUpdate()	If bTorchHotkeyPressed != Input.IsKeyPressed(iTorchHotkey)		bTorchHotkeyPressed = !bTorchHotkeyPressed		If bTorchHotkeyPressed			bEquipTorch = !bEquipTorch			If bEquipTorch				PlayerREF.EquipItem(Torch01)			Else				PlayerREF.UnequipItem(Torch01)			EndIf		EndIf	ElseIf bMenuHotkeyPressed != Input.IsKeyPressed(iMenuHotkey)		bMenuHotkeyPressed = !bMenuHotkeyPressed		If bMenuHotkeyPressed			Debug.ToggleMenus()		EndIf	ElseIf Input.IsKeyPressed(iQuitGameHotkey)		Debug.QuitGame()	EndIf	RegisterForSingleUpdate(0.2)EndEvent

Regardless of what you do, I've to emphasize you're http://www.gamesas.com/topic/1352280-most-efficient-way-of-referencing-the-player/page__view__findpost__p__20378748 for PlayerREF and hotkeys as GetPlayer() and GetValueInt() unnecessarily add 'expense' to your script.
User avatar
Vickytoria Vasquez
 
Posts: 3456
Joined: Thu Aug 31, 2006 7:06 pm

Post » Thu Jun 21, 2012 6:52 pm

Only http://www.creationkit.com/Latent_Functions specifically spawn new instances within functions and events

I'm not saying anything about this keypressed issue, but I think that calling functions from other scripts also allows other threads to enter your routine. It's only functions in the same script that are threadsafe, according to the http://www.creationkit.com/Threading_Notes_(Papyrus).
User avatar
Laura Elizabeth
 
Posts: 3454
Joined: Wed Oct 11, 2006 7:34 pm

Post » Thu Jun 21, 2012 6:59 pm

Eh...? I tested it at 0.1 intervals ind it http://www.gamesas.com/topic/1375262-iskeypressed-equipunequip/page__view__findpost__p__20813045 responded to each keypress/release exactly once, although 0.5 would probably be fast enough. I GUARANTEEE it works and is far 'cheaper' than your current iteration, but, whatever...

Your counter codes work exactly as it intended, BUT I think you misunderstanding the Debug itself

Event OnUpdate()	    If bHotkeyPressed != Input.IsKeyPressed(iTorchHotkey)			    bHotkeyPressed = !bHotkeyPressed ; Set bool to whatever it is not			    iCount += 1			    Debug.Trace("iCount: " + iCount)   <---------- [i][b]This is where the misunderstanding starts[/b][/i]			    If bHotkeyPressed					    bEquipTorch = !bEquipTorch					    If bEquipTorch							    PlayerREF.EquipItem(Torch01)					    Else							    PlayerREF.UnequipItem(Torch01)					    EndIf			    EndIf	    EndIfEndEvent

- Your counter's increment is nested inside a latent call., so it will only increment when Debug script let it.

- Debug script is a Singleton, which means only 1 instance of Debug at a time. Using a Singleton to test multi-threads is a bad idea, as Debug only process one thing at a time, while several OnUpdate's keep knocking at the door, begging to be processed

To get better result, maybe you could use a private int, let it be independent to any latent/Singleton/etc... increment it normally and only use Debug to print/trace it after the series of keystroke is over :ermm:

Again, if this is Vegas/Oblivion/Fallout3, I would have nothing to complain about your script, friend ;)
I found out about this threading-craziness after months working on my mounted combat mod (with the use of ScriptDragon and now SKSE). And I found out in a hard way too...


@Mofakin: I'm glad to hear it works for you. Although you have kinda ... too many GotoState inside a single Event, lol
User avatar
El Khatiri
 
Posts: 3568
Joined: Sat Sep 01, 2007 2:43 am

Post » Thu Jun 21, 2012 6:32 pm

Same exact result sans Debug. iCount increments once when the key is pressed and once when when it's released...
User avatar
Natalie Taylor
 
Posts: 3301
Joined: Mon Sep 11, 2006 7:54 pm

Post » Thu Jun 21, 2012 8:18 am

Justin, Justin...if it weren't for you, hell knows what I was going to do.

I recon there are minor changes in your last script. This however does what you tell, it works perfectly. No multiple threads, no slow response, no auto equip/unequip. I'm sorry, how did I become incredulous.

I promise, the other script didn't even remotely worked as well, but that one does. Justin 2:1 Other...:D

However. Just out of fun I've raised the OnUpdate to 0.01, and guess what...multiple threads. Maybe I should just combine your two scripts in order to get the best result. Or maybe not, it's working now, someone release it standalone before I do it.
User avatar
Jay Baby
 
Posts: 3369
Joined: Sat Sep 15, 2007 12:43 pm

Next

Return to V - Skyrim