UnderstandingUsing While LoopsArrays to do what I want to do

Post » Fri Nov 16, 2012 4:41 pm

So I'm trying to detect how many times "X" actor gets consecutively hit.

I.E., by increasing a counter by 1 per hit. But if the player stops hitting by not making a hit within 1-2 seconds from the last one, the counter would reset to zero.

I'm planning on, in another script (or possibly the same script) reading this counter to determine certain effects.


It seems really simple to do in my head, but I've been having trouble figuring out how to get it to work through papyrus, and I think the solution lies in while loops or arrays.

However, despite reading info on what those are, I'm still pretty confused on how to actually use them to do what I want to do, if that is even the best solution. Blame my noobishness to coding-related terminology and concepts :tongue: So how exactly do while loops and/or arrays work? How would I use them to do what I want to do?
User avatar
Kelly Osbourne Kelly
 
Posts: 3426
Joined: Sun Nov 05, 2006 6:56 pm

Post » Fri Nov 16, 2012 9:30 am

Hmm. Every time the player gets hit, UnregisterforUpdate, then RegisterforUpdate(1) or RegisterforUpdate(2). (I would make it 3, 1 or 2 seems unrealistic.) If the OnUpdateEvent fires, it then ends that part of the effect. I wouldn't use While loops at all; it's how I'd solve it in simpler programming, but not for this.
User avatar
Harry-James Payne
 
Posts: 3464
Joined: Wed May 09, 2007 6:58 am

Post » Fri Nov 16, 2012 7:05 pm

I would place a 'counter =+ 1' in an onHit event. Then right after that line I'd have it registerForSingleUpdate(1.0 or 2.0). In the onUpdate event, I'd have 'counter -= 1'. After that, I'd have a check to see if 'counter > 0' and if true, then run another regForSingUp(1 or 2.0). If false, then set 'counter = 0' and let the script expire. That's basically it.

The > 0 would be to ensure a ton of hits possibly causing the count to go below zero wouldn't accidentally cause the script to run perpetually. Setting the counter back to 0 would be for the next time the actor gets hit, it would ensure the correct starting point for that counter.

I agree with avoiding while loops or anything that loops faster than you REALLY need it to... this messes up other scripts and can potentially crash the whole game if TOO fast.

int counter = 0event onHit(whatever you want to be able to count towards being a 'hit')  counter =+ 1  registerForSingleUpdate(1.0)endEventevent onUpdate()  counter -= 1  if counter > 0    registerForSingleUpdate(1.0)  endifendEvent
User avatar
Wayland Neace
 
Posts: 3430
Joined: Sat Aug 11, 2007 9:01 am

Post » Fri Nov 16, 2012 2:32 pm

counter =+ 1
counter += 1

Also, the '> 0' isn't necessary as 'If counter' is cheaper and will be false when counter == 0.
User avatar
NAkeshIa BENNETT
 
Posts: 3519
Joined: Fri Jun 16, 2006 12:23 pm

Post » Fri Nov 16, 2012 9:42 pm

Cool.. I didn't know that about variables (just saying the name without the zero-test). And that =+ was a type-o.. heheheh thanks for pointing it out!
User avatar
Marguerite Dabrin
 
Posts: 3546
Joined: Tue Mar 20, 2007 11:33 am

Post » Sat Nov 17, 2012 12:20 am

Thanks for that bit of advice on counters, didn't know you could do that either.

So I'm to assume I don't need to deal with while loops and other such concepts :P Good! For now...
User avatar
James Potter
 
Posts: 3418
Joined: Sat Jul 07, 2007 11:40 am

Post » Fri Nov 16, 2012 12:27 pm

For this case, I definitely would NOT use while loops. If you ever do use them in the future, ensure that something inside it will slow it down so that it doesn't run top speed (eg- inserting a wait(0.1), at least). Having enough code inside it to SIMULATE it slowing down may appear to do so on slower systems, or if a bunch of mods are running with intense or erroneous scripting; but on high-end systems it would run much quicker and cause stack-dumping (studders in the timing, CTD, erratic behavior, etc).

Something I noticed that may cause a little drama in the above code: in the onHit event, rather than having a plain regForSingUp.. I would use a check similar to the one I posted in the onUpdate event. Since we have the register function in the onUpdate event to keep it going once started, by putting another one in the onHit event it may double-up and cause unexpected behavior.

I also realised that the check in the onUpdate event (> 0) may still be necessary if removing it doesn't work for negative numbers (I think it only checks if the variable isn't zero). Knowing what I've seen with Papyrus and timing issues, there's a SLIGHT possibility that number could go negative, if the actor is bombarded by hits. Those hits SHOULD count back down as expected (since adding the check in the onHit event); but just to make sure, I would leave the > 0 there. In a script this slow (1sec or more in your case), the extra little time to check the variable to an actual number (instead of just the 'if counter') wouldn't make any difference; that's why I would leave it.. just in case.

The <= 1 would also help prevent unexpected behavior; but is probably more overkill than the above. I've seen Papyrus do strange things, and if you already have the check doing a ==, then I see no harm in ensuring strange circumstance doesn't affect anything by changing it to <=.

int counter = 0event onHit(whatever you want to be able to count towards being a 'hit')  counter += 1  if counter <= 1    registerForSingleUpdate(1.0)  endifendEventevent onUpdate()  counter -= 1  if counter > 0    registerForSingleUpdate(1.0)  endifendEvent
User avatar
Destinyscharm
 
Posts: 3404
Joined: Sun Jul 23, 2006 6:06 pm

Post » Fri Nov 16, 2012 10:10 pm

Quick question on the above...


Does the "Register for Single Update" thing reset every time a hit is made? I.E. if I make another hit before the 1-second window of Register For Update, does it reset that RegisterForUpdate time (instead of executing it so my counter continues to rise) until I stop and let it update? Because if so, then it'll work with what I want to do. If not, then it won't work (because the counter would just constantly count down every second, and I'd have to make hits faster than its counting in order to overcome it. I need to be able to see exactly what hit consecutive-hits are).

Keep in mind I don't want the script to reset the counter to zero unless I've not made any hits within the past second or two. But if I have, then have it continue to count. If making a hit before RegisterForUpdate has a chance to fire prevents it from firing, then it'll work great.

Also, assuming I'm using an active magic effect instead of OnHit, would I still get the same effect if the above was true? The thing is, I'm using the perk system to apply a combat spell to actors I hit (and all the spell does, is increase or reset the counter if no more hits were made). That is one of the only ways to do what I want to do and have it so I can take full advantage of the Perk's robust condition checkers instead of relying on papryus for that. Part of the problem with Papyrus having no means to detect when attacks are made with certain types of weapons and attack styles, but the Perk system has plenty of conditions that can check for that stuff.



I.E.:

Player makes a hit with valid weapon type using a valid attack style, independent of who exactly he hit.

Game: "Hmm, player made the correct hits with a correct attack style. We'll increase the hit counter by one."

Player continues making valid hits/attacks.

Game: "Player continues to land valid attacks, so we'll continue to increase the hit counter by one."

Player performs a non valid attack type (i.e. powerattack instead of doing a normal one).

Game: "Player just made a powerattack when I'm told to check only for standard attacks. We'll not count this as a valid hit." (This is determined in the perk ability conditions).

Player then stops attacking.

Game: "Because the player hasn't made any valid hits within the past two seconds, we'll go ahead and reset the hit counter back to zero."

Meanwhile, the player has an ability that checks for what level this counter is at, and performs effects based on it.
User avatar
James Baldwin
 
Posts: 3366
Joined: Tue Jun 05, 2007 11:11 am

Post » Fri Nov 16, 2012 6:29 pm

registerforsingleupdate will override itself (taking on the timer value of the newest register). a script can only register for an update event once at a time (which is what makes that function REALLY handy)
User avatar
Victoria Bartel
 
Posts: 3325
Joined: Tue Apr 10, 2007 10:20 am

Post » Fri Nov 16, 2012 10:36 pm

Wow, great to know. So if I'm applying this script via a script-spell cast onto enemies instead of directly attaching a script to a specific actor, will each hit I make cast a different instance of the spell (therefore, not causing the RegisterForUpdate to reset, as each instance of the spell would run its own script), or will it simply over-write the existing instance of the spell?
User avatar
Anna Krzyzanowska
 
Posts: 3330
Joined: Thu Aug 03, 2006 3:08 am

Post » Fri Nov 16, 2012 1:19 pm

they would each register separately from each other, since the script is being applied in multiple instances. what you could do is create a master script with only an update event in it (probably attach this on a quest or something), and have each mgef register to update the master script's update event. that way all mgef scripts will cancel each other's registers when you need them to
User avatar
Stephanie Kemp
 
Posts: 3329
Joined: Sun Jun 25, 2006 12:39 am

Post » Fri Nov 16, 2012 11:40 pm

How would I register an update on the master script? That sounds exactly what I need to do, but I wasn't aware you could remotely register/unregister updates across other scripts.
User avatar
Christine
 
Posts: 3442
Joined: Thu Dec 14, 2006 12:52 am

Post » Fri Nov 16, 2012 8:12 pm

declare and fill a quest property pointing to your quest that contains the script

then use

(QuestProperty as QuestScript).RegisterForSingleUpdate(#.#)


replace QuestProperty with the name of your declared property and QuestScript with the name of the script attached to the quest.

the code will register for that script's update and will run the OnUpdate block in that script
User avatar
Kelly Osbourne Kelly
 
Posts: 3426
Joined: Sun Nov 05, 2006 6:56 pm

Post » Fri Nov 16, 2012 8:36 pm

You could also store the counter in a global variable... which would be polled from a master script. I haven't messed around with perks or magicEffects yet so am not too familiar with them.

But as written, the above code won't do what you want... for more than one resaon. I was thinking you wanted to count how many times Player got hit (sorry!). Say you land 10 hits in 3 seconds... then stop attacking. The above code would take 10 seconds to clear - not clear after one second of 'silence' as you want. If Amethyst is correct, the code below would be more of what you'd use in a 'master' script. (I didn't know that was the case about regSingles nullifying each other.. strange things I've seen led me to believe otherwise, but I never explored it).

int counter = 0event onHit(whatever you want to be able to count towards being a 'hit')  counter += 1  registerForSingleUpdate(1.0)endEventevent onUpdate()  counter = 0endEvent

According to Amethyst, if you continue to land hits, the inUpdate event will never run until your desired time has expired. To apply this to EVERY actor in the game may require altering a Vanilla script.. which I don't recommend. Again, I know nothing of perks; so I dunno if there's a way you can pull this off for ALL actors. But if you only want it to apply to special/custom actors (eg: a training environment, or a certain scene); then the above should work.

Using the method described for accessing other scripts, I would put the onHit event in that other script, attached to the actors; but they would be controlling the counter and regForSingUp in the master script (wherever you attach or run it from). Personally, I avoid alias-driven stuff as much as possible.. but that's just a personal preference, and to do what you want you may HAVE to.
User avatar
Amy Siebenhaar
 
Posts: 3426
Joined: Fri Aug 10, 2007 1:51 am

Post » Fri Nov 16, 2012 1:05 pm

@sluckyD - ive been using regsingle extensively and its the only way i know for a fact (regsingle + onUpdate) you can control papyrus threading with 100% accuracy.

regsingle = guaranteed thread kill (killing all previous requests)

onUpdate = guaranteed new thread (using real-time values and not threaded ones)



for example compare


If (someCondition)
SomeValue = http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/1
Utility.Wait(1)

If Somevalue =http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/= 1
SomeValue = http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/2
EndIf

EndIf


vs


If (someCondition)
SomeValue = http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/1
RegisterForSingleUpdate(1)

EndIf

Event OnUpdate()

If Somevalue =http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/= 1
SomeValue = http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/2
EndIf
EndEvent



in the first example, Somevalue will always == 1 when it hits the If statement regarless of the time wait of 1 second, and another script has changed the value of SomeValue to 2

using reg/update the value of SomeValue will always pull from the actual real-time value that has been changed externally from another script function.


this is why registering abides by the rule of 1, it HAS to remain in real-time and not threaded or cached otherwise it defeates the whole point.
User avatar
Julie Serebrekoff
 
Posts: 3359
Joined: Sun Dec 24, 2006 4:41 am

Post » Fri Nov 16, 2012 8:33 am

Wonderful, this is very good information. Will be useful for future scripts I'll want to work on as well.

Had no idea that SingleUpdates weren't threaded. This'll allow for things that require precise timing too (nothing I need right now calls for exact timing but I might need it in the future).
User avatar
Rik Douglas
 
Posts: 3385
Joined: Sat Jul 07, 2007 1:40 pm

Post » Fri Nov 16, 2012 10:53 am

I might disagree, Amethyst. It doesn't take up another thread, but it will stack to the same thread if the register interval is too short for the system/engine to complete before the next one is fired. I don't know if caching and stacking are the same thing, but it sounds like it. I couldn't find the phrase "rule of one" (outside of Star Wars references) in any quick searches (google or ck wiki), so I'm not sure what you're trying to explain there - I'm under the impression it meant that in-game, only one form could have a certain ID#, overriding other plugins or masters that have the same... I've never heard it applied to scripting.

I discovered the stacking effect, as pertaining to variables and movement, months ago and posted it here - http://www.gamesas.com/topic/1370110-impact-of-system-stress-scripting-errors-on-game-performance/ (though not the OP, a couple down), and on my ship mod's comment section. Originally, my boat script RELIED on stacking.. but I quickly found it to be unreliable depending on system performance. Some systems would studder while others worked, and others yet would CTD.

During this testing, http://www.gamesas.com/topic/1386736-performance-timing-testing-using-scripted-movement/, I have a platform that moves by Player moving forward or backward to control the speed (conditional checks in a repeating quest). The platform is steered to Player's current heading. Now if the reg interval was too fast, the platform's controls would lag and eventually become erratic (stack-dumps).

EG: I would press forward to get the platform moving. I would then cause it to turn left then right then left, over about 3 seconds. If the script was stacking, that smooth lrl movement wouldn't occur for a few seconds - but it did eventually, and how I told it to. If the script was NOT stacking, then the lrl movements actually cut each other off (if close enough together). I already knew that translateTo cancels a transTo already in progress and seemlessly picks up the next one... which my script STILL relies on for smooth real-time movement.

As for the examples you give above, theoretically both scripts should return two after running... Since the interval and waits are so slow, this doesn't show stacking. I just did the following test to see if this is the case. This script, most of which was cut/paste from your post, was attached to a metalLever01 placed in whiterunExterior16.

Spoiler

scriptName aatest extends objectReferenceint someValue = http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/0event onActivate(objectReference triggerRef)	SomeValue = 1	Utility.Wait(1)	If Somevalue == 1		SomeValue = 2	EndIf	Utility.Wait(1)	debug.notification(someValue)	startReg()endEventfunction startReg()	SomeValue = 3	RegisterForSingleUpdate(1)endFunctionEvent OnUpdate()	If Somevalue == 3	  SomeValue = 4	EndIf	Utility.Wait(1)	debug.notification(someValue)EndEvent

Notice I changed the variables' values slightly (for better tracking), and removed the if-endif checks for (someCondition). It returned 2 and 4, as expected (where your example would return 2 and 2). But when I added more code to force the update event to repeat, and to simulate external influence with a custom function, it starts to do weird things.

Spoiler

event onActivate(objectReference triggerRef)	SomeValue = http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/1	Utility.Wait(1)	If Somevalue == 1		SomeValue = 2	EndIf	Utility.Wait(1)	debug.notification(someValue)	startReg()	Utility.Wait(2)	someValue = 5	startReg()	Utility.Wait(2)	someValue = 6	startReg()	Utility.Wait(2)	someValue = 7	startReg()	Utility.Wait(2)	someValue = 8	startReg()endEventfunction startReg()	SomeValue = 3	RegisterForSingleUpdate(1)endFunctionEvent OnUpdate()	If Somevalue == 3	  SomeValue = 4	EndIf	Utility.Wait(1)	debug.notification(someValue)EndEvent

It returned 2,3,3,4. Theoretically, it should have returned 2,4,4,4,4,4 correct? Why were ANY 3s shown, much less two of them?? And why were two notifs not even shown (and presumably not run)? The timing is enough that the update events don't overlap (the regSing cancelling each other theory wouldn't apply). In my experience, running custom functions from the onActivate loop is buggy and sometimes won't fire, or the timing will be WAY off (ie: a bug in Papyrus somewhere)... I have no idea how this could happen otherwise.

To further test the onActivate-bug theory, I made the following changes.

Spoiler

event onActivate(objectReference triggerRef)	SomeValue = http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/1	Utility.Wait(1)	If Somevalue == 1		SomeValue = 2	EndIf	Utility.Wait(1)	debug.notification(someValue)	RegisterForSingleUpdate(1)endEventfunction startReg()	SomeValue = 3	If Somevalue == 3		SomeValue = 4	EndIf	Utility.Wait(1)	debug.notification(someValue)endFunctionEvent OnUpdate()	startReg()	Utility.Wait(2)	someValue = 5	startReg()	Utility.Wait(2)	someValue = 6	startReg()	Utility.Wait(2)	someValue = 7	startReg()	Utility.Wait(2)	someValue = 8	startReg()	debug.notification("done")EndEvent

This returned 2,4,(hesitation) 4,4,done.. but shouldn't it return 2,4,4,4,4,4,done? What the hell is going on here? I thought functions have to complete before the rest of the code continues... even if that isn't the case, the waits are long enough so that the notif in the function should still fire correctly.

None of this illustrates the 'stacking effect' though. In order to actually see those effects, the interval must be tiny enough to overload the individual system... which is difficult to quanitfy using notifs. I'll see if I can devise a test using notifs that can show stacking and post separately if I figure something out.

The above tests only serve to show that seemingly buggy behavior happens for no apparent reason... and I now need to find out how and why; am I missing something here? If I can't figure this out quickly (or someone can explain what's going on) - it may destroy my will to mod Skyrim... which is already severely waning for reasons I don't want to go into here.
User avatar
Victor Oropeza
 
Posts: 3362
Joined: Sun Aug 12, 2007 4:23 pm

Post » Fri Nov 16, 2012 10:03 pm

Ok, it's getting worse now... this shows neither the onActivate nor the custom function is to blame.

This return 2,4,4 done. It should show 2,4,4,4,4,4,done.

Spoiler

scriptName aatest extends objectReferenceint someValue = http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/0int counter = 0event onActivate(objectReference triggerRef)	SomeValue = 1	Utility.Wait(1)	If Somevalue == 1		SomeValue = 2	EndIf	Utility.Wait(1)	debug.notification(someValue)	RegisterForUpdate(1)endEvent	Event OnUpdate()	SomeValue = 3	If Somevalue == 3		SomeValue = 4	EndIf	Utility.Wait(1)	debug.notification(someValue)	counter += 1	if counter == 6		unregisterForUpdate()		debug.notification("done")	endifEndEvent

Is it the notification function that's buggy? In my experience (especially in the test linked to above, about movement timing), notifs will show three deep - as in 2,4,4 if they were fired close enough together.. then the engine waits for one of those three to disappear before showing the next notif - which stack and are eventually shown.

The following returns 2,4,4,done. This shows me that it isn't the update event that's to blame.

Spoiler

scriptName aatest extends objectReferenceint someValue = http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/0int counter = 0event onActivate(objectReference triggerRef)	SomeValue = 1	Utility.Wait(1)	If Somevalue == 1		SomeValue = 2	EndIf	Utility.Wait(1)	debug.notification(someValue)	regFunction()endEvent	function regFunction()	SomeValue = 3	If Somevalue == 3		SomeValue = 4	EndIf	Utility.Wait(1)	debug.notification(someValue)	counter += 1	if counter == 6		unregisterForUpdate()		debug.notification("done")	else		regFire()	endifendFunctionfunction regFire()	regFunction()endFunction

This returns the SAME 2,4,4,done.... which leads me to believe it's the notif function that's buggy, or the game engine being picky-choosy about what it feels like showing. This one shows a while-loop in the onActivate.. to add pertinence toward the OP. Why is it dropping half of the notifs?

Spoiler

event onActivate(objectReference triggerRef)	SomeValue = http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/1	Utility.Wait(1)	If Somevalue == 1		SomeValue = 2	EndIf	Utility.Wait(1)	debug.notification(someValue)	while counter < 6		SomeValue = 3		If Somevalue == 3			SomeValue = 4		EndIf		Utility.Wait(1)		debug.notification(someValue)	counter += 1	endWhile	debug.notification("done")endEvent

SOLVED IT. It's the notification function that's either buggy, not firing, or not being shown by the engine properly. The following script adds an xMarker next to the lever, and placeAtMe's a basket. All the baskets appear, but still only half the notifs show... it seems #s 3,4,5 are the notifs that got skipped.

Spoiler

scriptName aatest extends objectReferenceint someValue = http://forums.bethsoft.com/topic/1389486-understandingusing-while-loopsarrays-to-do-what-i-want-to-do/0int counter = 0objectReference property xTest autoMiscObject property basket01 autoevent onActivate(objectReference triggerRef)	SomeValue = 1	Utility.Wait(1)	If Somevalue == 1		SomeValue = 2	EndIf	Utility.Wait(1)	debug.notification(someValue)	while counter < 6		SomeValue = 3		If Somevalue == 3			SomeValue = 4		EndIf		Utility.Wait(1)		debug.notification(someValue)		xTest.placeAtMe(basket01)	counter += 1	endWhile	debug.notification("done")endEvent

The moral of the story that I'M taking away from this drama is that debug-notifs are an unreliable way to test things in-game. This undermines my will to mod, but at least it hasn't destroyed it as a buggy onUpdate event or function would have. Now I wonder if debug-tracing is just as buggy...

[EDIT: nope... tracing works as it should; but it svcks because I can't see certain things while still in-game. I really wish things would work properly - 3/4 of a year after it's release and I can't even do something as fundamental and simple as debug the way I should be able to... Do I hear CryEngine on the horizon?]
User avatar
Brentleah Jeffs
 
Posts: 3341
Joined: Tue Feb 13, 2007 12:21 am

Post » Fri Nov 16, 2012 3:09 pm

give me a minute. im in the middle of doing 14 things right now. but i can say, the test you ran in your first post is not what i'm talking about

in any case i was able to kill the mannequin dupe bug forever solely because of the fact that regsingle's cancel and force a new real-time update (thus never giving the equiparmor function a chance to ever return an old value) if regsingles stacked, this would not even be possible to do using the script i have

brb
User avatar
Penny Wills
 
Posts: 3474
Joined: Wed Sep 27, 2006 6:16 pm

Post » Fri Nov 16, 2012 5:51 pm

Well if anyone cares for an update on the OP, here's what things look like that got it working exactly as intended thanks to some help in this thread.

1. Perk that casts a spell ability on enemies when I hit them, through "Activate Combat Hit Spell" entry point (or similarly worded). This spell ability (it must be an ability to work with the perk entry point) simply runs an OnEffectStart script that adds 1 to my GlobalVariable Hit Counter. It then registers for an update on my QuestCounterResetScript, using the methods Amethyst describe in this thread. After that, it removes the spell from the "akTarget" (because Abilities are permanent when applied to NPC's, so you have to remove them in order to cast the same ability on it a second time).

2. Meanwhile, my QuestCounterResetScript simply runs on an "OnUpdate" event, that resets my Hit Counter back to zero. So, if my RegisterForSingleUpdate from the script in #1 ever successfully fires within the time I set for it, it'll trigger the on update in the QuestCounter script, resetting my counter back to zero.

3. Meanwhile, I have a seperate script attached to the player via a quest that is set to detect what level this counter is at, and correctly output the level with a 2nd global variable (so I can track if that part of my ability is working). It as well, does the affect I want to (increase weapon speed depending on counter level).


Works perfect :)

If I hit continuously without powerattacking and with a greatsword, my Counter will increase by one for each consecutive hit. My ability will also correctly output the "level" my ability is at. The moment I stop attacking, or attack with a powerattack, both my ability will reset and my counter resets back to zero.
User avatar
Emmie Cate
 
Posts: 3372
Joined: Sun Mar 11, 2007 12:01 am

Post » Fri Nov 16, 2012 7:02 pm

Example 1

I set up 2 barrels next to each other and applied this script to barrel 1
Spoiler

Scriptname aaatest1 extends ObjectReferenceGlobalVariable Property TestGlob  AutoEvent OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)RegisterForSingleUpdate(10)TestGlob.Value += 2EndEventEvent OnUpdate()TestGlob.Value += 10EndEvent



and this to barrel 2

Spoiler

Scriptname aaatest2 extends ObjectReferenceGlobalVariable Property TestGlob autoEvent OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)RegisterForSingleUpdate(1)EndEventEvent OnUpdate()TestGlob.Value += 13EndEvent


ShowGlobalVars TestGlob == 24

BOTH updates fired from each script as i mentioned would happen above







Example 2

same script on barrel 1


new script on barrel 2

Spoiler

Scriptname aaatest2 extends ObjectReferenceGlobalVariable Property TestGlob autoObjectReference Property Barrel  AutoEvent OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)(Barrel as aaatest1).RegisterForSingleUpdate(1)EndEventEvent OnUpdate()TestGlob.Value += 13EndEvent


ShowGlobalVars TestGlob == 11


Barrel 2 CANCELLED Barrel 1's register, exactly as i said above, which is why korjax's master script thing worked as i expected.



that example i posted afterwards was a bad example admittedly, because it was too simple. in that case, the Wait was able to successfully keep up with the thread because the script was way too easy to process. there is a fundamental difference between Wait and RegisterSingle, though. when your script starts having complex interwoven function calls across multiple scripts (such as synching up 12 mannequins simultaneously oncellattach) and is too hefty for papyrus to digest at once the Wait will fail to keep up with real-time values when the threading queue is clogged. Register/Update will kill and refresh in real time. thats the whole point of it.


(yes, i'm aware the math doesn't add up, but thats exactly why i never use globals, but the point i'm illustrating stands)
User avatar
benjamin corsini
 
Posts: 3411
Joined: Tue Jul 31, 2007 11:32 pm

Post » Fri Nov 16, 2012 8:59 am

btw "rule of 1" = last hand wins

Script 1 called register first and threw down its card (but has to wait 10 seconds for its update to come in).

script 2 called register on script 1's update (with only 1 second delay) and threw down its card on top of script 1's card. before script 1's update could come in.

since there are now 2 registers for the same script, rule of 1 dictates last hand wins = script 2. the remaining seconds on script 1s original register is ignored. this is by design, otherwise register/update is pointless
User avatar
Danel
 
Posts: 3417
Joined: Tue Feb 27, 2007 8:35 pm

Post » Fri Nov 16, 2012 2:32 pm

Ok, it's getting worse now... this shows neither the onActivate nor the custom function is to blame.

This return 2,4,4 done. It should show 2,4,4,4,4,4,done.

Is it the notification function that's buggy? In my experience (especially in the test linked to above, about movement timing), notifs will show three deep - as in 2,4,4 if they were fired close enough together.. then the engine waits for one of those three to disappear before showing the next notif - which stack and are eventually shown.

"It's not a bug it's a feature." Sending the exact same message two times in a row triggers a spam filtering mode which hides the following messages. The only thing I haven't bothered to check is whether it only hides more of that same message or if it hides all new messages for the next few seconds like it did in Oblivion. I'm assuming it works like Oblivion and hides all new messages for a little while.

If you really need to watch values, try the Trace function. It doesn't seem to have the filter.
User avatar
jessica sonny
 
Posts: 3531
Joined: Thu Nov 02, 2006 6:27 pm

Post » Fri Nov 16, 2012 1:57 pm

cdcooley: It's cool you got it working. It sounds like a cool effect - is it the mod in your sig (perks n skills adv)? I've learned some things about perks/etc from YOU, for when/if I ever need it! But yea, I know trace works.. but I like to see things in-game for certain testing. The trace only shows that it happened, but it's hard to know the impact in-game.

heheheh - I wouldn't call that a feature of a DEBUG function... more like a curse (or a feature for a non-existent MESSAGE option). Why'd they have to go and get rid of the 'message "blah blah"' thing from Obliv? Thankfully I don't have a use for it in a real mod - but timing-testing and whatnot is limited.


Amethyst: I see what you're saying now about them cancelling. I was kinda wondering how you did that, but now I see with two refs and two scripts. I still think that if either of them looped, it would stack and throw things off though... I haven't gotten to making a test for this yet. When I get a chance, I'll modify your scripts above to repeat; or modify the 'platform test' mod to dump into a second object as you show.

And it isn't pointless; it's just that we're trying to push the function/language past what it was presumably intended for... that being (in my opinion), to have a timed interval that you don't need to constantly unreg/rereg for. Also.. with a flat regForUp, that event runs (theoretically) with or without the previous block finishing; I think this is what causes the actual stacking. This as opposed to running independent calls for regForSing. As you say, one regForSing would cancel another... but is it only if it hasn't begun yet? I think it may stack if one is already in progress is my point; but I'll be testing this when I can (as my ship mod depends heavily on this).

I'll post over to that movement timing thread any results or answers I find - I've kinda hijacked this thread enough heheh.

[EDIT: It seems you took a different approach to mannequin duping than I did. I solved it months ago by adding an onItemRemove event, which the Vanilla script lacked. The problem was that the slot wasn't properly cleared when the item was removed, not the equipCurrArmor function. I think the onObjectUnequipped event was/is buggy (ie: doesn't run if in the same inventory 'session' as when it was added)... so I essentially changed it to the remove thing.]
User avatar
Charles Weber
 
Posts: 3447
Joined: Wed Aug 08, 2007 5:14 pm

Post » Fri Nov 16, 2012 8:52 pm

if you have 2 scripts registering a loop on the same update call it will of course cause problems, but the problem is not in the design at that point. it would not be dissimilar to saying that Driver's Ed dual-steering wheel vehicles (do those even exist anymore? god i feel old) should never have been made because any random 2 people (a non-instructor) could potentially cause an accident by turning the wheels at the same time.


the concept of register/update (primarilly the kill/refresh aspect of it) is not invented by papyrus (if memory serves, either javascript or C# or whatever language Unity3D uses has one as well, that serves this exact same purpose, where while loop would otherwise be the same thing). you NEED to have this type of function for anything that has the potential of stacking threads. otherwise why not just stick with wait/while if register/update does the same thing.


anyway, once the update event is called it is threaded into the spool, so while that block is executing, another register can happen, but as far as i know, update can only run once at a time (if i am correct, this is again "failsafe'd" by design) you can regupdate (0.001) on a loop but the loop will only cycle as fast as papyrus can crunch the block in its entirety (which is why fast loops are entirely dependent on available resources and frame rate). it will never run multiple update blocks simultaneously (on the same script). like i said i havent fully tested this, but if it does, it would be a bug. update should never be allowed to run multiple threads. that would contradict its own definition. you have to have a real-time failsafe.

you will always be able to run multiple updates that happen on separate scripts (which then becomes a bottlenecking competition) but never on the same script. what you really need to watch out for is having 2 separate fast loops writing to the same global (there is no failsafe for that - again, dual wheel vehicle anology applies).


edit: you can also override register on itself by using only a single script btw, which is also by design and reaaaaaaaly comes in handy
User avatar
Chris Jones
 
Posts: 3435
Joined: Wed May 09, 2007 3:11 am

Next

Return to V - Skyrim