A Switch Statement for Fireplace

The latest Tavern Brawl, “An Evil Exchange”, is really cool. It introduces several new cards with interesting mechanics.

One of them, “Uncover Staff Piece”, is a card that works a lot like Shadowform: It updates the player’s Hero Power with a different one, depending on which one is currently in play.

This is where I realized that Shadowform and Justicar Trueheart could be solved in the DSL by introducing a simple Switch statement. Instead of messing around with Find() and nested else clauses, which is possible but looks awful.

So we got one.

This is the new Shadowform:

play = Switch(FRIENDLY_HERO_POWER, {
	"EX1_625t": Summon(CONTROLLER, "EX1_625t2"),
	"EX1_625t2": (),
	None: Summon(CONTROLLER, "EX1_625t"),
})

The first argument to Switch() is a selector, which must evaluate to either 1 entity or none at all (otherwise, it will error out as unsupported). Luckily, it is not possible to have more than one FRIENDLY_HERO_POWER in play.

The second argument is a map between a card ID and a list of actions. The Switch statement will look for the found entity’s ID, performing the matching actions when triggered. None is a special key which contains the default case. If there is no entity, or the found entity does not match any key, the action in None will be performed. Without a None key, no action will be performed by default.

It is also possible (as evidenced in the EX1_625t2 case, which is “upgraded twice”) to specifically perform no action in a case, allowing for a non-null default case with specific null outcomes.

Bootstrapping

In other news, Fireplace’s bootstrapping process has been entirely removed. This is the culmination of weeks of work, greatly simplifying the installation process. The Python Hearthstone library is now on PyPI, which means it can be installed directly from pip. The released versions actually include the latest CardDefs.xml file. Useful! Installing Fireplace will soon be as simple as pip install fireplace.

Game loop rewrite

The next big chunk of work is going to be a rewrite of the game loop. Details are in #329.

When a choice card is played, the game loop is interrupted until the choice input resolves. This means that, for example, when playing a Discover card with a Knife Juggler on the board, the knife will trigger after the Battlecry completes, which includes the resolution of the choice. In fireplace, the battlecry will finish without waiting for the choice - but fireplace will prevent the user from performing further actions on the game.

A more powerful implementation of the Choice mechanic is blocked by this. Eye of Orsis (LOEA16_13) most notably requires such an implementation: The resolution of the choice is needed to complete the play action (the remainder of the play action being “give the player two more copies of the picked card”).

A tick-based loop would also potentially simplify the Kettle server, defining clearly when to check for updates.

52 files changed, 671 additions(+), 454 deletions(-)

Jerome