From bf898ddefba9fcc8ca258bcfb346c62e0e447b9c Mon Sep 17 00:00:00 2001 From: Sol Date: Wed, 26 Dec 2012 04:31:43 +0000 Subject: [PATCH] - Added very basic AddPhase AF - Added support in PhaseHandler for Additional phases - Convert Finest Hour to AddPhase --- .gitattributes | 2 + res/cardsfolder/f/finest_hour.txt | 5 +- .../forge/card/abilityfactory/ApiType.java | 1 + .../card/abilityfactory/ai/AddPhaseAi.java | 18 +++++++ .../effects/AddPhaseEffect.java | 31 ++++++++++++ src/main/java/forge/card/trigger/Trigger.java | 14 ++++-- .../java/forge/game/phase/CombatUtil.java | 35 ------------- .../java/forge/game/phase/PhaseHandler.java | 50 +++++++++++-------- src/main/java/forge/game/phase/PhaseType.java | 2 +- 9 files changed, 98 insertions(+), 60 deletions(-) create mode 100644 src/main/java/forge/card/abilityfactory/ai/AddPhaseAi.java create mode 100644 src/main/java/forge/card/abilityfactory/effects/AddPhaseEffect.java diff --git a/.gitattributes b/.gitattributes index e02dde6f63c..e30ba00373c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -12918,6 +12918,7 @@ src/main/java/forge/card/abilityfactory/CommonDrawback.java svneol=native#text/p src/main/java/forge/card/abilityfactory/CommonSpell.java -text src/main/java/forge/card/abilityfactory/SpellAiLogic.java -text src/main/java/forge/card/abilityfactory/SpellEffect.java -text +src/main/java/forge/card/abilityfactory/ai/AddPhaseAi.java -text src/main/java/forge/card/abilityfactory/ai/AddTurnAi.java svneol=native#text/plain src/main/java/forge/card/abilityfactory/ai/AlwaysPlayAi.java -text src/main/java/forge/card/abilityfactory/ai/AnimateAi.java -text @@ -13013,6 +13014,7 @@ src/main/java/forge/card/abilityfactory/ai/UnattachAllAi.java -text src/main/java/forge/card/abilityfactory/ai/UntapAi.java -text src/main/java/forge/card/abilityfactory/ai/UntapAllAi.java -text src/main/java/forge/card/abilityfactory/effects/AbandonEffect.java -text +src/main/java/forge/card/abilityfactory/effects/AddPhaseEffect.java -text src/main/java/forge/card/abilityfactory/effects/AddTurnEffect.java -text src/main/java/forge/card/abilityfactory/effects/AnimateAllEffect.java -text src/main/java/forge/card/abilityfactory/effects/AnimateEffect.java -text diff --git a/res/cardsfolder/f/finest_hour.txt b/res/cardsfolder/f/finest_hour.txt index f7c1a5f5f9d..580fcd434d7 100644 --- a/res/cardsfolder/f/finest_hour.txt +++ b/res/cardsfolder/f/finest_hour.txt @@ -1,8 +1,11 @@ Name:Finest Hour ManaCost:2 G W U Types:Enchantment -Text:Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that creature. After this phase, there is an additional combat phase. +Text:no text K:Exalted +T:Mode$ Attacks | ValidCard$ Creature.YouCtrl | Alone$ True | TriggerZones$ Battlefield | Execute$ TrigUntap | FirstCombat$ True | TriggerDescription$ Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that creature. After this phase, there is an additional combat phase. +SVar:TrigUntap:DB$ Untap | Defined$ TriggeredAttacker | SubAbility$ DBAddCombat +SVar:DBAddCombat:DB$ AddPhase | ExtraPhase$ BeginCombat | AfterPhase$ EndCombat SVar:PlayMain1:TRUE SVar:Rarity:Rare SVar:Picture:http://www.wizards.com/global/images/magic/general/finest_hour.jpg diff --git a/src/main/java/forge/card/abilityfactory/ApiType.java b/src/main/java/forge/card/abilityfactory/ApiType.java index 37ff2b0ffc5..b97a6b31480 100644 --- a/src/main/java/forge/card/abilityfactory/ApiType.java +++ b/src/main/java/forge/card/abilityfactory/ApiType.java @@ -11,6 +11,7 @@ import forge.card.abilityfactory.effects.*; public enum ApiType { Abandon (AbandonEffect.class, AlwaysPlayAi.class), + AddPhase (AddPhaseEffect.class, AddPhaseAi.class), AddTurn (AddTurnEffect.class, AddTurnAi.class), Animate (AnimateEffect.class, AnimateAi.class), AnimateAll (AnimateAllEffect.class, AnimateAllAi.class), diff --git a/src/main/java/forge/card/abilityfactory/ai/AddPhaseAi.java b/src/main/java/forge/card/abilityfactory/ai/AddPhaseAi.java new file mode 100644 index 00000000000..f9b7ac135c4 --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/ai/AddPhaseAi.java @@ -0,0 +1,18 @@ +package forge.card.abilityfactory.ai; + +import forge.card.abilityfactory.SpellAiLogic; +import forge.card.spellability.SpellAbility; +import forge.game.player.Player; + +/** + * TODO: Write javadoc for this type. + * + */ +public class AddPhaseAi extends SpellAiLogic { + + @Override + protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) { + return false; + } + +} diff --git a/src/main/java/forge/card/abilityfactory/effects/AddPhaseEffect.java b/src/main/java/forge/card/abilityfactory/effects/AddPhaseEffect.java new file mode 100644 index 00000000000..1254908cf86 --- /dev/null +++ b/src/main/java/forge/card/abilityfactory/effects/AddPhaseEffect.java @@ -0,0 +1,31 @@ +package forge.card.abilityfactory.effects; + +import forge.Singletons; +import forge.card.abilityfactory.SpellEffect; +import forge.card.spellability.SpellAbility; +import forge.game.phase.PhaseHandler; +import forge.game.phase.PhaseType; + +/** + * TODO: Write javadoc for this type. + * + */ +public class AddPhaseEffect extends SpellEffect { + + @Override + public void resolve(SpellAbility sa) { + PhaseHandler phaseHandler = Singletons.getModel().getGame().getPhaseHandler(); + PhaseType extra = PhaseType.smartValueOf(sa.getParam("ExtraPhase")); + + PhaseType after; + if (sa.hasParam("AfterPhase")) { + after = PhaseType.smartValueOf(sa.getParam("AfterPhase")); + } + else { + after = phaseHandler.getPhase(); + } + + phaseHandler.addExtraPhase(after, extra); + } + +} diff --git a/src/main/java/forge/card/trigger/Trigger.java b/src/main/java/forge/card/trigger/Trigger.java index 1c17a1cc74f..f9fde62a424 100644 --- a/src/main/java/forge/card/trigger/Trigger.java +++ b/src/main/java/forge/card/trigger/Trigger.java @@ -32,6 +32,7 @@ import forge.card.abilityfactory.AbilityFactory; import forge.card.cardfactory.CardFactoryUtil; import forge.card.spellability.Ability; import forge.card.spellability.SpellAbility; +import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.zone.ZoneType; import forge.util.Expressions; @@ -227,20 +228,27 @@ public abstract class Trigger extends TriggerReplacementBase { * @return a boolean. */ public final boolean phasesCheck() { + PhaseHandler phaseHandler = Singletons.getModel().getGame().getPhaseHandler(); if (null != validPhases) { - if (!validPhases.contains(Singletons.getModel().getGame().getPhaseHandler().getPhase())) { + if (!validPhases.contains(phaseHandler.getPhase())) { return false; } } if (this.getMapParams().containsKey("PlayerTurn")) { - if (!Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(this.getHostCard().getController())) { + if (!phaseHandler.isPlayerTurn(this.getHostCard().getController())) { return false; } } if (this.getMapParams().containsKey("OpponentTurn")) { - if (Singletons.getModel().getGame().getPhaseHandler().isPlayerTurn(this.getHostCard().getController())) { + if (phaseHandler.isPlayerTurn(this.getHostCard().getController())) { + return false; + } + } + + if (this.getMapParams().containsKey("FirstCombat")) { + if (!phaseHandler.isFirstCombat()) { return false; } } diff --git a/src/main/java/forge/game/phase/CombatUtil.java b/src/main/java/forge/game/phase/CombatUtil.java index b388dee7601..078bb673e38 100644 --- a/src/main/java/forge/game/phase/CombatUtil.java +++ b/src/main/java/forge/game/phase/CombatUtil.java @@ -3092,41 +3092,6 @@ public class CombatUtil { } final Player phasingPlayer = c.getController(); - // Finest Hour untaps the creature on the first combat phase - if ((phasingPlayer.getCardsIn(ZoneType.Battlefield, "Finest Hour").size() > 0) - && Singletons.getModel().getGame().getPhaseHandler().isFirstCombat()) { - // Untap the attacking creature - final Ability fhUntap = new Ability(c, "0") { - @Override - public void resolve() { - crd.untap(); - } - }; - - final StringBuilder sbUntap = new StringBuilder(); - sbUntap.append(c).append(" - (Finest Hour) untap."); - fhUntap.setDescription(sbUntap.toString()); - fhUntap.setStackDescription(sbUntap.toString()); - - Singletons.getModel().getGame().getStack().addSimultaneousStackEntry(fhUntap); - - // If any Finest Hours, queue up a new combat phase - for (int ix = 0; ix < phasingPlayer.getCardsIn(ZoneType.Battlefield, "Finest Hour").size(); ix++) { - final Ability fhAddCombat = new Ability(c, "0") { - @Override - public void resolve() { - Singletons.getModel().getGame().getPhaseHandler().addExtraCombat(); - } - }; - - final StringBuilder sbACom = new StringBuilder(); - sbACom.append(c).append(" - (Finest Hour) ").append(phasingPlayer).append(" gets Extra Combat Phase."); - fhAddCombat.setDescription(sbACom.toString()); - fhAddCombat.setStackDescription(sbACom.toString()); - - Singletons.getModel().getGame().getStack().addSimultaneousStackEntry(fhAddCombat); - } - } if (phasingPlayer.getCardsIn(ZoneType.Battlefield, "Sovereigns of Lost Alara").size() > 0) { for (int i = 0; i < phasingPlayer.getCardsIn(ZoneType.Battlefield, "Sovereigns of Lost Alara").size(); i++) { diff --git a/src/main/java/forge/game/phase/PhaseHandler.java b/src/main/java/forge/game/phase/PhaseHandler.java index 06c940f8677..8d6ca1fe19b 100644 --- a/src/main/java/forge/game/phase/PhaseHandler.java +++ b/src/main/java/forge/game/phase/PhaseHandler.java @@ -19,6 +19,7 @@ package forge.game.phase; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Stack; import com.esotericsoftware.minlog.Log; @@ -59,8 +60,7 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable { // Start turn at 0, so first untap step will turn it to 1 private final transient Stack extraTurns = new Stack(); - - private int extraCombats = 0; + private final transient Map> extraPhases = new HashMap>(); private int nCombatsThisTurn = 0; private boolean bPreventCombatDamageThisTurn = false; @@ -465,17 +465,6 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable { this.resetAttackedThisCombat(this.getPlayerTurn()); this.bCombat = false; - // TODO: ExtraCombat needs to be changed for other spell/abilities - // that give extra combat can do it like ExtraTurn stack ExtraPhases - if (this.extraCombats > 0) { - final Player player = this.getPlayerTurn(); - - this.bCombat = true; - this.extraCombats--; - game.getCombat().reset(); - game.getCombat().setAttackingPlayer(player); - this.phase = PhaseType.COMBAT_BEGIN; - } break; case CLEANUP: @@ -489,13 +478,29 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable { default: // no action } + StringBuilder sb = new StringBuilder(); if (this.bRepeat) { // for when Cleanup needs to repeat itself this.bRepeat = false; + sb.append("Repeat Phase"); } else { - this.phase = phase.getNextPhase(); + // If the phase that's ending has a stack of additional phases + // Take the LIFO one and move to that instead of the normal one + if (this.extraPhases.containsKey(phase)) { + PhaseType nextPhase = this.extraPhases.get(phase).pop(); + // If no more additional phases are available, remove it from the map + // and let the next add, reput the key + if (this.extraPhases.get(phase).isEmpty()) { + this.extraPhases.remove(phase); + } + this.phase = nextPhase; + sb.append("Additional Phase"); + } else { + this.phase = phase.getNextPhase(); + sb.append("Phase"); + } } - game.getGameLog().add("Phase", this.getPlayerTurn() + " " + this.getPhase().Name, 6); + game.getGameLog().add(sb.toString(), this.getPlayerTurn() + " " + this.getPhase().Name, 6); // **** Anything BELOW Here is actually in the next phase. Maybe move // this to handleBeginPhase @@ -659,15 +664,20 @@ public class PhaseHandler extends MyObservable implements java.io.Serializable { return this.extraTurns.push(new ExtraTurn(player)); } - /** *

- * addExtraCombat. + * addExtraPhase. *

+ * */ - public final void addExtraCombat() { - // Extra combats can only happen - this.extraCombats++; + public final void addExtraPhase(final PhaseType afterPhase, final PhaseType extraPhase) { + // 300.7. Some effects can add phases to a turn. They do this by adding the phases directly after the specified phase. + // If multiple extra phases are created after the same phase, the most recently created phase will occur first. + if (!this.extraPhases.containsKey(afterPhase)) { + this.extraPhases.put(afterPhase, new Stack()); + } + + this.extraPhases.get(afterPhase).push(extraPhase); } /** diff --git a/src/main/java/forge/game/phase/PhaseType.java b/src/main/java/forge/game/phase/PhaseType.java index 737264ec6e2..75616ee2b62 100644 --- a/src/main/java/forge/game/phase/PhaseType.java +++ b/src/main/java/forge/game/phase/PhaseType.java @@ -105,7 +105,7 @@ public enum PhaseType { } /** - * TODO: Write javadoc for this method. + * Get the next PhaseType in turn order. * @return */ public PhaseType getNextPhase() {