Jump to content

While Loop, Timers, Variables, and Scope


Recommended Posts

Hi all,

 

I'm struggling to wrap my head around a solution to this script problem I face. I have a moveable static, and I'm attaching a light to it via PlaceAtNode. The MSTT's FX animation lasts 8 seconds, so for those 8 seconds I want the light to move with it (SplineTranslateToRef is visually adequate) as it havok's around, then die after the 8 seconds.

 

What I can't seem to grasp is how to get the OnTimer event to fire while the OnLoad while.. loop is running. I've tried passing both a local boolean and a global as the "while" condition that's changing when the timer expires. As it stands the While...Loop runs forever. I reeeeeeeeally don't want to do something like "while <iVar> < 8, translate and utility.wait(0.1)" because I've tried that and it looks horrible.

Below is the relevant section of code.

bool TimerExpired = False

Event OnInit()
	SelfREF = Self as ObjectReference
	StartTimer(8,1)
EndEvent

Event OnLoad()
	LightREF = SelfREF.PlaceAtNode("LightAttachPoint", LightToPlace, 1, False, False, True, False)

	while MMD_TimesUp.GetValue() as float == 0.0  ;/// I've also tried "while TimerExpired == False ///;
		LightRef.SplineTranslateToRefNode(SelfREF, "LightAttachPoint", 1.0, 1200)
	EndWhile

        LightREF.Delete()	
        LightREF = None

EndEvent

Event OnTimer(int aiTimerID)
	if aiTimerID == 1
		Debug.Notification("Times up!")
		MMD_TimesUp.SetValue(1.0)  ;///I've also tried TimerExpired = True///;
	endif
endevent

Edited by mmdestiny
Link to comment
Share on other sites

Your "while" loops forever because your global's value is never changing while it loops, you do need to increment it for it to move on - and it'd be probably be simpler to use an Int than a Global. Since the "while" locks your function till it completes, your OnTimer event never gets to fire.

 

But if you don't want to use utility.wait(whatever time you want) and iVar += 1, I really can't think of another way to do this - provided I understood correctly that you want to repeat your SplineTranslateToRefNode function several times for a duration of 8 seconds.

Link to comment
Share on other sites

Two things pop: SelfREF is defined in the OnInt() scope so it should not actually be visible to the OnLoad() block, and I never trust stuff kicked by OnInt(), can you move StartTimer to the top of OnLoad ?

bool TimerExpired = False

Event OnLoad()
	SelfREF = Self as ObjectReference
	LightREF = SelfREF.PlaceAtNode("LightAttachPoint", LightToPlace, 1, False, False, True, False)
	StartTimer(8,1)
	while TimerExpired == FALSE
		LightRef.SplineTranslateToRefNode(SelfREF, "LightAttachPoint", 1.0, 1200)
	EndWhile
    LightREF.Delete()	;LightREF will cleanup with the OnLoad block
EndEvent

Event OnTimer(int aiTimerID)
	if aiTimerID == 1
	TimerExpired == TRUE
	endif
endevent
Link to comment
Share on other sites

Your "while" loops forever because your global's value is never changing while it loops, you do need to increment it for it to move on - and it'd be probably be simpler to use an Int than a Global. Since the "while" locks your function till it completes, your OnTimer event never gets to fire.

 

But if you don't want to use utility.wait(whatever time you want) and iVar += 1, I really can't think of another way to do this - provided I understood correctly that you want to repeat your SplineTranslateToRefNode function several times for a duration of 8 seconds.

As you'll notice in one of the comments in the code, my first try was with bool TimerExpired because it was simpler, but that didn't work so I tried the global out of desperation. The reason to continually update the SplineTranslate is that this MSTT can spawn in the air, and the speed of gravity is such that if I need to keep firing to keep up with the fall. Utility.Wait causes a really ugly skipping affect.

 

I did find a partial answer by calculating how many times the SplineTranslate line could fire in 8 seconds (about 425), and tried "While [someinteger] < 425 ...Loop". However, this would be inconsistent and obviously be different for each person's game because the papyrus load for each user would be different depending on mods installed, what they're doing, etc, so I don't think that's a usuable solution.

 

I suppose maybe I can just set things up so it can't spawn in the air, that would at least minimize the havok headache :(

 

 

Two things pop: SelfREF is defined in the OnInt() scope so it should not actually be visible to the OnLoad() block, and I never trust stuff kicked by OnInt(), can you move StartTimer to the top of OnLoad ?

 

Funnily enough, SelfREF is indeed visible in OnLoad. Everything in the code is tested and works, except when I introduce the timer into the loop (i.e. "LightRef.SplineTranslateToRefNode(SelfREF, "LightAttachPoint", 1.0, 1200)" works in integer loops, with Utility.Wait, etc).

I have tried putting the timer in the OnLoad as you suggest, but as Hoamaii confirmed, it's all moot because no other events (i.e. OnTimer) can fire during a while loop.

 

I've tested this by starting a 10 second timer, running a while loop with 10x Utility.Wait(1.0), and a debug message OnTimer. Sure enough, the debug message doesn't fire until 10 seconds AFTER the 10 second While loop.

Edited by mmdestiny
Link to comment
Share on other sites

Yeah, I would have suggested you calculate how many times you need to fire that SplineTranslate to fire, but not every modder is as patient as I tend to be when I set my mind to solving an issue, but 425 times!.. Wow, yeah, chances are script latency in other games (and even yours, as it changes all the time) will mess up your calculations completely. Plus yes, using "wait" is not that accurate, and would probably cause some strange visual effects.

 

Have you tried to look at it completely differently, like working on the nifs instead for instance? What I mean is attaching you light to the node you want directly in Nifskope to create an alternate movable static object that you could release to havok, and then disable it with your script and replace it with a lightless version of the same movable (or not movable) static once the first animation has done playing? SetMotionType could help you control that second nif's reaction to havok as you want.

 

It's a workaround, I know, but in some cases when you can't exactly achieve what you want, they're worth a try.

Link to comment
Share on other sites

Instead of fussing with constant calls to SplineTranslateToRefNode (or directly editing the NIF) try just setting the last parameter of PlaceAtNode to true which seems designed to do the exact thing you want: attach the light to the parent object and keep it there.

 

Event OnLoad()
	ObjectReference LightREF = Self.PlaceAtNode("LightAttachPoint", LightToPlace, 1, False, False, True, True)
	Utility.Wait(8)
	LightREF.Delete()
	LightREF = none
EndEvent
Edited by Reneer
Link to comment
Share on other sites

Instead of fussing with constant calls to SplineTranslateToRefNode (or directly editing the NIF) try just setting the last parameter of PlaceAtNode to true which seems designed to do the exact thing you want: attach the light to the parent object and keep it there.

 

Event OnLoad()
	ObjectReference LightREF = Self.PlaceAtNode("LightAttachPoint", LightToPlace, 1, False, False, True, True)
	Utility.Wait(8)
	LightREF.Delete()
	LightREF = none
EndEvent

 

I was really excited when I read your post, Reneer, but alas the light still sticks to the same location as the MSTT's original spawn, and does not havok with it. I believe that parameter only "attached" it to the parent object for instances such as moving the parent object with SetPosition, MoveTo, etc, where the parent object is literally teleported somewhere, not as a result of physics.

 

 

Have you tried to look at it completely differently, like working on the nifs instead for instance? What I mean is attaching you light to the node you want directly in Nifskope to create an alternate movable static object that you could release to havok, and then disable it with your script and replace it with a lightless version of the same movable (or not movable) static once the first animation has done playing? SetMotionType could help you control that second nif's reaction to havok as you want.

 

It's a workaround, I know, but in some cases when you can't exactly achieve what you want, they're worth a try.

 

I did find a somewhat tolerable alternative. Long story short, this is a thrown weapon that on explosion creates a placed, animated version of itself (the MSTT, which I attach a light to via script) - based off how the artillery flare works. If I can stomach having the object lit up from the start, I can just make the projectile nif be the animated one and set the projectile light setting to be my light - that causes the light to stay perfectly with the object. Problem is, I can't figure out how to keep lobbers from rotating like crazy when they're thrown (and it also bounces much more forcefully than when it was a placed object since it now has velocity in addition to gravity). As a result, the cast shadows skitter wildly.

 

I'm interested in what you mean by attaching the light in the nif itself. Light forms don't have mesh data, they're all setting based, so I'm not sure what I could put in my nif other than my attach node.

Edited by mmdestiny
Link to comment
Share on other sites

Does the MSTT have a LightAttachPoint node in the NIF? I mean, I can't imagine that the Attach parameter wouldn't actually attach to the node, given that it is how Bethesda created the Vault Boy stand and the magazine racks. But it might not actually work, I haven't tested it.

Edited by Reneer
Link to comment
Share on other sites

Yes. And when I was trying the constant calls the light would constantly move the that exact point, so I can tell it was working in that regard at least.

 

At this point I suppose my options are

A.) Stick with the placed MSTT idea and figure out why the light won't stay on the attach point as the MSTT havoks, or

B.) Set the animated nif as the projectile (which does allow me to successfully attach a sticky light, see my previous post), and figure out why the animated nif's physics are so much worse than the non-animated nifs. I've tried copying the bhkNPCollisionObject data from the non-animated nif, but it didn't seem to work. I THINK it might be including the bounding spheres from the little flame meshes that are also in the BSOrderedNode, and that's what's causing the collision to be so wonky?

Edited by mmdestiny
Link to comment
Share on other sites

Ok, I did some digging because I knew that I had seen something like this before. In one of the Automatron quests, you attach a "radar beacon" to your robot companion Ada. That radar beacon that gets attacked is an Object Mod (DLC01Bot_Torso_Quest_MQ02RadarBeacon02) that attaches to ap_Bot_HomingMod keyword. And the radar beacon, once attached, has a light on it.

 

Now, it might turn out that that only works on robots, etc, etc, but it might be an avenue you can explore. You might try out AttachMod, which would attach your objectmod to your MSTT.

Edited by Reneer
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...