A while ago, I said something foolish around the Sweet Lemon office.

We were talking about Terrible Monster, the micro game we’d recently launched in Essen. I asked if there were plans for a digital version.

There weren’t any plans, so I said, “Maybe I could program something for Tabletop Simulator?”

For those who don’t know, Tabletop Simulator is a kind of virtual gaming room where a bunch of people can play tabletop games online. There are cards, little 3D miniatures, dice – digitized versions of anything that comes in the box.

Importantly, these adaptations come in two varieties.

Unscripted games only include the objects themselves, and require players to move everything around, follow the rules, etc. Depending on the game, this can be a very fiddly experience – but they’re relatively easy to implement.

I was interested in the second variety. Scripted games automate everything, so players just need to make decisions, take their turns, and talk smack about the other players.

And how hard could it be, anyway? Terrible Monster is a two player game with only 20 cards.

The foolish confidence of the rookie coder!

For the benefit of others about to take the plunge, here are some of the little joys and big headaches of digitizing my first game.

There is a steep learning curve

I don’t have a background in computers, and until recently WordPress was the most complex system I’d tackled.

However, over the last two or three years I’ve become more interested in coding, and online courses gave me a handful of key concepts (Hello world!).

If this is your first project, you should expect a serious learning curve – and not the fun kind, either, where you’re testing and experimenting with new concepts in a gradually unfurling process.

It might take hours to understand where that file was saved, or whether you need to buy a ‘compiler’, or what kind of extension this is supposed to be. You’ll find introductory textbooks written for maximum density and minimum coherence. Online forums will vary from helpful to disparaging, and Google will insist that nobody else has ever had this problem before.

  Interview: Johnson of EmperorS4 Games

You will need to learn a programming language.

These challenges begin before writing a single line of code, and continue sporadically throughout the process. They aren’t the sorts of things you envisioned solving, but – like the printing and production issues that figure so large in traditional publishing – they are inevitable.

Just relax, take a deep breath, and try to remember that tedious, baffling problems are part of the process. It’s worth the investment!

Computers are beautifully strange

I’ve put my girlfriend through a lot of weird conversations over the years, but nothing so strange as trying to untangle exactly how programming works.

Here’s a section from Terrible Monster:

function woundGreenTwice(source)
if greenHealthValue == 1 then
woundGreen()
elseif greenHealthValue > 1 then
greenHealthValue = greenHealthValue – 2
greenHealthObjects = greenHealth.getObjects()
greenHealthObjects[1].destruct()
greenHealthObjects[2].destruct()
end
if source == ‘needleStrike’ then
actionEnd()
end
end

What does it do? Something every tabletop gamer understands as ‘deal two damage’.

But you can’t tell a computer to deal two damage. You need to hold its hand every step of the way – do this, now that, but watch out for the other thing! Because a program is a fragile thing, especially if a rookie programmer is involved.

In exchange for this, you’ll receive some fascinating insights into the (il)logic of computers. Loops and variables, conditional logic and callbacks will slowly begin to make sense.

If nothing else, you’ll have an appreciation for how amazingly intuitive the human mind is, as well as the multitude of concepts (“play a card”, “remove a token”, “spend an action”) that gamers have developed and shared over the years.

  How To Make Bombs Out Of Farming Animals

Digitizing provides a very intimate understanding of your game’s implicit rules.

It’s a lot of work

There’s a huge disconnect between the level of instruction required in human rules compared to ‘computer rules’.

Human:

Draw a card.

Computer:

function dealCard(quantity)
if quantity == 1 then
broadcastToAll(playersTurnCharacter .. ‘ draws 1 card.’, alertColor)
elseif quantity == 2 then
broadcastToAll(playersTurnCharacter .. ‘ draws 2 cards.’, alertColor)
else
broadcastToAll(playersTurnCharacter .. ‘ draws 3 cards.’, alertColor)
end
if drawZone.getObjects()[1] == nil then
discardDeck = discardZone.getObjects()[1]
discardDeck.setRotationSmooth({180, 0, 0})
discardDeck.shuffle()
discardDeck.dealToColor(quantity, playersTurn)
discardDeck.setRotationSmooth({180, 0, 0})
discardDeck.setPositionSmooth({-20, 1, 0})
elseif drawZone.getObjects()[1].getQuantity() == -1 then
if quantity > 1 then
drawZone.getObjects()[1].setRotationSmooth({0, 0, 0})
drawZone.getObjects()[1].setPositionSmooth(getOwnersHandPosition())
discardDeck = discardZone.getObjects()[1]
discardDeck.setRotationSmooth({180, 0, 0})
discardDeck.shuffle()
discardDeck.dealToColor(quantity – 1, playersTurn)
discardDeck.setPositionSmooth({-20, 1, 0})
else
drawZone.getObjects()[1].setRotationSmooth({0, 0, 0})
drawZone.getObjects()[1].setPositionSmooth(getOwnersHandPosition())
end
elseif drawZone.getObjects()[1] == 2 then
if quantity == 2 then
drawZone.getObjects()[1].dealToColor(1, playersTurn)
drawZone.getObjects()[1].setRotationSmooth({0, 0, 0})
drawZone.getObjects()[1].setPositionSmooth(getOwnersHandPosition())
elseif quantity == 3 then
drawZone.getObjects()[1].dealToColor(1, playersTurn)
drawZone.getObjects()[1].setRotationSmooth({0, 0, 0})
drawZone.getObjects()[1].setPositionSmooth(getOwnersHandPosition())
discardDeck = discardZone.getObjects()[1]
discardDeck.setRotationSmooth({180, 0, 0})
discardDeck.shuffle()
discardDeck.dealToColor(1, playersTurn)
discardDeck.setPositionSmooth({-20, 1, 0})
else
drawZone.getObjects()[1].dealToColor(quantity, playersTurn)
end
else
drawZone.getObjects()[1].dealToColor(quantity, playersTurn)
end
if drawZone.getObjects()[1] ~= nil then
drawZone.getObjects()[1].interactable = false
end
end

Okay, I cheated a little because I’m not a very efficient coder, and  because this block also includes “refresh the deck if it’s empty.” But it’s exactly these mutually dependent elements that make programming take such a long time.

Without careful planning and foresight, each change can have domino effects that ripple elsewhere – typically bringing everything to a grinding halt.

The best way around this?

Spend as long as possible conceptualizing and planning your program before writing a single thing. This will keep you from having to redesign the entire system with each new card, but it’ll also give you a better sense of the project’s scope.

  Coconuts Story: Part I

The screen changes things

For reasons I’m not clever enough to understand or articulate, games play differently on the screen.

For example, a key part of Terrible Monster is the ability to interrupt an opponent’s card by playing a counter token.

You can do it at any time, but the default is not to counter, meaning this key decision lives somewhere in the background during most tabletop games – only sometimes drawing the player’s focus.

In digitizing Terrible Monster, I needed to provide clear, mechanical alternatives to the social interaction that normally happens around the table. So each player is explicitly asked (while their tokens remain) if they’d like to accept or counter the enemy’s move.

Given that countering is my favorite part of Terrible Monster, this attention was a nice surprise. I wasn’t expecting it, but I love it.

The character abilities also undergo a similar expansion in the digital version, somehow drawing more of your attention than on the tabletop.

Is either better? Not really – just different. And it’s fascinating to see a game you’ve played hundreds of times somehow change on the screen.

end
end
end

After all that, I’m very happy to say that Terrible Monster is now freely available for you to try on Tabletop Simulator!

If you like it, share it with your friends. If you love it, why not try out the physical game?

And if you have any questions about your own projects, send us a tweet at @sweetlemonpub.

It’s a mind-bending experience for a greenhorn programmer, but digitization brings more games to more people – and that helps all of us.