The Long Road - Module Library - Vassal
Vassal is an open-source game engine for building and playing online adaptations of board games and card games.

I have been busy splitting my code into a fourth action counter (as discussed in my other thread about execution speed), so that the added calculations will not slow the code down.
]]>You can request a version update with the change.
That said, the simplest fix is to update the Allied Powers Player Hand and Central Powers Player Hand Board (And any other location in which cards will be dealt to) with the following Key Command application. I would go back and do this as an update to the original 10.8 version, to retain the original card play method versus creating more boards which would create more player confusion. The original card dealing method by cattlesquat is an elegant method for dealing the cards to the player boards. But remember to update the new version number, also to limit confusion.
Again, I recommend attempting to contact the current project owner, however you may consider creating a separate project page specifically for Paths of Glory CDG Solo System as it would prevent confusion for new players as to which version to download and play, depending on if they want the original version or the CDG Solo System version. At any rate, communication with the current module owner as to your requests, and/or intentions is always the fair thing to do, and when appropriate, give credit if you post a new project.
]]>That usually works without disabling protections completely.
Just to be clear: The two methods either downloading via curl or some other utility, or xattr on MacOSX does not disable protections completely - only for Vassal. Also, the method of going through the GUI does the same as the xattr method.
@adamevois - if you have screenshots that illustrate the procedure on a relatively new MacOSX machine, please consider to post them so that we can add it to the main body of the article.
Yours,
Christian
In my latest version of the module for “Carrier Battles: Philippine Sea” I make some hex calculations that sometimes do not give the right result. Maybe somebody could advise me a better algorithm.
For hex-grid calculations it can be beneficial to do a transformation to different coordinates. In particular the so-called cube coordinates can be quite beneficial.
If you have the location (x,y) where x is the column number, and y the row number, then the cube coordinates q, r, s are given by
where % is the modulo operator (x % 2 is 0 for x even, 1 for x odd), the division above is a truncating (integer) division (3/2 = 1, f.ex.), and o is an offset (0 or 1) depending on whether rows are high or low in even columns.
Distance between L1=(q1,r1,s1) and L2=(q2,r2,s2)
|L1 L2| = (|q1 - q2| + |r1 - r2| + |s1-s2_|) / 2
This means that distances calculated in the column or diagonal directions (straight lines) are fairly straight forward.
For more on different hexagonal coordinate systems, see this excellent page.
Incidently, Vassal uses cube coordinates internally.
Also note, that the the calculations above are entirely integer calculations, which means there’s no rounding error problems.
I recreate these coordinates in my module The Battle of Agincourt. There, I need to know, given a units facing
Suppose you have configured your grid to have locations of the format XXYY where XX is the zero-padded column, and YY is the zero-padded row. Then you can do something like
ColumnNumber{Integer.parseInt(Location.substring(0,2))}RowNumberLocationQ{ColumnNumber}LocationR{RowNumber - (ColumnNumber + (ColumnNumber % 2)) / 2}LocationS{-LocationQ - LocationR}Define similar properties for other locations - say Target to have those in the cube coordinates. Then you can calculate distances like
DistanceToTarget{(Math.abs(TargetQ-LocationQ)+Math.abs(TargetR-LocationR)+Math.abs(TargetS-LocationS))/2}Because the calculations of row and column numbers uses Integer.parseInt, everything will be done as integer calculations with no rounding errors (possibly overflow - but very unlikely).
Hope that can be of some help.
Yours,
Christian
Then click on the link to Niedowidek’s page…
Then select message to inform the owner of the Dien Bien Phu The Final Gamble of the issue and the solutions I offered.
]]>The problem is in the Thumbs Test [Action Button] The Button Icon is looking for the image
thumbs up — kopia.png. It is still in the images folder but has been delinked from the button icon.
I can’t be sure, but it looks like this action was a test that is not implemented into the module or never completed. Without knowing the designer’s intent for this action it’s impossible to tell.
The fixes would be to restore or complete the intended action button purpose or if the action is not needed, remove the action completely
or - a new image for the Button Icon can be selected, saved, then removed to clear the process and resaved.
]]>NetworkError: Request failed
]]>Vassal is an open-source game engine for building and playing online adaptations of board games and card games.
I am interested to play some of these games:
Red Storm: The Air War Over Central Germany, 1987
or the expansions
Red Storm: Baltic Approaches
Thank you
Pierre
]]>...using VASSAL 3.17.20
3.7.20 presumably (the latest version).
]]>But I’ll give it a shot.
]]>As Gemini suspects, I am not comfortable with constructing custom Java code for Vassal, but it seems like I should take a look.
As it stands, my current code gives the correct hexes for most positions. In fact, so much that after having noticed the problem once, I had difficulty recreating it. But once I had found the situation I used as an example, all intercept distances larger than 2 cause an error.
In order to give the players a fine module that works for everything else, I might calculate the distance of the raid to the target, and print a warning message to the playerif it is not correct! Then I could issue a correction later,
]]>Gemini AI (caveat emptor):
]]>The issue described in the post is a classic “grid rounding” error. The user is treating hex coordinates (the 4-digit strings like 1605) as standard Cartesian (X,Y) coordinates and applying linear interpolation to them independently. This fails in hex grids because the relationship between the horizontal and vertical axes is not square, and standard rounding on two separate axes often results in a “drift” to an adjacent hex that doesn’t actually lie on the straightest path.
To solve this for a Vassal module, the most robust approach is to convert the coordinates to Cubic Coordinates (x, y, z) where x + y + z = 0.
The Solution: Linear Interpolation (Lerp) in Cube Space
Instead of the user’s current BeanShell math, the algorithm should follow these steps:
Convert to Cube Coordinates: Convert the Origin and Target hexes from Offset (the 4-digit Vassal format) to Cube.
Linear Interpolation: Find the point that is exactly $N$ distance away from the Target toward the Origin.
Cube Rounding: This is the most critical step. Since the “exact” point will have decimals (e.g., x=1.2, y=-3.4, z=2.2), you must round them back to the nearest integer such that the x+y+z=0 constraint remains true.
Convert back to Offset: Convert the result back to the 4-digit string.
Recommended BeanShell/Vassal Implementation
Since the user asked if a function already exists to find a path, they should use the
GridLocationandMapclasses in Vassal’s API if they are comfortable with custom Java code. However, for a pure BeanShell solution within the module, they can use this logic:1. Calculate the Ratio
The user wants a hex at a specific
InterceptRangefrom the target. The “progress” along the line (from Target to Origin) is:
t = InterceptRange / Distance2. The “Cube Lerp” Logic
For each axis (x, y, z), the coordinate of the intercept hex is:
Intercept_x = Target_x + (Origin_x - Target_x) * t(And similarly for y and z).
3. The “Cube Rounding” Function
This is where the user’s current code fails. To fix it, they need to implement this rounding logic:
Java
rx = Math.round(Intercept_x) ry = Math.round(Intercept_y) rz = Math.round(Intercept_z) x_diff = Math.abs(rx - Intercept_x) y_diff = Math.abs(ry - Intercept_y) z_diff = Math.abs(rz - Intercept_z) if (x_diff > y_diff && x_diff > z_diff) { rx = -ry - rz } else if (y_diff > z_diff) { ry = -rx - rz } else { rz = -rx - ry }Why the user’s current code failed
The user’s example (Origin 1605, Target 1410, Range 4) failed because they were doing:
((Origin_a - Target_a) / Distance) * InterceptRangeThis treats the hexes like they are on a square grid. On a staggered hex grid (like the one in Carrier Battles), every other column is offset vertically. Simple division doesn’t account for the “zigzag” movement required to move diagonally in a hex coordinate system.
By switching to Cube Coordinates, the “distance” between any two adjacent hexes is always 1, and “straight lines” are mathematically consistent, which eliminates the +1/-1 hex error they are seeing.
The situation is this: A Japanese is sent from an origin hex to a target hex some distance away. The target detects the raid when it is 0-5 hexes away from the target. I need to calculate the number of a hex lies the interception distance away from the target hex in a straight line. I have the distance between the origin and the target through the Range() function of attached counters.
I split the hex numbers into a) the first two digits, and b) the last two digits and treat the a and b parts separately. My algorithm goes like this: subtract target from origin, divide by distance, and multiply by Intercept Range, then round. My BeanShell code for the a part is this:
{((Math.abs(((RaidOrigin_a-RaidTarget_a)*100)/Distance*InterceptRange)+50)*((RaidOrigin_a-RaidTarget_a<0)?-1:1)/100)+RaidTarget_a}
The code for the b part is similar.
It works for most situations, but sometimes it gives a wrong result because the rounding of the a and b parts conspire to give a result that is off by one hex.
I can best illustrate this with an example.
Here the origin is Guam at 1605, the target is TF58 at 1410, and the interception range is 4, so the raid should be at 1506 or 1607, but it ended up at 1507 which is only 3 hexes away from the target.
.Perhaps there already exists a function that gives the straight path between two hexes so that one can count until the right hex is found for the raid?
We can ignore the situation where the interception is further away than the distance between origin and target because in that case the raid is placed in the origin hex.
]]>I own Borodino 41 too, and Black sea and Aachen fom the same serie.
I am french
Daniel
]]>Probably I’m very stupid but I cannot find out them.
Help me, please.
]]>Scott
]]>The Scott_Eagles account was a placeholder account created during last year’s module library conversion. Placeholder accounts were created when there were usernames we couldn’t automatically associate with accounts.
I’ve merge the placeholder Scott_Eagle account into the seagles account.
]]>As an aside, losing the server connection still leaves the user logged into the game. That created another issue as I was the game host and Vassal would not let me log back in.
]]>I split up the code in three “action markers” that call each other sequentially, and kill themselves after use, and that did the trick. The code is now executing at the speed I hoped for.
Actually, there is one stage where there is a slight wait time while the code calculates the facing of a couple of units based on the direction to a target. The rest of the code in the same action counter executes fast, so I can’t speed it up further by introducing a fourth action counter. This code does some simple arithmetic, and I might be able to speed it up by trying to eliminate BeanShell, by I don’t know if it is worth it.
I have not transformed the tables because the speed is already fast.
Instead of making the action counters invisible, I gave them some red graphics that flashes like a little explosion in the hex, and looks nice in my opinion.
Thanks for the thoughts and inspiration.
]]>☐ Perform different Key Commands depending on whether properties match
Are you referencing some document or the like? Please provide the source for the above - I cannot seem to find it.
You need two Trigger Action traits - one for the true condition and one for the false condition. If you want the command visible in the context menu, then you may need three Trigger Action traits - one to steer the call, and the other two for the true and false conditions.
Without context menu command
Ctrl-C[Ctrl-J,Ctrl-C] (or IncrRowIndex and CheckSlotAgain){RowIndex == $RowIndex$ && PieceName != $PieceName$ && CurrentMap == "YourMapName"}Ctrl-C[Ctrl-M] (or MoveToSlot){RowIndex != $RowIndex$ || PieceName == $PieceName$ || CurrentMap != "YourMapName"}If you need a visible command from the context menu, add the two above Trigger Action traits, but replace the Key in both cases with somethine else - say doCtrlC (named command), and add another trigger trait
"Do the command" (Context menu entry)Ctrl-C[doCtrlC]The reason is, that Vassal will always try to add commands with context menu titles - even if their conditions are disjoint.
BTW, your condition seems off. The condition is executed in the context of the piece, which means that PieceName and $PieceName$ as well as RowIndex and $RowIndex$ will always be the same. Thus, your test is always false. However, if you Piece’s name is A, then
{PieceName!=$PieceName$}
will effectively become
{String("A")!=A}
which will cause an exception, because the variable A is not defined, and you cannot compare a string to an undefined value. Instead, you need
{PieceName!="$PieceName$"}
which will become
{String("A") != "A"}
which is valid. In short, it seems you need to remove the PieceName!=$PieceName$ and RowIndex==$RowIndex$ from your condition.
The pattern PropertyName == $PropertyName$ is really most useful when a command is sent from one piece to another - as in Global Key Command, Place Marker, Replace with Other, Set Piece Property, or Attachment, when matching against other pieces. For example, piece A with property Foo with value "Bar" want to send a command to other pieces with the properpty Baz that has value "Bar", then a selection criteria would be
{Baz == "$Foo$"}
Note the quotes - the $...$ expressions are substituted, on the sender side, with the literal value of the property on the sender side - before the comparison is done on the receiver side.
Yours,
Christian
in the Trigger window? I’m trying to add If True: If False:
Trigger Action: CheckSlot
- Command: CTRL C
- Condition:
AnyPiece(
RowIndex == $RowIndex$
&& CurrentMap == "YourMapName"
&& PieceName != $PieceName$
)
- If TRUE Performs:
CTRL J (IncRowIndex)
CTRL C (CheckSlot again)
- If FALSE Performs:
CTRL M (MoveToSlot)
]]>S.
]]>If so, “Please merge my duplicate accounts.” ![]()
Thanks,
Scott
Ask for them to be merged.
]]>I’m the owner but have no editing capability. What I want to do is add another site user as an Owner.
Anyone know what I’m missing here?
Thanks, Scott
]]>For my game, I have larger cards that are the locations and smaller cards that are items, enemies, or heroes, which should be placed on top of the larger cards without movement restrictions. To avoid selecting the larger cards, I set them to only be selected when CTRL is pressed.
So far so good. Now I wanted to create a Mouse-over Stack Viewer function to zoom in on all the pieces that are on top of the larger card, but the best I could do was show only one card at a time.
Is there a solution to this? Please help me.
]]>Players do have to have the center of the ship counter inside the system hex for correct reporting. Players can click on the ship in the list to center the view on selected ship/Base/Trade-Demand
]]>