Can i make infinite loops?

Post » Thu Jun 21, 2012 6:54 am

I'm trying to make it such that a zombie is always looking for an appropriate actor to eat. Here is what I've got:

Scriptname ZombieAttackProtocol extends ActorKeyword Property ActorTypeUndead autoKeyword Property ActorTypeNPC autoKeyword Property ArmorCuirass autoKeyword Property ClothingBody autoKeyword Property VendorItemArmor autoKeyword Property VendorItemClothing autoFaction Property AAAZombieFaction autoFormList Property DoorList autoSpell Property AAAZombieTurnAb autoevent OnCellAttach()FindLunch()self.RegisterForSingleUpdate(0.50)endEventfunction FindLunch()Actor Lunchwhile Lunch==NONE	  ;constantly looking for the next meal	  while Lunch==Game.GetPlayer() || Lunch.GetRace().HasKeyword(ActorTypeUndead)==true || Lunch.HasKeyword(ActorTypeUndead)==true || Lunch==NONE ||Lunch.IsChild()==true		   Lunch= Game.FindClosestActorFromRef(self, 2000)		   Utility.Wait(0.10)	  endWhile	  self.StartCombat(Lunch);waits for Lunch to die	  while Lunch.IsDead()==false		 Utility.Wait(1)	 endwhile	 Lunch=NONEendWhileendFunctionevent OnHit (ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)   (akAggressor as Actor).addSpell(AAAZombieTurnAb)endEventevent OnUpdate()if self.IsInCombat()==false  FindLunch()endIfself.RegisterForSingleUpdate(3.0)endEventevent OnItemAdded(Form akBaseItem, int aiItemCount, ObjectReference akItemReference, ObjectReference akSourceContainer)  if akBaseItem.HasKeyword(VendorItemArmor)==true || akBaseItem.HasKeyword(VendorItemClothing)	 self.EquipItem(akBaseItem)  endIfendEventevent OnCombatStateChanged(Actor akTarget, int aeNewState)if aeNewState==0  self.SetFactionRank(AAAZombieFaction, 1)endIfif aeNewState==1  self.SetFactionRank(AAAZombieFaction, 0)endIfendEvent

But find lunch seems to only run once, if at all. I want it to always be looking for its next meal.
User avatar
Christine
 
Posts: 3442
Joined: Thu Dec 14, 2006 12:52 am

Post » Thu Jun 21, 2012 2:31 am

In your FindLunch() function, you forgot to put in a condition for a dead actor in the first while loop.
User avatar
GEo LIme
 
Posts: 3304
Joined: Wed Oct 03, 2007 7:18 pm

Post » Thu Jun 21, 2012 2:35 pm

In your FindLunch() function, you forgot to put in a condition for a dead actor in the first while loop.
I don't think that's the problem. If the found actor is dead then combat will end, Lunch is assigned NONE, and the initial WHILE resumes. Or at least it should.

event OnUpdate()    if IsInCombat()==false        FindLunch()    endIf    RegisterForSingleUpdate(3.0)endEvent
This could be an issue. It's possible for this additional update to fire while your zombie is idle because of threading. Take that out. In fact, I'd try using OnLoad() instead.

event OnCellAttach()endEventEvent OnLoad()	FindLunch()endEvent

And just because you can do a thing doesn't always mean you should. :) IMO endless WHILE/ENDWHILE's are dangerous. I'd put your scanning logic into an event.
User avatar
Lady Shocka
 
Posts: 3452
Joined: Mon Aug 21, 2006 10:59 pm

Post » Thu Jun 21, 2012 9:19 am

I think OnUpdate only runs once, because you are only registering for the Onupdate event once:

RegisterForSingleUpdate
When I have done this, I have used this mechanism: http://www.creationkit.com/OnUpdate_-_Form#Notes and all is good
User avatar
Chris Guerin
 
Posts: 3395
Joined: Thu May 10, 2007 2:44 pm

Post » Thu Jun 21, 2012 12:11 pm

I don't think that's the problem. If the found actor is dead then combat will end, Lunch is assigned NONE, and the initial WHILE resumes. Or at least it should.

Looking at it again, I realize that the reason it's not working is because it's using FindClosestActorFromRef. The closest actor from a ref that happens to be an actor is itself. It's stupid, but that's why this function is of very limited use. Instead, the function should be using FindRandomActorFromRef.

Again, there would need to be a check that the actor isn't dead. Otherwise, if you're unlucky you would keep ending up with the dead actor and so never end up attacking a live one.

event OnUpdate()	if IsInCombat()==false		FindLunch()	endIf	RegisterForSingleUpdate(3.0)endEvent
This could be an issue. It's possible for this additional update to fire while your zombie is idle because of threading. Take that out. In fact, I'd try using OnLoad() instead.

...

And just because you can do a thing doesn't always mean you should. :smile: IMO endless WHILE/ENDWHILE's are dangerous. I'd put your scanning logic into an event.

The RegisterForSingleUpdate inside the OnUpdate event would not cause multiple threads. When you call a function (eg FindLunch) inside another event or function (eg OnUpdate), the called function (FindLunch) must complete before the calling event/function (OnUpdate) resumes.

So until the FindLunch function finishes running, the RegisterForSingleUpdate does not occur, and there will not be multiple threads. However, I do agree that endless while loops can be dangerous.
User avatar
Joanne
 
Posts: 3357
Joined: Fri Oct 27, 2006 1:25 pm

Post » Thu Jun 21, 2012 4:44 pm

Looking at it again, I realize that the reason it's not working is because it's using FindClosestActorFromRef. The closest actor from a ref that happens to be an actor is itself. It's stupid, but that's why this function is of very limited use. Instead, the function should be using FindRandomActorFromRef.
Wow. Just ... wow. Glad I haven't tried that function before because I would have been going insane until I checked here/the wiki.

The RegisterForSingleUpdate inside the OnUpdate event would not cause multiple threads. When you call a function (eg FindLunch) inside another event or function (eg OnUpdate), the called function (FindLunch) must complete before the calling event/function (OnUpdate) resumes.

So until the FindLunch function finishes running, the RegisterForSingleUpdate does not occur, and there will not be multiple threads. However, I do agree that endless while loops can be dangerous.
Really? That is actually good. It's been really difficult getting used to Papyrus after coding in .Net. I'm still not 100% sure of what spawns instances so I automatically assume the worst! *lol*
User avatar
Undisclosed Desires
 
Posts: 3388
Joined: Fri Mar 02, 2007 4:10 pm

Post » Thu Jun 21, 2012 10:59 am

I agree totally with RandomNoob. You may use a find package or a mantle spell to search for new victims instead.

Aenara, any call to any function or any event will create an istance of that funcion or event, but in the case of a propperly made registerforsingleupdate loop (with the second call in the last line of the onupdate event)the call won't happen untill the onupdate has finished, so, one instance will end before the new one is created.
User avatar
Antony Holdsworth
 
Posts: 3387
Joined: Tue May 29, 2007 4:50 am

Post » Thu Jun 21, 2012 9:35 am

Aenara, any call to any function or any event will create an istance of that funcion or event, but in the case of a propperly made registerforsingleupdate loop (with the second call in the last line of the onupdate event)the call won't happen untill the onupdate has finished, so, one instance will end before the new one is created.
Should have added "threaded-instance" there. There are plenty of ways to get asynchronous instances to spawn... the Wiki lists tons of latent functions that could be repeatedly called in completed OnUpdate events. Then I keep reading how the timers are based on frame rate. And there don't seem to be any monitoring calls to gauge how angry Papyrus is at any given moment. So I guess I'm on my guard. *lol* I'm a very cynical coder. ;)
User avatar
Gen Daley
 
Posts: 3315
Joined: Sat Jul 08, 2006 3:36 pm

Post » Thu Jun 21, 2012 6:13 am

The method of using a RegisterForSingleUpdate at the end of an OnUpdate is what's called a "single update chain", and is the most desirable way to run scripts that run continuously in the background. Unlike RegisterForUpdate, a single update chain ensures that multiple threads of the same script do not spawn. This prevents issues with script engine stability and bloated save-games as too many of the same script "stack up" upon one another.

Good luck :biggrin:
User avatar
Connie Thomas
 
Posts: 3362
Joined: Sun Nov 19, 2006 9:58 am

Post » Thu Jun 21, 2012 2:41 am

Wow, didn't know there was a name for it. Just seemed like an intuitive answer.
User avatar
Erin S
 
Posts: 3416
Joined: Sat Jul 29, 2006 2:06 pm


Return to V - Skyrim