Stack-Activity

The stack consists of following elements:

The idea is the following:

The player whose turn is, "does" something (like playing a card). That action goes as a stack item on the stack. The player than acknowledges his doings by saying "done" to the stack, which means, I'm finished for now (this can be automated, see configuration, otherwise you might find yourself hitting madly at the DONE button).

After that the other player (opponent) gets a chance to react to the current things on the stack. He can do that ONLY by playing out instants or possibly abilities of cards (with Portal-cards only a few instants are available and (I think) no ability) ).

This "playing out of an instant" is handled as above communication. After doing all he can do (which isn't much) he too can pass the stack. If he actually "changed" the stack by playing a card or so, the "pass"-information of the player is resetted. So it goes on and on till both players actually agree to the stack which means both players pass the stack. This "both must pass" is crucial, even if the stack is empty! Only after the stack is passed by both players one of two things can happen:

  1. Stack is resolved (if stack was passed by both players and at least one item is on the stack)

  2. Turn ends (if empty stack was passed by both players)

To stay at our example from above we go into a) (and assume the opponent didn't play out Mystic Denial the only possible Portal instant for MainPhase).
(By the way implementing Mystical Dinial was VERY easy, three lines of "card script":
...
    Card toNegate = match.getStackCard(match.getStackSize()-1);
    match.removeStackItem(player, card, 0);
    match.moveCardFromHandToGraveyard(match.getOwner(toNegate), toNegate);
...
)

Anyway, following our example from above, we enter the match "event"-dispatcher and there the
...
    handleStack();
...
will now be called, since there is a stackItem on the stack (the card ("Ebon Dragon") we just played). After some checking, that all players passed the stack, the method "doStack()" will be called, which handles resolving the stack. The different StackItems are resolved, which again leads eventually to:
...
    MatchStackItem item = mMStack.read();
    boolean ret = stackBringCreatureIntoPlay(item);
...

Which finally (tries) to play our good old black dragon. Here the code, which interests us now:
...
    item.ev = new CardShellEnvironment(this, card, CardSituation.CARD PLAYED KEY);
    item.ev.execute();
    if (!item.ev.iRet.bRet) {return false; }
    else
    {
        boolean moved = mHand[mPlayerToInt.get(p)].moveCardTo(card, mCreature[mPlayerToInt.get(p)]);
    }
...

Here we encounter for the first time a scripting of a card. In this case there is a SituationKey:
CARD PLAYED KEY.
The card is requested to do what ever is scripted for the given situation (see cards). If the card has not finished, which means for example there is a communication the card has initiated, the script will return bRet=false; which in turn leads to that stackBringCreatureIntoPlay() will return false, which leads to that in doStack() the stackItem will NOT be removed, which means that the stack will be called AGAIN (after finishing by the card initiated communications, which are handled in priority to stack items) which finally leads to, that the match handles exactly the same situation again, with the only difference being, that a communication was handled. If you look at the code (won't copy it here), you will see that there is a code very similar to the implementation in doPlayCard() regarding the "mLastAnsweredCommunication".

For the example about handling the card script look at cards. Here I assume the communication for Ebon Dragon is handled (which is not all that simple, since at least one communication, possibly more are involved) successfully. Which means we are finaly done playing out a card (after cleaning up the stack, in doStack()). If no more cards are played we can finally go to the third possible Communication - the Game phases!