From f27b3e469a5493ea062ff54de3ffd6c9743c8cf3 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Mon, 20 Jan 2014 18:01:12 +0000 Subject: [PATCH] last call to gui eliminated in game code, will try to extract module next --- .gitattributes | 2 +- .../game/ability/effects/ManaEffect.java | 53 +- .../ability/effects/ManaReflectedEffect.java | 4 +- .../main/java/forge/gui/player/HumanPlay.java | 1 - .../player}/HumanPlaySpellAbility.java | 469 +++++++++--------- 5 files changed, 264 insertions(+), 265 deletions(-) rename forge-gui/src/main/java/forge/{game/spellability => gui/player}/HumanPlaySpellAbility.java (94%) diff --git a/.gitattributes b/.gitattributes index 10a443eddd3..31542bc92b4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15132,7 +15132,6 @@ forge-gui/src/main/java/forge/game/spellability/AbilityManaPart.java svneol=nati forge-gui/src/main/java/forge/game/spellability/AbilityStatic.java svneol=native#text/plain forge-gui/src/main/java/forge/game/spellability/AbilitySub.java svneol=native#text/plain forge-gui/src/main/java/forge/game/spellability/AbilityTriggered.java svneol=native#text/plain -forge-gui/src/main/java/forge/game/spellability/HumanPlaySpellAbility.java svneol=native#text/plain forge-gui/src/main/java/forge/game/spellability/ISpellAbility.java -text forge-gui/src/main/java/forge/game/spellability/OptionalCost.java -text forge-gui/src/main/java/forge/game/spellability/Spell.java svneol=native#text/plain @@ -15448,6 +15447,7 @@ forge-gui/src/main/java/forge/gui/menus/MenuUtil.java -text forge-gui/src/main/java/forge/gui/package-info.java svneol=native#text/plain forge-gui/src/main/java/forge/gui/player/HumanCostDecision.java -text forge-gui/src/main/java/forge/gui/player/HumanPlay.java -text +forge-gui/src/main/java/forge/gui/player/HumanPlaySpellAbility.java -text forge-gui/src/main/java/forge/gui/player/LobbyPlayerHuman.java -text forge-gui/src/main/java/forge/gui/player/PlayerControllerHuman.java -text forge-gui/src/main/java/forge/gui/player/TargetSelection.java svneol=native#text/plain diff --git a/forge-gui/src/main/java/forge/game/ability/effects/ManaEffect.java b/forge-gui/src/main/java/forge/game/ability/effects/ManaEffect.java index a37e2039870..b517c913fc5 100644 --- a/forge-gui/src/main/java/forge/game/ability/effects/ManaEffect.java +++ b/forge-gui/src/main/java/forge/game/ability/effects/ManaEffect.java @@ -20,7 +20,6 @@ import forge.game.spellability.AbilityManaPart; import forge.game.spellability.SpellAbility; import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; -import forge.gui.GuiChoose; public class ManaEffect extends SpellAbilityEffect { @@ -50,33 +49,31 @@ public class ManaEffect extends SpellAbilityEffect { if (activator.isHuman()) { //String colorsNeeded = abMana.getExpressChoice(); String[] colorsProduced = abMana.getComboColors().split(" "); + + final StringBuilder choiceString = new StringBuilder(); - List colorMenu = null; + ColorSet colorOptions = null; if (!abMana.isAnyMana()) { - colorMenu = new ArrayList(); - //loop through colors to make menu - for (int nColor = 0; nColor < colorsProduced.length; nColor++) { - colorMenu.add(forge.card.MagicColor.toLongString(colorsProduced[nColor])); - } + colorOptions = ColorSet.fromNames(colorsProduced); } else { - colorMenu = MagicColor.Constant.ONLY_COLORS; + colorOptions = ColorSet.fromNames(MagicColor.Constant.ONLY_COLORS); } for (int nMana = 1; nMana <= amount; nMana++) { String choice = ""; - Object o = GuiChoose.one("Select Mana to Produce", colorMenu); - if (o == null) { - final StringBuilder sb = new StringBuilder(); - sb.append("AbilityFactoryMana::manaResolve() - Human color mana choice is empty for "); - sb.append(card.getName()); - throw new RuntimeException(sb.toString()); - } else { - choice = MagicColor.toShortString((String) o); - if (nMana != 1) { - choiceString.append(" "); - } - choiceString.append(choice); + byte chosenColor = activator.getController().chooseColor("Select Mana to Produce", sa, colorOptions); + if (chosenColor == 0) { + final StringBuilder sb = new StringBuilder(); + sb.append("AbilityFactoryMana::manaResolve() - Human color mana choice is empty for "); + sb.append(card.getName()); + throw new RuntimeException(sb.toString()); + } else { + choice = MagicColor.toShortString(chosenColor); + if (nMana != 1) { + choiceString.append(" "); } + choiceString.append(choice); + } } abMana.setExpressChoice(choiceString.toString()); } @@ -116,26 +113,26 @@ public class ManaEffect extends SpellAbilityEffect { choice = colorsNeeded; } else { - List colorMenu = null; + ColorSet colorMenu = null; if (colorsNeeded.length() > 1 && colorsNeeded.length() < 5) { - colorMenu = new ArrayList(); + byte mask = 0; //loop through colors to make menu for (int nChar = 0; nChar < colorsNeeded.length(); nChar++) { - colorMenu.add(forge.card.MagicColor.toLongString(colorsNeeded.substring(nChar, nChar + 1))); + mask |= forge.card.MagicColor.fromName(colorsNeeded.substring(nChar, nChar + 1)); } + colorMenu = ColorSet.fromMask(mask); } else { - colorMenu = MagicColor.Constant.ONLY_COLORS; + colorMenu = ColorSet.fromNames(MagicColor.Constant.ONLY_COLORS); } - String s = GuiChoose.one("Select Mana to Produce", colorMenu); - if (s == null) { + byte val = act.getController().chooseColor("Select Mana to Produce", sa, colorMenu); + if (0 == val) { final StringBuilder sb = new StringBuilder(); sb.append("AbilityFactoryMana::manaResolve() - Human color mana choice is empty for "); sb.append(card.getName()); throw new RuntimeException(sb.toString()); - } else { - choice = MagicColor.toShortString(s); } + choice = MagicColor.toShortString(val); } abMana.setExpressChoice(choice); } diff --git a/forge-gui/src/main/java/forge/game/ability/effects/ManaReflectedEffect.java b/forge-gui/src/main/java/forge/game/ability/effects/ManaReflectedEffect.java index e112e0689b8..29f9d837fc7 100644 --- a/forge-gui/src/main/java/forge/game/ability/effects/ManaReflectedEffect.java +++ b/forge-gui/src/main/java/forge/game/ability/effects/ManaReflectedEffect.java @@ -3,6 +3,7 @@ package forge.game.ability.effects; import java.util.Collection; import java.util.List; +import forge.card.ColorSet; import forge.card.MagicColor; import forge.game.ability.AbilityUtils; import forge.game.ability.SpellAbilityEffect; @@ -10,7 +11,6 @@ import forge.game.card.CardUtil; import forge.game.player.Player; import forge.game.spellability.AbilityManaPart; import forge.game.spellability.SpellAbility; -import forge.gui.GuiChoose; public class ManaReflectedEffect extends SpellAbilityEffect { @@ -65,7 +65,7 @@ public class ManaReflectedEffect extends SpellAbilityEffect { baseMana = MagicColor.toShortString(colors.iterator().next()); } else { if (player.isHuman()) { - baseMana = GuiChoose.one("Select Mana to Produce", colors); + baseMana = MagicColor.toShortString(player.getController().chooseColor("Select Mana to Produce", sa, ColorSet.fromNames(colors))); } else { // AI doesn't really have anything here yet baseMana = sa.getManaPart().getExpressChoice(); diff --git a/forge-gui/src/main/java/forge/gui/player/HumanPlay.java b/forge-gui/src/main/java/forge/gui/player/HumanPlay.java index de2f53312a4..4f3bfa18756 100644 --- a/forge-gui/src/main/java/forge/gui/player/HumanPlay.java +++ b/forge-gui/src/main/java/forge/gui/player/HumanPlay.java @@ -52,7 +52,6 @@ import forge.game.cost.PaymentDecision; import forge.game.mana.ManaCostBeingPaid; import forge.game.player.Player; import forge.game.spellability.Ability; -import forge.game.spellability.HumanPlaySpellAbility; import forge.game.spellability.SpellAbility; import forge.game.spellability.TargetRestrictions; import forge.game.zone.ZoneType; diff --git a/forge-gui/src/main/java/forge/game/spellability/HumanPlaySpellAbility.java b/forge-gui/src/main/java/forge/gui/player/HumanPlaySpellAbility.java similarity index 94% rename from forge-gui/src/main/java/forge/game/spellability/HumanPlaySpellAbility.java rename to forge-gui/src/main/java/forge/gui/player/HumanPlaySpellAbility.java index a0cef29fd44..08ef922dc49 100644 --- a/forge-gui/src/main/java/forge/game/spellability/HumanPlaySpellAbility.java +++ b/forge-gui/src/main/java/forge/gui/player/HumanPlaySpellAbility.java @@ -1,233 +1,236 @@ -/* - * Forge: Play Magic: the Gathering. - * Copyright (C) 2011 Forge Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package forge.game.spellability; - -import java.util.ArrayList; - -import org.apache.commons.lang3.StringUtils; - -import com.google.common.collect.Iterables; - -import forge.card.CardType; -import forge.game.Game; -import forge.game.GameObject; -import forge.game.ability.AbilityUtils; -import forge.game.card.Card; -import forge.game.cost.CostPartMana; -import forge.game.cost.CostPayment; -import forge.game.player.Player; -import forge.game.player.PlayerController; -import forge.game.zone.Zone; -import forge.gui.player.HumanCostDecision; - -/** - *

- * SpellAbility_Requirements class. - *

- * - * @author Forge - * @version $Id$ - */ -public class HumanPlaySpellAbility { - private final SpellAbility ability; - private final CostPayment payment; - - public HumanPlaySpellAbility(final SpellAbility sa, final CostPayment cp) { - this.ability = sa; - this.payment = cp; - } - - public final void playAbility(boolean mayChooseTargets, boolean isFree, boolean skipStack) { - final Player human = ability.getActivatingPlayer(); - final Game game = ability.getActivatingPlayer().getGame(); - - // used to rollback - Zone fromZone = null; - int zonePosition = 0; - - final Card c = this.ability.getSourceCard(); - if (this.ability instanceof Spell && !c.isCopiedSpell()) { - fromZone = game.getZoneOf(c); - zonePosition = fromZone.getCards().indexOf(c); - this.ability.setSourceCard(game.getAction().moveToStack(c)); - } - - // freeze Stack. No abilities should go onto the stack while I'm filling requirements. - game.getStack().freezeStack(); - - // This line makes use of short-circuit evaluation of boolean values, that is each subsequent argument - // is only executed or evaluated if the first argument does not suffice to determine the value of the expression - boolean prerequisitesMet = this.announceValuesLikeX() - && this.announceType() - && (!mayChooseTargets || setupTargets()) // if you can choose targets, then do choose them. - && (isFree || this.payment.payCost(new HumanCostDecision(human, ability, ability.getSourceCard()))); - - if (!prerequisitesMet) { - if (!ability.isTrigger()) { - rollbackAbility(fromZone, zonePosition); - if (ability.isMadness()) { - // if a player failed to play madness cost, move the card to graveyard - game.getAction().moveToGraveyard(c); - ability.setMadness(false); - } else if (ability.getSourceCard().isBestowed()) { - ability.getSourceCard().unanimateBestow(); - } - } - return; - } - - if (isFree || this.payment.isFullyPaid()) { - if (skipStack) { - AbilityUtils.resolve(this.ability); - } - else { - this.enusureAbilityHasDescription(this.ability); - this.ability.getActivatingPlayer().getManaPool().clearManaPaid(this.ability, false); - game.getStack().addAndUnfreeze(this.ability); - } - - // no worries here. The same thread must resolve, and by this moment ability will have been resolved already - // Triggers haven't resolved yet ?? - if (mayChooseTargets) { - clearTargets(ability); - } - } - } - - private final boolean setupTargets() { - // Skip to paying if parent ability doesn't target and has no subAbilities. - // (or trigger case where its already targeted) - SpellAbility currentAbility = ability; - final Card source = ability.getSourceCard(); - do { - TargetRestrictions tgt = currentAbility.getTargetRestrictions(); - if (tgt != null && tgt.doesTarget()) { - clearTargets(currentAbility); - Player targetingPlayer = ability.hasParam("TargetingPlayer") ? - AbilityUtils.getDefinedPlayers(source, ability.getParam("TargetingPlayer"), currentAbility).get(0) : ability.getActivatingPlayer(); - - if (!targetingPlayer.getController().chooseTargetsFor(currentAbility)) - return false; - } - final SpellAbility subAbility = currentAbility.getSubAbility(); - if (subAbility != null) { - // This is necessary for "TargetsWithDefinedController$ ParentTarget" - ((AbilitySub) subAbility).setParent(currentAbility); - } - currentAbility = subAbility; - } while (currentAbility != null); - return true; - } - - public final void clearTargets(SpellAbility ability) { - TargetRestrictions tg = ability.getTargetRestrictions(); - if (tg != null) { - ability.resetTargets(); - tg.calculateStillToDivide(ability.getParam("DividedAsYouChoose"), ability.getSourceCard(), ability); - } - } - - private void rollbackAbility(Zone fromZone, int zonePosition) { - // cancel ability during target choosing - final Game game = ability.getActivatingPlayer().getGame(); - - if (fromZone != null) { // and not a copy - // add back to where it came from - game.getAction().moveTo(fromZone, ability.getSourceCard(), zonePosition >= 0 ? Integer.valueOf(zonePosition) : null); - } - - clearTargets(ability); - - this.ability.resetOnceResolved(); - this.payment.refundPayment(); - game.getStack().clearFrozen(); - } - - private boolean announceValuesLikeX() { - // Announcing Requirements like Choosing X or Multikicker - // SA Params as comma delimited list - String announce = ability.getParam("Announce"); - if (announce != null) { - for(String aVar : announce.split(",")) { - String varName = aVar.trim(); - - boolean isX = "X".equalsIgnoreCase(varName); - CostPartMana manaCost = ability.getPayCosts().getCostMana(); - boolean allowZero = !ability.hasParam("XCantBe0") && (!isX || manaCost == null || manaCost.canXbe0()); - - Integer value = ability.getActivatingPlayer().getController().announceRequirements(ability, varName, allowZero); - if (value == null) { - return false; - } - - ability.setSVar(varName, value.toString()); - if ("Multikicker".equals(varName)) { - ability.getSourceCard().setKickerMagnitude(value); - } - else { - ability.getSourceCard().setSVar(varName, value.toString()); - } - } - } - return true; - } - - private boolean announceType() { - // Announcing Requirements like choosing creature type or number - String announce = ability.getParam("AnnounceType"); - PlayerController pc = ability.getActivatingPlayer().getController(); - if (announce != null) { - for(String aVar : announce.split(",")) { - String varName = aVar.trim(); - if ("CreatureType".equals(varName)) { - String choice = pc.chooseSomeType("Creature", ability, CardType.getCreatureTypes(), new ArrayList()); - ability.getSourceCard().setChosenType(choice); - } - if ("ChooseNumber".equals(varName)) { - int min = Integer.parseInt(ability.getParam("Min")); - int max = Integer.parseInt(ability.getParam("Max")); - int i = ability.getActivatingPlayer().getController().chooseNumber(ability, - "Choose a number", min, max); - ability.getSourceCard().setChosenNumber(i); - } - } - } - return true; - } - - private void enusureAbilityHasDescription(SpellAbility ability) { - if (!StringUtils.isBlank(ability.getStackDescription())) { - return; - } - - // For older abilities that don't setStackDescription set it here - final StringBuilder sb = new StringBuilder(); - sb.append(ability.getSourceCard().getName()); - if (ability.getTargetRestrictions() != null) { - final Iterable targets = ability.getTargets().getTargets(); - if (!Iterables.isEmpty(targets)) { - sb.append(" - Targeting "); - for (final GameObject o : targets) { - sb.append(o.toString()).append(" "); - } - } - } - - ability.setStackDescription(sb.toString()); - } -} +/* + * Forge: Play Magic: the Gathering. + * Copyright (C) 2011 Forge Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package forge.gui.player; + +import java.util.ArrayList; + +import org.apache.commons.lang3.StringUtils; + +import com.google.common.collect.Iterables; + +import forge.card.CardType; +import forge.game.Game; +import forge.game.GameObject; +import forge.game.ability.AbilityUtils; +import forge.game.card.Card; +import forge.game.cost.CostPartMana; +import forge.game.cost.CostPayment; +import forge.game.player.Player; +import forge.game.player.PlayerController; +import forge.game.spellability.AbilitySub; +import forge.game.spellability.Spell; +import forge.game.spellability.SpellAbility; +import forge.game.spellability.TargetRestrictions; +import forge.game.zone.Zone; + +/** + *

+ * SpellAbility_Requirements class. + *

+ * + * @author Forge + * @version $Id: HumanPlaySpellAbility.java 24317 2014-01-17 08:32:39Z Max mtg $ + */ +public class HumanPlaySpellAbility { + private final SpellAbility ability; + private final CostPayment payment; + + public HumanPlaySpellAbility(final SpellAbility sa, final CostPayment cp) { + this.ability = sa; + this.payment = cp; + } + + public final void playAbility(boolean mayChooseTargets, boolean isFree, boolean skipStack) { + final Player human = ability.getActivatingPlayer(); + final Game game = ability.getActivatingPlayer().getGame(); + + // used to rollback + Zone fromZone = null; + int zonePosition = 0; + + final Card c = this.ability.getSourceCard(); + if (this.ability instanceof Spell && !c.isCopiedSpell()) { + fromZone = game.getZoneOf(c); + zonePosition = fromZone.getCards().indexOf(c); + this.ability.setSourceCard(game.getAction().moveToStack(c)); + } + + // freeze Stack. No abilities should go onto the stack while I'm filling requirements. + game.getStack().freezeStack(); + + // This line makes use of short-circuit evaluation of boolean values, that is each subsequent argument + // is only executed or evaluated if the first argument does not suffice to determine the value of the expression + boolean prerequisitesMet = this.announceValuesLikeX() + && this.announceType() + && (!mayChooseTargets || setupTargets()) // if you can choose targets, then do choose them. + && (isFree || this.payment.payCost(new HumanCostDecision(human, ability, ability.getSourceCard()))); + + if (!prerequisitesMet) { + if (!ability.isTrigger()) { + rollbackAbility(fromZone, zonePosition); + if (ability.isMadness()) { + // if a player failed to play madness cost, move the card to graveyard + game.getAction().moveToGraveyard(c); + ability.setMadness(false); + } else if (ability.getSourceCard().isBestowed()) { + ability.getSourceCard().unanimateBestow(); + } + } + return; + } + + if (isFree || this.payment.isFullyPaid()) { + if (skipStack) { + AbilityUtils.resolve(this.ability); + } + else { + this.enusureAbilityHasDescription(this.ability); + this.ability.getActivatingPlayer().getManaPool().clearManaPaid(this.ability, false); + game.getStack().addAndUnfreeze(this.ability); + } + + // no worries here. The same thread must resolve, and by this moment ability will have been resolved already + // Triggers haven't resolved yet ?? + if (mayChooseTargets) { + clearTargets(ability); + } + } + } + + private final boolean setupTargets() { + // Skip to paying if parent ability doesn't target and has no subAbilities. + // (or trigger case where its already targeted) + SpellAbility currentAbility = ability; + final Card source = ability.getSourceCard(); + do { + TargetRestrictions tgt = currentAbility.getTargetRestrictions(); + if (tgt != null && tgt.doesTarget()) { + clearTargets(currentAbility); + Player targetingPlayer = ability.hasParam("TargetingPlayer") ? + AbilityUtils.getDefinedPlayers(source, ability.getParam("TargetingPlayer"), currentAbility).get(0) : ability.getActivatingPlayer(); + + if (!targetingPlayer.getController().chooseTargetsFor(currentAbility)) + return false; + } + final SpellAbility subAbility = currentAbility.getSubAbility(); + if (subAbility != null) { + // This is necessary for "TargetsWithDefinedController$ ParentTarget" + ((AbilitySub) subAbility).setParent(currentAbility); + } + currentAbility = subAbility; + } while (currentAbility != null); + return true; + } + + public final void clearTargets(SpellAbility ability) { + TargetRestrictions tg = ability.getTargetRestrictions(); + if (tg != null) { + ability.resetTargets(); + tg.calculateStillToDivide(ability.getParam("DividedAsYouChoose"), ability.getSourceCard(), ability); + } + } + + private void rollbackAbility(Zone fromZone, int zonePosition) { + // cancel ability during target choosing + final Game game = ability.getActivatingPlayer().getGame(); + + if (fromZone != null) { // and not a copy + // add back to where it came from + game.getAction().moveTo(fromZone, ability.getSourceCard(), zonePosition >= 0 ? Integer.valueOf(zonePosition) : null); + } + + clearTargets(ability); + + this.ability.resetOnceResolved(); + this.payment.refundPayment(); + game.getStack().clearFrozen(); + } + + private boolean announceValuesLikeX() { + // Announcing Requirements like Choosing X or Multikicker + // SA Params as comma delimited list + String announce = ability.getParam("Announce"); + if (announce != null) { + for(String aVar : announce.split(",")) { + String varName = aVar.trim(); + + boolean isX = "X".equalsIgnoreCase(varName); + CostPartMana manaCost = ability.getPayCosts().getCostMana(); + boolean allowZero = !ability.hasParam("XCantBe0") && (!isX || manaCost == null || manaCost.canXbe0()); + + Integer value = ability.getActivatingPlayer().getController().announceRequirements(ability, varName, allowZero); + if (value == null) { + return false; + } + + ability.setSVar(varName, value.toString()); + if ("Multikicker".equals(varName)) { + ability.getSourceCard().setKickerMagnitude(value); + } + else { + ability.getSourceCard().setSVar(varName, value.toString()); + } + } + } + return true; + } + + private boolean announceType() { + // Announcing Requirements like choosing creature type or number + String announce = ability.getParam("AnnounceType"); + PlayerController pc = ability.getActivatingPlayer().getController(); + if (announce != null) { + for(String aVar : announce.split(",")) { + String varName = aVar.trim(); + if ("CreatureType".equals(varName)) { + String choice = pc.chooseSomeType("Creature", ability, CardType.getCreatureTypes(), new ArrayList()); + ability.getSourceCard().setChosenType(choice); + } + if ("ChooseNumber".equals(varName)) { + int min = Integer.parseInt(ability.getParam("Min")); + int max = Integer.parseInt(ability.getParam("Max")); + int i = ability.getActivatingPlayer().getController().chooseNumber(ability, + "Choose a number", min, max); + ability.getSourceCard().setChosenNumber(i); + } + } + } + return true; + } + + private void enusureAbilityHasDescription(SpellAbility ability) { + if (!StringUtils.isBlank(ability.getStackDescription())) { + return; + } + + // For older abilities that don't setStackDescription set it here + final StringBuilder sb = new StringBuilder(); + sb.append(ability.getSourceCard().getName()); + if (ability.getTargetRestrictions() != null) { + final Iterable targets = ability.getTargets().getTargets(); + if (!Iterables.isEmpty(targets)) { + sb.append(" - Targeting "); + for (final GameObject o : targets) { + sb.append(o.toString()).append(" "); + } + } + } + + ability.setStackDescription(sb.toString()); + } +}