Handling the mouse can become very complicated since a "mouse click" can do many different actions depending on the context: choose targets for a spell or ability, advance to the next phase, or is used to declare attacking creatures. Forge uses the state pattern to process all of the mouse input. Without the state pattern I have no idea what I would have done. I think it works well but it can be tricky to understand.
Below is the Input class that handles the mouse. To better understand the Input class let me briefly explain how Forge implements different phases. Each phase extends Input and shows the name of the phase to the user through showMessage(). Usually a phase will let a user do a specific action like the Main phases allow the user to play any type of card or a land. MainInput.selectCard() handles the processing of playing a card or land.
Input class is also used whenever a spell or ability needs to choose a target. The Input for Shock would use showMessage() to show the user a message like "Select target creature or player to receive 2 damage." If the player clicks on a card, selectCard() checks to see is that card a creature. If the user clicks on a player, selectPlayer() is called.
class InputThere are a few details that I have left out. First, how does an Input tell the rest of the program that it is done and the next Input should be processed? Forge handles all of the Inputs using a stack and the Input class has a method called stop() which just pops the stack. Second, how do the phases advance? I just hardcoded them, nothing fancy. Main 1 always advances to "Before Declare Attackers". When the Main 1 Input method selectButtonOK() is called, it pops itself and pushes the next Input onto the stack.
//showMessage() is always the first method called
public void showMessage()
public void selectCard(Card c, PlayerZone zone)
public void selectPlayer(String player)
public void selectButtonOK()
public void selectButtonCancel()
Since the method showMessage() is always the first method called, I can put code in there that I would usually put into a constructor. Another trick that I do with showMessage() relates to planeswalkers. Forge was written before planeswalkers were added to Magic so it didn't have the concept of "you can only use one of these abilities once a turn" or loyalty counters but I used showMessage() to fake it. I won't show you the code since it is very crufty and hacked-together even by my standards. Where there is a will, there is a way. :--)
Random quote, “Time is a great teacher, but unfortunately it kills all its pupils.”
I lied when I said that "Forge handles all of the Inputs like a stack". In reality Forge doesn't stack inputs. It has a stack but it is only one deep. This can be seen if you play two legendary creatures that have an effect when they go to the graveyard like Keiga, the Tide Star. If you play a 2nd Keiga, you only get to steal one creature. And knowing is half the battle. (Yes, I pretend to be funny even though I'm not.)
The Input class is also used for mulligans.