Dynamic Property not returning right value for use in Mouse Over Stack Viewer

Thanks for all the past help here everyone.

I have a module where the values on the counter reduce as the units go into combat. One value is the Lost Stacking Points or “SPLoss” and the second is the assault value “CalculatedAssaultValue” which is derived from the original assault value “origAssault” minus the ratio of the original assault value over the original stacking points times the number of SP losses.

(origAssault - ((origAssault/origSPs)*SPLoss))

In the example below, shown in the console in javascript, it looks like this:

var SPLoss = 0
var origAssault = 25
var origSPs = 13

SPLoss != 0 ? (origAssault - ((origAssault/origSPs)*SPLoss)) : origAssault
25. <- Result which should be the origAssault because SPLoss = 0

SPLoss = 4 <- Change SPLoss to 4

SPLoss != 0 ? (origAssault - ((origAssault/origSPs)*SPLoss)) : origAssault
17.307692307692307← the correct answer. Each SP loss shold reduce the total by slightly under 2. This is the current assault value of the unit.

When I put this formula into a Dynamic Property it looks like this:

This should work I believe as it is the same as the Javascript that does work. However it does not reduce the CalculatedAssaultValue by just under two as expected, but by 1.

The counter shows an SPLoss of 4 (13-4=9) but the Calculated Assault Value is 21 a reduction of the origAssault by 4 but it should be 17.307692307692307 (Just under 8) (ignore rouneing) which would be right.

I think I am doing something wrong, but I do not see where.

Any ideas?

You’re giving BeanShell/Java integer values, so it’s doing integer math (i.e., dropping all fractions when dividing). You need to force either the numerator or denominator to a real number, for example: `SPLoss != 0 ? (origAssault - (Integer.toFloat(origAssault) / origSPs * SPLoss)) : origAssault`.

Edit: On reflection, I’m not sure that “Integer.toFloat()" is the correct function. Someone please correct me if that’s the case.

Interesting. I an check that, but if you reduce the counter to 1 SP, that is take away 12 SPs then it gives you an Assault value of 12 which is wayyyyyy off. However that might be it so I will try to look that up and see what happens.

Thank you for the tip. Will let you know how it works

OK I put this in the Dynamic Property

SPLoss != 0 ? (Math.round((float)origAssault - ((origAssault/origSPs)*SPLoss))) : origAssaultIt is like this part here “origAssault/origSPs" is evaluating to 1 which is multipllied to the SPLoss and that is getting subtracted from the original value. 

OK you got the problem but that above is not the actual solution. I could use help on that.

On MY end, I changed the assault value to 48 and the steps to 12 so they when divided they are integers and it works now as expected with one loss to the SPs reducing the Assault value by 4 (48/12)

But I could still use the help for the syntax for the math function to round the results.

48 - (4x1) =44

Because my ratio was evaluating to 1 each time it multiplied the SPLoss by one so works perfectly as not expected.

LOL

You should cast either the numerator or denominator to float - it does not help you to cast the first term of the subtraction. Only if you change one or both of the numerator or denominator to a real number, do you get a real division. BeanShell correctly evaluates the division before the subtraction - even if the Micro$**t Windoze calculator does not. That is, the inner expression should be

origAssault - (float)origAssault / origSP * SPLoss

This can obviously be simplified, and you can do away with the ternary condition with

origAssault * (1 - (float)SPLoss / origSP)

This is the entire expression - if SPLoss is 0, then the second term in the second factor is 0 and you multiply origAssault with the identity (1).

To round to integer, you can use Math.round

Math.round(origAssault * (1 - (float)SPLoss / origSP))

or “poor-man’s” rounding by adding 0.5 and casting to int (effectively flooring)

(int)(origAssault * (1 - (float)SPLoss / origSP) + 0.5)

Note, neither are true rounding because it does not disambiguate 0.50..., which means Math.round has little advantage over the “poor-man’s” - except, perhaps, clarity.

Note, rather than using JavaScript to test things out, you can use the BeanShell interpretor stand-alone. For example, if you put the following code in a file called - say - test.bsh

// Set-up 
SPLoss      = 0;
origAssault = 25;
origSPs     = 13;
// Calculate value - a little too complicated
New         = (SPLoss != 0 ?
               (origAssault - ((origAssault/origSPs)*SPLoss))
               : origAssault);
Expect      = 25;
print("SPLoss     ="+SPLoss);
print("origAssault="+origAssault);
print("origSPs    ="+origSPs);
print("test       ="+New+" (expected="+Expect+")");

// Change input 
SPLoss = 4;
print("SPLoss     ="+SPLoss);

// Calculate value - integer division
New         = (SPLoss != 0 ?
               (origAssault - ((origAssault/origSPs)*SPLoss))
               : origAssault);
Expect      = 17.307692307692307;
print("test       ="+New+" (expected="+Expect+")");


// Calculate value - float division (cast numerator) and simplified
New         = (origAssault - (((float)origAssault/origSPs)*SPLoss));
print("test       ="+New+" (expected="+Expect+")");

// Calculate value - factor and simplify
New         = origAssault * (1 - (float)SPLoss / origSPs);
print("test       ="+New+" (expected="+Expect+")");

// Calculate value - float division, simplified, and rounded 
New         = Math.round(origAssault * (1 - (float)SPLoss / origSPs));
Expect      = 17;
print("test       ="+New+" (expected="+Expect+")");

// Calculate value - float division, simplified, and poor-man rounded 
New         = (int)(origAssault * (1 - (float)SPLoss / origSPs)+.5);
Expect      = 17;
print("test       ="+New+" (expected="+Expect+")");

and then run

java -cp /usr/share/java/jline.jar:/usr/share/java/bsh.jar jline.ConsoleRunner bsh.Interpreter test.bsh

you get a more valid test (adjust for your installation of BeanShell).

Though the development of BeanShell it self seems rather stale, not that Vassal uses and older or patched version of BeanShell, which means one cannot be entirely certain that Vassal will support everything that stand-alone BeanShell supports.

Yours,
Christian

This is really amazing. I appreciate it so much,

I do have it working but the expression you gave made sense to me but did not work so I set the numerator to float in the ternary expression I built and that did the trick with it wrapped in the Math.float

This is really wonderful to have you take the time. I will try out the debugging when I get more time. I now have 600 counters that need Photoshop and work in Vassal.

Customer (non-paying one…) is happy, I want to get access to more modules and make their counters dynamic. Vassal is BETTER than the original games and I want people to get access to some of this power .