Is there a way I can include random selection in my module? What I mean by this is could I for example make the random selection to accomodate certain situations such as cards in hand. If on Turn 1 I have 5 cards and need to discard a random card and then on turn 2 I may only have 3 cards and must discard a random card…
I can think of two ways to do this:
Simple: create a dice button with a number of sides equal to the max cards in a player’s hand (for example, 6). Each time you need to discard a random card, click the button. Count a number of cards off from the player’s hand and discard that card. If the die roll exceeds the number of cards in your hand, re-roll. (For example, if the player has 4 cards laid out left to right, roll the die. If you roll a 2, discard the second card on the left. If you roll a 5, re-roll until you get something from 1-4.) Maybe not the most coolest solution, but it’s simple to set up and play.
More complex: create 1 empty deck for each player that is set to random shuffle (call it a shuffle deck). Put a Return to Deck (RTD) trait on each card that returns the card to each player’s private shuffle deck, and another RTD that moves the card to the discard pile. To each shuffle deck, add a Deck GKC that will apply the Discard RTD command to 1 card.
When it’s time to discard a random card, use the first RTD to move all the cards to each player’s shuffle deck. (You could set up a Global Key Command button to do this for everyone at once.). Then right-click on each shuffle deck and trigger the Deck GKC…this will have the effect of moving 1 random card from the shuffle deck to the discard pile. Players can now retrieve the remaining cards from their shuffle deck and play resumes.
What I ended up doing is create a random die roll (using random text) according to the number of cards a player may have in his hand (min 2 - 7). Didn’t bother to include 1 since it wasn’t necessary. This takes up space on the icon bar but it’s quick and easy to use.
Clever. It appears that this may be the only way (without custom classes) to perform true automated randomness without the player having to supply a count value to a variable-sided die or manually count off cards.
I like your idea, but it has a few drawbacks: (1) Moving the cards back and forth could be disruptive if the player has arranged his cards in a certain way in his hand. (2) The cards to be randomly selected from might not all be in the same hand. (3) The intended result of the random selection might be something other than discarding the selected card. (4) The resulting number of cards to be randomly selected might be more than 1.
All of these things are true in the Cosmic Encounter module I’m developing. So I extended your idea to accomplish the following:
- Player selects one or more cards (anywhere in play; need not all be in the same hand, stack, whatever).
- Player clicks a Random Selection toolbar button: One of the selected cards is randomly indicated by activating or incrementing a Layer property.
- Player clicks a Select Another toolbar button: Another (different) card in the selection group is highlighted by setting its Layer.
- Player clicks a Clear All Random Selection buttons: all highlight layers are turned off.
- None of the selected cards are moved around or modified in any way except to set/clear the random-selection highlight layer.
There are too many details to cover here, and my prototypes are pretty complex (lots more stuff than just this), but I’ll describe the basic approach. The idea is to use your trick of sending pieces to a deck that’s set to always randomize, but instead of sending the actual cards I send something else in their place: a “delegate” that I create on the fly. A link is created from the delegate to the Card, all the delegates are sent to the always-random Delegate Pool deck, and one delegate is drawn from that deck. The act of drawing the delegate tells the delegate to tell its linked card to set its own highlight layer. The other delegates not chosen remain in the Delegate Pool so the user can click Select Another and get a second, third, etc. selection from among the remaining candidates. The delegates and their deck are off in another window that the players never really see.
Linking the delegate to the card is a little tricky. I know each object has its own unique ID, but the documentation doesn’t tell us if this is exposed to the designer; so I rolled my own. I have a global property called UniqueID that goes from 0 to 100000 with rollover. Each time a card is triggered for the selection process, it increments the global property (to produce a new unique ID), copies the UniqueID to its own DelegateID property, then does a Place Marker to create the delegate, passing a keystroke to the delegate. That keystroke makes the delegate copy down the UniqueID to its own CardID property (establishing the link between delegate and real card), then send itself to the Delegate Pool deck.
When the delegate is drawn, it sends a global key command to all pieces with DelegateID = $CardID$ … meaning the one card that uniquely matches the delegate. Thus that card (alone) highlights itself.
The toolbar button that draws a delegate is used by the main Multi-Action Button that performs the overall process, but it can also be clicked independently to get ‘Another’ selection from the same pool, since all it does is draw another delegate from the random Delegate Pool deck.
For cleanup, when the main Multi-Action Button is clicked to start a brand-new random selection, the first thing it does is issue a Global Key Command to tell all delegates everywhere to delete themselves. Thus, the delegates that get spawned from all the currently selected cards will be the only candidates in the Delegate Pool deck.
Sorry this isn’t more precisely written; if only I had more time. It’s working perfectly in my module, so if any reader can’t get this to work it is the fault of my rushed general notes and not the fault of Vassal.
First, I like your method, Justabill, and I have used something very similar to your delegates myself. However, I would like to point out that Mycenae’s model is essentially the one I use most often, and I believe the objections you raise can actually be resolved pretty simply:
(1) Before sending the cards to the deck, tell each to record its CurrentX and CurrentY, and send them back after you’ve done whatever you want to do.
(2) You can specify decks dynamically at runtime by using Send to Location instead of Return to Deck. So your players could still select whatever cards they want, in whatever maps they want, and send them all to their own private shuffle deck, or you could do this automatically with matching properties.
(3) Global Key Command with Matching Property: DeckName, or Deck Global context menus for that matter, can trigger any action you like.
(4) This can be a tricky workaround if you need to automatically draw a variable number of pieces specified at runtime; worst case scenario, do ‘fixed number of pieces’ = 1 in your global key command, set up a Trigger Action loop, and draw them one at a time until your loop expires. But it is possible for the brave.
I used the die method for random selection and the way I did it is like this. A player may have 1-6 cards in his hand at any one time so I created a die roll for each combination (1D6 with 2 sides, 1D6 with 3 sides…). This adds more icons to the top of the screen but it’s quick and simple to use. Of course you can always use a method that requires you to ask you opponent to pick a card from 1-6 (for example)and discard that card, but this is not useful when playing solo.
Does this restore their original stacking order?
The other problem is with actions that trigger upon cards changing maps. For example, when cards enter a player’s hand this triggers a layer that marks them as “new”. With your method, I think, the entire hand would get marked “new” because the cards all left and came back.
It just didn’t “feel” right from an architecture perspective to physically move the cards around; too much potential for side-effects.
I will admit that I hate stacks and so I’m not sure how the stack order is affected. You are probably right that they would be ruined.
For the triggers, I usually use the same trigger command for all maps and have the piece decide its behavior with the CurrentMap property. In this case, it is pretty simple to implement a ‘SuppressTrigger’ dynamic property to include in your property matches.
Another caveat to all of this, however, is that I think moving lots of pieces around can end up being pretty computationally expensive. I had recently written a sort routine for a module by sending the pieces to a deck and then having them move down the deck to the correct position. It worked as intended, but I ended up scrapping the whole process in favor of a custom class because the lag was inexcusable. So, if you need to perform lots of piece manipulation using decks, it may be faster to use delegates without images - but then, I haven’t tested whether that speeds up the processing or not.
Anyways, I don’t mean to say that I wouldn’t use something like your delegates - in fact, I think they are ultimately a more robust solution - only that in some cases they might be overkill.
I’m feeling the lag problem myself. It’s not a problem with the random selection function because it comes up so infrequently, but It’s sometimes painful at discard time. When any card is discarded, there’s a lot of processing to make sure it is rotated to 0 degrees, all flags are reset, the “magnify” layer is turned off, ownership is nulled out, and so on. It’s not too bad for a single card, but discarding a batch is pretty bad, and there’s not any kind of “please wait” indicator.
I’ve been thinking I should turn off all the normalization stuff and just force the players to de-rotate and de-annotate cards before discarding. It’s just that I know they will forget (at least the latter) and thus some cards in the deck will effectively be “marked”. I guess if that happens, they can always un-mark and reshuffle.
I suppose irritation from a player making a mistake is better than irritation from the module being slow. At least the players have the ability to do something about the former.