Wednesday, June 3, 2009

Zone Events - Part 1

I am slowly working on MTG Forge 2.0 and I'm trying to figure out what events should be generated. Granted that this is just a baseline and more events could be added later but my question is "What events do Magic cards care about?"

Many cards have some effect when another card is added or removed from a zone like Glorious Anthem. A card could even want to know when itself was put into play, like Venerable Monk. The triggered ability "when this card comes into play" is fairly common.

Several cards like Darksteel Colossus and Serra Angel have the replacement effect "If this card would be put into a graveyard from anywhere, reveal this card then shuffle it into its owner's library instead" and need to know if they are in a graveyard. (Technically the card would never be put in the graveyard since it is a replacement effect but let's forget that detail for now.) Remember that replacement effects start with the word "instead", see 419.1a "Effects that use the word 'instead' are replacement effects."

The reader should also note that these basic add and remove card events would not be enough to implement Megrim since it only concerned when an opponent discards a card. A card could be removed from a player's hand if he plays it or if he discards it. It would be best to add a discard event if we want to implement Megrim.

Stay tuned for part 2 on Monday. Same bat-time, same bat-channel :+)


Moxy said...

generically any zone change needs an event.

Something that is sorely missing from the current version is giving the user a chance to respond to the start and end of any phase and or step. I can't currently use Elvish Piper (or flash) at the beginning of the declare blockers (or end of declare attackers) step so that I can "sneak block"

willow said...

Am I wrong if I say that "moving a card from your hand to your graveyard" is equivalent to "discard". your events should be classes that inherit an abstract "Event" class. Then, a "move" event would have information regarding the card that was moved, which zone it was moved from and which zone it was moved to. To check if the card is discarded, you just have to ask the event if the "from" zone was a hand and the "to" zone was a graveyard.
Again, this is assuming these are equivalent, which I believe they are

Unknown said...

I've been thinking a lot about these sorts of things too. a "Comes into play" event, shouldn't necessarily be different from a "when another card comes into play" event - they should really be the same event, but the card-specific code just checks to see if the card that came into play was itself or another card. Similarly, a generic "card leaves play event" should be triggered on any card that registers as having such and event handler. Then the event handler checks, is it myself going to the graveyard, or some other card?
Currently there's a "comes into play" Command object implemented in the Card object. Each card should have not one Command object, but a list of Commands for each type of event. Some cards do more than one thing when an event occurs. The thing that they do may be generically defined by keyworded abilities, so mixing and matching needs to be supported, without having to explicitly code both actions into a single Command object. Plus, each Command object may have different actions depending on the circumstance....
This way the following pseudo code could be coded in three generic objects, and each will get executed.
if (Card comes into play and condition a is true)
do x
if (Card comes into play and condition b is true)
do y
if (Card comes into play)
do z

willow said...

@Rob Cashwalker:you should think in a more generic way.
I think you don't need a "come into play" event.
You just need an event "changedZone", with 3 attributes. The card, the "from" zone, and the "to" zone.
If "toZone" is "inPlay", then it is a "come Into Play" event.
Please have look at what I did in wagic, I think it works well enough:
Have a look at the following code in the Wagic svn. The function "putInZone" is of course called whenever a card needs to move from one zone to another. Look at the event creation on line 144. I create an event and send it to the "gameObserver". The abilities in play then do whatever they want of the event.

Forge said...

Am I wrong if I say that "moving a card from your hand to your graveyard" is equivalent to "discard".

Yes I agree but this post only talks about events that affect a single zone, addCard() and removeCard(). The next post talks about events that affect two zones, such as discard.

Forge said...

I've been thinking a lot about these sorts of things too. a "Comes into play" event, shouldn't necessarily be different from a "when another card comes into play" event

I see these two events being the same.

And yes MTG Forge needs more phases.

Incantus said...

Rares -

Actually, moving from hand to graveyard and discarding a card are 2 different events (especially if you consider replacement effects).

Also, that's the way Incantus does it. Everytime a card moves from one zone to another, the zone sends 2 events, and LeaveZoneEvent(zone, card) and an EnterZoneEvent(zone, card). Anybody who's interested can listen to those events and do something in response. This captures all the possible zone change events, including the ones that look back in time - for example, "Whenever a creature card enters graveyard from play", looks back to see if the card was a creature in play (this way it fires for things like animated lands).

Forge said...


Replacement effects are very hard. How does your program implement them?