Understanding Complex Trigger Actions

I am having a problem using Trigger Actions to do what I need and I suspect that the problem is my understanding of how they work. Below is a screen shot of the trigger. The AmmoPressed in the “when properties match” field is a Global Property that I thought I could use to track whether an Global Key Command button had been pressed. It doesn’t really work and now I suspect that this field must refer to a property on the piece itself and that I can’t use a Global Property to do what I wanted.

I send the “Ammo_HL_Off” named command from another Trigger Action that is activated by a Global Key Command from a button in the map window. I thought that it would only fire if the was true.

So my direct questions are: Is the “when properties match” field only referring to properties on the piece?

And: Is my understanding of the key command and the matched properties correct?

Thanks for any assistance.

Mike

I don’t quite understand the first question–it seems like it’s missing some words, i.e. what does “the” refer to?

For the property match expression pictured to evaluate as true, there must be a property named AmmoPressed with a value of 1 somewhere–that could be a Dynamic Property in the same piece where the Trigger is running, or a Global Property. Can you confirm you’ve created one of those?

The key command looks fine, if this Ammo_HL_Off named command is sent from another piece or toolbar GKC, the Trigger should fire (of course, contingent on the property match expression evaluating as true).

Joel,

There were some words missing. I used the less than and greater than to denote the field I was talking about and it must have seen those as an HTML tag. I fixed it with quotation marks.

I did use a Global Property, it was the “AmmoPressed” property, but it didn’t seem that it was behaving as expected and because of that behavior I was wondering if the Global Property could not be changed by a piece’s Trigger Action.

Mike

Actions resulting from a Trigger Action could–for example if this Set_AmmoPressed_No was the key command of a Set Global Property trait in the piece. So far it isn’t shown what traits the “perform these key commands” section correspond to.

As I understand your set-up

  • Some Global Key Command - e.g., a button in the toolbar - sets the Global Property AmmoPressed to 1 (are you sure you’ve set it to 1 and not true or something like that?)
  • Another Global Key Command - e.g., a button in the toolbar - sets the [Global Property] - e.g., a button on the tool bar - sends the named command Ammo_HL_Off to some or all pieces (on all maps or some map).
  • You then expect the pieces’ Reset_Ammo_HL_BTN and Set_AmmoPressed_No to be executed on the pieces that were targeted above.

The Trigger Action Trait on your pieces will only execute if Trigger when properties match is true. That expression can reference

  • properties in the piece
  • properties of the zone in which the piece is
  • properties of the map the piece is on
  • properties of the module
  • properties of VASSAL

To check if the Trigger Action Trait is truly being executed, perhaps try to add a Report Action trait to the pieces (preferably through a prototype) that triggers after the Ammo_HL_Off has executed. If that seems to work, check the actions Reset_Ammo_HL_BTN and Set_AmmoPressed_No actions in a similar way. Note, Report Action are executed after the action it is associated with has fully completed. Thus, you will see the message from Reset_Ammo_HL_BTN first, then from Set_AmmoPressed_No, and only then from Ammo_HL_Off.

Perhaps you can explain, in some more detail, what it is you are trying to achieve. Why is it, for example, needed to set AmmoPressed before executing the Ammo_HL_Off? And is Set_AmmoPressed_No intended to execute a Set Global Property trait to set AmmoPressed? If so, what is the goal?

Finally, if you can post your module somewhere - say Google Drive, One Drive, Dropbox, or similar (and make sure others can see it without signing up or similar) - then people may be able to help you better.

Oh, and when you get a satisfactory answer, remember to click the Solution button to mark the problem as solved and so that others may more easily find the solution to their similar problem.

Yours,
Christian

Hey Christian,

Thank you for the response.

I am fairly new to Vassal development and I am trying to get to understand what is possible with the module editor.

What I am trying to do is highlight units on the map that have an ammo problem. The status is done with a layer with 3 levels. The default is nothing, then low ammo and finally no ammo. When the low or no ammo level is active I set the level name as a suffix so I can test for the status by looking at the piece name. The levels are set to loop through but I don’t think that is a problem.

I have another layer with 2 levels. This layer is a circle around the unit. I call it a highlight. Level 1 is nothing and level 2 is the circle. When the “Ammo” button in the map window is pressed it sends a Global Command to increase the level from 1 to 2 on units that have an ammo problem thus highlighting units with an ammo issue. The highlight layer is set to loop through the levels so pressing the “Ammo” button again turns off the highlight. This appeared to be a good solution but an issue arose in practice. The issue is when the ammo highlight is activated and a player changes the status of an un-highlighted unit. When that happens pressing the “Ammo” button again turns off the highlight on the highlighted unit but turns on the highlight for the piece with the newly changed status.

My solution to this was to have a Global Property that could track whether the “Ammo” button had been pressed and check that status when pressed again and if it had been pressed then only send the named command to units that had the highlight already turned on. So the logic went like this.

  • Press the button
  • If the pressed flag was no then highlight the units with ammo issues
  • If the pressed flag was yes then only send the Global Key Command to units already highlighted.
  • Each press of the button would flip the status flag to the opposite status

It does not work. So I posted the question to see if perhaps the Global Property could not be changed by a Trigger Action on a piece and to make sure that the “Trigger when properties match” field behaved like I thought it would.

To address some comments from you and Joel.

I did use the Report Action to try and see if the Triggers fired. The turn on the highlight did and it changed the flag. However the turn off the highlight did not seem to fire.

I did use the Set Global Property trait in the piece.

There may be a better way to achieve what I am after using the module editor but I have not figured that out. Now that you and Joel have confirmed my understanding of how the Global Property works and how the “Trigger when properties match” works I am leaning towards this being a problem with my logic. Another logic issue is that multiple pieces are affected by the Global Key Command and so the Set Global Property is firing from every piece. I am going to have to explore the logic and perhaps start from scratch to find a way to achieve this. As an avid Advanced Squad Leader player I understand a lot can be accomplished using custom Java classes but I am nowhere near ready to tackle it from that angle for this game.

Any advice you could offer would be greatly appreciated as I am new to the module development process.

Mike

Aha–there is in fact a simpler way to get your desired effect. Layers expose additional properties on the piece that you can employ in property match expression logic–scroll all the way to the bottom of the Layer documentation.

Particularly useful here is <layer_name>_Level , where you’d sub in the defined name of your Layer for <layer_name>. Effectively you already have a way of identifying which units to highlight and which to ignore based on what level of their Layer is currently showing, and you can use that in your match expression to filter the subset of units that need to react to the inbound GKC.

I echo the advice to put your work-in-progress somewhere that it can be accessed, along with detailed instructions on where in the Editor to find the units/GKCs at issue.

I did something similar to what you are talking about for https://vassalengine.org/library/projects/Air__Armor_Würzburg_Tactical_Armored_Warfare_in_Europe_–_Designer_Signature_Edition

It allows a HQ unit to send a command to highlight all units of its division/brigade. Although the matching is done on the GKC.

Mike

And because I am slightly insane, I am upgrading the feature to combined on 1 locator piece. Players were complaining that they had trouble finding the HQ unit to then track the sub-units.

Players can move the locator to wherever they want it. then just click on the button for unit they want located.

Each “button” is triggered by an ‘Action Button’ and has 3 triggered Actions based on the status of the dynamic property. that checks to see the current status of that Unit’s locator On/Off

Jardic,

Thank you for the post. This is what my next task to tackle is. Selecting a leader and highlighting subordinate units. Your post will be very helpful

Mike

1 Like

Joel,

This may be the solution I am looking for. Thank you for the information. I will mark this as the solution after I make some changes and test it.

I do have another related question. I understand the importance of using Prototype Definitions. I have a working understanding of trait ordering. So I have a Combat Unit Infantry Prototype, a Combat Unit Artillery Prototype etc.. I have a Ammo Highlight Prototype that is placed in the Combat Unit Infantry Prototype. Can I include the the Ammo Highlight layer in the Ammo Highlight Prototype instead of the Combat Unit Infantry Prototype without causing issues with the trait ordering?

Mike

I am working on the third A&A module, but its almost identical to the Wurzsburg one listed above.Here you can see my use of prototypes, on this HQ unit. But I always have a bunch of reordering to do, to get them the way I want. If you are willing to use a sub-menu you can force the order of the commands.

On my unit locator, he is the sub-menu where I can order the commands. Hopefully the players will never use this and just click on the Action Buttons on the piece. The Locator is not in Wurzburg, I will eventually go and back-fit it.

There’s a relatively easy solution to this. Define a Change-Property Toolbar Button that toggles AmmoPressed. with Type set to Set value directly and the expression to be !AmmoPressed. Then, in your circle Layer trait, enable Levels follow expression value and set the expression to be

{AmmoPressed && LowOnAmmo ? 2 : 1}

As long as AmmoPressed is true, and the correct layer will be shown, even if the piece’s ammo status changes. If AmmoPressed is false, then only the first (empty) layer will be shown regardless of the ammo state of the piece.

Take a look at the Attachment trait. That provides a way to attach pieces to a piece (and vice versa), in a way that effectively allows commands to be passed between the pieces. I used that extensively in Littoral Commander: Indo-Pacific.

All depends on where in the trait list you add the prototype. When the prototypes are “unpacked”, their traits appear - in the order defined in the prototype - at the place of the prototype inclusion. Remember that rendering of the piece goes from the “bottom” down - or, more precisely from the inner most decorator (trait) to the outer most.

Yours,
Christian

Hey Joel, Christian,

I followed Joel’s suggestion but it did not resolve the issue. It did, however, teach me where part of the issue is. To clarify what I am trying to do I want to turn on and turn off this highlight with a single button. On the button push I call a Trigger Action that calls two Trigger Actions. One tests for if the highlight is off and if there is an ammo issue then turns it on. The other tests whether the highlight is on and turns it off. Both of these are using the level properties Joel showed me.

If I was writing this test in a programming language I would use an if - then type of statement and that is what I thought I was replicating using two Trigger Action traits. I was not. The order of the named commands in the first Trigger Action that calls the test Trigger Actions matter. They fire in the order that they are listed and the way I have them configured they cancel each other. If I test if it is off and turn it on when the next Trigger Action happens it tests if they are on and turns it off. Duh!

I have thought about using the same named command to launch both of the trigger actions so there is not a launch order to deal with but I suspect that will not really resolve the problem, only make it more challenging to troubleshoot.

Christian suggested using a ‘Change-Property Toolbar Button’, something I was not aware of, to accomplish this. Then use a ternary statement on the Highlight Layer in the “Levels Follow Expression Value”. Again, a capability I was not aware of. I am definitely learning some things here.

Unfortunately, I can’t get the ‘Change-Property Toolbar Button’ to work. It seems simple enough and I tested the logic in my Java IDE and it works as expected. I can’t see a way to declare the Global Property as Boolean but my understanding is that BeanShell will infer the type by the value assigned. So I assigned it an initial value of false. It threw an error:

  • Bad Data in Module: Source: {!AmmoPressed} Error: Expression evaluation error.

I set up the report format on the “Change-Property Toolbar Button” to report the old value and the new value ({“AmmoPressed was " + oldValue + " and now it is” + newValue}) and this is what it reports:

  • AmmoPressed was -1 and now it is

The blank after “it is” is correct. It is not changing the value of AmmoPressed and if I take the curly braces away the expression is treated as a String literal and the report returns: * AmmoPressed was -1 and now it is!AmmoPressed.

Since I have set the Initial Value of the Global Property to false I am confused by the oldValue being -1. I think in programming languages that equate the Boolean true/false to a numeric value that 0 is false and not zero is true, so the -1 has me puzzled.

I probably have a syntax issue here but searching the web hasn’t revealed anything useful.

What am I doing wrong?

Mike

Hi Mike,

Why do you run things in an IDE? What do you hope to learn from that?

In your Global Properties definition, enable Is numeric. Then set the starting value to false.

The {...} says to evaluate the contained code as a BeanShell expression, so those should not be removed. It seems like your Change-Property Toolbar Button expression is messed up and is interpreted as a string. Did you put {...} around it:

{!AmmoPressed}

so that it is evaluated as BeanShell expression? Anywhere you want an expression to be understood as a BeanShell expression, you need to put {...} around it.

You could, of course, set the initial value of AmmoPressed to 0, and in your Change-Property Toolbar Button expression have

{AmmoPressed == 0 ? 1 : 0}

and in your Layer trait follow expression

{AmmoPressed != 0 && LowOnAmmo ? 2 : 1}

I think that’s because you probably didn’t enable the Is numeric check-box in your global property.

BTW, check How to format forum posts - a bit of formatting can make your posts much easier to read and understand your problem.

Yours,
Christian

Hey Christian,

The only thing I ran in the IDE was the {!AmmoPressed} in order to see if it was flipping the value from ‘false’ to ‘true’. I am familiar with Java but it is not my strong suit so I wanted to make sure I understood what the expression was going to accomplish.

I tried that and it still results in ‘Bad Data in Module: Source: {!AmmoPressed;} Error: Expression evaluation error.

That I did understand. It throws the error when the expression when formatted properly as {!AmmoPressed}. I only tried it without the curly braces to see if that would resolve the issue. Obviously it did not.

Thanks for the guidance. I will endeavor to use the formatting.

You should rather use the interactive Beanshell interpreter to test out Beanshell expression. Using an IDE is way overkill for what you want to accomplish. Note that the Beanshell code is not Java per-se, but rather a separate interpreter interpreting something that looks a lot like Java.

In the above, you have a spurious ; after AmmoPressed. Try to remove that. Did you check your errorLog (see How to report problems)

OK, try the alternative with

{AmmoPressed == 0 ? 1 : 0}

Yours,
Christian