Skip to content

Serialization Format

danielyule edited this page Aug 11, 2014 · 12 revisions

Serialization Format

The following is proposal for a serialization format of the current board state of a game in Heartstone. It makes no assumptions about the state of the game, (i.e. the game can be serialized or deserialized part of the way through a turn, or at the end or beginning of a turn).

The proposed format is a JSON based format. In most cases it relies on standard Hearthstone Terminology, but a standard for effect names and descriptions will have to be agreed upon.

Some of the objects could possibly be merged into other objects, but are kept separate for discussion's sake. Later on, they can be combined if necessary (i.e. Deck into an array instead of an array inside an object)

Game Object

At the root is the game object, which consists of an array of two Player objects and an integer which gives the index of the player whose turn it is now:

{
    "players": [Player, Player]
    "active_player": Integer
    "current_sequence_id": Integer
}

current_sequence_id is an integer to keep track of when minions are created. Each time a new minion is placed, current_sequence_id is incremented, and the minion's sequence_id is set to the new value. This allows for proper execution of deathrattles.

Player Object

The Player object houses all information about a Player:

{
    "hero": Hero,
    "deck": Deck,
    "hand": [Card, Card, ...],
    "secrets": [Secret, Secret, ...]
    "card_filters": [CardFilter, CardFilter, ...],
    "minions": [Minion, Minion, ...]
    "mana": Integer,
    "max_mana": Integer
}

Hero Object

The Hero object refers to the avatar of the player in game:

{
     "character": "Mage" | "Paladin" | "Druid" | ... ,
     "weapon": Weapon,
     "health": Integer,
     "attack": Integer,
     "immune": Boolean,
     "frozen_for": Integer,
     "windfury": Boolean,
     "used_windfury": Boolean,
     "already_attacked": Boolean
}

Most properties are fairly self explanatory. frozen_for is an integer that specifies how many of the player's turns this hero will be frozen for. If the hero is frozen on the owning player's turn, then it will be frozen for the remainder of that turn, and the next one, so frozen_for will be 2. If it is frozen on the opposing player's turn, then frozen_for will be 1. At the end of the owning player's turn, frozen_for will be decremented, until it is 0, and the hero is no longer frozen.

If a hero's windfury is set to True, then the first time the hero attacks in a turn, used_windfury will be set to True. The second time, already_attacked will be set to True. This gives a way to know if a can still attack.

Weapon Object

The Weapon object simply gives the name of the weapon and its stats. Any effects (such as from Gladiator's Longbow) can be inferred from the weapon's name

{
     "name": String,
     "attack": Integer,
     "durability": Integer
}

Deck Object

The Deck object gives information about what cards are left in the deck. It is an array of DeckCard objects:

{
    "cards": [DeckCard, DeckCard,...]
}

A DeckCard object is simply the name of the card. Currently, this does not record which cards have already gone by

{
     "id": Integer
     "name": String
}

The id property must be unique across DeckCards and Cards.

Card Object

The Card object gives information about a card currently in the Player's hand.

{
     "name": String
     "id": Integer
}

The id property should be the same as when the card was still in the deck

Secret Object

The Secret object states information about secrets that a player might have

{
     "name": String
}

CardFilter Object

The CardFilter object is designed to change the mana cost of one or more of the player's cards. These filters are not generated as an aura effect by a minion on the board, but are generated as an effect (such as battlecry, deathrattle or a spell) Examples include Frozen Trap, or Loatheb's Battlecry.

{
     "amount": Integer,
     "filter": "minion" | "spell" | "secret" | "card",
     "until": "turn_ended" | "turn_started",
     "player": 1 | 2
}

amount is the amount to decrease the mana cost of affected cards

card_filter is the type of cards to affect. Possible values are "minion", "spell", "secret" and "card"

until: When to remove this effect. Possible values are are "turn_started" for the start of the next turn and "turn_ended" for the end of the current turn. The filter will be removed regardless of the only_first property.

only_first True if this card filter should be removed the first time a player plays a card which matches the filter

Minion Object

The Minion object represents a minion as placed on the board.

{
    "name": String,
    "sequence_id": Integer,
    "position": Integer,
    "health": Integer,
    "max_health": Integer,
    "attack": Integer,
    "stealth": Boolean,
    "taunt": Boolean,
    "divine_shield": Boolean,
    "spell_targetable": Boolean,
    "windfury": Boolean,
    "charge": Boolean,
    "exhausted": Boolean,
    "already_attacked": Boolean,
    "windfury_used": Boolean,
    "frozen_for": Integer,
    "immune": Boolean,
    "silenced": Boolean,
    "effects": [Effect, Effect, ...]
}

Most properties are fairly self explanatory, and frozen_for, windfury_used and already_attacked work similarly to how they work for Hero.

sequence_id is an integer that indicates when this minion was created, for the purpose of executing deathrattles. See the discussion in the Game object.

position is a zero based index of where the minion is on the board.

Effect Object

An effect describes something that has happened to a minion, either from its own text, or as a result of a spell or battlecry. Aura effects from other minions are not counted, except on the minion that is the source. For example, if a Stormwind Champion is down, each other minion on the board won't have a "PlusOnePlusOne" effect applied, but StormwindChampion will have a "GiveFriendlyMinionsPlusOnePlusOne" effect on it.

{
    "name": String
}

The name of the effect is used as a dictionary key to look up the effect and apply it. So, it is necessary to have a standardized list of possible effects. The names would be a description of what happens, like "DestroyRandomMinion" or "GiveAdjancentMinionsPlusTwo".

Another possibility is to have a more complex effect object (similar to the effect system in Focus) such as

{
   "type": "stealth",
   "until": "end_turn"
}

or

{
    "type": "increase_attack",
    "filter": "adjacent_minions",
    "amount": 2
}

This gives much more flexibility, and will allow for new effects without needing to add to the list of effects in the dictionary. It has the downside of being more complex.

Clone this wiki locally