*Beginning stages of Simultaneous Trigger Ordering.

Hardcoded triggers should either use the actual Trigger objects, or use AllZone.Stack.addSimultaneousStackEntry(SpellAbility) whenever they need to add itself to the stack. The Simultaneous Stack Entries are "flushed" onto the stack when priority is passed or a new phase is entered.
This commit is contained in:
jendave
2011-08-06 22:10:04 +00:00
parent 4881fc7e78
commit 3ba4a9dc32
20 changed files with 702 additions and 309 deletions

View File

@@ -542,6 +542,7 @@ public class Card extends MyObservable {
runParams.put("CounterType", counterName);
AllZone.TriggerHandler.runTrigger("CounterAdded", runParams);
AllZone.GameAction.checkStateEffects();
this.updateObservers();
@@ -1423,7 +1424,7 @@ public class Card extends MyObservable {
public void executeTrigger(ZCTrigger type) {
for(Ability_Triggered t:zcTriggers)
if(t.trigger.equals(type) && t.isBasic()) AllZone.Stack.add(t);
if(t.trigger.equals(type) && t.isBasic()) AllZone.Stack.addSimultaneousStackEntry(t);
}
public void clearTriggers() {
@@ -2091,6 +2092,8 @@ public class Card extends MyObservable {
HashMap<String,Object> runParams = new HashMap<String,Object>();
runParams.put("Card", this);
AllZone.TriggerHandler.runTrigger("Taps", runParams);
}
setTapped(true);
}
@@ -2101,11 +2104,13 @@ public class Card extends MyObservable {
HashMap<String,Object> runParams = new HashMap<String,Object>();
runParams.put("Card", this);
AllZone.TriggerHandler.runTrigger("Untaps", runParams);
}
for(Command var:untapCommandList) {
var.execute();
}
setTapped(false);
}

View File

@@ -398,6 +398,8 @@ public class Combat {
HashMap<String,Object> runParams = new HashMap<String,Object>();
runParams.put("Attacker", attacker);
AllZone.TriggerHandler.runTrigger("AttackerUnblocked", runParams);
}
}
}
@@ -624,6 +626,9 @@ public class Combat {
damageMap.clear();
c.clearAssignedDamage();
}
//This was deeper before,but that resulted in the stack entry acting like before.
}
public boolean isUnblocked(Card att){

View File

@@ -1811,6 +1811,7 @@ public class CombatUtil {
}
a.setCreatureGotBlockedThisCombat(true);
}
public static void executeExaltedAbility(Card c, int magnitude) {
@@ -1846,7 +1847,7 @@ public class CombatUtil {
sb.append(c).append(" - (Exalted) gets +1/+1 until EOT.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
Player phasingPlayer = c.getController();
@@ -1864,7 +1865,7 @@ public class CombatUtil {
sbUntap.append(c).append(" - (Exalted) untap.");
fhUntap.setStackDescription(sbUntap.toString());
AllZone.Stack.add(fhUntap);
AllZone.Stack.addSimultaneousStackEntry(fhUntap);
// If any Finest Hours, queue up a new combat phase
for (int ix = 0; ix < AllZoneUtil.getPlayerCardsInPlay(phasingPlayer, "Finest Hour").size(); ix++) {
@@ -1878,7 +1879,7 @@ public class CombatUtil {
sbACom.append(c).append(" - (Exalted) ").append(phasingPlayer).append(" gets Extra Combat Phase.");
fhAddCombat.setStackDescription(sbACom.toString());
AllZone.Stack.add(fhAddCombat);
AllZone.Stack.addSimultaneousStackEntry(fhAddCombat);
}
}
@@ -1929,7 +1930,7 @@ public class CombatUtil {
sb4.append("put it onto the battlefield attached to that creature, then shuffles library.");
ability4.setStackDescription(sb4.toString());
AllZone.Stack.add(ability4);
AllZone.Stack.addSimultaneousStackEntry(ability4);
} // For
}
}

View File

@@ -573,6 +573,8 @@ public class ComputerUtil
}
if(!cost.isPaid())
throw new RuntimeException("ComputerUtil : payManaCost() cost was not paid for " + sa.getSourceCard().getName());
}//payManaCost()

View File

@@ -47,8 +47,9 @@ public class EndOfTurn implements java.io.Serializable
StringBuilder sb = new StringBuilder();
sb.append("Sacrifice ").append(card);
sac.setStackDescription(sb.toString());
AllZone.Stack.add(sac);
AllZone.Stack.addSimultaneousStackEntry(sac);
}
if(!c.isFaceDown() && c.getKeyword().contains("At the beginning of the end step, exile CARDNAME.")) {
final Card card = c;
@@ -61,8 +62,9 @@ public class EndOfTurn implements java.io.Serializable
StringBuilder sb = new StringBuilder();
sb.append("Exile ").append(card);
exile.setStackDescription(sb.toString());
AllZone.Stack.add(exile);
AllZone.Stack.addSimultaneousStackEntry(exile);
}
if(!c.isFaceDown() && c.getKeyword().contains("At the beginning of the end step, destroy CARDNAME.")) {
final Card card = c;
@@ -75,8 +77,9 @@ public class EndOfTurn implements java.io.Serializable
StringBuilder sb = new StringBuilder();
sb.append("Destroy ").append(card);
destroy.setStackDescription(sb.toString());
AllZone.Stack.add(destroy);
AllZone.Stack.addSimultaneousStackEntry(destroy);
}
//Berserk is using this, so don't check isFaceDown()
if(c.getKeyword().contains("At the beginning of the next end step, destroy CARDNAME if it attacked this turn.")) {
@@ -91,8 +94,9 @@ public class EndOfTurn implements java.io.Serializable
StringBuilder sb = new StringBuilder();
sb.append("Sacrifice ").append(card);
sac.setStackDescription(sb.toString());
AllZone.Stack.add(sac);
AllZone.Stack.addSimultaneousStackEntry(sac);
}
else {
c.removeExtrinsicKeyword("At the beginning of the next end step, destroy CARDNAME if it attacked this turn.");
@@ -113,8 +117,9 @@ public class EndOfTurn implements java.io.Serializable
StringBuilder sb = new StringBuilder();
sb.append(vale.getName()).append(" changes controllers.");
change.setStackDescription(sb.toString());
AllZone.Stack.add(change);
AllZone.Stack.addSimultaneousStackEntry(change);
}
if(c.getName().equals("Erg Raiders") && !c.getCreatureAttackedThisTurn() &&
!(c.getTurnInZone() == AllZone.Phase.getTurn()) && AllZone.Phase.isPlayerTurn(c.getController())) {
@@ -130,8 +135,9 @@ public class EndOfTurn implements java.io.Serializable
StringBuilder sb = new StringBuilder();
sb.append(raider.getName()).append(" deals 2 damage to controller.");
change.setStackDescription(sb.toString());
AllZone.Stack.add(change);
AllZone.Stack.addSimultaneousStackEntry(change);
}
if(c.hasKeyword("At the beginning of your end step, sacrifice this creature unless it attacked this turn.")
&& !c.getCreatureAttackedThisTurn()
@@ -149,13 +155,18 @@ public class EndOfTurn implements java.io.Serializable
StringBuilder sb = new StringBuilder();
sb.append(source.getName()).append(" - sacrifice ").append(source.getName()).append(".");
change.setStackDescription(sb.toString());
AllZone.Stack.add(change);
AllZone.Stack.addSimultaneousStackEntry(change);
}
}
execute(at);
CardList all2 = AllZoneUtil.getCardsInPlay();
for(Card c:all2) {
if(c.getCreatureAttackedThisTurn()) c.setCreatureAttackedThisTurn(false);

View File

@@ -100,6 +100,8 @@ public class GameAction {
runParams.put("Destination", zone.getZoneName());
AllZone.TriggerHandler.runTrigger("ChangesZone", runParams);
return c;
}
@@ -618,6 +620,8 @@ public class GameAction {
HashMap<String,Object> runParams = new HashMap<String,Object>();
runParams.put("Card", c);
AllZone.TriggerHandler.runTrigger("Sacrificed", runParams);
}
public void destroyNoRegeneration(Card c) {
@@ -2142,7 +2146,9 @@ public class GameAction {
GameActionUtil.executeVampiricEffects(crd);
}
}
this.sacrificeDestroy(c);
return true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -16,10 +16,13 @@ import forge.card.spellability.Ability_Triggered;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Spell_Permanent;
import forge.card.spellability.Target;
import forge.gui.GuiUtils;
import forge.gui.input.Input;
import forge.gui.input.Input_PayManaCost_Ability;
public class MagicStack extends MyObservable {
private ArrayList<SpellAbility> simultaneousStackEntryList = new ArrayList<SpellAbility>();
private ArrayList<SpellAbility> stack = new ArrayList<SpellAbility>();
private ArrayList<SpellAbility> frozenStack = new ArrayList<SpellAbility>();
private boolean frozen = false;
@@ -422,6 +425,7 @@ public class MagicStack extends MyObservable {
runParams.put("Card", sp.getSourceCard());
AllZone.TriggerHandler.runTrigger("Cycled", runParams);
}
}
if(sp instanceof Spell_Permanent && sp.getSourceCard().getName().equals("Mana Vortex")) {
@@ -851,4 +855,91 @@ public class MagicStack extends MyObservable {
return ComputerCreatureSpellCount;
}
public void addSimultaneousStackEntry(SpellAbility sa)
{
simultaneousStackEntryList.add(sa);
/*
*Debug output.
System.out.println("STO add! Size:" + simultaneousStackEntryList.size());
*/
}
public void chooseOrderOfSimultaneousStackEntryAll()
{
/*
*Debug output.
if(simultaneousStackEntryList.size() > 0)
{
System.out.println("STO run! Size:" + simultaneousStackEntryList.size());
}
*/
chooseOrderOfSimultaneousStackEntry(AllZone.Phase.getPlayerTurn());
chooseOrderOfSimultaneousStackEntry(AllZone.Phase.getPlayerTurn().getOpponent());
}
public void chooseOrderOfSimultaneousStackEntry(Player activePlayer)
{
if(simultaneousStackEntryList.size() == 0)
return;
ArrayList<SpellAbility> activePlayerSAs = new ArrayList<SpellAbility>();
for(int i=0;i<simultaneousStackEntryList.size();i++)
{
if(simultaneousStackEntryList.get(i).getActivatingPlayer() == null)
{
if(simultaneousStackEntryList.get(i).getSourceCard().getController().equals(activePlayer))
{
activePlayerSAs.add(simultaneousStackEntryList.get(i));
simultaneousStackEntryList.remove(i);
i--;
}
}
else
{
if(simultaneousStackEntryList.get(i).getActivatingPlayer().equals(activePlayer))
{
activePlayerSAs.add(simultaneousStackEntryList.get(i));
simultaneousStackEntryList.remove(i);
i--;
}
}
}
if(activePlayerSAs.size() == 0)
return;
if(activePlayer.isComputer())
{
for(SpellAbility sa : activePlayerSAs)
{
sa.doTrigger(sa.isMandatory());
ComputerUtil.playStack(sa);
}
}
else
{
while(activePlayerSAs.size() > 1)
{
SpellAbility next = (SpellAbility) GuiUtils.getChoice("Choose which spell or ability to put on the stack next.", activePlayerSAs.toArray());
activePlayerSAs.remove(next);
if(next.isTrigger())
{
System.out.println("Stack order: AllZone.GameAction.playSpellAbility(next)");
AllZone.GameAction.playSpellAbility(next);
}
else
{
System.out.println("Stack order: AllZone.Stack.add(next)");
add(next);
}
}
if(activePlayerSAs.get(0).isTrigger())
AllZone.GameAction.playSpellAbility(activePlayerSAs.get(0));
else
add(activePlayerSAs.get(0));
//AllZone.GameAction.playSpellAbility(activePlayerSAs.get(0));
}
}
}

View File

@@ -293,6 +293,8 @@ public class Phase extends MyObservable
AllZone.TriggerHandler.runTrigger("Phase", runParams);
}
//This line fixes Combat Damage triggers not going off when they should
AllZone.Stack.unfreezeStack();
@@ -377,6 +379,8 @@ public class Phase extends MyObservable
AllZone.Phase.setNeedToNextPhase(false);
AllZone.Phase.nextPhase();
}
AllZone.Stack.chooseOrderOfSimultaneousStackEntryAll();
}
private Player handleNextTurn() {
@@ -513,6 +517,7 @@ public class Phase extends MyObservable
// pass the priority to other player
setPriorityPlayer(actingPlayer.getOpponent());
AllZone.InputControl.resetInput();
AllZone.Stack.chooseOrderOfSimultaneousStackEntryAll();
}
else{
if (AllZone.Stack.size() == 0){
@@ -523,6 +528,7 @@ public class Phase extends MyObservable
else{
AllZone.Stack.resolveStack();
}
AllZone.Stack.chooseOrderOfSimultaneousStackEntryAll();
}
}

View File

@@ -158,8 +158,9 @@ public class PlayerZone_ComesIntoPlay extends DefaultPlayerZone {
sb.append(source).append(" - tap all lands ");
sb.append(tisLand.getController()).append(" controls.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
CardList les = AllZoneUtil.getPlayerCardsInPlay(c.getOwner().getOpponent(), "Land Equilibrium");
@@ -181,7 +182,8 @@ public class PlayerZone_ComesIntoPlay extends DefaultPlayerZone {
CardList oLands = AllZoneUtil.getPlayerLandsInPlay(lesLand.getOwner().getOpponent());
//(pLands - 1) because this land is in play, and the ability is before it is in play
if(oLands.size() <= (pLands.size() - 1)) {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}
@@ -238,10 +240,13 @@ public class PlayerZone_ComesIntoPlay extends DefaultPlayerZone {
sb.append("return Sword of the Meek from your graveyard to the battlefield, then attach it to that creature.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}
/*
for (String effect : AllZone.StateBasedEffects.getStateBasedMap().keySet() ) {
Command com = GameActionUtil.commands.get(effect);
@@ -313,6 +318,8 @@ public class PlayerZone_ComesIntoPlay extends DefaultPlayerZone {
Command com = GameActionUtil.commands.get(effect);
com.execute();
}
}
public void setTrigger(boolean b) {

View File

@@ -341,7 +341,7 @@ public class AbilityFactory_GainControl {
if(bNoRegen) sb.append(" It can't be regenerated.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};

View File

@@ -557,7 +557,8 @@ public class CardFactory implements NewConstants {
sb.append(card.getController()).append(" loses "+num+" life");
etbLoseLifeAbility.setStackDescription(sb.toString());
AllZone.Stack.add(etbLoseLifeAbility);
AllZone.Stack.addSimultaneousStackEntry(etbLoseLifeAbility);
}
};
card.addComesIntoPlayCommand(etbLoseLife);
@@ -865,7 +866,8 @@ public class CardFactory implements NewConstants {
}
numCreatures[0] = count;
}
AllZone.Stack.add(devour);
AllZone.Stack.addSimultaneousStackEntry(devour);
}
};
@@ -924,7 +926,8 @@ public class CardFactory implements NewConstants {
if (ability.getTargetCard() != null){
ability.setStackDescription("Put " + card.getCounters(Counters.P1P1)
+ " +1/+1 counter/s from " + card + " on " + ability.getTargetCard());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}
}
@@ -1126,7 +1129,8 @@ public class CardFactory implements NewConstants {
sb.append("When ").append(card.getName()).append(" enters the battlefield, choose a creature type.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(intoPlay);
@@ -1210,7 +1214,9 @@ public class CardFactory implements NewConstants {
public void execute() {
ability.setStackDescription("As Sarpadian Empires, Vol. VII enters the battlefield, choose white Citizen, blue Camarid, black Thrull, red Goblin, or green Saproling.");
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.setText("As Sarpadian Empires, Vol. VII enters the battlefield, choose white Citizen, blue Camarid, black Thrull, red Goblin, or green Saproling.\r\n"
@@ -1273,8 +1279,9 @@ public class CardFactory implements NewConstants {
StringBuilder sb = new StringBuilder();
sb.append(card.getName()).append(" - returning creature to the battlefield");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//execute()
};//Command
@@ -1385,7 +1392,9 @@ public class CardFactory implements NewConstants {
Card c = (Card)o;
necrogen.setTargetCard(c);
once = true;
AllZone.Stack.add(necrogen);
AllZone.Stack.addSimultaneousStackEntry(necrogen);
}
}
stop();
@@ -1474,7 +1483,9 @@ public class CardFactory implements NewConstants {
AllZone.GameAction.exile(c);
AllZone.GameAction.exile(c2);
once = true;
AllZone.Stack.add(nightSoil);
AllZone.Stack.addSimultaneousStackEntry(nightSoil);
}
}
}
@@ -1811,7 +1822,8 @@ public class CardFactory implements NewConstants {
public void execute() {
ability.setStackDescription("If Mox Diamond would enter the battlefield, you may discard a land card instead. If you do, put Mox Diamond onto the battlefield. If you don't, put it into its owner's graveyard.");
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
SpellAbility spell = new Spell_Permanent(card) {
@@ -2151,8 +2163,9 @@ public class CardFactory implements NewConstants {
sb.append("Imprint - ").append(card.getController());
sb.append(" may exile an instant card with converted mana cost 2 or less from their hand.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
@@ -2458,7 +2471,8 @@ public class CardFactory implements NewConstants {
private static final long serialVersionUID = -6417019967914398902L;
public void execute() {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};//Command
@@ -2546,8 +2560,9 @@ public class CardFactory implements NewConstants {
StringBuilder sb = new StringBuilder();
sb.append(card.getName()).append(" - choose a creature type. Creatures of that type do not untap during their controller's untap step.");
comesIntoPlayAbility.setStackDescription(sb.toString());
AllZone.Stack.add(comesIntoPlayAbility);
AllZone.Stack.addSimultaneousStackEntry(comesIntoPlayAbility);
}
};
@@ -2810,7 +2825,8 @@ public class CardFactory implements NewConstants {
private static final long serialVersionUID = 2266471224097876143L;
public void execute() {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
@@ -2879,8 +2895,9 @@ public class CardFactory implements NewConstants {
StringBuilder sb = new StringBuilder();
sb.append("As ").append(card.getName()).append(" enters the battlefield, pay any amount of life.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(intoPlay);
@@ -3147,8 +3164,9 @@ public class CardFactory implements NewConstants {
sb.append("exile all creatures you control. ");
sb.append("Then put that many 5/5 red Dragon creature tokens with flying onto the battlefield.");
exileAll.setStackDescription(sb.toString());
AllZone.Stack.add(exileAll);
AllZone.Stack.addSimultaneousStackEntry(exileAll);
}
};
@@ -3176,8 +3194,9 @@ public class CardFactory implements NewConstants {
sb.append("sacrifice all Dragons you control. ");
sb.append("Then return the exiled cards to the battlefield under your control.");
returnAll.setStackDescription(sb.toString());
AllZone.Stack.add(returnAll);
AllZone.Stack.addSimultaneousStackEntry(returnAll);
}
};
@@ -3205,8 +3224,9 @@ public class CardFactory implements NewConstants {
sb.append(cardName).append(" - ").append(card.getController());
sb.append(" loses life equal to his or her life total.");
loseAllLife.setStackDescription(sb.toString());
AllZone.Stack.add(loseAllLife);
AllZone.Stack.addSimultaneousStackEntry(loseAllLife);
}
};
@@ -3226,8 +3246,9 @@ public class CardFactory implements NewConstants {
sb.append(cardName).append(" - ").append(card.getController());
sb.append("loses the game.");
loseGame.setStackDescription(sb.toString());
AllZone.Stack.add(loseGame);
AllZone.Stack.addSimultaneousStackEntry(loseGame);
}
};

View File

@@ -1431,7 +1431,7 @@ public class CardFactoryUtil {
Object o = GuiUtils.getChoiceOptional("Select a card", sameType.toArray());
if(o != null) {
//ability.setTargetCard((Card)o);
//AllZone.Stack.add(ability);
sourceCard.getController().discard(sourceCard, this);
Card c1 = (Card) o;
AllZone.GameAction.moveToHand(c1);
@@ -1505,7 +1505,7 @@ public class CardFactoryUtil {
Object o = GuiUtils.getChoiceOptional("Select a card", sameCost.toArray());
if(o != null) {
//ability.setTargetCard((Card)o);
//AllZone.Stack.add(ability);
sourceCard.getController().discard(sourceCard, this);
Card c1 = (Card) o;
@@ -4417,7 +4417,9 @@ public class CardFactoryUtil {
}
};
ability.setStackDescription("Fastbond - Deals 1 damage to you.");
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}
@@ -4430,7 +4432,9 @@ public class CardFactoryUtil {
}
};
ability.setStackDescription(city.getName()+" - sacrifice "+city.getName());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}

View File

@@ -1521,7 +1521,8 @@ class CardFactory_Auras {
private static final long serialVersionUID = 3595188622377350327L;
public void execute() {
AllZone.Stack.add(attach);
AllZone.Stack.addSimultaneousStackEntry(attach);
}
};
@@ -1548,7 +1549,8 @@ class CardFactory_Auras {
PlayerZone play = AllZone.getZone(Constant.Zone.Battlefield, card.getController());
if(AllZone.GameAction.isCardInZone(c, play))
AllZone.Stack.add(detach);
AllZone.Stack.addSimultaneousStackEntry(detach);
}
};
// Do not remove SpellAbilities created by AbilityFactory or Keywords.
@@ -2242,7 +2244,9 @@ class CardFactory_Auras {
StringBuilder sb = new StringBuilder();
sb.append(card.getController()).append(" untaps up to 5 lands.");
untapAbility.setStackDescription(sb.toString());
AllZone.Stack.add(untapAbility);
AllZone.Stack.addSimultaneousStackEntry(untapAbility);
}
};
if (optionUnTapLands) {

View File

@@ -189,7 +189,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = 8485080996453793968L;
public void execute() {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};//Command
ability.setStackDescription("Caller of the Claw - Put a 2/2 green Bear creature token onto the battlefield for each nontoken creature put into your graveyard from play this turn.");
@@ -456,7 +457,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = 2856638426932227407L;
public void execute() {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
@@ -507,8 +509,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card.getName()).append(" - choose: 3/3, 2/2 flying, 1/6 defender");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(intoPlay);
@@ -529,8 +532,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card.getName()).append(" - ").append(card.getOwner()).append(" creatures have Trample.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addDestroyCommand(destroy);
@@ -552,8 +556,9 @@ public class CardFactory_Creatures {
sb.append(card.getName()).append(" - ").append(card.getOwner());
sb.append(" creatures have Swampwalk.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addDestroyCommand(destroy);
@@ -688,8 +693,9 @@ public class CardFactory_Creatures {
sb.append(card.getName()).append(" - ").append(card.getOwner());
sb.append(" creatures have Haste.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addDestroyCommand(destroy);
@@ -711,8 +717,9 @@ public class CardFactory_Creatures {
sb.append(card.getName()).append(" - ").append(card.getOwner());
sb.append(" creatures have First Strike.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addDestroyCommand(destroy);
@@ -734,8 +741,9 @@ public class CardFactory_Creatures {
sb.append(card.getName()).append(" - ").append(card.getOwner());
sb.append(" creatures have Flying.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addDestroyCommand(destroy);
@@ -828,8 +836,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card.getController()).append(" sacrifices Drekavac unless he discards a noncreature card");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
@@ -902,8 +911,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card.getController()).append(" - discards at random or sacrifices ").append(cardName);
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(intoPlay);
@@ -980,7 +990,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = 4757054648163014149L;
public void execute() {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
StringBuilder sb = new StringBuilder();
@@ -1007,8 +1018,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = -3934471871041458847L;
public void execute() {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//execute()
};
card.addComesIntoPlayCommand(intoPlay);
@@ -1091,7 +1102,8 @@ public class CardFactory_Creatures {
if(o != null)//should never happen, but just in case
{
ability.setTargetCard((Card) o);
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}//else
}//execute()
@@ -1165,8 +1177,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card.getController()).append(" untaps up to 5 lands.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(intoPlay);
@@ -1227,8 +1240,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card.getController()).append(" untaps up to 7 lands.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(intoPlay);
@@ -1289,8 +1303,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card.getController()).append(" untaps up to 7 lands.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(intoPlay);
@@ -1371,8 +1386,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card.getController()).append(" untaps up to 2 lands.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(intoPlay);
@@ -1407,8 +1423,9 @@ public class CardFactory_Creatures {
sb.append(card.getController());
sb.append(" shuffles the cards from his hand into his library, then draws that many cards.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability );
}
};
card.addComesIntoPlayCommand(intoPlay);
@@ -1438,8 +1455,9 @@ public class CardFactory_Creatures {
sb.append(card.getController().getOpponent());
sb.append(" gains control of all other permanents you control");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(intoPlay);
@@ -1512,7 +1530,8 @@ public class CardFactory_Creatures {
if(computer.size() != 0) {
target = computer.get(0);
abilityComes.setTargetCard(target);
AllZone.Stack.add(abilityComes);
AllZone.Stack.addSimultaneousStackEntry(abilityComes);
}
else
AllZone.GameAction.sacrifice(card);
@@ -1545,8 +1564,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card.getName()).append(" - returning creature to the battlefield");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//execute()
};//Command
@@ -1663,7 +1683,8 @@ public class CardFactory_Creatures {
//computer chooses target in Command destroy
if(con.equals(AllZone.ComputerPlayer)) ability.setTargetPlayer(AllZone.HumanPlayer);
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//execute()
};
card.addDestroyCommand(destroy);
@@ -1707,8 +1728,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card).append(" - ").append(opponent).append(" discards cards");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//execute()
};
card.addDestroyCommand(destroy);
@@ -1753,8 +1775,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card).append(" - ").append(card.getController()).append(" draws cards");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//execute()
};
@@ -1799,8 +1822,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card).append(" - ").append(card.getController()).append(" gains life");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//execute()
};
@@ -1846,8 +1870,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card).append(" - ").append(card.getController()).append(" puts tokens onto the battlefield");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//execute()
};
card.addDestroyCommand(destroy);
@@ -2447,7 +2472,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = -2433442359225521472L;
public void execute() {
AllZone.Stack.add(new Ability(card, "0", "Adarkar Valkyrie - Return " + target[0] + " from graveyard to the battlefield") {
AllZone.Stack.addSimultaneousStackEntry(new Ability(card, "0", "Adarkar Valkyrie - Return " + target[0] + " from graveyard to the battlefield") {
@Override
public void resolve() {
PlayerZone grave = AllZone.getZone(target[0]);
@@ -2887,7 +2913,8 @@ public class CardFactory_Creatures {
else if(ability.canPlayAI()) {
ability.chooseTargetAI();
//need to add this to the stack
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}//execute()
@@ -3078,7 +3105,8 @@ public class CardFactory_Creatures {
public void execute() {
AllZone.GameAction.sacrifice(card);
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}));
}//*************** END ************ END **************************
@@ -3155,7 +3183,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = 6667896040611028600L;
public void execute() {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
});
@@ -3399,7 +3428,8 @@ public class CardFactory_Creatures {
sb.append("Mystic Snake counters ").append(AllZone.Stack.peek().getSourceCard().getName());
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}
};
@@ -4383,9 +4413,11 @@ public class CardFactory_Creatures {
if (card.getName().equals("Lost Auramancers")
&& card.getCounters(Counters.TIME) <= 0) {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
} else if (card.getName().equals("Academy Rector")) {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}// execute()
@@ -4459,7 +4491,8 @@ public class CardFactory_Creatures {
ButtonUtil.disableAll();
} else if(card.getController().equals(AllZone.ComputerPlayer)) {
ability.setTargetPlayer(AllZone.HumanPlayer);
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}//execute()
};//Command
@@ -4556,7 +4589,8 @@ public class CardFactory_Creatures {
else //computer
{
abilityComes.setTargetPlayer(AllZone.HumanPlayer);
AllZone.Stack.add(abilityComes);
AllZone.Stack.addSimultaneousStackEntry(abilityComes);
}//else
}//execute()
};//CommandComes
@@ -4578,8 +4612,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append("Laquatus's Champion - ").append(abilityComes.getTargetPlayer()).append(" regains 6 life.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//execute()
};//Command
@@ -4641,7 +4676,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = 8485080996453793968L;
public void execute() {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};//Command
ability.setStackDescription("As Meddling Mage enters the battlefield, name a nonland card.");
@@ -4810,7 +4846,8 @@ public class CardFactory_Creatures {
}
};
ability.setStackDescription(toString() + " - you may put a token that's a copy of " + getName() + " onto the battlefield.");
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
for(Entry<Card, Integer> entry : m.entrySet()) {
this.addDamage(entry.getValue(), entry.getKey());
@@ -4904,7 +4941,8 @@ public class CardFactory_Creatures {
public void execute() {
ability.setStackDescription("Singe-Mind Ogre - target player reveals a card at random from " +
"his or her hand, then loses life equal to that card's converted mana cost.");
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(intoPlay);
@@ -4987,7 +5025,8 @@ public class CardFactory_Creatures {
public void execute() {
ability.setStackDescription("Kinsbaile Borderguard enters the battlefield with a +1/+1 counter on it for each other Kithkin you control.");
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
@@ -5011,7 +5050,8 @@ public class CardFactory_Creatures {
public void execute() {
ability2.setStackDescription("When Kinsbaile Borderguard is put into a graveyard from play, put a 1/1 white " +
"Kithkin Soldier creature token onto the battlefield for each counter on it.");
AllZone.Stack.add(ability2);
AllZone.Stack.addSimultaneousStackEntry(ability2);
}
};
@@ -5038,8 +5078,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card.getName()).append(" - gain 2 life for each age counter on it.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};//command
@@ -5093,7 +5134,8 @@ public class CardFactory_Creatures {
public void execute() {
if(card.isKicked()) {
ability.setStackDescription("Kavu Titan gets 3 +1/+1 counters and gains trample.");
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}//execute()
};//CommandComes
@@ -5161,7 +5203,8 @@ public class CardFactory_Creatures {
else //computer
{
ability.setStackDescription("Gatekeeper of Malakir - targeting Human");
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//else
}
}//execute()
@@ -5192,7 +5235,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = 4245563898487609274L;
public void execute() {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(comesIntoPlay);
@@ -5232,7 +5276,8 @@ public class CardFactory_Creatures {
sb.append(card.getName()).append(" - Add 2 Level counters to each creature you control with Level up.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
card.addComesIntoPlayCommand(addLevelCounters);
@@ -5295,8 +5340,9 @@ public class CardFactory_Creatures {
StringBuilder sb = new StringBuilder();
sb.append(card.getName()).append(" - chosen type gets +2/+2 and Trample until EOT");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//execute
};//command
@@ -5326,7 +5372,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = -3734151854295L;
public void execute() {
AllZone.Stack.add(intoPlay);
AllZone.Stack.addSimultaneousStackEntry(intoPlay);
}
};
@@ -5620,7 +5667,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = 931101364538995898L;
public void execute() {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
@@ -5802,7 +5850,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = -4300804642226899861L;
public void execute() {
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
};
@@ -6002,7 +6051,8 @@ public class CardFactory_Creatures {
else if(list.size() != 0) {
Card target = CardFactoryUtil.AI_getBestCreature(list);
ability.setTargetCard(target);
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}
}//execute()
};
@@ -6082,7 +6132,8 @@ public class CardFactory_Creatures {
public void execute() {
sacOrSac.setStackDescription("When "+cardName+" enters the battlefield, sacrifice it unless you sacrifice any number of creatures with total power 12 or greater.");
AllZone.Stack.add(sacOrSac);
AllZone.Stack.addSimultaneousStackEntry(sacOrSac);
}
};
@@ -6119,7 +6170,8 @@ public class CardFactory_Creatures {
//Slight hack if the cloner copies a card with triggers
AllZone.TriggerHandler.removeAllFromCard(cloned[0]);
AllZone.Stack.add(copyBack);
AllZone.Stack.addSimultaneousStackEntry(copyBack);
}
};
@@ -6274,7 +6326,8 @@ public class CardFactory_Creatures {
private static final long serialVersionUID = 911163814565333484L;
public void execute() {
AllZone.Stack.add(toPlay);
AllZone.Stack.addSimultaneousStackEntry(toPlay);
}
};

View File

@@ -244,7 +244,8 @@ class CardFactory_Lands {
if(card.getController() == AllZone.HumanPlayer) {
AllZone.InputControl.setInput(CardFactoryUtil.input_targetSpecific(a[0], creats, "Select target creature you control", false, false));
} else {
AllZone.Stack.add(a[0]);
AllZone.Stack.addSimultaneousStackEntry(a[0]);
}
}
};

View File

@@ -111,7 +111,7 @@ abstract public class Ability_Mana extends Ability_Activated implements java.io.
if (source.getName().equals("Forbidden Orchard")) {
this.undoable = false;
AllZone.Stack.add(CardFactoryUtil.getForbiddenOrchardAbility(source, getActivatingPlayer().getOpponent()));
AllZone.Stack.addSimultaneousStackEntry(CardFactoryUtil.getForbiddenOrchardAbility(source, getActivatingPlayer().getOpponent()));
}
if(source.getType().contains("Mountain") && AllZoneUtil.isCardInPlay("Gauntlet of Might")) {
@@ -167,6 +167,8 @@ abstract public class Ability_Mana extends Ability_Activated implements java.io.
runParams.put("Ability_Mana", this);
runParams.put("Produced", produced);
AllZone.TriggerHandler.runTrigger("TapsForMana", runParams);
}//end produceMana(String)

View File

@@ -40,6 +40,7 @@ public abstract class SpellAbility {
private boolean spell;
private boolean trigger = false;
private boolean mandatory = false;
private boolean tapAbility;
private boolean untapAbility;
@@ -102,7 +103,7 @@ public abstract class SpellAbility {
public boolean canPlayAI() {
return true;
}
// This should be overridden by ALL AFs
public boolean doTrigger(boolean mandatory){
return false;
@@ -387,6 +388,8 @@ public abstract class SpellAbility {
public void setStackDescription(String s) {
stackDescription = s;
if(description == "")
description = s;
}
public String getStackDescription() {
@@ -432,6 +435,7 @@ public abstract class SpellAbility {
while(node != null){
if (node != this)
sb.append(" ");
sb.append(node.getDescription().replace("CARDNAME", node.getSourceCard().getName()));
node = node.getSubAbility();
@@ -589,4 +593,12 @@ public abstract class SpellAbility {
public boolean isTrigger() {
return trigger;
}
public void setMandatory(boolean mand) {
this.mandatory = mand;
}
public boolean isMandatory() {
return mandatory;
}
}

View File

@@ -79,7 +79,7 @@ public class Spell_Permanent extends Spell {
if(computer.size() != 0) {
target = computer.get(0);
championAbilityComes.setTargetCard(target);
AllZone.Stack.add(championAbilityComes);
AllZone.Stack.addSimultaneousStackEntry(championAbilityComes);
if(getSourceCard().getName().equals("Mistbind Clique")) {
//TODO this needs to target
CardList list = AllZoneUtil.getPlayerLandsInPlay(AllZone.HumanPlayer);
@@ -117,7 +117,7 @@ public class Spell_Permanent extends Spell {
sb.append(getSourceCard().getName()).append(" - returning card to battlefield.");
ability.setStackDescription(sb.toString());
AllZone.Stack.add(ability);
AllZone.Stack.addSimultaneousStackEntry(ability);
}//execute()
};//championCommandLeavesPlay

View File

@@ -283,7 +283,6 @@ public class TriggerHandler {
}
}
}
}
//Checks if the conditions are right for a single trigger to go off, and runs it if so.
@@ -948,7 +947,9 @@ public class TriggerHandler {
}
};
wrapperAbility.setTrigger(true);
wrapperAbility.setMandatory(isMandatory);
wrapperAbility.setDescription(wrapperAbility.getStackDescription());
/*
if(host.getController().isHuman())
{
AllZone.GameAction.playSpellAbility(wrapperAbility);
@@ -958,7 +959,8 @@ public class TriggerHandler {
wrapperAbility.doTrigger(isMandatory);
ComputerUtil.playStack(wrapperAbility);
}
*/
AllZone.Stack.addSimultaneousStackEntry(wrapperAbility);
return true;
}