Guest Post: Hitting a Moving Target

With the release of a new version to Distilled to Tabletop Simulator (TTS), I invited our resident deity of the digital Distilled, Seth Berrier, to be a guest poster about his amazing work in making the latest version of Distilled on TTS such an amazing, smooth machine. Take it a way, Seth!

Berserk Games (The makers of Tabletop Simulator) have really leaned into TTS during the pandemic.  I’m sure they see an opportunity both as a business and as lovers of D&D and tabletop experiences of all kinds.  TTS’s user base has undoubtedly grown as people seek ways to play safely.  For game designers, where playtesting is the lifeblood of game balance and helping your mechanics evolve, the pandemic stopped things dead in their tracks!  TTS (and other experiences like it) has been a lifeline that allows things to keep going safely and effectively.

The influx of users and capital into Berserk also seems to have accelerated the rate at which they are improving TTS.  This is great for all the players out there, enjoying new features like automatic card layout zones (more on those later) and universal translations (even if only done via google translate).  However, for developers like me, this has injected a bit of chaos into the process as new features break things that always used to work, or a simple solution pops up for which you had spent hours engineering a convoluted one!  For this blog post, I would like to talk about a few of those (and also maybe deposit a request with the devs at Berserk for some things that would make our lives even better, a bit of fairy dust).

Fumbling with Virtual Cards

Tabletop Simulator gets so many things right!  It recreates the tactile feel of physically interactive game pieces of all types, giving them satisfying heft and realistic sounds and physical reactions beyond just a simple, toy physics simulation.  People sometimes call it a “physics sandbox” but that does not do it justice.  So many players take the quality of the physical interaction for granted because the simulation is so good!  As a game programmer, I can appreciate the level of polish in all the ways you interact with game pieces and figures and player mats and boards and … well everything … except maybe cards.

What’s all this then? More on the amazing sorting bottle in a future blog post.

Don’t get me wrong!  TTS does about the best I think they could, given the circumstances.  Every card in a deck is unique and they make the task of supplying the art for all of that pretty easy and with just a little bit of practice and reading of the different controls available, you can learn to be adept with decks and cards in TTS, but it takes time and practice, and it is one experience that is noticeably clumsier in the virtual world than in the real one.  This is a problem for Distilled because, well, it’s a card game!  Not just a card game, of course, it’s a strategy game, but there are hundreds of cards involved and managing them is vital to having fun with your inherited distillery.

Dave has done a marvelous job of bringing that management out of your head and onto the table with well designed player boards and coherent iconography throughout (with due credit going to Erik as well for the clarity of the icon language).  All of that translates over to TTS well, but there are still moments where cards were a struggle to deal with: the setup at the beginning of the game, the river mechanic for the markets, and rifling through decks to find matching signature ingredients and recipes.  The keen eyed among you might notice that these are all the places where my scripts have stepped in to remove the awkwardness.

So much information so efficiently communicated!

Last, but certainly not least, is the act of bottling a spirit.  You need to splay out your cards and count up both the victory points and the value of everything in the mix to see what you’ve made.  Will it be a malty whisky with notes of apple aged in an ex-bourbon oak barrel, or a failed moonshine with hints of rubber tire brewed up in a giant plastic vat!  It should be an exciting and interesting moment where players celebrate or mock one another, and in-person has always felt like where a good deal of the magic of Distilled comes through.

In TTS, however, it’s always been hampered by how difficult it is to splay out the cards and is punctuated more by careful calculation of the points rather than the creative fun of flavors and fancy bottles.  As the one in charge of scripting, I have longed for a way to remedy this!  How can we remove the artificial pause that bottling a spirit feels like in TTS and get back to that celebratory moment of “what did I make” or “what is my opponent’s strategy?”  I’ve tried many things on my end, mostly focusing on doing the math for you.  TTS does offer this in many cases and I’ve seen it work well in scripted experiences on the workshop and while this would not be done for you in the real world, I imagine that many players would have done the math already while they hold the spirit in their hand so that the big reveal is more impactful.  The regulars of Distilled are likely to note that this is, in fact, a feature that is yet to be realized!

TTS v13.0 was a huge update.

Lucky version 13

This was when Berserk entered with another big update, Tabletop Simulator v13.  Like any good dev, I was eagerly reading through the patch notes to see what new toys we might have to play with (I’m still very excited for the possibilities of arbitrary web requests BTW) and when I saw the prominent new feature “Layout Zones” my excitement just about piqued!

Here was a nice way to organize a deck of cards with subtle settings controlling the spacing and density of the cards, the number allowed per row, all sorts of knobs and buttons to push and twist that would let us get that feeling of bottling closer to the in-person one.  We quickly explored it, so fast we had to reverse-engineer the documentation for them a bit.  And with our latest update, we have stuck those in to manage the enormous spirits our play testers have been concocting.  It was a big step in the right direction and while it is clear Layout Zones are still growing (they have some weird behaviors from time to time that are indicative of something new that needs refinement) they payoff for Distilled was immediate.

Layout Zones are a real quality of life improvement for card games in TTS.

This wasn’t what I had been envisioning, with the math of a spirit’s value and VPs still being a manual step, but it was still a big improvement right at the point in the game where it was needed.  Naturally, the complications of this within the scripting took some work and having to figure out how to use them without any documentation was rough, but Berserk is very consistent with their API (the interface that a scripter uses) so a few good guesses was all it took to get it right.  Mostly, I’m excited to know that Berserk put some love into the TTS card experience!  They know it can be better and they are working to empower us, as mod developers, to massage out the awkwardness.  In my mind this bodes well for the future.

Speaking of the Future

But I still envision something better for the bottling experience, and if I may be so bold, I’d like to describe my wish for TTS (after being featured on their blog, we know someone at Berserk may, in fact, be listening 👋).  METADATA!!  Okay, that may not have been the exciting feature you were all imagining, it’s pretty programmer nerdy, but a way to properly manage and enrich all objects in TTS (especially cards) with the metadata that they posses in our game would be marvelous.

Let me explain!  All the core data associated with a programming object, the bits that were planned for and designed into the object, are usually called properties.  Every TTS object has a lot of these, and they are well documented and serve a purpose to making the object look, sound, and feel like it should.  But what about all the data that wasn’t planned for?  In Distilled, every market card and upgrade has both a cost and a value, and some also have VPs.  Obviously, not every card in every game will have these things so they aren’t inherent properties of a TTS object, but they are tremendously important to playing Distilled and most games have similar properties in their game.  I (and I think most programmers) call this metadata: extra information that is important to the object but isn’t known up-front and may change in structure and size for each use-case.

All sorts of data that we can’t properly encode in TTS.

Where this is important for Distilled is all that math I would like to be able to do for the player.  Berserk did allow an object to have a ‘value’ which can be used for some math, but in our scenario (which is not at all unusual) every card has a BUNCH of different ‘values’ that all serve different purposes in the strategy of the game.  Your rubber tire moonshine might not win any awards, and therefore not yield many VPs, but if you put in a lot of valuable ingredients, it can still be a really great payoff for a trip to the market!  Your apple whiskey, on the other hand, might receive the “ion award” (😉) for best flavored whiskey and be worth a whole slew of VPs but only have one key ingredient leading to less value in the market (this is what goes through Seth’s head when he bottles a spirit).

This generic metadata is where I’ve really struggled to do what I want with our cards in TTS.  There really is no good mechanism for this in the API.  I’ve read tales of other scripters embedding this information in other properties like the GM notes or the description, and I did flirt with those tricks a bit, but they always felt very hackish and delicate.  Every time Dave and his team would change values on a card or update the mechanics, all of this info would need to update too and any approach I could find was going to involve a lot of manual data entry.  Not a reasonable tradeoff for a fairly small feature in the overall scheme of things.

So, that is my big wish for TTS!  Allow every object (even the ones in bags and decks … and decks inside of bags) to have persistent metadata that is serialized along with the object to the json save file and can be restored easily on load.  It should be something you can associate with an individual object WITHOUT having to give it a script, because giving every individual card a script is, well, crazy!  And it should be flexible enough that data of any type or structure could be stored (JSON comes to mind).

The last Missing Piece

With the WebRequest Lua API sitting out there, calling to me, I envision an almost perfect world where Dave and the rest of the design team could be updating all this metadata whenever they like and the TTS workshop mod would send off a request into the cloud, second star to the right and straight on till morning, to a fantasy spreadsheet, filled with glorious metadata that never grows old!  And my scripts could fly there as soon as the game is loaded, and dash through every card in every deck sprinkling them with magical dust that fills in all those VPs and costs and enables us to do the math and bring back that big reveal moment in all its glory.  All that is missing is the metadata fairy-dust!  I suppose a boy can dream.