Monday, July 26, 2010

Activatables

If not for Activatables, cards in Sharpening would be very useless, unless you turn it into some sort of collector's simulator. So what are activatables? A lot of things.
  1. They are the activated abilities of permanents.
  2. They are the act of casting any spell.
  3. They are any alternate way of casting any spell. (Flashback,Buyback,Cycling,Ninjutsu,"You may X instead of paying this card's casting cost")

Basically, they're everything you can do with a card beyond holding it in your hand.Activatables contain:

  • A Condition, "CanBeActivated"
  • A CompoundEffect, "ActivatedEffect"
  • A CompoundCost
  • A CardBase, "CardSource"
  • A string, "Description"
  • Tags for wether the Activatable is a mana ability or a regular ability.

The plan is that when you click on a card in the GUI side of things, the UI raises an event in it's bridge to the Sharpening core (More on the bridge in a future entry) and the library will round up all the Activatables of the clicked card and ask them if they could be used at the moment. For this, each Activatables "CanBeActivated" checks whatever is needed. For instance, Flashback "CanBeActivated"s checks that the card is in the graveyard and returns true if so.Then, the library will make a call back in to the GUI to present the player with a choice of the Activatables that were usable (unless of course there was only one, then that will be run). Then, the chosen or lone Activatable's CompoundEffect(One or more effects) "ActivatedEffect" is run. The effect will often, but not always, start by setting the InputStateMachine to "Pay Cost" mode so that it's CompoundCost(One or more Costs, of any type) can be paid one by one. Then, the Effect will do whatever it specifically should. Continuing with the Flashback example, this would be "Do the same as the hardcasting Activatables Effect, AND then exile the card.".

To simplify card creation, I provide two Factory classes that the cards can use to create Costs(not just mana costs) or full-on Activatables. For example, to add Flashback to a card, you could simply use a statement like

this.activatables.Add(ActivatableFactory.Create(this,"Flashback:2 U
U,Discard(1,Any)"));

and the ActivatableFactory would create the two costs for you (using the CostFactory), insert the proper CanBeActivated condition and copy the hardcasting directly from the card(with the added Exile effect).

If at anytime a card would require an activatable that the ActivatableFactory can't create(not a rare situation), a custom Activatable can be written directly in the cards code using anonymous delegates for the Condition and Effects. I am also thinking about letting the ActivatableFactory create a BaseActivatable that only takes care of paying the costs and let the card writer tack on the actual effect at the end. Otherwise, you'd have to write boilerplate cost-paying code everytime you write a custom Activatable.

Oh crap, I'm starting to ramble. Well, that's Activatables.If something doesn't make sense, it could be either that I muddled it up or because it depends on something else that I havn't touched on yet. In closing, I want to make a pledge.

"I'd swear on my mother's grave, were she not alive and well, that I will never, EVER, place card-specific code in the core of Sharpening, so help me Niv-Mizzet." Amen.

2 comments:

  1. This is pretty much how I do activated/casting abilities in Incantus, although python let's you easily build mini languages, so the card code is more declarative in nature, and not a series of nested objects.

    ReplyDelete
  2. Well that's just down to a difference in ideology of the respective languages, if that makes any sense. It just happens that Everything-Is-An-Object is easier for me to wrap my head around. :)

    ReplyDelete