Ownership Model

I’m designing my first module, have read the entire wiki and designers’ guide through at least once, and probably three times in the areas that apply to my project. I’m getting the hang of traits and able to model some fairly complex behaviors and piece-to-piece communication. For example, I have multiple decks with different back designs and their own discard piles, whose non-rectangular cards correctly flip, rotate, and magnify in any combination, tag and untag themselves with various overlays, discard to the correct piles, auto hide and reveal themselves when required, and even recalculate their own values with simple multiplication and (faked) division. Some of them also fetch a corresponding component from another stack and command it to send itself to them. So I feel like I’m starting to “get” the Vassal paradigm.

One thing that vexes me, though, is that Vassal appears to maintain some kind of ownership model that is not exposed to the developer. It seems that cards and pieces become owned when they are masked, and presumably when added to a player hand or private window, but I can’t seem to set, query, or reset that attribute. So I’ve struck out on my own:

  • Every card and piece in my module has a DP called Owner if its ownership can change, or a Marker called Owner if it cannot (but never both). Ctrl-Alt-O performs Owner = $playerSide$ on demand, and it’s also invoked for pieces ending movement in the player’s hand or private window. I plan to implement ‘Give’ traits later.

  • Ctrl-Alt-Shift-O performs Owner = Nobody. Then via another trigger, this key is trapped to see if the piece should actually have a default Owner, which is overridden with the appropriate string literal for the Side.

  • I have an alternate highlighter corresponding to each player Side that hardcodes color = red when Owner = Red, etc.

Most of this works great, but I have two problems I don’t understand:

  1. My alternate highlighters worked like a charm, then abruptly just stopped working (everywhere). At the time I was resequencing traits to get mask, rotate, and non-rectangular to all behave together properly because I had just re-added non-rectangular, so at first I thought this was the culprit. But my alternate highlighters were failing for everything, including pieces in an at-start stack with an Owner marker; not a single thing about these pieces had been changed in days. I wrote a diagnostic Report action to dump out key characteristics and verified that my Owner DPs were indeed flipping around between Red, Yellow, and Nobody exactly as expected … but the highlighters checking for these were being ignored. So I added more highlighters with no conditions at all, or guaranteed-true conditions like Type = Ship (with precise capitalization), but not a single one of them shows up, even when I make the widths extra-large to overcome any possible highlight stacking-order issues. Baffled.

  2. I didn’t like the inefficiency of having a ‘disown’ trigger for every Side to check for pieces that should revert to that Side as a default owner. It seemed like I could eliminate the need for conditionals by exploiting Vassal’s attribute hierarchy, so I added a Marker to such pieces called Color, which is basically ‘default owner’ and contains one of the string literals for a Side. Then I modified my original Disown key to set Owner = $Color$, believing that when a piece had no Color marker defined, this would fall back to the GP I had already defined called Color, with a value of Nobody. Instead, my neutral pieces end up with their Owner DP set to the string literal ‘Color’ — and I definitely did not forget the dollar signs.

Any insight on whether I could have actually tapped into some official ownership model, or streamlined this approach to somehow avoid the issues I’m seeing? Or am I just making a dumb mistake somewhere?

FYI, I am building Cosmic Encounter — perhaps one of the most ambitious titles I could have chosen for my first module, due to the fact that virtually every piece behavior and piece-to-piece relationship you could hope to shortcut is a candidate for being overridden by some game effect that may or may not be in the current game. It’s quite a challenge.

Hi! Sounds like you’re really committed, and highly competent to boot. I’ll directly support you with code updates and refinements! I’m sure I will like Cosmic Encounter (Fantasy Flight’s?), though I haven’t seen it before.

I was trying to do up Pandemic. You can search for my pleas for help on this forum. But I now see you has the “help” I’ve been looking for. I’ll help you closely as you build Cosmic Encounter.

There definitely are some limitations in assigning ownership in Vassal, it seems. We can explore this area together.

You might also wanna skip the Traits engine altogether, and start with a more logical scripting engine. I think this scripting engine hasn’t been done yet. But you and I can do this together. See why I think you should give the Traits engine a miss here.

Along the way, you and I may even draw up some definitive tutorials and documentation for Vassal. Currently, even the Traits engine and its vital quirks are not explained anywhere clearly.

Thanks for your reply. I’m not quite sure what to make of it. It sounds like…

  • You’re on the development team.
  • You’ve had trouble getting help from the other developers, but I have the help you’ve been looking for (not sure what that means).
  • You don’t have any specific information for me on the ownership model.
  • You’re willing to make code enhancements to support my module.
  • You recommend I stop using traits and wait for a scripting engine to be developed, or collaborate with you to develop it.
  • You’d like me to help with writing tutorials and documentation.

Am I interpreting all of this correctly? Sorry, I’m not trying to be obnoxious, but I’m sort of overwhelmed by all of this information and not really sure what it all means.

Spot on! You’re as quick in interpreting messages as you are competent in exploring the Vassal engine.

Spot on, with just a few exceptions…

Other developers are helping out just fine, we’re all volunteers here. Just that Vassal engine isn’t quite as advanced as it can be. There are no animation threads possible (though quite a few here have asked for it, and even conceptualized it correctly). Some of the code is just plain oddball (Traits engine takes the lead on that). Let’s just say, I see Vassal engine becoming much much more. And I see you being able to stretch our (developers’) imagination and programming to healthy lengths.

You have what I’m looking for. The drive to stretch the Vassal engine to its limits, and the ability to do so too.

Also, you seem fresh, on Vassal engine, that is. Most Vassal veterans are entrenched in doing things the Traits engine way, and may have given up daring to dream up more for Vassal. Many veterans have been “beaten into shape (and limits)” to conform to the Traits engine, not the other way around. The Traits engine sure did unravel my Java programming skills whenever I spent 1-2 hours with it. :confused:

Newbies who are non-programmers may or may not stick with Vassal, depending on how fanatic they are about the games they are making.

Newbies who are programmers seem to come in quite hard and fast, doing quite a lot with the Vassal engine right off the bat. Then they realize there are limitations, then post for feature requests, then probably leave once they got busy with something else.

I’m hoping you are that fresh driving force that will stretch Vassal and us developers well. :slight_smile: The ability to dream.

I will, once I read your questions carefully. (I’ll reread your original post again right after this). I have neat access to the codes, so much so that I can know most anything about the Vassal engine within 5-10 minutes of digging.

Also, if you’ll phrase your questions neatly (not that you didn’t), it’ll make it even faster for me to address them.

I’m a little scared of this exercise (sizable), but I’m willing to take the plunge. A main developer has decided on Python as the scripting language. We can just start off with BeanShell2, fashion some convenient tools (along lines of SendToLocation, and other Traits). Then when Python comes to Vassal, we can easily port the tools over.

That scripting mechanism was already decided as the way forward. Our collaboration here will add tremendously to the Vassal engine.

So, why not the Traits engine? The problem with the Traits engine right now boils down to an “over-extension” of the Traits engine.

You see, the Traits are decorators wrapped layer by layer onto a game piece. The innermost Trait’s values (if set) are superseded by the outermost Trait’s values (if their variables intersect). “Inner” traits are listed above “outer” traits in the Module Editor when you edit any game piece.

As such, this layer and Traits concept works just as expected. In programming any conventional language parser (PHP, C, Java, whatnot), there are declarations of variables. The variables declared further down supersede the onces above. (In programming variable scope, if you’re familiar with the concept, we also use this layer concept, implemented in stacks usually).

declare varA = 1;
if (blah) {
  declare varA = 5;
  print varA; // will show 5, not 1
}

So how is the Traits engine “over-extended”? When we start coding Behaviors as Traits. Before we get confused between Traits and Behaviors… Traits are properties (variable declarations) while Behaviors are operations (from value assignments to function calls to maths operations).

You see, Behaviors should flow top-down. But since behaviors are coded as layers of Traits as well, we see behaviors being executed bottom-up (like peeling an onion). This goes against every single logical programming language out there. HTML, Javascript, Java, C, PHP, you name it. (Actually, as a quick fix, I believe I can reverse this flow, but that would break every game module currently out there)

So, before you waste much time unraveling the Traits engine, and before you feel you have thrown away enough of your life on Vassal engine, I propose that we work together to get a proper scripting mechanism going in place of the overloaded Traits engine.

Depends on who is faster at doing what. If you’re stronger at coding, I’ll do the tutorials and docs. I’m just looking for collaborators. :slight_smile: I do have less patience designing games (if only because of the fact that I can’t offload the coding to a crazy hack and slash coder like myelf :stuck_out_tongue:). I did start out with Pandemic, but very quickly discovered too many limitations requiring workarounds.

As a first step, we could get familiar with all the Traits. Then we will be in a position to do the scripting tools quickly.

If you do wanna start building your game right away using the Traits engine, you can, and I’ll support you for that. Just make sure you still write your game logics in pseudo code (logical human-readable scripts), then transfer your logic to the Traits engine. Otherwise, it’s easy to get lost working with the Traits engine.

I’ll check this ownership code for you. What I’ll need from you is your game module (.vmod). If we’re working on the same .vmod, it’ll make it terribly fast for me to replicate any bugs you’re seeing.

I do suggest you don’t workaround these things too much. Spend reasonable effort working around limitations, but let me know to create proper tools if the limitations are too much.

Use NamedKeyStroke(s) which is in the v3.2 branch. Either download the latest builds from here, or tell me to document a HowTo in setting your own development platform. With your own “programmer’s platform”, you can apply any patch I send you right away, and immediately see your issues fixed.

We’re supposed to write that HowTo at some point anyway.

NamedKeyStroke work inside any KeyStroke fields. Just type any printable characters (say ‘a’) twice, and the field will interpret your input as a NamedKeyStroke. Think of a NamedKeyStroke as a “function name” of sorts.

Implement a new Trait called ‘Give’?

There are some inconsistent behaviors in “evaluating expressions” (the dollar sign thingy). I fixed one such error myself in v3.2 just a few days ago here.

Offhand, I am pretty sure you simply cannot have access to ownership using “coding” (Traits engine). There simply isn’t a Trait like “AssignValueToOwnership”.

And that was what caught my eye, brave Jedi. I’m a decent engineer. Lend me your force powers? :slight_smile:

Using a NamedKeyStroke in place of a standard keystroke makes no difference whatsoever in what the keystroke (regardless of type) functionally does. It does/will makes things easier remembering what things do if you cant keep track of all your key commands and what they do in complex sequences

vassalengine.org/tracker/sho … gi?id=1928

For example in the case above, I could use “Ctrl Alt O” or I could use “Change Owner” - they will still both do the same thing so I don’t see what you are getting at here in using them. I think the problem here is something other than keystrokes

I was worried the OP would come upon a problem I faced early on: trying to get “some fairly complex behaviors and piece-to-piece communication” working via too many functions named after keystrokes (eg Ctrl+Alt+O, Ctrl+Alt+Shit+O, etc). Using keystrokes to name my functions meant:

[]Using a severly limited namespace[/]
[]Functions names could easily be mixed up, and calls were misfired[/]

Getting the OP started on the NamedKeyStroke(s) would clean up his game module codes, and likely reduce clutter and clutter-related bugs.

Getting more overwhelmed here. What seemed like a straightforward process of learning a development platform and creating a game module looks like it’s turning into a much larger project … learn a scripting language, get familiar with two additional upcoming code branches, compile a list of feature requests required to make my module work, write documentation … how does the average newbie ever even get up to speed on all this?

I’ve just spent an entire evening trying to implement one of the most unbelievably simple things: how many cards are in each player’s hand? Several hours later I am ready to throw the whole damned thing in the trash. I can’t really express how frustrated I am right now.

I’ve read the wiki. I’ve read the developers’ guide. I totally get the concept of clearing a global to zero and then having each card that meets certain criteria increment that global. But that is just the tip of the iceberg …

First, I have seven different player hands and at least four other maps/boards. So, in theory, every time a card moves — anywhere — I have to have each of those hands clear its global and count all of its cards, since I don’t really know which hand the card has come from and/or gone to. Over one hundred cards each have to wake up and try to increment some global based on where they think they live at the moment. This is horribly inefficient and causes a lag of like 20-30 seconds every time somebody drags a card. Total deal-breaker.

So to improve performance, I decided to update totals only for the cards that are actually moving. I wrote a bunch of traits to be triggered by “piece ending movement on” at the map level. This required triggers that call other triggers that call set global property methods. Nightmare of keystrokes, but I mapped it all out in advance and documented it all in my 3D master Excel keystroke cube. When a card ends movement on any map, I check to see if its new board differs from its old board, then increment a global associated with the new and decrement a global associated with the old. This generates a lot of error reports since not every map has such a global, but I can fix that later. At least the counting works.

Or does it? I got all this working only to discover that “piece ending movement” only applies to mouse drag-and-drop. Seriously? If I use a keystroke to Send a card to the table, this apparently doesn’t count as ending movement on the table. Fantastic; everything I’ve written is useless, unless I want to trap every possible keystroke that moves cards from one map to another and have all of those trigger the increment/decrement triggers-wrapping-triggers. I don’t have the energy to even contemplate that.

Now, I’m sure somebody is thinking “dumb noob, that’s what you get for having too many keys; should have just forced the players to drag and drop everything”. But this is not practical. Sometimes you have to discard a lot of cards, taken from various places. It’s not possible to do that with the mouse unless you drag them one at a time. If you drag the group to (say) the discard pile, only the one(s) that end up in actual physical proximity to the discard pile actually land there; the others land wherever they happen to be based on the deltas between their starting positions. So some of them land on top of a draw deck, or some other stack of cards, completely corrupting the game state. Thus, it is absolutely essential to have a Ctrl-D Discard command that performs a Send to Deck. But of course, this completely thwarts everything I’ve spent this evening crafting to count the cards in the hands.

I suppose you’ll tell me this is another reason to scrap Traits and invest in a scripting language. Well, I’ve already invested weeks in writing a module that’s 95% ready to play. I really don’t want to “start over” on the implementation of all my behaviors – especially in a development framework that hasn’t been tested yet and (by definition) is going to require yet another rewrite when it has to be converted from the temporary scripting language to the “real” scripting language.

Sorry about the rant. I’m just completely fed up right now with the fact that it takes fifty-three steps to find out how many cards are in a freaking hand. (Can it really be true that in the history of Vassal nobody said “hey, we need to expose a numPieces property for each map and board”?) Even worse, just about everything I try requires several different attempts because the capitalization or naming isn’t consistent and the use of dollar signs isn’t consistent and you never know in what context you can and can’t get to currentBoard or CurrentBoard or oldBoard or oldLocation or whatever the hell property you think you need for the trait you’re working in. Things you think you can logically infer from one part of the system simply do not work in another part, as if every trait was written by a different developer. I keep writing Report actions to disclose out what I think my properties are holding, and 90% of the time they spit out blanks. I just want to scream, so here it is … my virtual scream.

I know everybody’s working hard to make it better, and I appreciate that. But holy crap am I sick of herding cats right now.

One technique I lifted from another module recently was to give every card in my game a Marker trait with a value–e.g., CardCount=1. My Game Piece Inventory Window shows only things on the 6 player hand “maps”, then displays the folder label as follows: $CurrentMap$ = $sum_CardCount$

In my case I’m actually tracking the number of two types of cards, so it’s slightly more involved, but that’s the basic idea. If there is any chance whatsoever that something other than a card will ever end up in the player’s hand, it needs to get the same Marker with a value of 0, I’ve discovered–quite bizarrely, the technique I described will add 1 to $sum_CardCount$ even if a piece without that Marker is present. So in my case, where I’m tracking basic event cards and home cards, they all have to get a Marker for both types: event cards get CardCount=1 and HomeCardCount=0, and home cards get the reverse.

That’s not a bad idea, but has two drawbacks: yet another window to keep open somewhere on the desktop, and you have to constantly click a Refresh button to see current card counts.

I was trying to work this information into a master “control piece” in the main game window that shows the current phase and sub-phase, what role each player is currently in, and their hand counts. It’s too bad I can’t just put $RedHand_numPieces$ or $RedHand_sum_MyCustomProperty$ in a text label and be done with it. This is the first real “elegance crash” I’ve run into that I couldn’t find a reasonable solution to.

The average newbie works around this. As I said, I noticed that newbies simply bend themselves to fit the Vassal Engine, just as every veteran had done.

As I said “don’t workaround these things too much”. Veterans hardly have time to hand-hold a newbie through the convoluted maze (the oddball Traits engine and bugs) they painstakingly navigated (and worked around to limited success).

You’re a newbie Game Designer. I’m a newbie Developer (no, I really won’t mess up Vassal Engine). I won’t consider it rude if you told me “make this thing work for my convenience”. In fact, I’ll consider it inefficient if you tried to work around inconveniences. We want the Vassal Engine to rival even the likes of GameMaker. So, please don’t waste anymore time on working around inconveniences in Vassal Engine. Start telling me what you need. :slight_smile:

And… we should shortcut it right here, at the tip of the iceberg. Work with me to incorporate necessary enhancements to the Vassal Engine. Necessary because they just plain cripple the Game Designer if absent.

Again, I desperately implore you to use the latest builds and NamedKeyStroke from here.

We may not even need to address that inconsistency in handling “piece ending movement” if we just gave you a “Deck::CountCards” function. Please, brave Jedi, your R2D2 is here! Don’t let engineering defects hinder your force powers!

Erm, that’s how I gave up rewriting Pandemic. :slight_smile: You’re not alone, mutant. Mutant and proud! (Wait, weren’t you a Jedi before? Just kidding, X-man. Great movie, that First Class, by the way.)

Yes, that is pretty much how the current Vassal Engine is to be used. But you and us (Vassal community) are gonna change that. In fact, I envision a better version of Civilization 5 done using Vassal Engine (see my proposal here), just as how Transport Tycoon Deluxe was infinitely improved by OpenTTD and Simutrans.

Of course it isn’t. Many veterans have successfully resorted to coding custom Java classes (in place of Traits, look at VASL). The point is not that we should not learn Java (or similar scripting tools), but that Game Designers should not have to compile their custom additions.

If you’re still up for it, we could add a new Trait that reads beanshell (latest version actually is beanshell2).

No, we don’t scrap the Traits engine. Never throw away something we can reuse.

Even as we do the scripting engine, we still require existing constructs (read “Functions” by programmers), eg Behaviors like SendToLocation, CanRotate (should really be just Rotate), etc. And how these constructs interact with each other (eg how SendToLocation may be influenced by DoesNotStack) will need to be thrashed out now, way before we start on the scripting engine.

Do realize that much of that work (relating Behaviors with Behaviors and Traits) were already done, and their logics are existing in the current Traits engine. The developers of Vassal Engine had done all that in the past years.

As a stop-gap measure now, as well as an exploratory exercise, we can start by correcting the Traits you are using. Shall we?

Yes, it is true. Apparently, a group of Game Designers had gone the way of the “custom Java classes”, and never looked back. As can be expected, there are virtually no limitations to that approach (it’s like crafting your own set of Traits).

As a programmer myself, I can tell you this bad habit that mean coders often have (I speak for myself). We often feel so “usefully busy” when doing repetitive work, that we actually miss opportunities to “cut down amount of work”. It is possible that we found the integrated circuit boards (custom Java classes) approach so powerful that we forgot to turn them into microwave ovens (scripting constructs, Traits constructs).

Leave the cats be. Let us create catnip for that. We need you to bend the minds of greater threats, brave Jedi. May the force be with you. (I know I am. :slight_smile:)

Okay, let’s start with this then.

RfE: Piece Counters for Maps and Boards

Each Map or Board can have a [Piece Counters] node (added via right-click on the map or board node).
Each [Piece Counters] node could contain one or more “Piece Counter” components (again added via right-click).
Each “Piece Counter” would have the following attributes:

  • Piece Counter Name

  • Visible to All Players: If not selected, visibility of counter information reverts to visibility of the map or board (i.e., a private window’s counters could be hidden from opponents by leaving this unchecked, but on the main map window the checkbox would be irrelevant because that map is already publicly “owned”).

  • Matching Properties: The properties the piece must have to be counted by this particular Piece Counter. Example: A board has one Piece Counter called Cosmic Cards with Matching Properties Type = Cosmic, and another called Reward Cards with Matching Properties Type = Reward. Each card contributes to the sum for the appropriate counter based on its marker; cards that have both markers are counted by both counters.

  • Property to Sum: This gives the module designer the freedom to sum up either the number of pieces or their values. If blank, each matching piece adds one to the counter’s total regardless of its other characteristics. If not blank, the indicated property is used to determine how much each matching piece contributes to the counter’s total (if the property’s value can be interpreted as numeric). Example: Some of the cards in the Red Hand private window represent money in various denominations. These kinds of cards have a marker of type Dollars with a value of 1, 5, 10, or 20. All other card types (say, a bunch of Action cards) lack the Dollars marker (it is not required that they define Dollars = 0). Red Hand has a Piece Counter called Wealth that has a Property to Sum of Dollars; this counter maintains a running sum of the current amount of money in the Red Hand. The module designer could access this total using $Red Hand_Wealth$. Negative property values should be supported, and the counter’s total should be allowed to go negative.

  • Hotkey to Refresh: If specified, pressing the hotkey will cause the counter to be recalculated from scratch. (In theory, this should not be needed if the code to keep the counter updated is bulletproof, but you never know when things might get out of synch because of reloading a saved game from an old version or whatever.)

  • Refresh Button Text / Refresh Button Icon: If specified, places a button on the map’s toolbar to manually refresh the counter. (Should rarely be needed.)

  • Include pieces in Decks: Checked by default. If unchecked, pieces in decks are excluded from the total.

  • Include pieces in Stacks: Checked by default. If unchecked, pieces in stacks are excluded from the total. (I’m not sure exactly how stacks are managed and realize that it might not be practical to implement this attribute. I do not need it for my module, and included it only for flexibility. But I’m not really sure how often somebody would even need to sum up only unstacked pieces.)

  • Report Format: A Message Format that, if supplied, will be echoed to the Chat window whenever the piece counter’s value changes. If multiple changes occur, only one message is echoed with the final value.

Code behavior:

  • Every Piece Counter automatically begins with a value of zero. The current value can be obtained using $MapName_PieceCounterName$ or $BoardName_PieceCounterName$. This value is read-only.

  • If the user sitting at the Vassal keyboard is not authorized to see a particular piece counter (i.e., it is defined within a window that is not available to his Side and it does not have its Visible to All Players attribute checked), then $MapName_PieceCounterName$ or $BoardName_PieceCounterName$ should probably return a blank or null.

  • For efficiency, piece counters are updated only when pieces enter/leave the scope of the piece counter (or when their values change if the piece counter has a Property to Sum). Hopefully the code will not zero and re-sum every piece counter in the module every time the state of some piece changes.

  • When a piece enters a map or board (from somewhere other than that map or board), all of that map’s Piece Counter components that match the piece are increased by 1 (or the piece’s Property to Sum value).

  • When a piece leaves a map or board, all of that map’s Piece Counter components that match the piece are decreased by 1 (or the piece’s Property to Sum value).

  • Every possible activity that results in a piece entering or leaving a map/board must be respected by the Piece Counters: drag and drop, Send to Location, Return to Deck, Clone, Delete, Replace with Other, instantiation of an at-start stack, loading a scenario, and everything else I’ve missed! Any action which alters the number (or value) of matching pieces must increment/decrement the relevant counter(s) appropriately. Alternatively, all Piece Counters can be brute-force re-synched just before the players start playing, whenever a saved game is loaded, etc. However, for best performance, it would be ideal to store and maintain the current values of all Piece Counters to avoid the redundant calculations.

  • When any (numeric) Dynamic Property of a piece changes its value, if that Dynamic Property is the Property to Sum for any relevant Piece Counter, the difference between the DP’s new value and old value is added to every relevant Piece Counter.

  • The Matching Properties attribute should support as many properties as possible, including such things as $OldBoard$. This could (in theory) be used to show the number of “newly added” pieces by having an additional Piece Counter that includes in its matching properties CurrentBoard != $OldBoard$ … although I admit I can’t certify the viability of this example, since I have no idea how long the OldBoard value persists for a given piece. I assume that the first time a piece is moved around within the board it would lose its “new” status (since OldBoard would now be the same as CurrentBoard), and of course if it left the board it would no longer get counted. That’s the behavior I would expect and want, anyway. It seems like there is interesting potential here.

It might also be helpful to support Piece Counters on decks. In Cosmic Encounter, for example, the discard pile is open information and there are cards that access it in various ways. Having an auto-generated summary of the types and numbers of cards in the pile could spare players from having to physically dig through the discards just to determine whether it’s worth playing such a card in the first place, before having to dig through it again to get the card they want.