Using Alert()

In another thread, I asked if anyone had successfully used the Alert() method, which is an option when using beanshell expressions. Someone said some module had, but I don’t remember which one and where, so I decided to post this because I can’t figure out how to get it to work.

I have a game where each player has money (credits), which they are constantly spending and earning. The cardboard version has a lot of cardboard credit tokens to handle this, but I found It to be a PITA to manage credits in the electronic version. So instead each player has a global property in their own map window that is the total credits they currently have (“credits”). They also have a bunch of buttons (a keypad) they can push to add or subtract amounts to their credits. For example, to spend 70 credits, they might press the “=50” and “-20” buttons. I show the credits in a static piece that has a text trait for “credits.”

Sometimes though I find a player may accidentally spend more credits than they have, and I thought, gee, wouldn’t it be nice if I popped up an alert window saying “Stop! You don’t have enough credits for that!” Note that the global property is numeric, and its minimum value is negative (e.g. -1000).

So in a keyboard button (for example, the “-10” button, but I would have to do something similar for all negative buttons), I would set a global property trait where I incremented/decremented that player’s credits (hopefully) like this:
Credits = { if (credits < 10, alert(“Not enough money”), -10}

This would work, or could work or might work, if alert() returned a 0 or any numeric value, but it doesn’t, and I don’t know what it returns. Actually, when I tested this, I found no matter what credits was, I got the same, single result: credits got decremented by 10 AND the alert popped up. Yes, both true and false results. Also an error message showed up in the chat window.

I then tried fooling it by assuming alert() might return the “” string or null, so I replaced alert() with 0+alert() and “0”+alert(), but vassal would have none of it. So since most/all places I would use alert() require expressions, particularly numeric expressions, I can’t figure out a way to make it work. If it truly is not possible, I’d request a vassal enhancement to have alert() return something useable—zero, for example.

I am at wit’s end here. A virtual lollipop to anyone who can get alert to work in this scenario.

No I have not used Alert. I certainly have wondered what it does however.

Also when I use Global properties I tend to find restricting them to the window where they logically belong seems more trouble than it is worth. I always end up pushing them to the top.

The easiest solution I can think of to your problem is to use the “Restrict command” option to check for when the global properties are too low. I suppose this might not work if the buttons are in the toolbar but if they are pieces acting as buttons I believe it could work.

A more radical approach would be to retain all the trappings of the physical game but to provide bells and whistles to make it easier to manage - such as commands to move the chits to the various locations faster and so on.

No lollipop for you.

The alert method pops up a dialog box with whatever text you want to put in it.

I have had no problem with putting global properties at different levels as long as I obey the scoping rules it forces. I suppose selectively restricting commands would work, but I’m not looking for a different solution to my credits problem. I am looking for an answer on alert(), and the credits problem is just an example to better illustrate what I want to do.

How about instead of trying to call alert “on the fly” in the If statement, you trigger a dynamic property to be set (e.g. DisplayAlert is set to If(Credits < 10, 1, 0) ), and then check THAT in a Trigger trait’s “matching expression” in which case you send a trigger that then FORCES the Alert to be evaluated?

Have you tried reversing the logic to see what happens? Maybe its lazy…
Credits = { if (credits < 10, alert(“Not enough money”), -10}
Credits = { if (credits > 10, -10, alert(“Not enough money”)}

The trouble is Trigger wants a list of keystrokes, which have nothing to do with beanshell. It’s either expressions or key strokes.

As I wrote this, it occurred to me maybe Alert() returns null, and perhaps I could fool it by using strings. After wasting a lot of time because I was calling alert instead of Alert, I got it to work! Indeed, it appears Alert() returns a null, so this worked:
If (credits < 10, 0 + Alert(“You’re broke!”), -10)
Notice I prefixed the Alert() call with “0+” to force a number plus whatever followed—null I hoped. There may be hidden side effects, but I won’t see them unless I dove into the code.

And if I had a String property x, I could set it directly as: x = Alert(“Hello world”)
It would load null into x.

So there you go. A bit convoluted and unexpected, and something I think a novice would Never latch onto. By the way, if I left off the “0+” prefix, I got two alert windows with an error in the chat window. Why two? I don’t know and don’t care.

I didn’t see this until after I composed my last message.
I accidentally tried this, and it didn’t matter. BTW, it has to be Alert with a capital A.
It complains using your syntax because it wants a number, and Alert doesn’t return a number. It will create a pop up window, but you will also get complaining in the chat window. Game players tend to get antsy when they see such things, so I try to minimize them or hide them if I can.

It appears that Alert() returns a null string, but I can’t prove it. And it doesn’t evaluate a null as a zero when a number is required. So I had to fool it by writing 0 + Alert() or “0”+Alert().

Reflecting on the situation, I’m not sure if the vassal guys changing what Alert() returned would improve matters. Sure, it could return 0, but String usage might then have problems. Convert nulls to zeroes across the boards everywhere when integers are needed? Maybe, but then it raises some backward compatibility issues. Perhaps the best solution is if Alert() and the other beanshell methods were documented, the solution could be explained there.

Yes, Alert with a capital ‘A’ (all Vassal provided Beanshell functions commence with a capital letter) and yes, it returns the null string. Returning anything else does not make any sense since the evaluator doesn’t know how you want to use it and for the compatibility reasons you lay out.

Beanshell does attempt to convert null to 0 if you add it to a number using +, which is why your ‘0 + Alert(“”)’ solution works without complaint.

You mean like on the ‘Beanshell Expression’ manual page you get to if you click the ‘Help’ button on the Calculated Expression trait, then the highlighted ‘Beanshell Expression’ link?

Any updates you have for any Reference Manual pages would be gratefully received by the Vassal development team.

AANNNDDD so I attempted to implement what I said, and it didn’t work. I had pared down my test case to simplify, so this worked:
credits = 0 + Alert(“No money”)
but this didn’t: credits = if(credits < 10, 0+Alert(“no money”), -10)
What failed was not the Alert but the If. It unconditionally shows the Alert dialog box regardless if the “if” is true or false. It doesn’t matter how much money the player has, he gets the warning. It decrements properly, but he always gets the Alert every time.It’s as if vassal were executing both the true and false expressions at the same time. I wonder if there is a problem embedding one method inside another. In any case, I give up. I am out of ideas.

I don’t know if you meant to be snarky, but if so, it’s not helpful. I touched help from the Expression Builder and got the Expression Builder help page, but that page as far as I can tell has nothing there about the various functions. And I don’t see any links from there to anywhere else. I said “if it exists” because the function docs may exist, but I don’t know where they are. As far as updates, I couldn’t write anything with any certainty that it would be accurate. All my conclusions are from personal testing, and its easy to make mistakes.

I apologize for sounding grumpy Stan. I was tired and ill and mis-read what you wrote.

You are currently THE expert on the Alert function and are best placed to suggest changes to the reference manual. Documentation is an area where non-technical users can make a big contribution to a project. Developers are hopeless at writing documentation because often, they aren’t using the software ‘for real’.

The Beanshell If statement is a Vassal add-on, it’s not a piece of ‘code’ that is ‘executing’. It is presented with the 3 arguments (test, true case, false case) already fully evaluated. Normally, this wouldn’t cause any problems if you are just evaluating numbers or strings. But the Alert function has the side-effect of popping up a message so yes, you will always see it regardless of whether the If test is true or false. The Alert has already displayed before the If function checks the result of the Test. There is no real way around this. However, I may be able to upgrade Vassal to use the latest version of Beanshell which includes the A ? b : c ternary operator, the lack of which is the original reason I created the add-on if statement. This would allow you to write { credits < 10 ? alert(“Not enough money”) : -10} and the alert would only get evaluated/executed if the test was true.

The Alert function seemed like a good idea at the time, but as you have shown, it is actually next to useless in practice as you can’t fire it off when you need it. Probably should have made it a trait triggered by a keystroke.

Well holy crap! Our Beanshell already supports the ? operator. I got something like this:

{ (credits < 10) ? Alert(“Not enough money”)+0 : -10}

working. If credits < 10 do the popup and don’t decrement, otherwise decrement.

Just be careful about using the Alert function in any calculated property displayed in a label or you will end up in an infinite loop of Alert boxes!

Wow! It works! It’s the answer! You earned yourself a virtual lollipop. What flavor? I’d choose coconut cream pie.

So I experimented myself a little and discovered what you might already know: ++, --, >>, <<, bit operators & and | work too.
About ++, --. They work after a fashion, but not in a useful way. If I have properties x = 0, y = 0, and I set a global property x like this: x = ++y, then it increments y and stores the result in x, but it does not change y itself. It’s as if it put y in a register, incremented it, but never loaded it back into memory.

Just for fun too, I put this into the expression builder: int add(int a, int b) { return a + b; }
It gave me a green check mark (!), but I didn’t bother trying it out because it wasn’t an expression.

Beanshell is a full, interpreted version of Java. However, the binding between Vassal properties and Beanshell variables is only one way. Beanshell can read Java properties but not write to them.

An expression is converted into a small program fragment and ‘compiled’ which returns a list of undeclared variables. The undeclared variables will be references to Vassal properties. At run-time when the expression is evaluated, the undeclared variables are created as temporary variables and set to the value of the corresponding Vassal property before evaluation.

Writing values back into Vassal properties is beyond the scope of the ‘Expression evaluation’ use case and Vassal is (mostly) not built to handle it.

I just got this to work in a useful way for me. This strikes me as something that should be added to “Tips and Tricks!” at the very least.

I was able to get this working, but don’t have a second computer handy. Do you know who sees these alerts? Is it the active player? Everybody? Or is it map-based?

Good question. I ran a test, and only the player who issued a command to cause it got the message, so you can’t suddenly broadcast to everyone “winner! winner! chicken dinner!”

Bummer. I was hoping to use it for interrupts, preempts, op fire etc…

I wonder if there is a way to GKC it to something that everyone would see…

Strange. That should not happen if both clients are running the same version of the module, the same beanshell should get executed against the same properties on both clients and issue the Alert to each player on their own machine.

Perhaps it’s intentional? In any case, please don’t change that behavior–we use Alert() in the Terraforming Mars modules to provide additional instruction when a player has to place a tile which has special placement restrictions. It would be rather annoying if the Alert pop-ups were visible to all the players.

Aha. I know what is happening and no, we won’t be changing the existing behavior.

Technical blah: The reason the Alert box is not being seen by other players is that the Alert box does not generate a Command as such, it is just the side effect of the execution of a piece of Beanshell during the creation of a Command in the source client (Assuming the Beanshell is even executing during creation of Command, which is not necessarily true). However, the generated Command has already incorporated the results of the Beanshell execution so that the destination clients don’t actually run the Beanshell at their end, they just use the results of the Beanshell calculations sent through from the source to directly update their state.

So, in a nutshell, if we want a Dialog popup that will be seen by other players, the behavior has to be incorporated into a Command that is sent through sendAndLog() and a Beanshell function inside the Expression Evaluator is not the place to do it. It really has to built into a new Trait. Good starter project for you m3tan :slight_smile: