Action Queue

From WiCWiki

Jump to: navigation, search

Contents

The Action Queue is a really neat invention. There are two different kinds of action queues, the “normal” version and a “rogue” version. To simplify it, the action queue is a way of making things happen in a predefined order with or without the possibility of being interrupted by other things.


The “normal” queue

The normal queue is the queue that won't be interrupted by anything else. When the method “execute” is called the queue will start from the top and execute everything that is written in it. It looks like this in its simplest form.

queMyActionQueue = ActionQueue( 'queMyActionQueue' )
queMyActionQueue.Execute( )  

You might find it a bit unnecessary to use it from the beginning, but we will add more things to it and the more things the more useful it will be, I promise. That and if you read the case study on the following page, I hope it will convince you to use it.


The parameter on the first line is simply the queues name and can be whatever you want. Its mostly for debug purpose, it is much easier to search a name you are familiar with. The second line is what will execute the action queue and is commonly used in a reaction.

If we look at one example from the chapter about message boxes which looked like this.

RE_OnCommandPointTaken( 'CP_Village', TEAM_NATO, Action( ShowMessageBox, 'Test_2', 2 ) )

For now we will just use the queue to show a message box so I understand if you think there is no reason to use it, at the moment it’ll end up in more code and still work almost the same as before.

queMyActionQueue = ActionQueue( 'queMyActionQueue' )
queMyActionQueue.AddMessageBox( 'Test_1', 1 )
RE_OnCommandPointTaken( 'CP_Village', TEAM_NATO, Action(queMyActionQueue.Execute ) ) 

It is important that the reaction, in this case, that calls the execute-method is not written before the queue itself because if you try to call an action queue that’s not created yet the game will crash.

So, why should I use the Action Queue?

Imagine if you have two objectives active at the same time, one is a primary that you will complete when you take a command point, the other is a secondary that you will fail if an artillery is destroyed. This is two totally different situations of which we will add message boxes, and they are completely separated. If you use the old way of adding message boxes there will be no way of making sure they won’t collide because they will just be triggered when they are told to.

This means that you can end up with a kind of hilarious situation where your commanding officer compliments you for the success with the command point at the same time as he nags you about the loss of the artillery.


“There you go! Nice work!”

“What have you done? Now we have to bury another good soldier”

“Now we can start to fortify this position! I can see us actually make it through the night”

“Let’s hope you will never do such a thing again”.


Yea, you see the picture here.

This won’t happen if you use the “normal” action queue.


But almost every good thing has a bad side, and a queue that won’t be interrupted is not always a good thing and this is where the rogue queue comes in.

Something about the rogue action queue

We’ll have a look at the previous message box example again. Imagine you have a bunch of message boxes in the queue that will be executed when the primary is completed but you want to create some enemy units at the same time. If you use the normal queue and the queue with all the message boxes in have started, the enemy units won’t be created until the first queue is done. Here we have an example on when it’s better to use a rogue queue. Everything that won’t mess up the pacing, message boxes and things like that can be placed inside a rogue queue like unit creating, instant placed TA and such.


queMyTestQueue = ActionQueue( ' queMyTestQueue ', False ) 
queMyTestQueue.AddMessageBox( 'e1_2', 102 )
queMyTestQueue.Execute( )

This queue will not interrupt anything else.


Things that is good to put in an action queue.

Almost everything is good to put in the queue. For a small event with pretty common code in it you can put everything in queues (except the reactions that will execute the queues off course). A common event will have a start-queue, an objective completed-queue and an objective failed-queue.

Here is a short, simple example which pretty much is the base for a whole event. The things we’ve not yet covered will be covered in the following chapters; this is just an example to give you an idea of how it looks.

queVillageStart = ActionQueue( 'queVillageStart' ) 
queVillageStart.AddObjective( mapvars.objVillage )
queVillageStart.Execute( )

queVillageComplete = ActionQueue( 'queVillageComplete' )
queVillageComplete.AddMessageBox( 'e1_2', 102 )
queVillageComplete.AddObjectiveCompleted( mapvars.objVillage )
RE_OnCommandPointTakenEx( [ 'CP_Village' ], TEAM_NATO,) Action( queVillageComplete.Execute ) , True )

queVillageFail = ActionQueue( 'queVillageFail' )
queVillageFail.AddObjectiveFailed( mapvars.objVillage ) 
queVillageFail.AddFunction( wicg.EndGame, TEAM_USSR )
RE_OnCommandPointTakenEx( [ 'CP_Village' ], TEAM_USSR, Action(queVillageComplete.Execute ), True )


There’s a bunch of action queue methods you can use. You will find them in the wic\python\wicgame\ actionqueue.py file.


About delays in action queues

It is really handy to use delays in action queues sometimes. For example if you want waves of attacks or artillery strikes. There are two different ways of adding them and each way is good in its own way. The first one is.

myQueue.AddDelay( 50 )

The parameter is in seconds and it will prevent the rest of the queue to be executed until the delay is over. It will also put every other action queues (except the rogue queues) on ‘hold’ until the delay is over.

It could be useful sometimes but remember if one queue with a delay has started it won’t be interrupted until it is finished and that includes the delays. This can lead to, for example, the player has to wait for as long as the delay is set to until an objective is completed or failed and this is very bad.


The second one is

myQueue.AddAction( Action( Delay, 50, Action( allunits.LastStand2 ) ) )

If you add the delay like this, the only thing that will wait to be executed is the function or functions in the action list. This way is much safer to use in an action queue.


Appendix

Changed files in this chapter:

Server.py


Changes in the server.py file.


def VillageCam( ):
  DebugMessage( "VillageCam::" )

  # Start the objective camera for the village objective. We want the command point to be visible
  # in the camera so we set it to active and then shows a message box.

  queVillageCam = ActionQueue( 'queVillageCam' )            
  queVillageCam.AddFunction( SetCommandPointActive, 'CP_Village', True )
  queVillageCam.AddMessageBox( 'e1_1', 101 )
  queVillageCam.Execute( )  

  [More code here.]

def VillageStart( ):
  DebugMessage( "VillageStart::" )

  # Now its time to add the objective and after that the event string disappears we post an event
  # to start the secondary rescue arty objective.

  queVillageStart = ActionQueue( 'queVillageStart' )
  queVillageStart.AddFunction( PostEvent, 'RescueArtyStart' )
  queVillageStart.Execute( )

  queVillageFail = ActionQueue( 'queVillageFail' )
  queVillageFail.AddFunction( wicg.EndGame, TEAM_USSR )
  mapvars.reactVillagePlayerDead = RE_OnEmptyPlatoon( mapvars.pltPlayer, Action( queVillageFail.Execute ) ) 
  
  queVillageComplete = ActionQueue( 'queVillageComplete' )
  queVillageComplete.AddMessageBox( 'e1_2', 102 )
  queVillageComplete.AddFunction( SetCommandPointActive, 'CP_Village', False )
  queVillageComplete.AddFunction( VillageEnd )

 # setup a reaction for when Nato takes the CP and then run the complete queue. And remove the fail reaction.
 # Use the complex reaction so we can test if NATO already owns the command point.

 RE_OnCommandPointTakenEx( [ 'CP_Village' ], TEAM_NATO, [ Action( RemoveReaction, mapvars.reactVillagePlayerDead ) ,Action( queVillageComplete.Execute ) ], True )


def RescueArtyStart( ):
 [More code here.]          
 mapvars.reactRescueArtyFail = RE_OnEmptyGroup( mapvars.grpRescueArty, Action( PostEvent, 'RescueArtyDead' ) )

  # Give the objective but wait 30 secunds before the units that are attacking the arty is created.

  queRescueArtyStart = ActionQueue( 'queRescueArtyStart' )
  queRescueArtyStart.AddMessageBox( 'e1_4', 104 )
  queRescueArtyStart.AddFunction( Delay, 30, Action( allunits.RescueArtyAttack ) )
  queRescueArtyStart.AddFunction( Delay, 30, Action( PostGroupSize, mapvars.grpRescueArtyRu1 ) )
  queRescueArtyStart.Execute( )         

  # If the russian attacker has been killed, complete the objective and give the arty to the player as a reward.
  # Also remove the fail reaction.

  queRescueArtyComplete = ActionQueue( 'queRescueArtyComplete' ) 
  queRescueArtyComplete.AddMessageBox( 'e1_5', 105 )
  RE_OnCustomEvent( 'RescueArtyRuDead', [ Action( RemoveReaction, mapvars.reactRescueArtyFail ), Action( queRescueArtyComplete.Execute ) ] )

  # If the arty is destroyed, fail the objective.
  # Also remove the complete reaction.

  queRescueArtyFail = ActionQueue( 'queRescueArtyFail' )
  queRescueArtyFail.AddMessageBox( 'e1_6', 106 )
  RE_OnCustomEvent( 'RescueArtyDead', [ Action( RemoveReaction, mapvars.reactRescueArtyComplete ), Action( queRescueArtyFail.Execute ) ] )


 # Show a messagebox when the arty is under fire.

 [More code here.]

 [More code here.]

def PostGroupSize( aGroup ):

  # Post the size of a group, 

  PostEvent( 'GroupSize', aGroup, aGroup.Size( True ) )

def CreateCommandPoints( ):         

 [More code here.]


Chapter 6: Message Boxes < > Chapter 8: Objectives and the Objectives browser
Personal tools
User Created Content