Vassal 4 Wishlist from an experienced module designer

Greetings! I don’t know the current state of the Vassal 4 project, as there don’t seem to have been updates for some time, but in the hopes that it is still live (or if some further updates to the 3 line after the coming 3.3 are to be considered instead), I have a few wishlist features to contribute. I’ve got about 400 hours of work into the Paths of Glory 9.4 module, during which time I’ve been able to hone a wishlist down to things that I think are “legitimate” – i.e. things that are either not presently do-able in the existing engine, or are only do-able in a very cumbersome (slow performance) kind of way. Possibly some of these have already been suggested in the past, but I thought it might be useful to the team have a list from an experienced module builder.

Chat - Ability to set different bold/italic/font-size/font-color/etc in the Chat window, for different game messages. Presently all the game messages come out in a single monotone of one color and boldness setting, and only “chat messages” from the players themselves and system messages are entitled to a separate color. It would be fantastically useful to be able to have certain “more important” messages have a different boldness, and to have certain classes of messages have a different color. Ideally the boldness could be changed WITHIN a single message, so that I could bold e.g. a single word or phrase within a report message.

SumStack – instead of only being able to sum the value-of-a-property across a stack, it would be fantastic to also be able to sum the number of pieces in a stack that have a particular property. So SumStack(“GE”) would return the number of pieces in the stack that contained a GE property. Even better would be able to SumStack the number of pieces that matched an expression (e.g. a SumStack for the expression {Side == “GE”}. Also useful would be to sum for the number of unique values of a particular property (e.g. a SumStack for the marker “Side”, such that if a stack of three pieces contained two pieces where Side==”GE” and one piece where Side==”AH” then the sum returns “2” for two unique values.)

Movement Trails – there are many use cases in which Movement Trails are mostly useful only if they can be turned on or off globally for all pieces. Unfortunately the current 3.2.17 implementation only offers per-piece switching, it also makes building a global-trails support extremely cumbersome because (a) only “toggling” trails is supported, no way consistent way to force trails to a known state, (b) trails internal “locallyVisible” flag is often only first initialized when the piece is drawn for the first time, creating bugs with not-yet-seen units sitting on reinforcement boards. Functionality that would help:
(1) Provide an option to force trails on and off globally for all units (preferably with a “matches expression” field)
(2) Either initialize locallyVisible at At-Start Stack execution time, or ensure that a clear-movement-history command will set it properly rather than using the unitialized garbage value.
(3) Allow the trails-on flag for an individual piece to be forced to a known state (rather than only toggled).
(4) Allow the trails-on flag for an individual piece to be “read” as a property.
(5) Allow the “Moved” flag for an individual piece to be “written” as a property, and if it is written to false the move history should be cleared.

Stack Selection - When I roll over a stack and receive a “Mouse-over Stack Viewer” box, how about if I can hold the SHIFT key down to force the box to stay up while I can then select an individual piece from the stack by clicking on it? And potentially drag pieces left/right to reorder them?

Hand Arrangement - When I draw a bunch of cards from a “deck” and put them in my hand, I’m allowed to have a hand as big as I want, but the cards only want to arrange themselves horizontally in a massive line. How about the option to have hands use multiple lines of cards e.g. if I resize my hand window to have room for several rows of cards?

“Once Per Stack” Commands - When the player has selected a whole stack of pieces, and then executes a key command on the stack (from either right+click menu or a hotkey), it would be super-useful to have a system property FirstPiece which was set to “true” for the very first piece in the stack to receive the key command in question and “false” for every other piece. That was I could implement functions to be performed once per stack rather than for every single piece in the stack. In the present version, a few once-per-stack functions can be implemented by using a kludgey global semaphore, but there are others for which even this is not possible.

Turn Trackers “writeable” – when I create a Turn Tracker, it writes its value(s) into global properties (e.g. “Turn”), which is helpful. However, if I then set the value of that Global Property myself (responding, perhaps, to the Turn marker being dragged a different place on the board), the Turn Tracker does not notice the change and does not update. This leaves me with the unfortunate choice of either “building my own” Turn Tracker (e.g. with my in-game Turn marker) which means giving up the dockability-into-the-toolbar, or else staying with the toolbar turn tracker and accepting that I can’t have any functions in the module itself that update the Turn (e.g. to set up a scenario that “starts in 1942” or to allow dragging the turn marker on the board to update the turn).

“Mask” ownership of cards to be properly/consistently initialized at startup to a predictable state. Presently cards that start face down in decks on the mapboard appear to receive “random” (presumably uninitialized) mask ownership data (so for example doing a draw-specific-cards from a face-down deck at runtime will randomly mask some cards and not others – this can be “fixed” in a scenario setup by manually dragging every single card to the discard pile and then putting it back where it goes - must be manual as even a global send-to-location doesn’t work - but this is unbelievably cumbersome and prone to introduce misplacement of cards in the scenarios). It would be great if this Mask ownership were either automatically initialized to “” (unmasked) ownership, or (better) if there were a way to specify the initial ownership, with being the default.

Pieces not so hair-trigger fidgety - Ability to set a pixel tolerance value for pieces/locations, such that accidental “drags” of pieces for only a few pixels will have the pieces snap back to their original locations w/o firing any triggers. Presently the pieces are so sensitive that many attempts to “double click” on a stack are instead resolved into moving it a few pixels, which both fires a lot of moved-on-map triggers unnecessarily and also tends to mush around pieces nicely arranged on cards to go to the wrong places. Ideally, when this pixel-tolerance is in effect, the player can still force a piece to be adjusted “by one or two pixels” through the expedient of first dragging the piece outside the minimum tolerance zone, and then adjusting it back in – when I start dragging the piece/pieces/ will actually stay completely put until I’ve dragged at least, say 5 pixels (but let module designer adjust this) and then be moving “live” once I hit the tolerance zone – I could then move it back inside the tolerance zone if I really did want to adjust the thing only a pixel or two.

Ability to hide and unhide toolbar items - Presently I can either put something on the toolbar or not put it there, but I can only hide it in a “requires restart” mode. I would like to be able to fire GCK’s that enable and disable toolbar items.

A few more:

Search - In my really big modules (open the latest Paths of Glory if you want to get an idea - look at Global Prototypes, and look at the at-start stacks under Map), the lists of things get REALLY LONG. I would LOVE to be able to do a “search” for an item. Preferably would be a default option to search only for things named that (i.e. where the search string is a substring of the name of the Piece, Prototype, At-Start Stack, or whatever), or to search for things in Traits as well. I find myself using XMLSPY to search the buildfile on the side, which is effective but awkward.

Folders- I wish I could make folders for my At-Start Stacks especially, but also for my Global Prototypes. So that I could organize things better and not have to scroll through them.

Drag from toolbarI wish I could put a few frequently-used markers right onto the Toolbar, and have them be draggable straight onto the board as if they were on a Marker Palette.

Deselect PieceWhen moving a stack of pieces there are use cases where I’d like to be able to “drop off some strength points” (e.g. For the People) while I’m moving. So when I drop them off, I wish there was an option to not have them “stick to my stack” by staying selected and stacked with my moving units. I wrote a custom java class that seems to more or less fix this for me, but I think it would be a good core feature.

Dragging Options - right now when a group of pieces is dragged to a location on the map, Vassal tries to drop them at the same relative x,y offsets. I have a use case (For The People) where this is not desirable, and I need to be able to have everything being dragged to a space go to the same location. I solved this with a custom java class, just overriding one method/line of the PieceMover, but it would be an easy flag to include on e.g. a by-map basis. And obviously if Vassal 4 is going to have scripting instead of custom java classes then it will be even more important to folks like me that the option be supported.

Dragging Trigger - When a disparate group of pieces is dragged to a new location, they can each individually detect that they have moved (“MovedOnMap” trigger from the Map in my case), can each fire GCK’s, and so forth, but I have no way to fire ONE GCK for the whole group without having every one of them fire it off (causing potentially a bunch of unnecessary performance lag). I would set a semaphore to make sure only one of the pieces fires off the GCK, but once the semaphore is tripped I have no way to know when to clear it again (i.e. when movement of the whole group is done). So I wish there was an option similar to the when-moved trigger from the map, but it would only send it to ONE of the pieces in the group that just moved. I don’t actually care which piece gets the trigger, I just care that one-and-only-one gets it. (Use Case – in For The People stacks can get unwieldy with piles of Armies, Generals, and Strength Point markers, but there’s actually a lot of room in each space, so I have pieces in a space “auto-organize” when a piece moves in or out – stacking so that you can easily see the relevant info for each of the three main types of pieces. So I fire a quick pair of GCK’s to pieces in the “new” location, and a quick pair of GCK’s to pieces remaining in the “old” location. The GCK’s are pretty quick, but not if I’m dragging e.g. 4 pieces in a group and so it’s firing SIXTEEN GCK’s… and tragically, the original 4 GCK’s would do just fine)

Radius for Mouse-over Stack Viewer - In the mouse-over stack viewer controls, I wish there was a checkbox and field for “Include pieces within X radius” of the point the mouse is at. This way I wouldn’t have to ensure pieces all arrive at the exact same pixel location for them to be accessed by the rollover magnifier/viewer. It’s nice to be able to let players have more control over how they arrange their pieces in a space, but also important to be able to accurately find out what’s IN a space - preferably without having to toggle on/off various layers. The Stack Viewer is perfect for this, but would be much more useful with a configurable radius (or alternatively, a setting that said “include anything at same Location”)

p.s. Imma just keep putting these here, haha :slight_smile: Call me an optimist!

Drag-Selection filters - the “Do Not Stack” feature offers some selection filters, one I’m finding I really want would be a protection against drag-selecting only. In other words, for pieces to be “normally” selectable when simply clicked on, but to be filtered out of “dragging a box around pieces”. So for example, dragging a box around a group of units would pick up all the units but not pick up any of the markers. Obviously I can already do this if I’m willing to make the markers only be selected by e.g. alt+click, but that’s unintuitive to teach a player; likewise I could make the markers unmoveable, but I don’t want that either. Whereas letting the player click on the markers normally (and especially right+click on them to get the context menu), and then just blocking the markers from accidentally getting swept up in a box-drag scenario would be very useful.

Aaaaanyway, I have been able to overcome this for my module by overloading/overriding the KeyBufferer class, and simple ignore the mouse events if “p instanceof Immobilized”, in other words nothing in my module that has Do Not Stack property will be box-selected.

But I think it would be a super-useful Vassal 4 feature if I could have more filter controls on what is allowed to be box-selected and when. Ideally I’d be able to box-select these types of pieces as long as there are ONLY that kind of pieces in the box-select, but as soon as it gets one “real” unit it kicks all of the filtered ones back out. I could rewrite my KeyBufferer to do that, but I’m trying to minimize the maintenance factor for future revisions – just suggesting it as the ideal implementation for a future Vassal.

Brian

Simple Path-Finder for e.g. Supply Lines - A somewhat heavier lift than some of the other items, but since I’m thinking of writing a custom java class for it myself that makes me think it is straightforward enough (and useful enough) to be a possible Vassal 4 feature: imagine I get to specify a Region (e.g. LocationName) on my grid and tell it to ping out a pathfind – and I can then check any OTHER location to see if it is connected to the first. One would need a way to set which points on an irregular grid (or for that matter a regular grid) are actually connected to each other, which is something we haven’t previously included in Vassal modules, but it wouldn’t be technically difficult to include fields in the mapboard grids for that. And then one would want to be able to pass an expression to specify certain pieces to look for (or better, Traits-of-Pieces) to look for along the way that would block a path from being traced through/into that space. I imagine it was having an interface analogous to the “If” function in current Vassal expressions, e.g.:

Pathfind(LocationName, “Washington, DC”, ((EnemyUnitsHere==false) && (EnemyControlHere == false)))

And the return value would either be zero for “fail” or the number of spaces as a distance. With this function one could then easily and conveniently highlight which units are in supply, out of supply, etc.

I have a meta question about VASSAL 4.

Since this is moving to C++ it seems a lot of work will have to be done. This gives an opportunity to rethink the design. So for example some properties that mean essentially the same thing have different names according to context. for example “pieceName” versus “PieceName” and “OldMap” versus “CurrentMap”. There could be other issues like that. So at one level it would make sense to try and rationalise. On the other hand this would BREAK EVERYTHING.

So which of the following options is envisaged:

1.) Maintain absolute like-for-like backwards compatibility?
2.) Break everything and be damned (surely it would make sense to pick a different name then)?
3.) Rationalize everything but maintain backwards compatibility for some time?
4.) Build a conversion tool?

This is just my suggestion thread rather than an actual blog by the developers, but what I’ve picked up from the various hints they’ve left around is that (a) there will be a conversion tool, and (b) they may not “break everything” but they’re definitely intentionally going to “break” (i.e. radically change for good reasons) at least a few important things (like save/log files won’t contain piece & prototype definitions).

Thus spake Cattlesquat:

This is just my suggestion thread rather than an actual blog by the
developers, but what I’ve picked up from the various hints they’ve left
around is that (a) there will be a conversion tool, and (b) they may not
“break everything” but they’re definitely intentionally going to “break”
(i.e. radically change for good reasons) at least a few important things
(like save/log files won’t contain piece & prototype definitions).

This is correct. The aim is that modules without custsom Java code will
be convertible.


J.

Okay, next installment! As I’ve started to hear a bit about the architecture of Vassal 4 (i.e. C++ with scripting in perhaps LUA), I’ve started to think about the faster performance this could bring (hey, my clunky module will run a lot faster!). It also reminded me of a ripe area for performance improvement – since even in C++ I’ll bet a Global Key Command with several hundred pieces and cards will still have a perceptible delay, especially it has to go in & out of script to matching conditions, etc.

So… How about the following commands, to move some of the most common filtering over to the fast side of the equation:

  • “Zone Key Commands” - Zone is specified in a field, and only pieces in the Zone receive the signals. Everything else just like GKC.
  • “Region Key Commands” - Region is specified in a field (i.e. LocationName matches), so only pieces in e.g. “Berlin”.
  • “Piece Key Commands” - Is there a way I could reference a specific individual piece, perhaps by its unique id? And then send a command ONLY to that piece. Because there are a LOT of GKC use cases that involve a single piece (e.g. “Move this army’s separate strength marker to its new strength level”, “Add a victory point and move the marker”, “Increase the Union Blockade Level marker by one”, etc, etc, etc). Admittedly those are already the fastest GKC’s because the filtering already works pretty well, but they often need to be done alongside other chunkier GKC’s so they end up adding in.
    * “Stack Key Commands” (?) - Would be like a piece key command, but would apply to everything in its stack. (And for example a piece could apply this command to its OWN stack).

Brian

I’ve also done some further thinking (and prototyping in custom classes) on the earlier issue that I called Dragging Trigggers, addressing the present difficulty of getting something to happen “exactly once” per drag-of-pieces or press-of-key. As I’ve prototyped through the various use cases in my own modules, here’s what I’ve come up with so far as my best foot forward for a future architecture:

Command Counter

  1. Two properties, “CommandCounter” and “CommandTotal” are exposed by Vassal.
  2. The “CommandCounter” is reset to 0 whenever any of the following three things happen
    a) A group of one or more pieces is dragged to a new position by the player
    b) The player invokes an actual keystroke
    c) The player selects an item from a right-click menu (e.g. of a piece or group of pieces)
  3. “CommandTotal” is set to the total number of pieces that are being dragged (or the total number about to receive a trigger from the right-click menu command or hotkey press)
  4. In the case of a drag-move, CommandCounter is incremented by one as each piece receives its keystroke-on-move for its map. In the case of a right-click menu or keystroke, CommandCounter is incremented by one as each piece receives the relevant keystroke.

This allows a piece receiving either a key-on-move OR a menu/hotkey command to know where it falls in the processing of a command. So for example…

  • A piece in Paths of Glory notices it is the first to receive an activation hotkey, so it puts an activated-to-Move marker on top of its stack, knowing any other pieces it is stacked with will realize they aren’t the first and won’t create additional spurious markers.
  • When a group of pieces just got dragged somewhere in For The People, they all issue their “reports” to the log and they all increment/decrement any properties they’re keeping track of based on the move, but only the LAST piece to get moved runs the “now pretty up the arrangement of pieces in this square” GKC.

Hopefully this is useful when you’re thinking about Vassal 4. Even if you don’t choose to do it, I hope you’ll at least make a way that a module designer could apply logic like this from a script. (Lest all my modules break permanently with Vassal 4, eek!)

Brian

Hi Brian,

There are many things that the Vassal 3 does not do well (or at least not flexibly enough). You have picked two of them that certainly need work. I would put these under the headings:

  • Global Key Commands - Efficiency and Flexibility
  • PieceMover - Flexibility

Global Key Commands are handled particularly badly. They do not scale well at all. When you issue a Global Key Command, the following happens:

  • Get a list of all the Maps in the Game.
  • For each Map:-
    • Get a list of every piece on the map
    • For each piece on the Map:
      • Check of the properties match and apply the Global Key Command if a match is found.

No shortcuts. Even if you use a range-limited GKC command, it still checks every counter on the current map.

At a minimum in Vassal 4, I would like to see all counters within a regular grid to be stored in qtree so that we can efficiently find units within a specified area.

The PieceMover is just totally inflexible.

In Vassal 4, the idea is that there will be many more ‘hooks’ available where you can specify Lua code to customise the operation of components. For the PieceMover, you might have the following hooks:

  • BeforeMove hook - Called before the drag starts.
  • AfterMove hook - Called after the drag ends, before the pieces are dropped.
  • AfterDrop hook - Called after the pieces have been dropped on the target map.
    There would be standard functions you could call within the hooks to examine the list of selected counters, and takes actions such as send them back to where they came from if the target location is invalid.

You might also be able to define custom PieceMovers with different properties that can be linked to specific Maps or Zones etc.

Some of the other things Vassal 3 does not do well:-

  • Seat allocation and identity
  • Decks and card handling in general
  • Piece Image regeneration when state changes

Brent.

That sounds heavenly, Brent! :smiley:

Lots and lots of hooks! Yay!

Brian

So what I think would be really great is if formal design documents were produced. I think there should be enough domain knowledge to produce such documents, and enough experience in the community to produce constructive comments.

Thus spake slimy:

So what I think would be really great is if formal design documents were
produced. I think there should be enough domain knowledge to produce
such documents, and enough experience in the community to produce
constructive comments.

This what I aim to do after 3.3.0 is released.


J.