Regular and Beanshell (& building a complex Expression for Newbies)

Hi All;
I am trying to automate some dice rolls and having the result of one die roll trigger another. I am stuck on setting the conditions for the 2nd roll.

The conditions are that the piece must be in one of four Zones (Ten Thirty, Twelve, One Thirty and Vertical Dive) and the first die roll (M-3 German Offensive Fire_result) must be a 5 or 6.

I found how to do a Regular Expression for the Zones: CurrentZone =~ Ten Thirty|Twelve|One Thirty|Vertical Dive, which works.

and a Beanshell for the die result {GetProperty(“M-3 German Offensive Fire_result”) > 4} which works.
Can these be combined somehow into the one expression for the Trigger or do I need both to be Beanshell or Regular?

I can’t find info on how to combine the Zones in a Beanshell, the Regular is the only way I know how.

Regards;
Darren

Through Trial and error I came up with a Regular Expression that works;

CurrentZone=~Ten Thirty|Twelve|One Thirty|Vertical Dive && M-3 German Offensive Fire_result > 4

but is there a Beanshell that can do the same? Using the OR with Beanshell is where I am stumped. Also - how do you reproduce those Pipe symbols using a keyboard only?

Regards;
Darren

Look for a key with a pipe / straight line on it. On my keyboard it is paired with back-slash, next to the return/enter key.

2 Likes

This expression would check the die roll and whether the piece is in one of the qualifying zones. Does that do it for you?

{GetProperty(“M-3 German Offensive Fire_result”) > 4 && CurrentZone =~ "Ten Thirty|Twelve|One Thirty|Vertical Dive"}

1 Like

Hello Mark, unfortunately no and no green tick but thanks for your help. :slightly_smiling_face:

Maybe I am going about this wrong, I still have to allow for some die roll modifiers as well, a complex array of triggers with Expressions such as this will be required. Perhaps it might be better to try one of those Calculated Properties then I can reference the CP instead?

All these years and I never noticed it. Yes I got it now , thanks.

Regards;
Darren

The Beanshell equivalent of

CurrentZone =~ Ten Thirty|Twelve|One Thirty|Vertical Dive

is

{CurrentZone=~"Ten Thirty|Twelve|One Thirty|Vertical Dive"}

so this should work:

{CurrentZone=~"Ten Thirty|Twelve|One Thirty|Vertical Dive" && GetProperty(“M-3 German Offensive Fire_result”) > 4}

Every Old-style expression does have a Beanshell argument. Usually, you just have to change the right-hand side of any comparison needs to be change to be quoted, and change any = to ==.

2 Likes

BTW, you can convert an old-style Property Match expression to Beanshell by opening any Global Key Command, paste the old expression into the ‘Additional matching expression’ and click the Calculator icon. This will open the Beanshell editor and convert the old expression to Beanshell

2 Likes

{CurrentZone=~“Ten Thirty|Twelve|One Thirty|Vertical Dive” && GetProperty(“M-3 German Offensive Fire_result”) > 4} doesn’t work but this…

{(CurrentZone=~“Ten Thirty|Twelve|One Thirty|Vertical Dive”) && (GetProperty(“M-3 German Offensive Fire_result”)>4)}

…does. Don’t ask how I got it because I have no idea. The expression builder added some extra brackets somehow. This just the beginning there is more I have to add to this equation yet and there are many variations of this expression that will be needed for several Triggers.

I followed these directions and also got …

{(CurrentZone=~“Ten Thirty|Twelve|One Thirty|Vertical Dive”) && (GetProperty(“M-3 German Offensive Fire_result”)>4)} and it works so it must be right :thinking:

The Expression Builder is being conservative, those extra () aren’t needed mostly, but it makes it clearer and is just as correct.

1 Like

Hello Brent;
Thanks for the advice. I have a better idea of how to use the “Or” in Beanshell now.

Regards;
Darren

Hi;
On to the next problem which is applying DRM to the M-3 German Offensive Fire die roll. The conditions are a -1 DRM if the fighter has been damaged and a roll of 6 is always a hit regardless of the DRM. There is a Layer trait called “FighterContinues” that switches to level 2 when the fighter has been damaged and the -1 should be applied. So I tried this Ternary Expression…

{((GetProperty(“M-3 German Offensive Fire_result”) != 6 && FighterContinues_Level == 2) ? -1 : 0)}

…and also…

{((GetProperty(“M-3 German Offensive Fire_result”) < 6 && FighterContinues_Level == 2) ? -1 : 0)}

…so that -1 would be subtracted from the roll only when it was not (or less than) 6. No good. I should be getting results of 0-4 & 6 (no 5) but instead it is 0-5 and no 6 so Vassal is ignoring the first (GetProperty(“M-3 German Offensive Fire_result”) < 6 part of this Expression. Any idea what I have done wrong? This is my first attempt at these Ternaries.

[EDIT] Actually, I think it is ignoring the entire expression, I realised that level 2 for the FighterContinues layer was not activated either. it is subtracting the -1 and ignoring the entire expression.

{2nd EDIT] I split the 2 parts of the Expression up and tried them separately in the Ternary function and both are definitely not working. That will do for today I have had enough.

When/if I get this right it has to be added to the expression above to control when the second die roll occurs and then another created for a -2 DRM.

Regards;
Darren

It’s hard to diagnose these isolated problems out of context of where they exist in the module and seeing exactly what is triggering what.

I have a an upcoming 3.7 beta build that will add a function that allows you to dump out an Audit of an expression each time it runs (or only when an expression is true). You could use this and it will print the current values of all the properties being used to evaluate the expression. Should make this sort of debugging vastly easier.

1 Like

It’s more likely a case of I don’t know what I am doing than anything else. This Expression is in a Trigger that is supposed to be activated by the result of a previous die roll. The Ternary was supposed to adjust the total die roll down by -1 if certain conditions were met. Maybe it doesn’t work because it isn’t a Property Expression? Unless someone has a better idea this will be another for the “Too Hard Basket” unfortunately.

As I mentioned, pasting an isolated Beanshell expression here and saying it doesn’t work doesn’t achieve much. I can see that the expression is OK, so there must be a problem with the properties mentioned, or in where and how you are using it. This is impossible to tell without more information.

Ergo…

What information is required?

You’ll usually get the quickest solution if you are able to provide a link to the module, either on the Vassal site, or on a cloud service. Plus a Save game with simple instructions on how to reproduce the problem. This is the gold standard and there are several experienced users around who are happy to investigate.

Alternatively, you can take and post screenshots of the configuration screen for each of the components involved in the process. i.e. the two dice buttons and each component along the way in the chain that leads to where the expression in question is failing. Plus a description of what is happening. That will help identify any of the common errors.

Regards.

I deleted the Module copy yesterday which had the problem Expression so had to set it up again to be available for download. This time I am getting an error which wasn’t there before;

2023-07-10 15:00:56,774 [6452-AWT-EventQueue-0] WARN VASSAL.tools.ErrorDialog - Piece: Average Trait: Trigger Action - Rolls on B-5 - - GermanAttack => RollONbeefive Source: Expression={GetProperty(“M-3 German Offensive Fire_result”) != 6 && ((FighterContinues_Level == 2) ? -1 : 0)}, Error=internal Error: Unimplemented binary String operator Error: Expression evaluation error. See the errorlog for more details.
Expression Audit:
Source type=Piece Trait
Source name=Piece: Average
Source description=Trait: Trigger Action - Rolls on B-5 - - GermanAttack => RollONbeefive
Source field=Trigger when properties match
Source Expression={GetProperty(“M-3 German Offensive Fire_result”) != 6 && ((FighterContinues_Level == 2) ? -1 : 0)}
FighterContinues_Level=1
Error=internal Error: Unimplemented binary String operator.

Could this be because I am trying to use a Property Match Expression field for something else?

The only difference from yesterday is I tidied up the trait order to see if there was an improvement. Also for some reason I had “add to each side -1” enabled in the dice button and that has been removed - that is why -1 was being subtracted yesterday. Other than that the Expression still does not work as per yesterday. The module will be up for download here shortly if someone wants to take a look it would be appreciated.

Regards;
Darren

Well here it is, To reproduce the problem;

The display will load as it appears then right-click on one of the Grey German fighter symbols to add one of the fighter Pieces

Then Right-click on the Piece and left-click M-3 German Offensive Fire. The result will appear in the Chat display.

What I am trying to achieve is -1 subtracted form the roll except for 6 which is a “6”. So results should be 0 - 4 and 6 (no 5). Thank you in advance for your help.

Regards;
Darren

Hi Darren,

First up, not sure how you created those images, but they can be very greatly reduced in size without loss of quality. They seem to be completely uncompressed. For example, the size of the YB40_Planview.png reduced from 5.6Mb to 0.4Mb and Strategic_Map_Blank.png from 5.5Mb to 0.006Mb (6Kb) just by resaving them in Gimp , stripping the guff and turning on maximum compression. That’s even before running them through something like optipng.

Ok, First problem that is causing the Bad Module error is your main statement is not correct

{(GetProperty("M-3 German Offensive Fire_result") != 6 && ((FighterContinues_Level == 2) ? -1 : 0}

should be

{(GetProperty("M-3 German Offensive Fire_result") != 6 && (FighterContinues_Level == 2)) ? -1 : 0}

That groups your two comparisons as one and feeds them into the ? which has to have a true or false as the first argument. What you has was trying to do ( true && -1) which does not compute.

The second problem is that this isn’t the place to be returning -1 or 0.The ‘Trigger when properties match’ (or any other ‘Match expression’ field must have an expression that results in either true or false. Actually false, doesn’t really matter, true or “true” is taken as true and anything else is false.

The Trigger Action trait can’t actually change any values, it is just a sequencing mechanism to tell other traits to fire off in a specific order when something else happens.

I think what you actually need here is a Calculated Property (I’ll go through that in a moment).

Third problem is that the value of FighterContinues_Level is actually 1 when I ran this, not 2, so no -1 will be added (even though this is the wrong place).

A Calculated property creates a Named ‘pretend’ property that does some calculations and be used elsewhere just like a normal property.

So, assuming the FighterContinues_Level problem is resolved, then create a Calculated property called M3Result with the following expression:

GetProperty("M-3 German Offensive Fire_result") + ((GetProperty("M-3 German Offensive Fire_result") != 6 && FighterContinues_Level == 1) ? -1 : 0)

This is taking the result of the roll, then adding -1 if the roll was not 6 AND the FighterContinues_Level == 2

You can now use M3Result as a property anywhere else INSIDE that piece and it should have the value you want.

If you want to use that value OUTSIDE that piece, then you need use more advanced techniques like Set Global Property and Global Key Commands or Global Hotkeys, controlled by more Triggers.

NOTE that you can’t change what the Dice button generates without these more advanced techniques, but you can remove the Report Format from the Dice Button so that it doesn’t report anything, and then report the roll result using a Report Action trait on your fighter piece.

Hope this gives you some ideas.
Regards.

2 Likes