TurnAbout
 
TurnAbout:
How to Play
History & Future
Decks and Cards
New Deck Styles
Writing a Game
TurnAbout API
More About Lua
Included Games
Toy Status

Arcadia:
Home
Download

Community:
Forums
Java Chat
Firewall/Router Help

Arcadia Toys:
Collaboration
DomiNation
Empyrion
synChess
synJam
synJet
synPool
synSpades
synSpace
synVille
synVideo
Turnabout

Other Games:
Well of Souls
Warpath
Rocket Club

Developers:
TurnAbout API
New Parks
New WoS Worlds
Rocket Club Models

Company:
Synthetic Reality
Golden Souls
Donate $
Contact Us

TurnAbout is one of the toys which can be played in Arcadia. It is a user-programmable, cards-metaphor, open-API, Lua-scripted, board game engine.. thing.

To get TurnAbout, download Arcadia then Fetch Toys


How To Play:

TurnAbout is a work in progress, but you can check out the TurnAbout development notes in the Arcadia forum of the synthetic reality bulletin board. If you want to try it after all that, download and install Arcadia, then 'fetch new toys' and pick up a copy to explore.

The general idea is:

  • Start or enter an Arcadia Server where TurnAbout is the selected Toy
  • Be the Moderator
  • Select one of your Decks from your Toy Options dialog
  • Press START GAME

If you are interested in crafting your own TurnAbout mini-games, you might enjoy reading about the TurnAbout API

How Did We Get Here And Where Are We Going?

Since starting the game around 4 years ago, the concept sort of grew and flew off in different directions, so I am as interested as anyone in seeing what actually lands, so to speak. Originally I was thinking: "Hmm, I ought to do some sort of board game." And by that, I was thinking of rolling a die, moving your marker along a path on a board and performing the action demanded by the spot you landed.

At that time, some people in the forums were asking for a Magic-The-Gathering-Like engine, and that got me thinking about 'cards' games. (as opposed to 'card games' like synSpades)

Anyway, so that got me thinking about a hierarchical card editor (letting you define a card which 'inherited' named properties from other cards - "rent=50" for example) and a deck editor to assemble a collection of cards.

Then, I thought, you could form the board by dealing a bunch of cards 'in a circle' and then have little tokens which walked around the circle in response to rolling a die. Wow. a 'card' game and a 'board' game all in one. I thought of Stonehenge about that time and decided the cards should be vertical and why not use your Arcadia Face as your token.... and make it semi-3D.

OK, great, so then I had a hierarchical card/deck editor so that individuals could craft their own game styles and have cards with custom properties like "name" and "type" and "hit points" and "gold earned when your token lands on one" etc.

But I knew I would need a scripting language to make truly interesting games. (My goal is to empower the end user to extend TurnAbout by making new Deck Styles). My experience with Well of Souls taught me how scripting languages could grow and grow and grow, and I didn't really like the thought of a very complicated bunch of script on the cards themselves, but less than that was going to be too simplistic and restrictive.

Finally I opted to go with 'lua' because it was powerful, popular and free. And once I got over the hump of moving the text of the script from the cards themselves to a single file (one per deck style), I could finally see how all the pieces should fit together.

At this point, it's all about the API.. supporting the lua script with TurnAbout functions, events, and services which make the script's job as easy as possible, while facilitating a huge range of potential game styles.

TurnAbout ships currently with several decks: Uncle Dan's MiniMUD which is a simple text adventure, which can be extended by adding cards to the deck. Also included are an implementation of Blackjack, a ballistic Battle game, and a sailboat simulator. All are functioning multiplayer games with full source included.

So, What is TurnAbout Then?

TurnAbout is, in fact, an unlimited number of different games. Let's PRETEND that all the TurnAbout games are cards-based board games, though you will see that is not actually true.

To start a TurnAbout game, you need a moderator with a deck of cards. All the cards in that deck inherit from the same deck style. Therefore, we will use the term deck style when we mean: 'one of the mini games you can play in TurnAbout.' (I would say "Toylet" but that has an unfortunate homonym.)

A deck style might be, for example monopoly. (Um, I mean something similar to, but not legally the same as, of course!). While there is only a single monopoly deck style, you might have 5 monopoly decks, each with different mixes of cards, resulting in, perhaps, different real estate on the board, or different chance cards. For Example: "The Simpsons Edition of Monopoly" is a 'deck' while "monopoly" is a style.

So, to show where this fits into the overall umbrella of Arcadia, you have:

Arcadia (handles chat, voice, servers, player management, sound, graphics... on behalf of its toys)

TurnAbout (one of the Toys in Arcadia) Provides an interface between Arcadia Services and the Deck's Style Script. Offers several Render options to the stye script

Deck Style: Monopoly (a style of TurnAbout board game), has its own script file (monopoly.script) which controls how the game is played. Players can make up new deck styles and share them.

Card: A collection of named properties ("name=park place", "rent=180", ..) Players can make new cards. Each card belongs to a single Deck Style.

Deck: A deck of cards from a given deck style (is used to start up a game session with other players). Players can make new decks. Only the cards in the selected deck are available during the game.

To start the game, the moderator picks one of his or her decks, and presses Start Game. The deck's style defines the lua game script which is to be loaded. The deck's cards provide assets like... locations, monsters, items, random events to be used by the script. It is up to the Deck Style itself to determine how cards are used in that game.

What happens after that is entirely up to the script. TurnAbout regularly informs the style script when interesting events happen (like someone enters the game, or clicks on a user interface panel). The script then asks TurnAbout to perform various jobs on its behalf, like send packets of data to other players.

More About Decks

Decks are pretty straightfoward. To select a deck, just pick it from the Deck Selection dialog, and press the START GAME button. Your deck will then be copied to the other players and the COPY will be used/modified over the course of the game, while your original deck will be unharmed

To make a NEW deck, you open the Toy Options dialog and click the Deck Editor button. This lets you create a new deck or modify an existing one. If you create a new deck, you must indicate which 'deck style' it will use. Then you just drag cards in and out of your deck from the cards you have defined in the past.

More About Cards

The Toy Options Dialog has a button which opens the Card Editor, which lets you make new cards, or modify the properties of existing cards.

Every card has a parent (or base) from which it inherits properties. It may then add additional properties which will then be inherited by its own children. All cards ultimate inherit from the 'root' card which defines the basic properties which ALL cards must have.

Every card has a unique 'cardId' (which is a number like: 0000001_23) (the 23rd card created by the player with serial number 00000001 (that's me!))

Any card which has the root card as its direct parent, is a 'style card' and defines a deck style. It would not, for example, be 'dealt out' in a game. It just defines the basic properties you need for decks to be used by your style script.

For Example, the inheritance tree for monopoly cards might look something like this (card id numbers shown are just pretend, yours would vary):

root (#00000001_1)

style: monopoly (#00000001_3)
property CardType=unknown

name: Real Estate (#00000001_7)
CardType=RealEstate
property Rent=0

name: Park Place (#00000001_21)
Rent=100

name: Montgomery Ave (#00000001_22)
Rent=50
...

name: Rail Road (#00000001_8)
CardType=RailRoad
property Tax=50%

name: Reading Railroad (#00000001_25)
Tax=35%

name: Caltrans (#00000001_27)
Tax=12%
...

name: Utility (#00000001_9)
CardType=Utility
property Fee=50

name: gas (#00000001_28)
name: electric (#00000001_35)
...

name: Chance (#00000001_10)
CardType=Chance
property MoneyEarned

name: You go to jail, pay bail! (#00000001_32)
MoneyEarned = -1000

name: You win lottery! (#00000001_99)
MoneyEarned = 1000000
...

See how the Style Card defines a property called "CardType" which is inherited by all cards of this style and has the default value of 'unknown'. Four cards are defined with the Style Card as their parent, and they each set the value of this property (to: RealEstate, RailRoad, Utility, and Chance) creating four basic 'flavors' of card within the monopoly 'style'

In this example, the RealEstate card defines a property 'Rent' which only applies to Real Estate cards (not to Railroads, utilities, or chance cards). it has a default value of 0, but every Real Estate card overrides this with a unique rent value (Montgomery Avenue charges 50).

But as a counter example, the utility cards do not override their parent's "Fee" property, so they all charge the same fee (50) (they inherit both the 'Fee' property AND its default value)

I Hope that gives you the idea. You design cards for the purposes your game needs, then later your script can ask for the current value of property X on cardId Y. For monopoly, only the RealEstate, RailRoad, and Utility cards would form the game board (making the circle through which the player tokens move), while the Chance cards would be just data used by the script to punish/reward you when you landed on an appropriate board spot. (The actual 'chance' spot on the game board might be a special RealEstate card, named "Chance" with a custom property "WhenUserLandsHereDrawARandomChanceCard = yes")

You could, in fact, define a deck of 52 playing cards, and use TurnAbout to implement multiplayer poker, cribbage, etc. (Someday, I mean, not actually today, since the API does not yet allow the script to actually render anything beyond that stonehenge of cards!!)

More About Lua

Lua refers to itself as an extensible extension language (read about it here: http://www.lua.org/pil/). It extends TurnAbout, but then is itself extended by TurnAbout. Now that's synergy!

If you have never programmed before, here's your chance to learn something totally new! At no cost!

If you are a veteran programmer, you might find lua a bit odd. Here is a little example function which I think recaps the bits which I personally find sufficiently odd that I have to watch myself to not make mistakes:

-- This is a comment. Two dashes. Do NOT use semicolons or pound signs or slashes!

function SortTwoNumbers( x, y )

-- no curly braces! use 'end' to mark the end of a block of code
-- Don't forget the 'then' after your 'if'
-- Don't use semicolons at the end of lines! (it won't burn you until much later)

if ( x > y ) then

return y, x

else -- or "elseif( condition ) then" if you have additional cases to check

return x, y

end

end

Note those returns! Lua can return more than one thing at a time!

local a
local b

a, b = SortTwoNumbers( 3, 4 )

So, what's in 'a' now?

Other random factoids

  • not-equal is tested like this: "if ( a ~= 3 ) then" Do NOT use "!="
  • equality is tested like this: "if ( a == 3 ) then" (i.e. pretty normal) and this also works for strings
  • the string concatenation operator is TWO dots. str = "b= " .. b .. ", and a = " .. a
  • 1 and 0 are BOTH TRUE. for false you use 'nil' (an undefined value)
  • Array indices start at ONE, not ZERO
  • Initialize an array like this: "array = {}"
  • Add something to an array like this: "array[ 12 ] = 44"
  • Add an array into an array like this: "array[ 7 ] = {1, 2, 3, 4}"
  • so, "Array[ 7 ][ 3 ]" has "3" in it
  • but Array[ 99 ] has 'nil' in it (we haven't put anything there, all arrays are 'sparse')
  • Arrays are really hashes: array[ "bill" ] = { "male", "friend", "april" }
  • so: array[ "bill" ][ 2 ] = "friend"
  • to turn a string into a number, do this: local numberValue = 0 + stringValue
  • if you don't say local, then your variable is GLOBAL, no matter what scope it is defined in.
  • Lua is all about references, so: local temp = array[ "bill" ] does not COPY the entry from 'array', it sets 'temp' to a reference to the original. So if you modify temp, you are also modifying the original.
Security Issues

So.. why not just let you compose Toys directly in C++ and skip this whole TurnAbout/lua thing? Well, Toys are written in an environment which has full access to the player's computer, which means they could potentially read or modify any file on the player's disk drive. This means they could, in fact, be nasty viruses or spyware.

I have spent years establishing my credibility as a programmer/publisher who does NOT do nasty things. I ultimately felt I could not expose my reputation to the risk of allowing 3rd parties to make Arcadia Toys directly. This made me sad since that was my original intention.

TurnAbout/Lua, however, is an environment where I can impose certain sandbox controls upon the fledgling game designer. For example, I do not provide lua any direct io access at all. You cannot read/write files directly. (A pain to be sure!) You have to beg TurnAbout to do that sort of thing for you, and TurnAbout is very stingy as to what it will grant you access to.

But isn't Lua Slow? I heard it was reeeeeally slow!

It's slower than the GPU of your 3D card, yes, so I do not recommend trying to do any ray-tracing 3D graphics within lua itself. But how much speed do you need to do a board/card game?

In fact, Lua is suprisingly peppy:

  • 450 nanoseconds for TurnAbout to call a function in your Lua script and get a value back
  • 50 microseconds for lua to do "for var=1,1000 do" with no work in the loop (50 nanoseconds per loop)
  • 15 nanoseconds to do a floating point multiply
  • 200 nanoseconds to write to a hash: data[ var ] = "test"
  • 100 nanoseconds to read value back and compare it: if( data[ var ] ~= "test")

All values measured on a 2.6GHz Pentium IV, with each action performed thousands of times (first execution might be slower than subsequent since lua is a 'just in time compiled' language)

So.. in one second, lua could 'count to' about twenty million. Not as fast as 'C' running on the same computer, but still probably a hundred or thousand times faster than your dad's Apple ][.

How Do I Start a New Deck Style From Scratch?

It's probably silly of me to document this at this time, but something like this:

  • Open the Card Editor and press "Make New Deck Style"
  • Give it a nice name, say: "Parchesi" (it must only use legal windows file name characters, and be brief). This will create the 'style card' for your new deck style. All your cards will ultimately need to be children or grand-children of this style card.
  • Notice your current serial number, since you will need to provide a style script with a matching name, as in: c:/arcadia/toys/toy10/assets/styles/<my serial number in hex>/parchesi/parchesi.script
  • An initial script file is created for you automatically (as a copy of 00000001/blank/blank.script)
  • Think about any cards you absolutely must have, to achieve your vision, and the 'family tree' organizing them
  • Make some cards to flesh out your family tree. Just enough to get started.
  • Use the Deck Editor to create a new deck "My Parchesi Deck," based on your Parchesi style card, and drag some parchesi style cards into it. (Your deck must include at least one card)
  • Use the text editor of your choice to edit your script file (parchesi.script) and be sure to periodically back it up in some safe place. You never know when your cat will decide to walk across the keyboard while you're asleep.
  • Use lots of TA_Log( "I made it this far!" ) messages to help you debug your code during development
  • Error messages will appear either in the chat window or in the Debug/FunPack window.
How Do I Write a Multiplayer Game?

You might want to start out with solo games if you're a total newbie, but the trick to multiplayer games is to send packets between the players. My generic example script shows one way to organize this. But in general you need to work out what sort of information needs to be shared by packet, versus information which can just be baked into the script or the card deck, which everyone will have a copy of at the beginning of the game. Send as few, small, packets as you can. Don't send the bullets, send the trigger.

Once you have that thought out, ask if you want each player to shout to everyone else "Hey, I rolled a six!" or if you want the chaos controlled by the moderator. You generally want the latter. In that model, for a game action to take place, the initiator sends a 'request' packet to the moderator. the moderator validates it, then sends a 'doAction' packet to all players (including himself). All players then execute the actual action specified, which changes the 'state' of the game. In theory, after that everyone agrees on the new state of the game.

As much state as possible should be configured by the script automatically at the start of the game. This might include the moderator sending a packet with a random seed value in it (TurnAbout will do this for you, actually) so that the same random number sequence can be used by all players, leading to random, but synchronized, starting game state.

Newcomers in mid-game will need some extra synchronization, but if your game uses a lot of state, you might just refuse to allow newcomers, rather than sending them hundreds of packets.

For example:

  • Player One rolls a three (let's pretend that is synched)
  • Player one sends a packet to the moderator 'requesting' his token be moved 3 spaces
  • Moderator receives request, checks that it is player one's turn, accepts that '3' is correct
  • Moderator sends packet to all (including himself and player one) "move player one 3 spaces"
  • Everyone receives that packet, and executes a function like:

function MovePlayerForward( playerSerNum, numSpaces )

local oldPosition = playerPositionArray[ playerSerNum ]
local newPosition = oldPosition + numSpaces
newPosition = math.mod(newPosition, numPositionsOnBoard) -- wrap it around
playerPositionArray[ playerSerNum ] = newPosition

end

  • And then the script makes magical TA_xxx calls into TurnAbout to actually animate the player token walking around the game board. Since this happens on every player's machine, they all see the player walking. But the script might sometimes check if the player serial number from the packet matches the local player's own serial number and do something different, say, inject a different message "YOU walk to the 7-11" Instead of "Bill walks to the 7-11"
OK, How Do I Send a Packet?

Um, er, OK... well, at present, to send a packet from your lua script, you use this:

TA_SendPacket( serNum, num1, num2, num3, num4, string1, string2, string3 )

That is to say, your lua packet can contain no more than 4 numbers and 3 strings. Though it can contain less. And the numbers in the packet are integers (max range -2 billion to +2 billion)

'serNum' determines who will receive the packet. You can send it to a single player (their serNum), to all players (use serNum 0) or just the moderator (use either the moderator's serNum or -1). For example, this might be a packet that requests the moderator MOVE (command = 3) playerSerNum 1234, 5 spaces forward. um, and play sound effect "butterfly.wav"

TA_SendPacket( -1, 3, 1234, 5, 0, "butterfly.wav", "", "" )

That's just an example, how you organize your packet is up to you. Only you will ever see these packets, since once you send them, they go only to the lua scripts running on the other player's machine. Your script must define an event handler function to 'receive' incoming packets

function TA_OnPacket( serNumSender, num1, num2, num3, num4, str1, str2, str3 )

-- serNumSender is the origin of the packet (the guy who called TA_SendPacket)
-- This is probably different from serNum of the player being moved
-- (in num2 of our example)
-- Often serNumSender is the moderator, and you probably want to ignore certain
-- packets UNLESS they came from the moderator.

-- num1 is the COMMAND
-- num2 is the player who is being moved
-- num3 is how many spaces he is moving
-- str1 is the name of the WAVE file to be played

if ( num1 == 3 ) then

-- Command 3 is the MOVE command, we have decided
MovePlayerForward( num2, num3 )
PlaySoundEffect( str1 ) -- assuming you have a function like this

end

end

The thing to watch out for are packets which stimulate the sending of the same packets that stimulated the sending of the packets that stimulated.... And if you feel you need more than 4 numbers and 3 strings in your packet, ask yourself if there is anything in your packet which could be stored in a lookup table in your script? I mean, rather than sending "Order of the Butter Knife" in the packet, send "1" where "1" is the index of the appropriate entry in an array.

Also, you can cram multiple bits of info into a single string, like this:

A5Z2/butter/2.34/

Where both the sender and receiver of the packet know that the FIRST letter indicates what month the player was born, the SECOND character is an index into an array of six weaponIds indicating which gun he has selected, the Z is his currently selected radio channel, the 2 is how many spare clips he has, the slashes help you find the boundaries of variable length fields (lua has a boatload of regular expression parsing stuff) and the 2.34 is a floating point value that you couldn't stick in one of the four num fields. (Though you COULD have sent it in a num field as "234" and just known to divide it by 100 after receiving it. Which is also a nice way to control the precision of arguments)

Mandatory TA_OnXXX Event Handlers

Your Style Script MUST define the following functions. They are how TurnAbout tells your script that important things have happened. Your script does NOT have the luxury of running a continuous game loop. Your script is event-driven and must return from each event as rapidly as it can, or the game will feel laggy to the player.

Go here.

Available TA_xxxx Requests

Your event handlers can then call external functions provided by TurnAbout to carry out various actions on your behalf. Feel free to suggest additional functions if you feel there is a compelling need.

Go here.

Turnabout API / Tutorial

This is a work in progress, but the reference material will be kept here.

This can be expected to change without warning, so stay flexible!

Included Deck Styles

These are mini-games which come with TurnAbout.

TurnAbout Blackjack
The classic game of 21

TurnAbout Feud
A multiplayer ballistic battle

TurnAbout WindChasers
A Multiplayer sailboat simulation


Toy Status:

The game is somewhat incomplete, but the API is robust enough now that it is possible to craft multiplayer mini games. (See examples above, of functional multiplayer games written in TurnAbout)

To Install Toys:

  1. Run Arcadia
  2. Select your 'channel'
  3. Push the "Check for New Toys" button
  4. Follow Instructions.
 
  Copyright 1999-2014, Synthetic Reality Co. All Rights Reserved